LoadImage работает по-разному в зависимости от настройки цвета выигрыша

Привет, я использую 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 color, я получаю следующее значение bmBitsPixel = 32, но если я устанавливаю цветной дисплей Windows на 16, я получаю bmBitsPixel = 16

Может ли кто-нибудь объяснить, что это значит. Если бы я использовал следующую формулу для расчета размера bmp, то размер bmp зависит от настройки цвета окна.

размер = bmWidth * bmHeight* bmBitsPixel/8

Спасибо и с уважением


person pankaj    schedule 26.10.2010    source источник
comment
Не похоже, что вы хотите использовать LoadImage(). Используйте <gdiplus.h> для манипуляций с растровыми изображениями. Хотя требуется С++. Или просто прочитайте BITMAPFILEHEADER + BITMAINFO из файла.   -  person Hans Passant    schedule 26.10.2010


Ответы (3)


HBITMAP – это растровое изображение, зависящее от устройства: его внутреннее представление зависит от цветового формата вашего экран.

Соответственно, если вы установите цветовой формат дисплея на 32 бита на пиксель (bpp), то ваш растровый рисунок будет использовать 32 бита на пиксель. Если вы переключите свой цветовой формат на 16 бит на пиксель, растровое изображение будет следовать и использовать 16 бит на пиксель.

Ваша формула верна, вы должны учитывать bmBitsPixel при вычислении размера растрового изображения.

person Frédéric Hamidi    schedule 26.10.2010

HBITMAP можно загрузить как независимое от устройства растровое изображение при использовании API LoadImage, указав флаг LR_CREATEDIBSECTION вместе с другими флагами — без него Windows преобразуется в растровое изображение, зависящее от устройства. Это будет работать только тогда, когда исходное изображение является растровым изображением 32BPP. Более низкие битрейты (8BPP, 16BPP, 24BPP и т. д.) будут загружаться с ТОЧНЫМИ битовыми плоскостями/глубиной цвета, которые должны быть преобразованы в глубину цвета монитора для фактического отображения.

Поскольку никакой обработки не происходит, вы можете получить BMP 32BPP без предварительного умножения для альфа-рендеринга (функция 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), когда применяются определенные флаги.

person Legobotics    schedule 21.02.2015

Функция LoadImage не работает, потому что ей нужна положительная высота. Некоторые растровые изображения сохраняются со значением -height, поэтому изображение начинается в левом нижнем углу. Функция LoadImage VC++ 6.0 MFC не была запрограммирована для отрицательной высоты, поэтому она дает сбой и просто возвращает NULL. Просто измените biheight в структуре BITMAPINFOHEADER на положительное значение. Затем LoadImage откроет практически любое растровое изображение 8 бит, 24 бит или 32 бит с положительной двойной высотой.

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(...)
person Dman    schedule 22.04.2015