Как создать очень большое растровое изображение в C ++ / MFC / GDI

Я хотел бы иметь возможность создать большое (скажем, 20 000 x 20 000) растровое изображение пикселей в приложении C ++ MFC, используя производный класс CDC для записи в растровое изображение. Я пробовал использовать контроллеры домена памяти, как описано в документации MSDN, но они, похоже, ограничены размерами, совместимыми с текущим драйвером дисплея.

В настоящее время я использую драйвер печати для растровых изображений, но он работает очень медленно и использует очень большие объемы промежуточного хранилища из-за буферизации информации GDI.

Решение, которое я ищу, не должно включать метафайлы или буферизацию, поскольку модель, которую я рисую, требует для рендеринга многих миллионов вызовов GDI.

Я мог бы использовать подход «разделяй и властвуй» через несколько контроллеров домена памяти, но это кажется довольно громоздким и неэлегантным методом.

Есть предположения?


person SmacL    schedule 26.09.2008    source источник


Ответы (5)


CDC и CBitmap, похоже, поддерживают только растровые изображения, зависящие от устройства, возможно, вам больше повезет при создании растрового изображения с помощью :: CreateDIBSection, затем прикрепив к нему CBitmap. К сожалению, необработанные интерфейсы GDI выглядят немного устаревшими.

Вам, вероятно, не повезет с 20000 x 20000 при 32 битах на пиксель, по крайней мере, в 32-битном приложении, поскольку это дает около 1,5 ГБ памяти, но я получил действующий HBITMAP с 16 бит на пиксель:

BITMAPINFOHEADER bmi = { sizeof(bmi) };
bmi.biWidth = 20000;
bmi.biHeight = 20000;
bmi.biPlanes = 1;
bmi.biBitCount = 16;
HDC hdc = CreateCompatibleDC(NULL);
BYTE* pbData = 0;
HBITMAP hbm = CreateDIBSection(hdc, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, (void**)&pbData, NULL, 0);
DeleteObject(SelectObject(hdc, hbm));
person Simon Buchan    schedule 26.09.2008
comment
Спасибо, Саймон, именно то, что мне нужно. У меня 8 бит на пиксель, так что с этим все в порядке. - person SmacL; 26.09.2008

Это необычно, поскольку я часто создавал DC на основе экрана, который будет использоваться для растрового изображения, которое намного больше, чем экран - 3000 пикселей плюс в некоторых случаях - без каких-либо проблем. У вас есть образец кода, показывающий эту проблему в действии?

person Rob    schedule 26.09.2008

Учитывая такое большое разрешение изображения, вы не можете создать изображение, используя совместимые растровые изображения.

Пример:

глубина пикселя = 32 бита = 4 байта на пиксель

количество пикселей = 20,000 * 20,000 = 400,000,000

общее количество байтов = количество пикселей * 4 = 1.600.000.000 байтов = 1.562.500 кб ~ = 1525 МБ ~ = 1,5 ГБ

Я размышляю о конечных намерениях, но предположим, что вы хотите создать и позволить пользователям исследовать огромную карту с очень подробным увеличением. Вы должны создать собственный формат файла изображения; вы можете поместить в этот файл различные слои, содержащие сетки растровых изображений, например, для ускорения рендеринга. Процесс рендеринга может использовать GDI DIB или GDI + для создания частичных изображений, а затем их рендеринга вместе. Конечно, это требует некоторых экспериментов / оптимизации, чтобы достичь идеального пользовательского ощущения.

удачи

person xoreax    schedule 26.09.2008
comment
xoreax, совершенно верно насчет размера и точного отображения с картографическим приложением. Глубина цвета - это 8 битов, которые составляют чуть меньше 400 МБ для необработанного растрового изображения, что намного меньше, чем для JPEG. Саймон, ваш ответ CreateDIB на данный момент сработал. Я проверю SVG позже. - person SmacL; 26.09.2008

Чтобы использовать память в допустимых пределах, вам придется использовать стратегию «разделяй и властвуй». Это не взлом, если все реализовано правильно, на самом деле это очень элегантный способ работы с растровыми изображениями неограниченного размера. Если вы спроектируете его правильно, вы можете объединить подходы «только визуализировать / показать часть изображения», «визуализировать все изображение с низким разрешением для отображения на экране» и «визуализировать все это в растровое изображение на диске» в один движок и защитите пользователей вашего кода (скорее всего, себя через две недели;)) от внутренних компонентов. Я работаю над продуктом с теми же проблемами: рендеринг (потенциально больших) карт либо на экран, либо в файлы .bmp.

person Roel    schedule 26.09.2008
comment
Спасибо, Роэл. Я думаю, что «разделяй и властвуй» в сочетании с большим растровым кодом Саймона - хорошее долгосрочное решение. Вероятно, с использованием скользящего вертикального сканирования, большого буфера и очистки и повторения, когда и если буфер исчерпан. - person SmacL; 27.09.2008

Если изображение должно иметь такое разрешение - скажем, сканирование рентгеновского снимка в высоком разрешении - тогда вам может потребоваться написать для него специальные процедуры буферизации - 1,5 ГБ очень дорого - даже для современных настольных компьютеров.

Если он основан на векторе, вы можете посмотреть на SVG, поскольку он поддерживает порты просмотра и большинство из них позволяет выполнять рендеринг в других форматах. Я использую SVG в JPG через Batik (java), так что это возможно.

person graham.reeds    schedule 26.09.2008