Растровые изображения 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, В этом случае цветовые маски, которые задокументированы, чтобы следовать за заголовком, вместо этого взяты из соответствующих выделенных полей заголовков, и три DWORDs, которые следуют за заголовком, игнорируются.

    Это легко доказать, слегка изменив исходный код:

    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 структуры содержат дополнительные элементы для красной, зеленой и синей масок следующим образом.

    (акцент мой).

    Мы можем только сделать вывод из доказательств того, что это не так.
    Это меньше документации, чем я надеялся.

Другие вопросы по тегам