LoadImage的工作方式与win颜色设置不同

时间:2010-10-26 09:00:29

标签: c windows gdi

HI,   我正在使用loadImage加载24位bmp文件,然后尝试获取bmp信息

 hBitmap = (HBITMAP)LoadImage(NULL, "logo.bmp", IMAGE_BITMAP, 0, 0,
                LR_LOADFROMFILE | LR_DEFAULTSIZE)
 GetObject( hBitmap, sizeof(BITMAP), &bm );

当我使用windows颜色显示设置32 hi颜色执行相同操作时,我得到以下值 bmBitsPixel = 32,但如果我将Windows彩色显示设置为16比我得到的 bmBitsPixel = 16

任何人都可以解释一下这意味着什么。  我是否使用以下公式来计算bmp的大小,而不是bmp的大小取决于窗口颜色设置。

size = bmWidth * bmHeight * bmBitsPixel / 8

谢谢和问候

3 个答案:

答案 0 :(得分:1)

HBITMAPdevice-dependent bitmap:其内部表示取决于屏幕的颜色格式。

因此,如果将显示颜色格式设置为每像素32位(bpp),那么您的位图将使用32 bpp。如果将颜色格式切换为16 bpp,则会跟随位图并使用16 bpp。

您的公式是正确的,在计算位图大小时必须考虑bmBitsPixel

答案 1 :(得分:0)

当使用LoadImage API时,可以通过指定LR_CREATEDIBSECTION标志以及其他标志来加载HBITMAP作为独立于设备的位图 - 没有它,Windows将转换为依赖于设备的位图。这仅在源图像是32BPP位图时才有效。较低的比特率(8BPP,16BPP,24BPP等)将加载EXACT位平面/颜色深度 - 必须将其转换为显示器的颜色深度才能实际显示它。

由于没有进行处理,您可能会得到一个32BPP BMP,它不会预先乘以alpha渲染(AlphaBlend()函数),因此您将获得彩色边纹和其他不需要的伪像。对于这些情况,您需要对每个像素进行预乘。以下是一小段代码 - 但不会进行太多错误检查...在允许执行此代码之前,您需要测试BITMAP是否具有正确的平面/颜色深度。有几种方法可以优化下面的代码(例如使用查找表),但主要是出于解释目的。

此代码只能在bm.bmBits指针不为NULL,bm.bmPlanes等于1,bmBitsPixel等于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++;
  }
}

请注意,某些Windows GDI函数在应用某些标志时会接受非预乘的HBITMAP(例如ImageList)。

答案 2 :(得分:0)

LoadImage函数无法正常工作,因为它需要正高度。某些位图图像以-height值保存,以便图像从左下角开始。 LoadImage函数VC ++ 6.0 MFC未针对负高度进行编程,因此失败并返回NULL。只需将结构BITMAPINFOHEADER中的biheight更改为正值即可。然后,LoadImage将打开任何位图8bit,24bit或32bit,并具有正双峰。

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(...)