Why Must "Stride" in the System.Drawing.Bitmap Constructor Be a Multiple of 4

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

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);

C# Bitmap: Parameter is invalid on sizes that aren't a power of 2

Micke is right, the main reason is that in 32 bit size of register is 4 byte so to optimize speed and efficiency it should be multiple of 4,
Source

Application crash while Bitmap image assign to Picturebox in Winforms

You are using a raw pointer there. Where does that come from? It is advised to use managed arrays, unless you can be 100% sure that that pointer will remain valid.

If it comes from a LockBits operation on another image, it will not remain valid; it will stop being reliable from the moment the other image is unlocked.

If you are planning to clone or edit an 8bpp image, it is much safer to copy the contents of the images you're manipulating into normal managed Byte[] arrays, using LockBits and Marshal.Copy, and to copy them back into Bitmap objects the same way, rather than using pointers directly.

These pieces of code should set you on your way:

Get the backing byte array from an image:

/// <summary>
/// Gets the raw bytes from an image.
/// </summary>
/// <param name="sourceImage">The image to get the bytes from.</param>
/// <param name="stride">Stride of the retrieved image data.</param>
/// <returns>The raw bytes of the image</returns>
public static Byte[] GetImageData(Bitmap sourceImage, out Int32 stride)
{
BitmapData sourceData = sourceImage.LockBits(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly, sourceImage.PixelFormat);
stride = sourceData.Stride;
Byte[] data = new Byte[stride * sourceImage.Height];
Marshal.Copy(sourceData.Scan0, data, 0, data.Length);
sourceImage.UnlockBits(sourceData);
return data;
}

Create an image from a byte array: (rather than from a pointer)

  • A: Why must “stride” in the System.Drawing.Bitmap constructor be a multiple of 4?

And, combined and optimised:

Make a deep clone of an image to load it without any linked resources

  • A: Free file locked by new Bitmap(filePath)

Note, as for your disposing... you should never dispose an image still linked to the UI, since the next repaint of the UI will attempt to use the disposed image, which will inevitably cause a crash. The correct way to do this is to store the image reference in a variable, then make it null on the UI, and then dispose it:

 if (Picturebox1 != null && Picturebox1.Image != null)
{
Image img = Picturebox1.Image;
Picturebox1.Image = null;
img.Dispose();
}

Why does BitmapSource.Create throw an ArgumentException?

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.



Related Topics



Leave a reply



Submit