sean green
sean green

Reputation: 53

What pixel format to use with Byte array to bitmap

I have been trying to get a simple byte array in to a Picture box using c#. Most examples I tried give me parameter invalid. If I don't use a using or converter and break it out like so (see code below) I do get an image but it looks wrong (all black with some random colored dots up top).

 Bitmap bmp = new Bitmap(48, 32, PixelFormat.Format24bppRgb);
            BitmapData bmpData = bmp.LockBits(
                                 new Rectangle(0, 0, bmp.Width, bmp.Height),
                                 ImageLockMode.WriteOnly, bmp.PixelFormat);
            Marshal.Copy(blob, 0, bmpData.Scan0, blob.Length);
            bmp.UnlockBits(bmpData);
            return bmp;

The byte array looks like this.

01 c7 f0 70 3f 03 00 c3 f0 60 1e 01 80 63 ff c3 1c 71 88 21 ff c7 3c f3 8e 31 f0 c7 fc ff 86 31 f0 c7 fc ff c4 31 f0 c1 fc 3f c0 31 e0 e0 7e 0f c0 f1 e1 f8 3f 83 c0 31 e1 fe 1f e1 c6 31 e0 ff 9f f9 86 30 f0 fb 9c 79 8f 38 f0 e3 98 79 8f 38 f8 63 98 79 80 30 38 62 1c 61 80 70 10 70 3e 03 ff ff ff ff ff ff ff ff ff ff ff ff 00 7e 00 78 7f f0 88 3c 18 18 3f f0 8e 3c 7e 0f 0f c3 86 30 ff 07 87 87 c4 31 ff 87 e0 8f c0 71 ff e7 f8 0f c0 71 ff e7 f0 0f c0 71 ff e7 f0 0f c6 71 ff e7 f0 1f 86 10 ff 87 e1 1f 8f 18 ff 8f 87 87 8f 18 7f 0f 0f c3 80 1c 0c 18 3f f0 80 7e 00 38 7f f0

My image should be 192 bytes and a 48 x 32 res image. What am I doing wrong?

Upvotes: 0

Views: 1290

Answers (1)

Nyerguds
Nyerguds

Reputation: 5639

As Michael Liu commented, if your data is 192 bytes, and you need to get 32 lines of data out of that, then each line will be 6 bytes, meaning that to get 48 pixels out of such a line, you need to multiply it by 8, or, in other words, use 1 bit per pixel, which is PixelFormat.Format1bppIndexed.

As for your problems in visualizing the data, you need to take the stride into account; the actual amount of bytes per line of pixels.

Images created by the .Net framework always use a multiple of four bytes as width of each line of pixels, so the new 48x32 image you make will have 8 bytes on each line. However, your image data is completely compact data, so it only has 6 bytes per line.

So you need to copy it line by line, keeping the stride of both your input and output into account. This means you should replace the single Marshal.Copy by a loop over the height that does one Marshal.Copy per line, copying the data per 6 bytes from the input array to the correct start pointer of each line on the output.

The adjusted Marshal.Copy operation should be something like this:

Int32 newDataWidth = ((Image.GetPixelFormatSize(pixelFormat) * width) + 7) / 8;
Int32 targetStride = bmpData.Stride;
Int64 scan0 = bmpData.Scan0.ToInt64();
for (Int32 y = 0; y < height; y++)
    Marshal.Copy(blob, y * stride, new IntPtr(scan0 + y * targetStride), newDataWidth);

...with stride the stride of your input array (so in this case, 6).

To automate the input stride calculation, if you know you have completely compact data, you can use the formula I already kind of showed in the previous block:

public static Int32 GetMinimumStride(Int32 width, Int32 bitsLength)
{
    return ((bitsLength * width) + 7) / 8;
}

I already posted code here on SO to build an image from bytes in any format, so you can just use that, I guess. Using that BuildImage function, you can build your image like this:

public static Bitmap BuildMonoBitmap(Byte monoBytes, Int32 width, Int32 height)
{
    Color[] pal = new Color[] {Color.Black, Color.White};
    Int32 stride = GetMinimumStride(width, 1);
    return BuildImage(monoBytes, width, height, stride, PixelFormat.Format1bppIndexed, pal, null);
}

The result, shown in my test program:

Bliss Box

Upvotes: 1

Related Questions