Выше уже было сказано, что одиннадцатый аргумент функции StretchBlt() - это код растровой операции. Другими словами, это код, который определяет, как при операции будут взаимодействовать биты, определяющие заливку и изображение совместимого контекста с изображением на действительном контексте. Комбинируются биты на основе логических операций над ними. По укоренившейся в книге по программированию для Windows традиции, эти операции записываются в обратной польской нотации (не путать с венгерской, автор польской нотации не имеет к Microsoft ни малейшего отношения).
По той же традиции, биты, определяющие bitmap совместимого контекста, обозначают буквой S (source - источник, исходный), биты заливки - буквой P (pattern - образец), а биты, на которых будет прорисовываться изображение - буквой D (destination - назначение, место назначения). Операции обозначаются следующим образом: a - побитовое И (AND), n - побитовое НЕТ (NO), o - побитовое ИЛИ (OR), x - побитовое исключающее ИЛИ (XOR).
Несколько слов о польской нотации. В ней операции записываются слева направо. Знак операции
следует за операндами. Появление знака операции означает, что нужно произвести следующие
действия:
- взять два последних операнда
- произвести с ними требующуюся операцию
- записать результат на место последних двух операндов.
Фактически польская нотация описывает действия таким образом, словно операнды и операции находятся в стеке, для чего, собственно, эта польская нотация и была изобретена.
Обозначив знак операции как Op, в польской нотации действия с битами можно записать таким образом:
PSOp
Это говорит о необходимости взять пиксель патерны и прорисоваемого bitmap'а и произвести над ним операцию. Если в операции участвуют три операнда, то получим:
DPSOp1Op2
Что мы должны сделать в этом случае? Правильно, сначала произвести действие, определяемое Op1, с битами патерны и прорисовываемым bitmap'ом, после этого произвести Op2 с полученным результатом и битами действительного контекста. Ничего сложного здесь нет.
Каждый код растровой операции представляется 32-битным целым. Старшее слово кода представляет собой индекс битовой операции, младшее - код операции. Как определяется индекс операции?
Давайте представим, что нам необходимо определить индекс растровой операции, определяемой в польской нотации записью DPSxx. Попутно можно определить и индекс операции PSx. Запишем друг под другом ОПРЕДЕЛЕННЫЕ значения P,S и D, а под ними - результаты побитовых операций PSx и DPSxx:
P | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
S | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 |
D | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
PSx | 0 | 0 | 1 | 1 | 1 | 1 | 0 | 0 |
DPSxx | 0 | 0 | 0 | 1 | 0 | 1 | 1 | 0 |
Итак, индекс операции PSx - 0x3C, а индекс операции DPSxx - 0x96.
Уважаемый читатель, я прошу обратить внимание на то, что друг под другом записываются не
произвольные, а строго определенные значения. Эти значения позволяют перебрать все возможные
комбинации патерны, исходного и целевого bitmap'ов. Теперь, когда все стало ясно, вы можете
попробовать попрактиковаться в определении индексов дюбых операций. Несмотря на то, что
существуют 256 индексов растровых операций, на практике используются только некоторые из них. В
файле wingdi.h для наиболее часто используемых растровых операций определены идентификаторы,
которые приведены в таблице:
Наименование | Индекс операции |
Польская запись |
Эффект |
BLACKNESS | 0x00 | 0 | Заполнение действительного контекста черным цветом |
NOTSRCERASE | 0x11 | DSon | |
NOTSRCCOPY | 0x33 | Sn | Прорисовываемый bitmap отображается в негативном виде |
DSTINVERT | 0x55 | Dn | Изображение действительного контекста проявляется негативным |
PATINVERT | 0x5A | DPx | |
SRCINVERT | 0x66 | DSx | |
SRCAND | 0x88 | DSa | |
MERGEPAINT | 0xBB | DSno | |
MERGECOPY | 0xC0 | PSa | |
SRCCOPY | 0xCC | S | Копирование прорисовываемого bitmap'а на действительный контекст |
SCRPAINT | 0xEE | DSo | |
PATCOPY | 0xF0 | P | Копирование патерны на действительный контекст |
PATPAINT | 0xFB | DPSnoo | |
WHITENESS | 0xFF | 1 | Заполнение действительного контекста белым цветом |
На основании данных таблицы я затрудняюсь объяснить, как изменяется изображение при использовании разных растровых операций. Рекомендую читателю запустить приведенную выше программу несколько раз, и каждый раз в функции StretchBlt() указывать новую растровую операцию.
Теперь и одиннадцатый аргумент PatBlt() стал ясным и понятным - я просто копирую bitmap в окно. Только и всего. Кстати, понимание логики работы с растровыми операциями может позволить избежать трудоемких преобразований bitmap'ов перед копированием.