2009-12-31 10 views
7

estoy tratando de conseguir un mapa de bits creado a partir de los datos en bruto para mostrar en WPF, mediante el uso de una imagen y un BitmapSource:¿Por qué BitmapSource.Create lanza una ArgumentException?

Int32[] data = new Int32[RenderHeight * RenderWidth]; 

for (Int32 i = 0; i < RenderHeight; i++) 
{ 
    for (Int32 j = 0; j < RenderWidth; j++) 
    { 
     Int32 index = j + (i * RenderHeight); 

     if (i + j % 2 == 0) 
      data[index] = 0xFF0000; 
     else 
      data[index] = 0x00FF00; 
    } 
} 

BitmapSource source = BitmapSource.Create(RenderWidth, RenderHeight, 96.0, 96.0, PixelFormats.Bgr32, null, data, 0); 

RenderImage.Source = source; 

Sin embargo, la llamada a BitmapSource.Create lanza una excepción ArgumentException, diciendo "Valor no lo hace caer dentro del rango esperado ". ¿No es esta la manera de hacer esto? ¿No estoy haciendo esa llamada correctamente?

Respuesta

35

Su paso es incorrecto. Stride es la cantidad de bytes asignados para una línea de exploración del mapa de bits . Por lo tanto, utilizar lo siguiente:

int stride = ((RenderWidth * 32 + 31) & ~31)/8; 

y sustituir el último parámetro (actualmente 0) con stride como se definió anteriormente.

Aquí es una explicación para la misteriosa fórmula zancada:

Hecho: Scanlines deben estar alineados en límites de 32 bits (reference).

La fórmula ingenua para el número de bytes por línea de barrido sería:

(width * bpp)/8 

Pero esto no nos puede dar un mapa de bits alineados en un límite de 32 bits y (ancho * bpp) podría ni siquiera haber sido divisible por 8.

lo tanto, lo que hacemos es forzar nuestro mapa de bits para tener al menos 32 bits en una fila (suponemos que width > 0):

width * bpp + 31 

y luego decir que no importa el orden bajo los bits (bits 0 a -4), porque estamos tratando de alinear en límites de 32 bits:

(width * bpp + 31) & ~31 

y luego dividir por 8 para volver a bytes:

((width * bpp + 31) & ~31)/8 

El relleno puede ser calculado por

int padding = stride - (((width * bpp) + 7)/8) 

La fórmula ingenuo sería

stride - ((width * bpp)/8) 

Pero width * bpp podría no alinearse en un límite de bytes y, cuando no lo haga, esta fórmula contará más el relleno por un byte. (Piense en un mapa de bits de 1 píxel de ancho usando 1 bpp. El paso es 4 y la fórmula ingenua diría que el relleno es 4 pero en realidad es 3.) Así que agregamos un poco para cubrir el caso de que width * bpp no es un límite de bytes y luego obtenemos la fórmula correcta dada anteriormente.

+0

Gracias, pero ¿cómo diablos se te ocurrió esa expresión? ¿Por qué no es simplemente RenderWidth * 4? ¿No es esa la cantidad de bytes para una línea? –

+1

Disculpa, debería haber proporcionado detalles. En su caso tiene 'bpp = 32' así que sí, la fórmula se reduce a' RenderWidth * 4'. Pero hay casos extraños (los LCD baratos usan 18 bpp) y el hecho de que las líneas de exploración deben alinearse en los límites de 32 bits. Proporcioné la fórmula general y una explicación de cómo encontrarla arriba. Espero que sea dilucidante. – jason

+1

Gracias. Una pregunta más. ¿Qué hace la tilde en un número como ese? –

Cuestiones relacionadas