开发者

LoadImage is working differently based on win color setting

HI, I am using loadImage to load an 24bit bmp file and then try to get the bmp info

 hBitmap = (HBITMAP)LoadImage(NULL, "logo.bmp", IMAGE_BITMAP, 0, 0,
                LR_LOADFROMFILE | LR_DEFAULTSIZE)
 GetObject( hBitmap开发者_运维问答, sizeof(BITMAP), &bm );

When I do the same operation with windows color display setting 32 hi color than i got the following value bmBitsPixel = 32 but if i set the windows color display to 16 than i got bmBitsPixel = 16

Can any one please explain what does it mean. I if i used the following formula to calculate the size of the bmp than the size of the bmp depends on the window color setting.

size = bmWidth * bmHeight* bmBitsPixel/8

Thanks and Regards


An HBITMAP is a device-dependent bitmap: its internal representation depends on the color format of your screen.

Accordingly, if you set your display color format to 32 bits per pixel (bpp), then your bitmap will use 32 bpp. If you switch your color format to 16 bpp, the bitmap will follow and use 16 bpp.

You formula is correct, you have to take bmBitsPixel into account when computing the bitmap size.


A HBITMAP can be loaded as a Device-Independent-Bitmap when using LoadImage API by specify the LR_CREATEDIBSECTION flag along with the other flags - without it, Windows is converting to a device-dependent bitmap. This will only work when the source image is a 32BPP bitmap. Lower bit-rates (8BPP, 16BPP, 24BPP etc.) will be loaded with the EXACT bit-planes/color depths - which would have to be converted to the monitor's color depth to actually display it.

Because no processing occurs, you may get a 32BPP BMP that is not pre-multiplied for alpha-rendering (AlphaBlend() function) so you will get color fringing and other unwanted artifacts. For those cases, you need to do the pre-multiply on every pixel. The following is a small snip of code - but does not do too much error checking... you will need to test that the BITMAP is of the correct plane/color depth before allowing this code to execute. There are a few ways to optimize the code below (such as using a lookup table), but this is for explanation purposes mainly.

This code can only work IF the bm.bmBits pointer is not NULL, bm.bmPlanes equals 1, and bmBitsPixel equals 32:

RGBQUAD* lprgbSrc = (RGBQUAD*)bm.bmBits;
if( lprgbSrc )
{
  RGBQUAD* lprgbEnd = (RGBQUAD*)((size_t)lprgbSrc + (size_t)bm.bmHeight*bm.bmWidthBytes);
  while( lprgbSrc != lprgbEnd )
  {
    switch(lprgbSrc->rgbReserved)
    {
    case 255: // Pixel at full opacity - no color shift required...
      break;
    case 0:   // Pixel at full transparency - must go full black
      *(DWORD*)lprgbSrc = 0;
      break;
    // Need to pre-multiply by the alpha (rgbReserved) and 
    // divide by 255 to get a correct brightness level for correct
    // rendering of the color when mixed on top of the background
    default:  
      lprgbSrc->rgbRed = ((size_t)lprgbSrc->rgbRed * (size_t)lprgbSrc->rgbReserved) /255;
      lprgbSrc->rgbBlue = ((size_t)lprgbSrc->rgbBlue * (size_t)lprgbSrc->rgbReserved) /255;
      lprgbSrc->rgbGreen = ((size_t)lprgbSrc->rgbGreen * (size_t)lprgbSrc->rgbReserved) /255;
      break;
    }
    lprgbSrc++;
  }
}

Note that certain Windows GDI functions accept non-premultiplied HBITMAP (ImageList for instance) when certain flags are applied.


The LoadImage function not working because it needs a positive height. Some bitmap images are saved with a -height value so that the image will start at the lower left corner. The LoadImage function VC++ 6.0 MFC was not programmed for negative heights so it fails and just returns NULL. Just change the biheight in structure BITMAPINFOHEADER to a positive value. The LoadImage will then open just about any bitmap 8bit, 24bit or 32bit with a positive biheight.

BITMAPFILEHEADER m_bmfHeader;
BITMAPINFOHEADER m_bi;

HANDLE hFile = CreateFile(image_filename,
                GENERIC_READ,
                0,
                NULL,OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL, NULL);

if(hFile == INVALID_HANDLE_VALUE)
{
    AfxMessageBox("Cannot Open a New File");
    return;
}

DWORD dwBytesWritten = 0;

ReadFile(hFile, (LPSTR)&m_bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);

ReadFile(hFile, (LPSTR)&m_bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);

int m_nSizeImage = m_bi.biSizeImage;
BYTE *lpbitmap;
lpbitmap = (BYTE*)malloc(m_nSizeImage); 

ReadFile( hFile, (LPSTR)lpbitmap, m_nSizeImage, &dwBytesWritten,NULL);
CloseHandle(hFile);

hFile = CreateFile(image_filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

DWORD dwBytesWritten = 0;
m_bi.biHeight = (int)fabs(m_bi.biHeight); //Height Always Positive!!!

WriteFile(hFile, (LPSTR)&m_bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, (LPSTR)&m_bi, sizeof(BITMAPINFOHEADER),&dwBytesWritten, NULL);

WriteFile(hFile, (LPSTR)lpbitmap, m_bi.biSizeImage, &dwBytesWritten, NULL);
CloseHandle(hFile);
free(lpbitmap); // Now you can use the LoadImage(...)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜