Растровые изображения Windows: BITMAPV5HEADER и BITMAPINFO совместимы?
Из документации поCreateDIBSection
Я наблюдаю это CreateDIBSection
принимает указатель на BITMAPINFO
как второй параметр.
Тем не менее, я сталкивался с различными местами, указывающими, что может быть разрешено передавать указатели другим структурам (в частности, BITMAPV5HEADER
), в том числе
У меня такое ощущение, что в этом есть смысл (BITMAPV5HEADER
можно рассматривать как "расширенную версию" BITMAPINFO
по структуре макета), но я не смог найти ни одного официального документа по этой теме.
Кто-нибудь может подтвердить, что прохождение BITMAPV5HEADER*
вместо BITMAPINFO
является действительным и, возможно, предложить некоторую документацию?
1 ответ
Краткий ответ должен быть нет. BITMAPV5HEADER*
не является заменой BITMAPINFO*
и не может быть передан всякий раз, когда BITMAPINFO*
ожидается (просто потому, что BITMAPINFO
содержит цвета палитры после заголовка и BITMAPV5HEADER
это просто заголовок).
Это конечно хорошо, чтобы пройти BITMAPV5HEADER*
вместо BITMAPINFO*
при условии, что BITMAPV5HEADER
является частью BITMAPINFO
и имеет требуемый вид данных о цвете палитры после него. Это задокументировано, хотя и косвенно, через инструкции по использованию и здравый смысл:
BITMAPV5HEADER
задокументировано, что это "расширенная версияBITMAPINFOHEADER
структура ", так что эта часть ясна.BITMAPINFO
задокументировано объединить данные заголовка и цвета. Заголовок включается по значению, а не по указателю, поэтому на данный момент ясно, что заголовок может не просто увеличиваться в размере, как ему угодно, иначе было бы невозможно получить доступBITMAPINFO.bmiColors
и вся идея иметь расширенную версию заголовка была бы бессмысленной.И эта проблема затем решается в другом месте документации (раздел "Замечания"):
Приложение должно использовать информацию, хранящуюся в
biSize
член, чтобы найти таблицу цветов вBITMAPINFO
структура, как следует:pColor = ((LPSTR)pBitmapInfo + (WORD)(pBitmapInfo->bmiHeader.biSize));
Хотя я считаю, что эта часть не смутила вас с самого начала.
Теперь для длинного ответа.
Похоже, есть два случая, когда BITMAPV5HEADER*
можно передать за BITMAPINFO*
, Ни один из этих двух документов не задокументирован конкретным образом, и если для первого мы можем применить тот же здравый смысл, который мы применяли выше, второй кажется ошибкой в документации:
- когда
BITMAPINFO.bmiColors
задокументированоNULL
, Вы можете найти полный список таких случаев в документации дляBITMAPINFOHEADER
, Когда заголовок
BITMAPV4HEADER
или жеBITMAPV5HEADER
растровое изображение имеет 16 или 32-битные цвета, а сжатие установлено наBI_BITFIELDS
, В этом случае цветовые маски, которые задокументированы, чтобы следовать за заголовком, вместо этого взяты из соответствующих выделенных полей заголовков, и триDWORD
s, которые следуют за заголовком, игнорируются.Это легко доказать, слегка изменив исходный код:
typedef struct tagV5BMPINFO { BITMAPV5HEADER bmiHeader; DWORD bmiColors[3]; } V5BMPINFO; int _tmain(int argc, _TCHAR* argv[]) { V5BMPINFO bmpinfo = { 0 }; BITMAPV5HEADER bmpheader = { 0 }; bmpheader.bV5Size = sizeof(BITMAPV5HEADER); bmpheader.bV5Width = width; bmpheader.bV5Height = height; bmpheader.bV5Planes = 1; bmpheader.bV5BitCount = 32; bmpheader.bV5Compression = BI_BITFIELDS; bmpheader.bV5SizeImage = 400*200*4; bmpheader.bV5RedMask = 0x00FF0000; bmpheader.bV5GreenMask = 0x0000FF00; bmpheader.bV5BlueMask = 0x000000FF; bmpheader.bV5AlphaMask = 0xFF000000; bmpheader.bV5CSType = 0x57696e20; // LCS_WINDOWS_COLOR_SPACE bmpheader.bV5Intent = LCS_GM_BUSINESS; bmpinfo.bmiHeader = bmpheader; // Put them in reverse order here compared to the above bmpinfo.bmiColors[0] = 0x000000FF; bmpinfo.bmiColors[1] = 0x0000FF00; bmpinfo.bmiColors[2] = 0x00FF0000; void* converted = NULL; HDC screen = GetDC(NULL); HBITMAP result = CreateDIBSection(screen, reinterpret_cast<BITMAPINFO*>(&bmpinfo), DIB_RGB_COLORS, &converted, NULL, 0); ReleaseDC(NULL, screen); DIBSECTION actual_data; GetObject(result, sizeof(actual_data), &actual_data); std::cout << std::hex; std::cout << actual_data.dsBitfields[0] << std::endl; std::cout << actual_data.dsBitfields[1] << std::endl; std::cout << actual_data.dsBitfields[2] << std::endl; std::cout << std::dec; DeleteObject(result); return 0; }
Результат:
ff0000 ff00 Ф.Ф.
Казалось бы, документация была рассеянно скопирована между
BITMAPINFOHEADER
,BITMAPV4HEADER
а такжеBITMAPV5HEADER
когда он должен был быть изменен для последних двух. Самое близкое объяснение, которое мне удалось найти, - это типы заголовков растровых изображений, которые по крайней мере распознают существование выделенных полей маски, но при этом подразумевают, что значения должны быть предоставлены как в этих полях, так и после заголовка вbmiColors
:Красные, зеленые и синие битовые маски для
BI_BITFIELD
растровые изображения сразу же следуют заBITMAPINFOHEADER
,BITMAPV4HEADER
, а такжеBITMAPV5HEADER
структур.BITMAPV4HEADER
а такжеBITMAPV5HEADER
структуры содержат дополнительные элементы для красной, зеленой и синей масок следующим образом.(акцент мой).
Мы можем только сделать вывод из доказательств того, что это не так.
Это меньше документации, чем я надеялся.