Я пытаюсь использовать упомянутый код Записать текст на BITMAPINFO в память. Мой код ниже.
BITMAPINFO MyBMInfo = {0}; //debug
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader); //debug
int lines; //debug
HDC hdc = GetDC(0);
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP hbitmap = CreateBitmap(10, 10, 1, 8, bmp_buffer);
GetDIBits(memdc, hbitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS); //debug
HBITMAP oldbmp = SelectObject(memdc, hbitmap);
TextOut(memdc, 0, 0, "123", 3);
SelectObject(memdc, oldbmp);
lines = GetDIBits(memdc, hbitmap, 0, 10, bmp_buffer, &MyBMInfo, DIB_RGB_COLORS); //<-here was used other BMInfo structure
DeleteObject(hbitmap);
DeleteDC(memdc);
ReleaseDC(0, hdc);
Это не работает так, как ожидалось. Во время устранения неполадок я обнаружил, что GetDIBits возвращает 0 строк, например, не удалось скопировать содержимое растрового изображения в bmp_buffer, позже я попытался просмотреть текущее выбранное растровое изображение внутри memdc, выполнив GetCurrentObject(memdc, OBJ_BITMAP), и оно не изменилось, поэтому по какой-то причине hbitmap не «выбрано». " внутри memdc.
Потом я перепробовал много разных идей и обнаружил, что если hbitmap создан CreateCompatibleBitmap(), то строки bmp_buffer обновляются. Я запросил атрибуты такого созданного растрового изображения, и похоже, что оно имеет правильные размеры, но имеет настройку цвета в 1 бит. Следуя этому треку, если я перейду на hbitmat=CreateBitmap(10, 10, 1, 1, bmp_buffer), это будет работать, по крайней мере строки != 0 и некоторые байты в bmp_buffer обновятся. Это означает, что hbitmap, созданный CreateBitmap(10, 10, 1, 8, bmp_buffer), «несовместим» с memdc. Переход на монохромный — не решение, так как мне нужны цвета в растровом изображении.
В документации GDI говорится, что любой DC, созданный CreateCompatibleDC(), является монохромным и имеет размер 1x1 пиксель. В нем также говорится, что его необходимо обновить позже, чтобы использовать цветные изображения разных размеров, но нет никаких предложений, как изменить размер цвета. Что я делаю неправильно, код, которому я следую, использует только 24 бита на пиксель, и он работал в каком-то другом приложении.
@ 500-InternalServerError, можете ли вы подсказать, на что обращать внимание? Я подозреваю, что проблема в моем коде возникла немного раньше, чем GetDIBits, ближе к моменту создания внутреннего растрового изображения.
Вы использовали CreateCompatibleBitmap с оригинальным DC? Вы не должны использовать его с памятью DC.
@ElderBug Что может быть «оригинальным DC», если я хочу сделать виртуальный холст TextOut, а затем сохранить его в файл? Я пытался использовать результат CreateDC(0) или CreateDC(hwnd to main window) и наткнулся на ту же стену, но на этот раз GetDIBits работает только для 32-битного цветового пространства.
Проблема с аппаратно-зависимыми растровыми изображениями (DDB) заключается в том, что они зависят от устройства, поэтому формат соответствует формату DC. Поскольку в вашем случае это 32 бита на пиксель, вы застряли на 32 битах на пиксель. Если вы этого не хотите, вам следует использовать DIB вместо DDB.
@ElderBug Похоже, вы используете неверный API. Как правильно создать DC для последующей работы с TextOut и создания растрового изображения в файл?
Какова именно ваша цель? Если вы никогда не собираетесь использовать вывод устройства, то GDI для этого не подойдет. Рисование текста без устройства не имеет смысла в GDI. Как для вас должен выглядеть текст? Для GDI это полностью зависит от устройства. В зависимости от монитора ClearType будет отображаться по-разному. GDI также предназначен для принтеров, где рендеринг снова сильно отличается. Вы не можете просто сказать «Нарисуй мне текст» без контекста. Чтобы упростить задачу, вы либо используете GDI с контроллером домена, который вам подходит (например, экран), либо используете другую библиотеку, такую как DirectWrite или freetype.
@ElderBug Моя цель — отобразить растровый файл с использованием шрифтов Windows. Я ожидаю, что контекст устройства памяти имеет такую функциональность. Что касается моей проблемы с цветовым кодированием, в документации Microsoft говорится Learn.microsoft.com/en-us/windows/win32/gdi/… «Прежде чем приложение сможет начать рисование, оно должно выбрать растровое изображение с соответствующей шириной и высотой. в DC, вызвав функцию SelectObject». Похожая тема stackoverflow.com/questions/33181728/… но вызов CreateCompatibleDC(0) у меня не работает.
@ElderBug после рассмотрения моя проблема не в том, что растровое изображение, с которым я работаю, TextOut, совместимо с устройством/экраном или чем-то еще. Но в конце я хотел бы сохранить это изображение после добавления графиков и изображений из приложения в 8-битный файл BMP.
Честно говоря, вы могли бы просто работать с совместимым DC со скоростью 32 бита на пиксель, я не думаю, что возникнут какие-либо проблемы. Вероятно, вам следует попробовать отключить ClearType, но я не знаю, как это сделать.
@ElderBug Но как тогда сопоставить растровое изображение 32 бит/пиксель с данными 8 бит/пиксель? Будет ли GetDIBits делать это автоматически?
GetDIBits должен конвертироваться, если не ошибаюсь. Вам необходимо изменить структуру информации о растровом изображении на желаемую.
@ElderBug Это любезно, мне потребовалось несколько часов, чтобы обнаружить, что «BITMAPINFO», используемый в качестве аргумента, должен иметь палитру, без этого GetDiBits отказывается работать. Однако он по-прежнему не работает в полной мере, как ожидалось. Если я сделаю TextOut("123") и выгружу изображение в режиме 32bpp, я получу последовательности FF-FF-FF-00 и 00-00-00-00, это ожидаемо, белый и черный цвета. Но если я создам палитру, содержащую 2 цвета «bmiHeader.biClrImportant = 2», первый цвет FF-FF-FF-00, а второй 00-00-00-00, и попытаюсь сопоставить изображение с 8bpp, я получу два типа байтов. на выходе 0x00 и 0x13. Любой совет?
Размер таблицы указан в biClrUsed, а не в biClrImportant.
Кроме того, кажется, вы пытаетесь ввести таблицу цветов, но я думаю, что таблица цветов является результатом. Если вы укажете формат 8bpp, GetDIBits заполнит 256 записей в таблице.
@ElderBug Я попробовал установить как «biClrUsed», так и «biClrImportant». Кажется, у меня есть все части этого пазла, но я все еще пытаюсь что-то узнать, я все еще не знаю, откуда берутся эти значения, попытка вызвать GetDIBColorTable на `memdc` не приносит никакой ценности, так как memdc - это RGB, поэтому функция просто терпит неудачу. Два новых вывода: GetDIBits(... DIB_RGB_COLORS) получает пиксельные данные, начиная с FF FF 00 00 00 00 FF FF FF FF, а GetDIBits(... DIB_PAL_COLORS) получает 13 13 00 00 00 00 13 13 13 13 00 00 .... Таким образом, существует своего рода отображение палитры, используемое внутри GetDIBits.
@ElderBug Я еще раз прочитал документацию GetDiBtis на самом деле сгенерировал новую палитру и ЗАПИСАЛ в BITMAPINFO, не используя предоставленную палитру. Для DIB_RGB_COLORS палитра состоит из четырех байтов, RGB плюс один байт, для DIB_PAL_COLORS палитра состоит из 16-битных чисел (точно, как сказано в документе), но в позиции 0x13 находится значение 0x13. Существует 20-цветная палитра окон, где черный цвет находится в конце списка (0x13 = 19 dec), НО эта палитра построена так, что определены первые 10 и последние 10 (номера 245-255). Но если GetDiBtis попытается сгруппировать «знать» цвет в начале, это может объяснить мои наблюдения.
Да, как я уже сказал, таблица — это результат. Вам также необходимо установить bbiCompression на BI_RGB для палитры.





У меня было мало недоразумений при чтении документации и примеров кода, используемых в вопросах, они кратко изложены ниже:
GetDIBits не использует предоставленную палитру, а просто перезаписывает существующий массив памяти. В документации это прямо указано, я пропустил эту часть. Также не подчиняется ни biClrUsed ни biClrImportant, поэтому выделите достаточно памяти.GetDC(0) возвращает контекст с рабочего стола, который составляет 32 бита на пиксель, и HDC memdc = CreateCompatibleDC(hdc) создает контекст с 1 бит на пиксель (как указано в документации).GetDIBits(), а использовать промежуточный буфер и скопировать изображение в буфер изображения файла bmp. Это дает возможность контролировать положение и цвет печатного текста.Мой рабочий пример:
char* local_img = malloc(100*100);
BITMAPINFO local_bmi = malloc(sizeof(BITMAPINFO)+sizeof(COLORREF)*255);
local_bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
local_bmi->bmiHeader.biPlanes = 1;
local_bmi->bmiHeader.biBitCount = 8;
local_bmi->bmiHeader.biHeight = 100;
local_bmi->bmiHeader.biWidth = 100;
local_bmi->bmiHeader.biCompression = 0;
local_bmi->bmiHeader.biSizeImage = 100*100;
local_bmi->bmiHeader.biClrImportant = 256;
local_bmi->bmiHeader.biClrUsed = 256;
HDC hdc = GetDC(0);
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP hbitmap = CreateCompatibleBitmap(hdc, 100, 100);
HBITMAP oldbmp = SelectObject(memdc, hbitmap);
TextOut(memdc, 0, 0, "123", 3);
SelectObject(memdc, oldbmp);
GetDIBits(memdc, hbitmap, 0, 100, local_img, local_bmi, DIB_RGB_COLORS);
DeleteObject(hbitmap);
DeleteDC(memdc);
ReleaseDC(0, hdc);
free(local_bmi);
//use local_img for own purpose, then free it!!!
Чтобы
GetDIBitsработало, вам необходимо правильно заполнить несколько полей в структуре MyBMInfo.bmiHeader, помимо размера.