From: Friedel Jantzen on
Hi!

> What commands can I look up to add a palette to a bitmap. I created a
> 16 color palette because I didn't want to add in 256 colors. What I
> want to do is create a bitmap that is not just monochrome.
>
> I am looking for how to create the bitmap then attach the pixel data
> and the palette.

The bmp palette is an array of RGBQUAD, following the BITMAPINFOHEADER.
With biBitCount = 4 you provide an array
RGBQUAD palette[16];
ZeroMemory(palette, sizeof(palette));
BYTE blue = 0, green = 0, red = 0;
for(int i = 0; i < 16; i++) {
palette[i].rgbBlue = blue;
palette[i].rgbGreen = green;
palette[i].rgbRed = red;
//palette[i].rgbReserved = 0;
blue += 16; // what you want
red += 4; // "
// green ...
}

Of course you can write this array into an alloced memory block after the
header.
For the 4bit format image data 1 byte includes 2 pixel indices into the
palette. E.g. a width of 16px results in an 8 byte scanline, no padding
required in this case. The data for a height of 16 is sized 8*16 bytes
then.

> This what I have for my current bitmap.
>
> BYTE cdata[] = {0xff, 0xff, 0xff,
> 0,0,0,
> 0xff,0,0, ...
> //RGB Color data
>
> int num = 16;
> BYTE * pdata = &cdata[0];
>
> int datasz = 3*num;
> int count = 0;
>
> while(count < datasz/num ){
>
> bfo.bmColor[count].rgbRed = *pdata++;
> bfo.bmColor[count].rgbBlue = *pdata++;
> bfo.bmColor[count].rgbGreen = *pdata++;
> bfo.bmColor[count].rgbReserved = PC_NOCOLLAPSE;;
> count++;
> }
>
> (I create a palette very similar to this in DX. But I can't figure
> out how to add the palette to the bitmap.)
>
> BITMAP bitmap = {0,16,16,2,1,1};

This means a bmp width of 16, so you must write (see above):
BITMAP bitmap = {0,16,16,8,1,4};

> bitmap.bmBits = data; //Pixel data
>
> hbitmap = CreateBitmapIndirect(&bitmap);

Here you are creating a HBITMAP object (not a DIB!)

> hdc = GetDC(hwnd);
> HDC hdcmem = CreateCompatibleDC(hdc);
>
> SelectObject(hdcmem, hbitmap);

Here you select a 4bits/px hbmp into a hdcmem compatible to your window,
which could have different bits/px. I am not sure that this works, and
prefer to create the bitmap object with CreateCompatibleBitmap. But then
you cannot choose the bits/px, it is set automatically to the correct
value.

> BitBlt(hdc, 100, 150, 16, 16 , hdcmem, 0, 0,
> SRCCOPY);
>
> DeleteDC(hdcmem);
> ReleaseDC(hwnd, hdc);

Note: Your HBITMAP object is not yet deleted.

Have a look at CreateDIBSection, perhaps this fits better for your needs.

hth,
Friedel
From: JoeC on
On Dec 7, 2:19 am, Friedel Jantzen <nospam_...(a)freenet.de> wrote:
> Hi!
>
> > What commands can I look up to add a palette to a bitmap.  I created a
> > 16 color palette because I didn't want to add in 256 colors.  What I
> > want to do is create a bitmap that is not just monochrome.
>
> > I am looking for how to create the bitmap then attach the pixel data
> > and the palette.
>
> The bmp palette is an array of RGBQUAD, following the BITMAPINFOHEADER.
> With biBitCount = 4 you provide an array
> RGBQUAD palette[16];
> ZeroMemory(palette, sizeof(palette));
> BYTE blue = 0, green = 0, red = 0;
> for(int i = 0; i < 16; i++) {  
>     palette[i].rgbBlue = blue;
>     palette[i].rgbGreen = green;
>     palette[i].rgbRed = red;
>     //palette[i].rgbReserved = 0;
>     blue += 16; // what you want
>     red  +=  4; //  "
>     // green ...
>
> }
>
> Of course you can write this array into an alloced memory block after the
> header.
> For the 4bit format image data 1 byte includes 2 pixel indices into the
> palette. E.g. a width of 16px results in an 8 byte scanline, no padding
> required in this case. The data for a height of 16 is sized 8*16 bytes
> then.
>
>
>
> > This what I have for my current bitmap.
>
> >      BYTE cdata[] = {0xff, 0xff, 0xff,
> >                      0,0,0,
> >                      0xff,0,0, ...
> > //RGB Color data
>
> >      int num = 16;
> >      BYTE * pdata = &cdata[0];
>
> >      int datasz = 3*num;
> >      int count = 0;
>
> >      while(count < datasz/num ){
>
> >        bfo.bmColor[count].rgbRed       = *pdata++;
> >        bfo.bmColor[count].rgbBlue      = *pdata++;
> >        bfo.bmColor[count].rgbGreen     = *pdata++;
> >        bfo.bmColor[count].rgbReserved  = PC_NOCOLLAPSE;;
> >        count++;
> >      }
>
> > (I create a palette very similar to this in DX.  But I can't figure
> > out how to add the palette to the bitmap.)
>
> >   BITMAP bitmap = {0,16,16,2,1,1};
>
> This means a bmp width of 16, so you must write (see above):
> BITMAP bitmap = {0,16,16,8,1,4};
>
> >   bitmap.bmBits = data; //Pixel data
>
> >   hbitmap = CreateBitmapIndirect(&bitmap);
>
> Here you are creating a HBITMAP object (not a DIB!)
>
> >   hdc = GetDC(hwnd);
> >   HDC hdcmem = CreateCompatibleDC(hdc);
>
> >   SelectObject(hdcmem, hbitmap);
>
> Here you select a 4bits/px hbmp into a hdcmem compatible to your window,
> which could have different bits/px. I am not sure that this works, and
> prefer to create the bitmap object with CreateCompatibleBitmap. But then
> you cannot choose the bits/px, it is set automatically to the correct
> value.
>
> >     BitBlt(hdc, 100, 150, 16, 16 , hdcmem, 0, 0,
> > SRCCOPY);
>
> >   DeleteDC(hdcmem);
> >   ReleaseDC(hwnd, hdc);
>
> Note: Your HBITMAP object is not yet deleted.
>
> Have a look at CreateDIBSection, perhaps this fits better for your needs.
>
> hth,
>  Friedel

Thanks for the help and pointing me in the right direction. I will do
some more work and see how close I can get. I think I did try that
header from an example program I have in Petzold's book. I ran into
some trouble when I was trying to attach a palette but the header
allowed only one element in the array. I will continue to work on the
project.
From: JoeC on
On Dec 7, 2:19 am, Friedel Jantzen <nospam_...(a)freenet.de> wrote:
> Hi!
>
> > What commands can I look up to add a palette to a bitmap.  I created a
> > 16 color palette because I didn't want to add in 256 colors.  What I
> > want to do is create a bitmap that is not just monochrome.
>
> > I am looking for how to create the bitmap then attach the pixel data
> > and the palette.
>
> The bmp palette is an array of RGBQUAD, following the BITMAPINFOHEADER.
> With biBitCount = 4 you provide an array
> RGBQUAD palette[16];
> ZeroMemory(palette, sizeof(palette));
> BYTE blue = 0, green = 0, red = 0;
> for(int i = 0; i < 16; i++) {  
>     palette[i].rgbBlue = blue;
>     palette[i].rgbGreen = green;
>     palette[i].rgbRed = red;
>     //palette[i].rgbReserved = 0;
>     blue += 16; // what you want
>     red  +=  4; //  "
>     // green ...
>
> }
>
> Of course you can write this array into an alloced memory block after the
> header.
> For the 4bit format image data 1 byte includes 2 pixel indices into the
> palette. E.g. a width of 16px results in an 8 byte scanline, no padding
> required in this case. The data for a height of 16 is sized 8*16 bytes
> then.
>
>
>
> > This what I have for my current bitmap.
>
> >      BYTE cdata[] = {0xff, 0xff, 0xff,
> >                      0,0,0,
> >                      0xff,0,0, ...
> > //RGB Color data
>
> >      int num = 16;
> >      BYTE * pdata = &cdata[0];
>
> >      int datasz = 3*num;
> >      int count = 0;
>
> >      while(count < datasz/num ){
>
> >        bfo.bmColor[count].rgbRed       = *pdata++;
> >        bfo.bmColor[count].rgbBlue      = *pdata++;
> >        bfo.bmColor[count].rgbGreen     = *pdata++;
> >        bfo.bmColor[count].rgbReserved  = PC_NOCOLLAPSE;;
> >        count++;
> >      }
>
> > (I create a palette very similar to this in DX.  But I can't figure
> > out how to add the palette to the bitmap.)
>
> >   BITMAP bitmap = {0,16,16,2,1,1};
>
> This means a bmp width of 16, so you must write (see above):
> BITMAP bitmap = {0,16,16,8,1,4};
>
> >   bitmap.bmBits = data; //Pixel data
>
> >   hbitmap = CreateBitmapIndirect(&bitmap);
>
> Here you are creating a HBITMAP object (not a DIB!)
>
> >   hdc = GetDC(hwnd);
> >   HDC hdcmem = CreateCompatibleDC(hdc);
>
> >   SelectObject(hdcmem, hbitmap);
>
> Here you select a 4bits/px hbmp into a hdcmem compatible to your window,
> which could have different bits/px. I am not sure that this works, and
> prefer to create the bitmap object with CreateCompatibleBitmap. But then
> you cannot choose the bits/px, it is set automatically to the correct
> value.
>
> >     BitBlt(hdc, 100, 150, 16, 16 , hdcmem, 0, 0,
> > SRCCOPY);
>
> >   DeleteDC(hdcmem);
> >   ReleaseDC(hwnd, hdc);
>
> Note: Your HBITMAP object is not yet deleted.
>
> Have a look at CreateDIBSection, perhaps this fits better for your needs.
>
> hth,
>  Friedel

Thanks again. I got the program to run but I don't get any output
yet.

I did this:

struct BITMAP_INFO{
BITMAPFILEHEADER bmHead;
RGBQUAD bmColor[16];
};

BYTE data[] = {0xff,0xff,0x80,0x01,...

BITMAPINFO* BitmapInfo = (BITMAPINFO*)(new BITMAP_INFO);

PBYTE BitmapBits = data; //reads bitmap data from an array.

hbitmap = CreateDIBSection(hdc, BitmapInfo, DIB_RGB_COLORS,
(PVOID*)&BitmapBits, NULL, 0);

HDC hMem = CreateCompatibleDC(hdc);
HDC hdcmem = CreateCompatibleDC(hdc);

HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMem, hbitmap);

BitBlt(hdc,10, 10, 16, 16, hMem, 0, 0, SRCCOPY);
StretchBlt(hdc, 250,250,16*5,16*5,hdcmem,0,0,16,16,MERGECOPY);

SelectObject(hMem, hOldBitmap);
DeleteDC(hMem);

Now I am trying to get some output some dots on the screen. Later I
will see how to edit this data with an editor. I already have a
monochrome bitmap object and editor.
From: Friedel Jantzen on
Hi!

> I did this:
>
> struct BITMAP_INFO{
> BITMAPFILEHEADER bmHead;
> RGBQUAD bmColor[16];
> };

You picked the wrong struct (see my first reply).
Try this:
struct BITMAP_INFO{
BITMAPINFOHEADER bmiHead; // ! required
RGBQUAD bmColor[16];
};

Then initialize this struct, see the link I posted for BITMAPINFOHEADER.

> BYTE data[] = {0xff,0xff,0x80,0x01,...
>
> BITMAPINFO* BitmapInfo = (BITMAPINFO*)(new BITMAP_INFO);
>
> PBYTE BitmapBits = data; //reads bitmap data from an array.

This parameter of CreateDIBSection is an _out_ parameter and points
to the pixel data in the new DIB, not to your data.
PBYTE BitmapBits = NULL;

>
> hbitmap = CreateDIBSection(hdc, BitmapInfo, DIB_RGB_COLORS,
> (PVOID*)&BitmapBits, NULL, 0);

Now you can copy your data to BitmapBits:
GdiFlush();
CopyMemory(BitmapBits, data, dataSize);

> HDC hMem = CreateCompatibleDC(hdc);
> HDC hdcmem = CreateCompatibleDC(hdc);
>
> HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMem, hbitmap);
>
> BitBlt(hdc,10, 10, 16, 16, hMem, 0, 0, SRCCOPY);
> StretchBlt(hdc, 250,250,16*5,16*5,hdcmem,0,0,16,16,MERGECOPY);
>
> SelectObject(hMem, hOldBitmap);
> DeleteDC(hMem);

There is an easy way to display DIBs: SetDIBitsToDevice
http://msdn.microsoft.com/en-us/library/dd162974(VS.85).aspx

You can find an interesting sample for manipulating the color table here:
http://blogs.msdn.com/oldnewthing/archive/2006/11/15/1081320.aspx
To get the complete thing working, download the "scratch" program from the
link on this page; if you are a newbie with Win32, this is a good starting
point.

hth,
Friedel