¿Por qué lanzar una excepción ArgumentException BitmapSource.Create?
-
22-09-2019 - |
Pregunta
Estoy intentando 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:
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 está dentro del rango esperado". No es esta la manera de hacer esto? ¿No estoy haciendo esa llamada correctamente?
Solución
Su zancada es incorrecta. Zancada es el número de bytes asignada a una línea de barrido de la 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 ( referencia ) .
La fórmula naive para el número de bytes por línea de exploración sería:
(width * bpp) / 8
Pero esto podría no nos dan un mapa de bits alineados en un límite de 32 bits y (ancho * bpp) podría ni siquiera han sido divisible por 8.
Por 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 decimos que no se preocupan por los bits de orden inferior (bits 0--4), porque estamos tratando de alinear en límites de 32 bits:
(width * bpp + 31) & ~31
y luego se divide 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 byte y cuando no lo hace esta fórmula sería contar sobre el relleno de un byte. (Piense en un 1 píxel de ancho de mapa de bits 1 BPP. El paso es 4 y la fórmula ingenua diría que el relleno es 4, pero en realidad es 3.) Por lo tanto añadiremos un poco para cubrir el caso de que no es un width * bpp
byte límite y entonces obtenemos la fórmula correcta dado anteriormente.