I have pixel data in memory along with a palette. I want to draw these to a client window, so I use CreateDIBSection().
The pixel data is an array of unsigned char (indicies into a 256 entry color palette), and the palette is an array of unsigned short (only 256 entries in the palette)
I've learned that a palette can be created by calling CreatePalette() and then calling SelectPalette(), then RealizePalette() to make it useable. However, the MSDN documentation for the BITMAPINFO::bmiColors member confuses me. I can't seem to set the bmiColors member anyway, since the definition is a static array with a single element: RGBQUAD bmiColors[1];. The compiler spits errors at me if I try to assign a static array or a dynamic pointer to this member. Am I supposed to put the palette in the bmiColors member, or am I supposed to create an HPALETTE? How do I assign a value to bmiColors when it's an array with a single element? Here is what I have so far:
This is as far as I have been able to get. Could someone explain where I am to put my palette? This is very confusing. Thanks.
MikeAThon
September 15th, 2006, 02:14 PM
Your palette goes right after the BITMAPINFOHEADER member of the BITMAPINFO structure. It's an an array of RGBQUAD structures, and it comprises the bmiColors member of the BITMAPINFO structure.
See http://msdn.microsoft.com/library/en-us/gdi/bitmaps_5f8y.asp
Mike
MrDoomMaster
September 15th, 2006, 03:48 PM
Thanks for the info.
I still can't get the bitmaps to draw properly. Currently they draw as yellow squares.
CBitmap* TileWindow::CreateWindowsBitmap( const HDC dc, const unsigned char* bits, int w, int h, const unsigned short* palette )
{
// This function is particularly slow, many optimizations could be made.
// The speed difference will probably not be very noticable.
SIBITMAPINFO bi = {0};
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biBitCount = 8;
bi.bmiHeader.biWidth = w;
bi.bmiHeader.biHeight = h;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biCompression = BI_RGB;
for( int i = 0; i < 256; ++i )
{
unsigned char r, g, b;
MAKE_RGB32( palette[i], r, g, b );
bi.bmiColor[i].rgbRed = r;
bi.bmiColor[i].rgbGreen = g;
bi.bmiColor[i].rgbBlue = b;
bi.bmiColor[i].rgbReserved = 0;
}
Mike
This has changed all bitmaps from drawing in yellow to pink, which is the first color in my palette. Index 0 in the palette is RGB( 255, 0, 255 );
Getting closer, but why are the bitmap pixels not drawing the correct color? I've stepped through the arrays in runtime, and the pixel data references various indexes in the palette, not just index 0. Pixels that reference index 94, for example, are drawing pink... which is index 0.
I checked the palette data as well, other palette indicies are the correct colors (not pink!).
MikeAThon
September 15th, 2006, 08:17 PM
OK, here's another stab at it:
return CBitmap::FromHandle( CreateDIBSection( dc, (BITMAPINFO*)&bi, DIB_RGB_COLORS, (void**)&bits, 0, 0 ) );
But in looking at the documentation for CreateDIBSection, I think that it's being used incorrectly. In CreateDIBSection, the fourth parameter, "ppvBits", is an output parameter, namely a pointer to a variable that receives a pointer to the location of the DIB bit values. From what you have described, you already have the DIB bit values, and you want to get a DDB for displaying them.
I think that after calling the function, you should be copying your bit values to the address pointed to by the returned ppvBits parameter. E.g.,
char* pBits;
HANDLE hBM = CreateDIBSection( dc, (BITMAPINFO*)&bi, DIB_RGB_COLORS, (void**)&pBits, 0, 0 );
memcpy( pBits, bits, <Number to copy> );
return CBitmap::FromHandle( bBM );
If I get time, I will check some archived code that does something similar, to see how it was done there.
Mike
MikeAThon
September 17th, 2006, 01:24 PM
The following code worked for me, in the OnDraw() handler of an MDI app:
void CPalettedDIBView::OnDraw(CDC* pDC)
{
CPalettedDIBDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
struct SIBITMAPINFO
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColor[3]; //exactly three colors in the palette
};
SIBITMAPINFO bi = {0};
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bi.bmiHeader.biWidth = 256;
bi.bmiHeader.biHeight = 256; // positive number == bottom-up DIB
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = 8;
bi.bmiHeader.biCompression = BI_RGB;
bi.bmiHeader.biClrUsed = 3; // only three colors are in the palette
// define the three colors in the palette (R, G and B)
// Set color-index values of the pixels
// This is a bottom-up DIB, so the colors will be in horizontal bands, 64 rows high,
// in the order (bottom-up) of R, G, B
for ( int iRow=0; iRow<256; ++iRow )
{
for ( int iCol=0; iCol<256; ++iCol )
{
switch ( (iRow/64)%4 )
{
case 0: *pBits = 0; break;
case 1: *pBits = 1; break;
case 2: *pBits = 2; break;
case 3: *pBits = 0; break;
}
pBits++;
}
}
// blt the DDB bitmap to the display device context