Search code examples
c#constructorbitmap

Why must "stride" in the System.Drawing.Bitmap constructor be a multiple of 4?


I am writing an application that requires me to take a proprietary bitmap format (an MVTec Halcon HImage) and convert it into a System.Drawing.Bitmap in C#.

The only proprietary functions given to me to help me do this involve me writing to file, except for the use of a "get pointer" function.

This function is great, it gives me a pointer to the pixel data, the width, the height, and the type of the image.

My issue is that when I create my System.Drawing.Bitmap using the constructor:

new System.Drawing.Bitmap(width, height, stride, format, scan)

I need to specify a "stride" that is a multiple of 4. This may be a problem as I am unsure what size bitmap my function will be hit with. Supposing I end up with a bitmap that is 111x111 pixels, I have no way to run this function other than adding a bogus column to my image or subtracting 3 columns.

Is there a way I can sneak around this limitation?


Solution

  • This goes back to early CPU designs. The fastest way to crunch through the bits of the bitmap is by reading them 32-bits at a time, starting at the start of a scan line. That works best when the first byte of the scan line is aligned on a 32-bit address boundary. In other words, an address that's a multiple of 4. On early CPUs, having that first byte mis-aligned would cost extra CPU cycles to read two 32-bit words from RAM and shuffle the bytes to create the 32-bit value. Ensuring each scan line starts at an aligned address (automatic if the stride is a multiple of 4) avoids that.

    This isn't a real concern anymore on modern CPUs, now alignment to the cache line boundary is much more important. Nevertheless, the multiple of 4 requirement for stride stuck around for appcompat reasons.

    Btw, you can easily calculate the stride from the format and width with this:

            int bitsPerPixel = ((int)format & 0xff00) >> 8;
            int bytesPerPixel = (bitsPerPixel + 7) / 8;
            int stride = 4 * ((width * bytesPerPixel + 3) / 4);