Re: Creating a GDI+ Bitmap from an 8-bit Bitmap

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance



Ok, when I create the GDI+ bitmap from a DIB, the image looks a bit better.
Most of the colors are correct, but there are still some that are wrong -
it's almost as if it isn't using all of the colors that I assigned to the
pallete. In fact, if I view the 8-bit image when my monitor is set to 32-bit,
it looks correct (i.e., identical to the screen when it was set to 8-bit
mode). That tells me that something is still a bit off with my palette.

I'm using the following code to create the DIB (this replaces the call to
CreateCompatibleBitmap() in my original code sample, below; the palette is
already selected into the DC at this point):
BYTE* pBits = NULL;
BITMAPINFO* pBmi = NULL;
if(NULL != pPalette)
{
int amtAlloc = sizeof(BITMAPINFO) + nColors*sizeof(RGBQUAD);
pBmi = (BITMAPINFO*)malloc(amtAlloc);
memset(pBmi, 0, amtAlloc);

for(unsigned int i = 0; i < nColors; i++)
{
pBmi->bmiColors[i].rgbRed = pPalette->palPalEntry[i].peRed;
pBmi->bmiColors[i].rgbGreen = pPalette->palPalEntry[i].peGreen;
pBmi->bmiColors[i].rgbBlue = pPalette->palPalEntry[i].peBlue;
}
}
else
{
pBmi = (BITMAPINFO*)malloc(sizeof(BITMAPINFO));
memset(pBmi, 0, sizeof(BITMAPINFO));
}

pBmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pBmi->bmiHeader.biWidth = szScreen.cx;
pBmi->bmiHeader.biHeight = szScreen.cy;
pBmi->bmiHeader.biPlanes = 1;
pBmi->bmiHeader.biBitCount = bitDepth;
pBmi->bmiHeader.biCompression = BI_RGB;
DWORD dwBytesPerLine = (((bitDepth * szScreen.cx) + 31) / 32 * 4);
pBmi->bmiHeader.biSizeImage = dwBytesPerLine * szScreen.cy;
pBmi->bmiHeader.biClrUsed = nColors;
m_hBmpScreen = CreateDIBSection(hDCScreen, pBmi, DIB_RGB_COLORS,
(LPVOID*)&pBits, NULL, 0);

free(pBmi);

I then call BitBlt() to copy the contents of the screen DC to the DIB.

I'm not entirely sure that I am creating the DIB correctly - is there a bug
there that is causing the incorrect colors to be displayed in the final image?

Thanks,
Andy

"Michael Phillips, Jr." wrote:

You could also try calling UnrealizeObject before creating your gdi+ bitmap.

This will force the system to completely remap the logical palette to the
system palette when RealizePalette is called again.

The system's palette is limited. You don't get to control all 256 colors
for an image as the system reserves colors for it's own use.

You could also try to create your screen capture with a bitmap created via
CreateDIBSection. Since the bitmap is device independent, you will have
complete control over the mapping of the DIB's colors to the palette. You
can then create a gdi+ indexed bitmap from the DIB when the screen is 8bpp.
The color table is already part of the DIB.


"Andy Schott" <AndySchott@xxxxxxxxxxxxxxxxxxxxxxxxx> wrote in message
news:2D972043-DD0B-4ED4-8A0B-EA95B2DBE90F@xxxxxxxxxxxxxxxx
Michael,
Thank you for your response.

I changed my code to use SelectPalette() instead of SelectObject(), and I
also moved the SelectObject() that selects the HBITMAP out of the device
context to before the GDI+ image is created. I also verified that the
HBITMAP
and HPALETTE are deleted after the GDI+ image is deleted. Unfortunately,
the
colors in the image still aren't correct.

When I compared the original palette to the palette from the GDI+ image,
they were different. I then created a new GDI+ palette, copied in the
contents of the HPALETTE, and set that as the new palette for the GDI+
image.
While the image still did not look correct, it looked as if at least some
of
the colors were correct.

I'm not really sure why the palette is wrong in the GDI+ image - is the
implementation of FromHBITMAP() doing something different to pull the
colors
from the HPALETTE than I am doing?

It is also odd that manually setting the correct palette to the image does
not cause the image to be displayed correctly. Is there something special
that I need to do in order to draw the image correctly? I am currently
just
calling Graphics::DrawImage(), passing it the Bitmap* and (0, 0) for the
location to draw the image at.

Andy

"Michael Phillips, Jr." wrote:

hPalOld = (HPALETTE)SelectObject(hDCBuffer, m_hPalScreen);

You should use SelectPalette to bring the palette into the device context
and use it again to take it out of the device before creating the gdi+
bitmap.

m_pImage = Bitmap::FromHBITMAP(m_hBmpScreen, m_hPalScreen);

SelectObject(hDCBuffer, hBmpOld);

You should select your m_hBmpScreen out of the device context(i.e.,
hDCBuffer) before you create the gdi+ bitmap.

Did you check the gdi+ bitmap's Palette object to see if it maches the
palette entries use to create it?

Keep in mind that the HPALETTE and the HBITMAP must not be deleted while
the
gdi+ bitmap is in scope.

"Andy Schott" <AndySchott@xxxxxxxxxxxxxxxxxxxxxxxxx> wrote in message
news:D4BF9524-D1B3-4116-B781-3CF686AA8340@xxxxxxxxxxxxxxxx
Hello,
I am trying to capture a portion of the screen, and then display that
using
GDI+. My current approach for doing this is to create a bitmap using
CreateCompatibleBitmap(), select that into a memory DC, and call
BitBlt()
to
copy the contents of the screen DC into my memory DC. I then pass the
HBITMAP
for the to the GDI+ Bitmap constructor.

This works very well when the display is set to use either 16-bit or
32-bit
color. However, if the display is set to 8-bit color, then the colors
in
the
captured bitmap aren't displayed correctly. At first, I thought that
this
was
because I wasn't passing an HPALETTE to the GDI+ Bitmap, however when I
capture the current palette and pass that as well, there is no change
in
the
displayed image.

I am sure that I am capturing the palette correctly, because if I draw
the
HBITMAP to the screen using the HPALETTE and normal GDI calls, the
image
is
displayed correctly.

I'm really not sure what else I have to do in order to get GDI+ to use
the
palette information for the bitmap. Do you have any ideas as to what I
am
doing wrong?

Here's the code that I am using to capture the screen:
HDC hDCScreen = GetDC(NULL);
SIZE szScreen = {
GetDeviceCaps(hDCScreen, HORZRES),
GetDeviceCaps(hDCScreen, VERTRES)
};

HDC hDCBuffer = CreateCompatibleDC(hDCScreen);

UINT bitDepth = GetDeviceCaps(hDCScreen, BITSPIXEL);
HPALETTE hPalOld = NULL;

LOGPALETTE* pPalette = NULL;
UINT nColors = 0;
if(bitDepth <= 8)
{
nColors = GetSystemPaletteEntries(hDCScreen, 0, 0, NULL);
pPalette =
(LOGPALETTE*)malloc(sizeof(LOGPALETTE)+(nColors-1)*sizeof(PALETTEENTRY));
pPalette->palVersion = 0x300;
pPalette->palNumEntries = (WORD)nColors;
GetSystemPaletteEntries(hDCScreen, 0, nColors, pPalette->palPalEntry);
m_hPalScreen = CreatePalette(pPalette);
hPalOld = (HPALETTE)SelectObject(hDCBuffer, m_hPalScreen);
RealizePalette(hDCBuffer);
free(pPalette);
}

m_hBmpScreen = CreateCompatibleBitmap(hDCScreen, szScreen.cx,
szScreen.cy);

HBITMAP hBmpOld = (HBITMAP)SelectObject(hDCBuffer, m_hBmpScreen);
BitBlt(hDCBuffer, 0, 0, szScreen.cx, szScreen.cy, hDCScreen, 0, 0,
SRCCOPY);

if(NULL != m_hPalScreen)
{
SelectObject(hDCBuffer, hPalOld);
}

m_pImage = Bitmap::FromHBITMAP(m_hBmpScreen, m_hPalScreen);

SelectObject(hDCBuffer, hBmpOld);
DeleteDC(hDCBuffer);

ReleaseDC(NULL, hDCScreen);

Thanks,
Andy






.



Relevant Pages

  • Re: Creating a GDI+ Bitmap from an 8-bit Bitmap
    ... You could also try calling UnrealizeObject before creating your gdi+ bitmap. ... This will force the system to completely remap the logical palette to the ... I am trying to capture a portion of the screen, and then display that ...
    (microsoft.public.win32.programmer.gdi)
  • Re: Creating a GDI+ Bitmap from an 8-bit Bitmap
    ... the BITMAPINFO structure to the colors of the captured palette? ... CreateDIBSection creates an empty bitmap. ... given to GDI+, ... You could also try to create your screen capture with a bitmap created ...
    (microsoft.public.win32.programmer.gdi)
  • Re: Creating a GDI+ Bitmap from an 8-bit Bitmap
    ... I also verified that the HBITMAP ... and HPALETTE are deleted after the GDI+ image is deleted. ... When I compared the original palette to the palette from the GDI+ image, ... calling Graphics::DrawImage, passing it the Bitmap* and for the ...
    (microsoft.public.win32.programmer.gdi)
  • Re: Creating a GDI+ Bitmap from an 8-bit Bitmap
    ... As for the system taking up some of the entries in the palette - that maybe ... given to GDI+, ... You could also try to create your screen capture with a bitmap created ...
    (microsoft.public.win32.programmer.gdi)
  • Re: GdipCreateHBITMAPFromBitmap + PixelFormat32bppARGB
    ... The Windows bitmap specification was drawn up for Windows 3.1 ... Alpha blended bitmaps were not supported. ... The documentation for AlphaBlend function implies that Windows GDI ... an alpha channel. ...
    (microsoft.public.dotnet.framework.windowsforms)