
- •1 Устройство графики в Windows
- •1.1 Graphics Device Interface и Device Context
- •1.2 Как рисовать в Device Context?
- •2.3 Как рисовать в окно приложения?
- •2.4 Когда рисовать в окно приложения? wm_paint - что это?
- •2.5 Как быстро рисовать в Device Context?
- •2.6 Как загрузить и вывести на экран изображение?
- •2.7 Как нарисовать что-либо на изображении?
2.5 Как быстро рисовать в Device Context?
С каждым DC, предназначенным для графического вывода, связан графический объект bitmap (растровое изображение), который хранит массив пикселей, выводимых на устройство. Для того, чтобы быстро переместить графические данные с одного контекста на другой, можно не повторять все действия по отрисовке, а просто скопировать данные связанного с контекстом bitmap. Для этого даны специальные функции быстрого копирования пикселей (BitBlt, StretchBlt).
Зачем это может быть нужно? Дело в том, что если вы часто рисуете достаточно сложную изменяющуюся картинку средствами GDI, сами операции рисования начинают занимать заметное для пользователя время и возникает неприятный эффект мерцания изображения - когда часть картинки уже перерисовалась, а часть еще осталась старой. Для того, чтобы избежать подобного эффекта новая картинка может создаваться в виртуальном DC в памяти, и потом быстро переносится на экран функциями копирования bitmap.
Пример:
// hdc - дескриптор контекста устройства для вывода
// iWidth, iHeight - размеры окна вывода
HDC hMemDC;
hMemDC = CreateCompatibleDC(hdc);
if ¯(hMemDC)
{
// рисуем все что требуется
...
// быстро копируем результат отрисовки
BitBlt(hdc, 0, 0, iWidth, iHeight, hMemDC, 0, 0, SRCCOPY);
// освобождаем контекст
DeleteDC(hMemDC);
}
else
{
// обработка ошибки получения контекста
}
2.6 Как загрузить и вывести на экран изображение?
Пользуясь базовыми функциями WinAPI, это к сожалению не так-то просто. Никаких встроенных функций по загрузке изображения из bmp файла не предусмотрено, поэтому требуется самостоятельно писать функцию загрузки. Эта функциональность уже тысячу раз реализована, одна из реализаций предлагается вам в примере, который прилагается к данному тексту.
В принципе, если вы не собираетесь выводить загружаемое растровое изображение на экран (а, скажем, только обрабатывать и сохранять), то его можно хранить в совершенно произвольных собственных структурах данных. Однако, если вы хотите иметь возможность быстро вывести ваше изображение на экран, или рисовать в нем средствами GDI, придется хранить его определенным образом. Потребуется создать графический объект bitmap, соответствующий параметрам файла bmp, и загрузить в него данные из файла (пиксели). Пример, как это сделать, содержится в классе DSimpleBitmap в примере MFC_GML3.
Для того, чтобы уметь быстро выводить загруженное изображение на экран, требуется сделать следующее - с помощью функции SelectObject привязать к созданному заранее memory DC загруженный bitmap (вместо default bitmap, создающегося вместе с контекстом) и затем функцией копирования битов вывести в дисплейный контекст, связанный с вашим окном. Пример:
// hdc - дескриптор контекста устройства для вывода
// iWidth, iHeight - размеры окна вывода
// hBitmap - дескриптор изображения для отрисовки
HDC hMemDC;
HBITMAP hOldBitmap;
hMemDC = CreateCompatibleDC(hdc);
if (hMemDC)
{
// рисуем все что требуется
hOldBitmap = SelectObject(hMemDC, hBitmap);
// копируем биты
BitBlt(hdc, 0, 0, iWidth, iHeight, hMemDC, 0, 0, SRCCOPY);
// возвращаем старый bitmap
SelectObject(hMemDC, hOldBitmap);
// освобождаем контекст
DeleteDC(hMemDC);
}
else
{
// обработка ошибки получения контекста
}
Не забудьте уничтожить все временные объекты, которые создавались (в данном случае - это memory DC). Не забудьте также перед тем как будете уничтожать memory DC, выбрать в него (через SelectObject) объект bitmap, который был создан вместе с контекстом, в противном случае произойдет утечка ресурсов.