Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does BitmapSource.Create throw an ArgumentException?

I'm trying to get an bitmap created from raw data to show in WPF, by using an Image and a 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;

However the call to BitmapSource.Create throws an ArgumentException, saying "Value does not fall within the expected range". Is this not the way to do this? Am I not making that call properly?

like image 929
Mike Pateras Avatar asked Dec 31 '09 03:12

Mike Pateras


1 Answers

Your stride is incorrect. Stride is the number of bytes allocated for one scanline of the bitmap. Thus, use the following:

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

and replace the last parameter (currently 0) with stride as defined above.

Here is an explanation for the mysterious stride formula:

Fact: Scanlines must be aligned on 32-bit boundaries (reference).

The naive formula for the number of bytes per scanline would be:

(width * bpp) / 8

But this might not give us a bitmap aligned on a 32-bit boundary and (width * bpp) might not even have been divisible by 8.

So, what we do is we force our bitmap to have at least 32 bits in a row (we assume that width > 0):

width * bpp + 31

and then we say that we don't care about the low-order bits (bits 0--4) because we are trying to align on 32-bit boundaries:

(width * bpp + 31) & ~31

and then divide by 8 to get back to bytes:

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

The padding can be computed by

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

The naive formula would be

stride - ((width * bpp) / 8)

But width * bpp might not align on a byte boundary and when it doesn't this formula would over count the padding by a byte. (Think of a 1 pixel wide bitmap using 1 bpp. The stride is 4 and the naive formula would say that the padding is 4 but in reality it is 3.) So we add a little bit to cover the case that width * bpp is not a byte boundary and then we get the correct formula given above.

like image 130
jason Avatar answered Oct 11 '22 06:10

jason