Я работаю над API для кэширования объектов GDI, написанных на C ++, в котором я реализую различные методы Create, имитирующие API win32. Одним из таких методов является CreateDIBPatternBrushPt()
, который принимает в VOID*
в упакованный DIB. VOID*
содержит BITMAPINFO
за структурой сразу следует массив байтов, определяющих пиксели растрового изображения. Я провел некоторое исследование на упакованных DIB. Согласно книге «Программирование Windows», как и в Википедии, длина равна произведению длины строки и biHeight
(член BITMAPINFOHEADER
), где:
RowLength = 4 * ((bmi.bcWidth * bmi.bcBitCount + 31) / 32) ;
Итак, в настоящее время я думаю сделать что-то вроде этого:
//copy BIMAPINFO to access width and height
//lpPackedDIB is the VOID* parameter of CreateDIBPatternBrushPt()
BITMAPINFO tmpBitmapInfo;
std::memcpy(&tmpBitmapInfo, lpPackedDIB, sizeof(BITMAPINFO));
//copy entire packed DIB
int rowLength = 4 * ((tmpBitmapInfo.bmiHeader.biWidth * tmpBitmapInfo.bmiHeader.biBitCount + 31) / 32);
std::memcpy(m_pPackedDIB, lpPackedDIB, sizeof(BITMAPINFO) + rowLength * std::abs(bitmapInfo.bmiHeader.biHeight));
Это похоже на правильный способ сделать это? Я также хотел бы знать, где lpPackedDIB
придет для людей, которые используют CreateDIBPatternBrushPt()
, чтобы я мог правильно проверить эту логику.
РЕДАКТИРОВАТЬ:
Рекомендации:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd183493(v=vs.85).aspx
https://en.wikipedia.org/wiki/BMP_file_format#File_structure
https://www-user.tu-chemnitz.de/~heha/petzold/ch15b.htm (в частности, раздел «Пиксельные биты DIB»)
Этот ответ был опубликован ранее, но почему-то снят. Это не касается непосредственно вопроса, но дает хорошее понимание проблемы, с которой я столкнулся. Кредит пользователю: Бармак Шемирани.
Вы можете просто использовать
CreatePatternBrush
получитьHBRUSH
отHBITAMP
Или использовать
CreateDIBPatternBrushPt
, Тем не менее, обратите внимание, что упакованный DIB всего на 14 байтов меньше, так как это не нужноBITMAPFILEHEADER
, Это делает его полезным для очень маленьких кистей. Например, 2×1 зеленая / черная кисть:typedef struct { BITMAPINFOHEADER header; unsigned char bits[2 * 1 * 4]; } DIBSTRUCT; const DIBSTRUCT dib = { { sizeof(BITMAPINFOHEADER), 2, 1, 1, 32, BI_RGB, 0, 0, 0, 0, 0 }, { 0,0xff,0,0, 0,0,0,0 } }; HBRUSH hbrush = CreateDIBPatternBrushPt(&dib, DIB_RGB_COLORS);
Вы также можете сделать кисть из растрового файла. Выделите чур, добавьте место для
BITMAPINFOHEADER
и таблица цветов. Затем скопируйтеBITMAPINFOHEADER
, затем таблица цветов (если есть), затем пиксели. Пример:HBRUSH getbrush(HBITMAP hbitmap) { BITMAP bm; GetObject(hbitmap, sizeof(bm), &bm); int colorCount = 0; if (bm.bmBitsPixel == 1) colorCount = 2; if (bm.bmBitsPixel == 4) colorCount = 16; if (bm.bmBitsPixel == 8) colorCount = 256; RGBQUAD rgb[256]; if (colorCount) { HDC memdc = CreateCompatibleDC(NULL); HGDIOBJ oldbitmap = SelectObject(memdc, hbitmap); GetDIBColorTable(memdc, 0, colorCount, rgb); SelectObject(memdc, oldbitmap); DeleteDC(memdc); } BITMAPINFOHEADER bminfo = { sizeof(BITMAPINFOHEADER), bm.bmWidth, bm.bmHeight, 1, bm.bmBitsPixel, BI_RGB, 0, 0, 0, 0, 0 }; DWORD size = ((bm.bmWidth * bm.bmBitsPixel + 31) / 32) * 4 * bm.bmHeight; char *dib = new char[sizeof(BITMAPINFOHEADER) + colorCount * 4 + size]; memcpy(dib, &bminfo, sizeof(BITMAPINFOHEADER)); memcpy(dib + sizeof(BITMAPINFOHEADER), rgb, colorCount * 4); memcpy(dib + sizeof(BITMAPINFOHEADER) + colorCount * 4, bm.bmBits, size); HBRUSH hbrush = CreateDIBPatternBrushPt(dib, DIB_RGB_COLORS); //clearnup DeleteObject(hbitmap); delete[]dib; return hbrush; }
Других решений пока нет …