Как рисовать прозрачные битмапы.
"Прозрачной" называется та часть картинки,
которая не изменяет содержимого экрана.
Например, функция DrawIcon может создавать
изображения с прозрачностью. Так же можно
добиться прозрачности при помощи функции BitBlt,
однако прийдётся воспользоваться
дополнительным кодом.
Сперва необходимо получить содержимое области,
где будет нарисован битмап, чтобы сохранить это
фоновое изображение в памяти контекста
устройства (DC). Далее накладывается маска на
область фона, которая отвечает за непрозрачную
часть битмапа, а также на все прозрачные пиксели
битмапа. Потом, используется растровая операция
XOR, чтобы совместить битмап картинки с битмапом
фоновой картнки. В заключении, при помощи BitBlt,
совмещённая картинка помещается в DC.
Теперь более подробно рассмотрим процесс
рисования прозрачных битмапов:
- Создаём DC для хранения битмапа.
- В DC выбираем битмап.
- Создаём в памяти DC для хранения конечной
картинки. В него будем выводить выводить
конечную картинку.
- Копируем часть экрана, на которое будет
наложена картинка в конечный DC.
- Создаём "маску AND", которая содержит маску
цветов для рисования (непрозрачная часть
картинки). Для этого делаем следующие шаги:
- Устанавливаем фоновый цвет в DC в цвет, который
будет прозрачным в картинке.
- Создаём монохромный DC.
- Применяем BitBlt к картинке в монохромном DC.
Путём установки фонового цвета
удовлетворяющих пикселей в белый(1), а всех
остальных в чёрный(0), будет создана маска AND для
битмапа.
- Используем BitBlt с растровой операцией SRCAND, чтобы
скопировать маску AND на конечный DC.
- Используем BitBlt с растровой операцией SRCAND, чтобы
скопировать инверсию маски AND в DC картинки.
- Используем BitBlt с растровой операцией SRCPAINT,
чтобы скопировать DC картинки в конечный DC.
- Используем BitBlt, чтобы скопировать содержимое
конечного DC в соответствующую часть экрана.
Следующая функция демонстрирует описанные
выше шаги:
void DrawTransparentBitmap(HDC hdc, HBITMAP hBitmap, short xStart,
short yStart, COLORREF cTransparentColor)
{
BITMAP bm;
COLORREF cColor;
HBITMAP bmAndBack, bmAndObject, bmAndMem, bmSave;
HBITMAP bmBackOld, bmObjectOld, bmMemOld, bmSaveOld;
HDC hdcMem, hdcBack, hdcObject, hdcTemp, hdcSave;
POINT ptSize;
hdcTemp = CreateCompatibleDC(hdc);
SelectObject(hdcTemp, hBitmap); // Выбираем битмап
GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);
ptSize.x = bm.bmWidth; // Получаем ширину битмапа
ptSize.y = bm.bmHeight; // Получаем высоту битмапа
DPtoLP(hdcTemp, &ptSize, 1); // Конвертируем из координат
// устройства в логические
// точки
// Создаём несколько DC для хранения временных данных.
hdcBack = CreateCompatibleDC(hdc);
hdcObject = CreateCompatibleDC(hdc);
hdcMem = CreateCompatibleDC(hdc);
hdcSave = CreateCompatibleDC(hdc);
// Создаём битмап для каждого DC.
// Монохромный DC
bmAndBack = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
// Монохромный DC
bmAndObject = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
bmAndMem = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);
bmSave = CreateCompatibleBitmap(hdc, ptSize.x, ptSize.y);
// В каждом DC должен быть выбран объект битмапа для хранения
// пикселей.
bmBackOld = SelectObject(hdcBack, bmAndBack);
bmObjectOld = SelectObject(hdcObject, bmAndObject);
bmMemOld = SelectObject(hdcMem, bmAndMem);
bmSaveOld = SelectObject(hdcSave, bmSave);
// Устанавливаем режим маппинга.
SetMapMode(hdcTemp, GetMapMode(hdc));
// Сохраняем битмап, переданный в параметре функции, так как
// он будет изменён.
BitBlt(hdcSave, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);
// Устанавливаем фоновый цвет (в исходном DC) тех частей,
// которые будут прозрачными.
cColor = SetBkColor(hdcTemp, cTransparentColor);
// Создаём маску для битмапа путём вызова BitBlt из исходного
// битмапа на монохромный битмап.
BitBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0,
SRCCOPY);
// Устанавливаем фоновый цвет исходного DC обратно в
// оригинальный цвет.
SetBkColor(hdcTemp, cColor);
// Создаём инверсию маски.
BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0,
NOTSRCCOPY);
// Копируем фон главного DC в конечный.
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdc, xStart, yStart,
SRCCOPY);
// Накладываем маску на те места, где будет помещён битмап.
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND);
// Накладываем маску на прозрачные пиксели битмапа.
BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
// XOR-им битмап с фоном на конечном DC.
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);
// Копируем на экран.
BitBlt(hdc, xStart, yStart, ptSize.x, ptSize.y, hdcMem, 0, 0,
SRCCOPY);
// Помещаем оригинальный битмап обратно в битмап, переданный в
// параметре функции.
BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcSave, 0, 0, SRCCOPY);
// Удаляем битмапы из памяти.
DeleteObject(SelectObject(hdcBack, bmBackOld));
DeleteObject(SelectObject(hdcObject, bmObjectOld));
DeleteObject(SelectObject(hdcMem, bmMemOld));
DeleteObject(SelectObject(hdcSave, bmSaveOld));
// Удаляем DC из памяти.
DeleteDC(hdcMem);
DeleteDC(hdcBack);
DeleteDC(hdcObject);
DeleteDC(hdcSave);
DeleteDC(hdcTemp);
}
Следующий пример показывает как вызывать
приведённую выше функцию DrawTransparentBitmap:
DrawTransparentBitmap(hdc, // Конечный DC.
hBitmap, // Битмап, который будет нарисован.
xPos, // координата X.
yPos, // координата Y.
0x00FFFFFF); // Цвет для прозрачных
// пикселей (в данном случае
// белый).
|