Bitterblue
Bitterblue

Reputation: 14075

WinApi - Byte Array to Gray 8-bit Bitmap (+Performance)

I have a byte array that needs to be displayed on the desktop (or Form). I'm using WinApi for that and not sure how to set all pixels at once. The byte array is in my memory and needs to be displayed as quickly as possible (with just WinApi).

I'm using C# but simple pseudo-code would be ok for me:

// create bitmap
byte[] bytes = ...;// contains pixel data, 1 byte per pixel
HDC desktopDC = GetWindowDC(GetDesktopWindow());
HDC bitmapDC = CreateCompatibleDC(desktopDC);
HBITMAP bitmap = CreateCompatibleBitmap(bitmapDC, 320, 240);
DeleteObject(SelectObject(bitmapDC, bitmap));

BITMAPINFO info = new BITMAPINFO();
info.bmiColors = new tagRGBQUAD[256];
for (int i = 0; i < info.bmiColors.Length; i++)
{
    info.bmiColors[i].rgbRed = (byte)i;
    info.bmiColors[i].rgbGreen = (byte)i;
    info.bmiColors[i].rgbBlue = (byte)i;
    info.bmiColors[i].rgbReserved = 0;
}
info.bmiHeader = new BITMAPINFOHEADER();
info.bmiHeader.biSize = (uint) Marshal.SizeOf(info.bmiHeader);
info.bmiHeader.biWidth = 320;
info.bmiHeader.biHeight = 240;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biBitCount = 8;
info.bmiHeader.biCompression = BI_RGB;
info.bmiHeader.biSizeImage = 0;
info.bmiHeader.biClrUsed = 256;
info.bmiHeader.biClrImportant = 0;
// next line throws wrong parameter exception all the time
// SetDIBits(bitmapDC, bh, 0, 240, Marshal.UnsafeAddrOfPinnedArrayElement(info.bmiColors, 0), ref info, DIB_PAL_COLORS);

// how do i store all pixels into the bitmap at once ?
for (int i = 0; i < bytes.Length;i++)
    SetPixel(bitmapDC, i % 320, i / 320, random(0x1000000));

// draw the bitmap
BitBlt(desktopDC, 0, 0, 320, 240, bitmapDC, 0, 0, SRCCOPY);

When I just try to set each pixel by itself with SetPixel() I see a monochrome image without gray colors only black and white. How can I correctly create a gray scale bitmap for displaying ? And how do I do that quick ?


Update: The call ends up in an error outside of my program in WinApi. Can't catch exception:

public const int DIB_RGB_COLORS = 0;
public const int DIB_PAL_COLORS = 1;

[DllImport("gdi32.dll")]
public static extern int SetDIBits(IntPtr hdc, IntPtr hbmp, uint uStartScan, uint cScanLines, byte[] lpvBits, [In] ref BITMAPINFO lpbmi, uint fuColorUse);

// parameters as above
SetDIBits(bitmapDC, bitmap, 0, 240, bytes, ref info, DIB_RGB_COLORS);

Upvotes: 0

Views: 1250

Answers (1)

arx
arx

Reputation: 16896

Two of the SetDIBits parameters are wrong:

  • lpvBits - this is the image data but you're passing the palette data. You should be passing your bytes array.
  • lpBmi - this is OK - the BITMAPINFO structure contains both the BITMAPINFOHEADER and the palette so you don't need to pass the palette separately. My answer to your other question describes how to declare the structure.
  • fuColorUse - this describes the format of the palette. You are using an RGB palette so you should pass DIB_RGB_COLORS.

Upvotes: 1

Related Questions