Сохранение растровых изображений в Windows 10 с активным масштабированием GDI

У меня есть приложение MFC с панелями инструментов (используя CMFCToolbar). Я создаю растровое изображение панели инструментов на лету, используя растровые изображения из файлов и ресурсов. DIB имеют разные цветовые форматы.

  • Поэтому я создаю пустое растровое изображение панели инструментов, совместимое с экраном DC.
  • Затем я открываю все растровые изображения и помещаю содержимое в растровое изображение панели инструментов (GDI выполняет преобразование и растяжение цветового пространства для меня).
  • Затем я сохраняю растровое изображение в 24-битном DIB-файле.
  • Затем я создаю объект панели инструментов и загружаю изображение.

Это работало целую вечность и работает сейчас, за исключением одного случая:

Недавно нам пришлось включить масштабирование GDI для Windows 10 1703 и более поздних версий. В системе с дисплеем с высоким разрешением и масштабированием 200% (например, Surface) происходит следующий эффект:

Все значки на панели инструментов искажены.

Я также нашел причину:

При сохранении составного изображения я получаю только верхнюю левую четверть изображения. Ширина и высота растрового изображения не изменились (скажем, 1024x15) по сравнению с обычным разрешением дисплея без масштабирования GDI. Но это растровое изображение содержит только пиксели верхней левой четверти (см. Пример ниже).

Поэтому я предполагаю, что контекст устройства сообщает Windows о 200% масштабировании. При перемещении от источника к цели изображение автоматически увеличивается, но размер растрового изображения не изменяется.

Как я могу сохранить немасштабированное растровое изображение?

-или же-

Как правильно сохранить масштабированное растровое изображение? Где взять недостающие пиксели? Где взять правильные размеры? (HBITMAP относится только к немасштабированным размерам).

Пример:

без масштабирования GDI, правильно:

без масштабирования

Масштабирование 200%, те же размеры, но только верхняя левая четверть правильного изображения:

с масштабированием 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.

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