none
Bitmap LockBits results in wrong stride! RRS feed

  • Question

  • I'm trying to copy a simple byte array to an 8bit indexed bitmap.  Using the exact same code as shown in countless answered questions on many forums, I still get the wrong result.  The data I'm trying to write to image files is 360 bytes, setup as an 18x20 byte linear array.  That is, the first 18 bytes (0-17) belong on the top row of the image, the next 18 bytes (18-35) belong on the 2nd row, etc.  I have confirmed that this data is correct, as I can manually parse it in Excel (and even visualize it by setting the background color of cells).  However, when I try to extract this using code in c#, I get a wrongly formatted image.  Here is the code...

    public Bitmap CopyByteDataToBitmap(byte[] byteData) {
        Bitmap bmp = new Bitmap(18, 20, PixelFormat.Format8bppIndexed);
        BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, bmp.PixelFormat);
        Marshal.Copy(byteData, 0, bmpData.Scan0, byteData.Length);
        bmp.UnlockBits(bmpData);

        return bmp;
    }

    The result is as follows.  The first row is written correctly.  However, the starting with the second row, there is a 2 byte offset.  That is, the first byte of the second row of the image ends up being byte #20 instead of byte #18 (starting from 0).  Also, if I set a breakpoint immediately after the LockBits call, I can see that the bmpData is has a "Stride" property = 20... even though the width is clearly set to 18.  Why is this happening? Please help.

    Sunday, July 14, 2019 2:07 AM

All replies

  • Stride is equal or greater than Width and it includes additional unused bytes that are appended to each row in some cases.

    Since your array does not include the additional bytes, try a loop like this:

    IntPtr d = bmpData.Scan0;

    for( int y = 0; y < bmp.Height; ++y )

    {

        Marshal.Copy( byteData, y * bmp.Width, d, bmp.Width );

        d += bmpData.Stride;

    }

     

    For other kinds of images, it needs some adjustments.

    Sunday, July 14, 2019 7:33 AM
  • Thanks... you nailed it!

    Sunday, July 14, 2019 4:55 PM
  • Viorel told you there might be padding, but not how it is computed.  It is, in fact, easy to compute the stride for any bitmap.  Each scanline in a Windows bitmap is padded out to an even dword boundary, so it's always a multiple of 4 bytes.  So, your 18x10 bitmap at 8 bpp needs to round up to 20 bytes.


    Tim Roberts | Driver MVP Emeritus | Providenza &amp; Boekelheide, Inc.

    Monday, July 15, 2019 6:41 AM