Сохранение растровых изображений в Windows 10 с активным масштабированием GDI
У меня есть приложение MFC с панелями инструментов (используя CMFCToolbar). Я создаю растровое изображение панели инструментов на лету, используя растровые изображения из файлов и ресурсов. DIB имеют разные цветовые форматы.
- Поэтому я создаю пустое растровое изображение панели инструментов, совместимое с экраном DC.
- Затем я открываю все растровые изображения и помещаю содержимое в растровое изображение панели инструментов (GDI выполняет преобразование и растяжение цветового пространства для меня).
- Затем я сохраняю растровое изображение в 24-битном DIB-файле.
- Затем я создаю объект панели инструментов и загружаю изображение.
Это работало целую вечность и работает сейчас, за исключением одного случая:
Недавно нам пришлось включить масштабирование GDI для Windows 10 1703 и более поздних версий. В системе с дисплеем с высоким разрешением и масштабированием 200% (например, Surface) происходит следующий эффект:
Все значки на панели инструментов искажены.
Я также нашел причину:
При сохранении составного изображения я получаю только верхнюю левую четверть изображения. Ширина и высота растрового изображения не изменились (скажем, 1024x15) по сравнению с обычным разрешением дисплея без масштабирования GDI. Но это растровое изображение содержит только пиксели верхней левой четверти (см. Пример ниже).
Поэтому я предполагаю, что контекст устройства сообщает Windows о 200% масштабировании. При перемещении от источника к цели изображение автоматически увеличивается, но размер растрового изображения не изменяется.
Как я могу сохранить немасштабированное растровое изображение?
-или же-
Как правильно сохранить масштабированное растровое изображение? Где взять недостающие пиксели? Где взять правильные размеры? (HBITMAP относится только к немасштабированным размерам).
Пример:
без масштабирования GDI, правильно:
Масштабирование 200%, те же размеры, но только верхняя левая четверть правильного изображения:
1 ответ
Резюме и решение:
Допустим, мы создаем растровое изображение памяти, совместимое с форматом экрана (DDB):
CBitmap toolBitmap;
toolBitmap.CreateCompatibleBitmap (pDC, 1000, 20);
Позже мы добавляем что-то в растровое изображение памяти (здесь не имеет значения). Теперь мы хотим сохранить растровое изображение (записать как DIB в файл).
Хотя мы знаем размеры (здесь: 1000x20), мы не должны их использовать. Поскольку в Window 10 и process активировано масштабирование GDI и используется отображение высокого разрешения с масштабированием - размеры могли измениться внутри. Таким образом, растровое изображение больше не 1000x20.
Этот провал:
BITMAP bmHdr;
toolBitmap.GetObject(sizeof(BITMAP), &bmHdr);
Заголовок растрового изображения содержит исходные размеры (1000x20). Использование их для сохранения в файл приводит к неполному изображению. Только верхняя левая часть будет сохранена.
Это работает - мы можем получить масштабированные размеры:
BITMAPINFO bi = {};
bi.dwSize = sizeof(bi);
int result = GetDIBits(pDC->GetSafeHdc(), (HBITMAP)toolBitmap.GetSafeHandle(), 0, 0, NULL, &bi, DIB_RGB_COLORS);
Теперь мы можем приступить к новым измерениям.
В итоге я использовал функции GDI+, которые также сохраняют полную (масштабированную) битовую карту:
Gdiplus::Bitmap bm((HBITMAP)toolBitmap.GetSafeHandle(), NULL);
Gdiplus::Status status = bm.Save(pwszFileName, &clsidEncoder, NULL);
Я предполагаю, что есть тонны старого кода MFC и GDI, которые не будут работать правильно с активированным масштабированием GDI в Windows 10.