Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Работа с зависимым от устройства битмапом

 

Небольшое замечание: так как битмап является объектом GDI, то вы обязаны удалить его, как только он станет ненужным. Это относится ко всем битмапам, как созданным с помощью функций CreateBitmap, CreateBitmapIndirect, CreateCompatibleBitmap, CreateDiscardableBitmap, так и к загруженным с помощью функции LoadBitmap. Освобождение неиспользуемых битмапов особенно важно, так как это едва–ли не самые большие объекты GDI, занимающие значительные ресурсы.

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

HBRUSH hbrBrush = CreatePatternBrush (hBmp);

DeleteBitmap (hBmp); // 2

После того, как мы создали кисть, битмап можно удалять, так как его образ скопирован в кисть и больше не используется. Если битмап больше, чем 8x8 пикселей, то для создания кисти будет использован его верхний–левый уголок, размером 8x8.

Все остальные операции по работе с битмапами осуществляются посредством специально создаваемого контекста устройства, ассоциированного с этим битмапом. Для этого был разработан специальный вид контекстов устройства — совместимый контекст (compatible device context, compatible DC, чаще называемый memory device context, memory DC). Такой разнобой в названиях контекста связан, с одной стороны, с названием функции, его создающей — CreateCompatibleDC — создающей контекст устройства, совместимого с другим, реально существующим устройством (см. раздел «Получение хендла контекста устройства»). А, с другой стороны, созданный таким образом контекст устройства не соответствует никакому физическому устройству, его область отображения — некоторое растровое изображение, хранимое в памяти. Отсюда второе название — memory DC.

Совместимость контекста не значит, что его цветовая организация совпадает с организацией реально существующего контекста, а только лишь то, что принципы выполнения операций над этим контекстом будут такими же, как для реального устройства — например, при выводе на совместимый контекст может применяться графический акселератор, если для контекста реального устройства, указанного в качестве прототипа при создании совместимого, такой акселератор используется (конечно, это зависит еще и от возможностей самого акселератора).

Только что созданный совместимый контекст устройства имеет монохромную область отображения размером 1 пиксель. Так как нарисовать что–нибудь осмысленное в такой области нереально, вы должны принять меры к тому, что бы область отображения этого контекста была ассоциирована с хранимым в памяти растровым изображением — зависимым от устройства битмапом. Это делается тривиально — битмап выбирается в совместимый контекст устройства с помощью обычной функции SelectObject. После этого область отображения совместимого контекста будет совпадать с указанным битмапом — как по размерам, так и по цветовой организации.

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

Общая схема при этом выглядит следующим способом:

HDC hCompatDC;

HBITMAP hBmp;

hCompatDC = CreateCompatibleDC (hDC);

// функция CreateCompatibleDC () создает совместимый

// контекст устройства, соответствующий одному монохромному пикселу

hBmp = LoadBitmap (hInstance, lpszName);

// для получения хендла битмапа мы могли воспользоваться любым

// способом - его загрузкой из ресурсов или созданием

SelectObject (hCompatDC, hBmp);

// теперь совместимый контекст устройства соответствует нашему битмапу.

//... здесь мы можем выполнять любые операции по рисованию на нашем битмапе

//... или передавать изображения между разными контекстами устройств.

DeleteDC (hCompatDC);

// после того, как мы выполнили все нужные операции над контекстом

// устройства, мы можем его удалить.

//... При этом битмап как объект GDI остается и мы можем свободно

//... применять его хендл. Например, для создания кисти, или для

//... отображения пункта меню.

DeleteObject (hBmp);

// после того, как битмап стал нам не нужен, мы можем его уничтожить

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

HDC hCompatDC;

HBITMAP hBmp;

hCompatDC = CreateCompatibleDC (hDC);

hBmp = CreateCompatibleBitmap (hDC, 500, 300)

SelectObject (hCompatDC, hBmp);

PatBlt (hCompatDC, 0,0, 500,300, PATCOPY);

//... здесь мы можем выполнять любые операции по рисованию на нашем битмапе

//... или передавать изображения между разными контекстами устройств.

DeleteDC (hCompatDC);

//... Работаем с битмапом как с объектом GDI

DeleteObject (hBmp);

В этом примере надо отметить два момента: Во–первых, при создании битмапа в качестве прототипа задается обязательно контекст реального устройства (с заданной цветовой организацией), а не совместимого (который соответствует одному монохромному пикселю). Битмап, совместимый с совместимым контекстом устройства будет монохромным! Во–вторых, созданный совместимый битмап содержит произвольные данные, поэтому перед его использованием изображение надо очистить. В этом примере функция PatBlt закрашивает битмап текущей кистью (операция PATCOPY), иногда для начальной закраски используют не текущую кисть (по умолчанию — WHITE_BRUSH может быть не белой), а белый или черный цвета (операции WHITENESS, BLACKNESS). Это зависит от дальнейшего использования: фон битмапа должен совпадать с фоном окна или должен быть конкретного цвета.

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

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

 

Операции передачи образов

 

Рассматривая применение битмапов мы обратили внимание на специальный механизм, осуществляющих передачу растровых изображений между различными контекстами устройств. Этот механизм называется операции по обмену блоками бит (b it b l ock t ransfer, BLT) или тернарными растровыми операциями (ternary raster operation).

Основная идея растровых операций (слово тернарные часто опускают, в отличие от слова бинарные — см. раздел «Режим рисования», стр. 26) заключается в организации обмена данными между двумя контекстами устройств. Эти операции универсальны — они работают с любыми контекстами устройств, поддерживающими обмен растровыми изображениями (например, устройства типа плоттера такими возможностями, естественно, не обладают). Таким образом вы можете осуществить передачу изображения и между битмапом, выбранным в совместимый контекст устройства и реальным устройством на котором хотите это изображение показать, между двумя битмапами или передать имеющееся изображение с реального устройства в битмап или на другое устройство.

GDI содержит 3 функции, осуществляющих такую передачу изображений — PatBlt, BitBlt и StretchBlt (заметьте, что аббревиатура BLT произносится как БЛИТ):

BOOL PatBlt (

hDC, nX, nY, nWidth, nHeight, dwROP);

BOOL BitBlt (

hDestDC, nDestX, nDestY, nDestWidth, nDestHeight,

hSrcDC, nSrcX, nSrcY, dwROP);

BOOL StretchBlt (

hDestDC, nDestX, nDestY, nDestWidth, nDestHeight,

hSrcDC, nSrcX, nSrcY, nSrcWidth, nSrcHeight, dwROP);

Все три функции выполняют сходные операции — они строят результирующее изображение на контексте–приемнике, используя в качестве исходных данных:

изображение, создаваемое на приемнике при закраске фона текущей кистью, выбранной в контекст–приемник (это называется образцом, pattern).

изображение, существующее на контексте–источнике (исходное изображение, source).

изображение, существующее в данный момент на контексте–приемнике (имеющееся изображение, destination).

В процессе выполнения растровой операции эти три исходных изображения (битовых последовательности) комбинируются и получается результирующее изображение. Так как в операции участвуют три исходных последовательности, то операция получила название тернарной (ternary).

Код выполняемой операции задается параметром dwROP — индексом тернарной растровой операции.

В документации по SDK можно найти таблицу, перечисляющую индексы 256 возможных растровых операций, их имена и короткое пояснение к каждой операции. Причем имена присвоены только 15 наиболее употребляемым операциям. Таблица, представленная в документации имеет следующий вид:

 

Number Hex ROP Boolean function Common Name
0 00000042 0 BLACKNESS
  ...    
0D 000D0B25 PDSnaon  
  ...    
       

 

Поле «Hex ROP» содержит индекс тернарной растровой операции, который вы должны использовать в качестве параметра dwROP. Поле «Boolean function» содержит пояснение к выполняемой операции, а поле «Common name» — имя растровой операции, если оно назначено. Однако разобраться в том, какая конкретно операция выполняется в процессе переноса изображения не так–то просто.

Попробуем пояснить это на примере: операция с индексом 000D0B25 обозначает операцию PDSnaon. Это обозначение содержит в обратной польской записи логические операции над битами, выполняемые в процессе растровой операции. Сначала указаны большими буквами используемые компоненты:

P: образец, (кисть, pattern)

D: существующее изображение (destination)

S: исходное изображение (source),

в общем случае для обозначения компонент операции используются эти три больших буквы, но порядок их перечисления зависит от выполняемой операции. После перечисления компонентов следуют маленькие буквы, указывающие выполняемые операции:

n: инверсия, not; операция использует 1 аргумент

a: пересечение, and; операция использует 2 аргумента

o: объединение, or; операция использует 2 аргумента

x: исключающее ИЛИ, xor; операция использует 2 аргумента

Для того, что бы понять как выполняются эти операции представим, что у нас есть стек, и каждая буква в записи указывает операцию: большая буква выполняет запись в стек, маленькая — операцию над нижними данными в стеке, причем они из стека извлекаются, а результат операции размещается в стеке. Посмотрим на примере:

 

Рисунок 17. Пример расшифровки обозначения растровой операции.


Таким образом, получаем последовательность операций для формирования результата. Однако использовать такую табличку со списком тернарных растровых операций может быть удобно только при получении справок. А вот если мы можем словами описать нужную последовательность действий, а для нее надо определить индекс растровой операции, то такая таблица совершенно неудобна (одного результата можно достичь, выполняя операции различным образом; даже если вы запишите требуемые действия в рассмотренной форме, нет никакой гарантии, что в таблице такая запись найдется).

Попробуем научиться как-то иначе получать индекс тернарной растровой операции.

Мы уже встречались с бинарными растровыми операциями (ROP2) когда рассматривали рисование линий. Сейчас мы воспользуемся примерно таким же подходом — мы будем исходить из предположения монохромных контекстов устройств (для простоты) и попробуем составить табличку, аналогичную той, что применялась для бинарных растровых операций:

 

Образец, кисть (pattern) 1 1 1 1 0 0 0 0
Исходное изображение (source) 1 1 0 0 1 1 0 0
Существующее изображение (destination) 1 0 1 0 1 0 1 0

 

Такая табличка позволяет описать все 256 тернарных операций, поэтому приводить ее целиком не имеет смысла. Однако нам будет удобно использовать подобную запись для определения индекса тернарной операции.

Попробуем, например, найти индекс растровой операции, в результате которой мы получим светлую точку, если:

а) контекст–источник имеет светлую точку

б) контекст–источник и контекст–приемник имеют темные точки

в) только в том случае, когда образец содержит темную точку

Имеется в виду операция ((а) или (б)) и (в). Составим табличку:

 

Образец, кисть (pattern) 1 1 1 1 0 0 0 0
Исходное изображение (source) 1 1 0 0 1 1 0 0
Существующее изображение (destination) 1 0 1 0 1 0 1 0
Желаемый результат 0 0 0 0 1 1 0 1

 

Как и в случае бинарных растровых операций мы можем использовать этот результат как номер операции (и заодно как старшее слово индекса). Этот номер равен 0b00001101 = 0x0D. Это уже рассмотренная нами операция с индексом 0x000D0B25 (PDSnaon).

Разобравшись с растровыми операциями, самое время разобраться с функциями, выполняющими эти операции. Самая простая из трех рассмотренных — функция PatBlt. Она не использует контекст–источник и выполняет операцию только над контекстом–приемником и образцом (фоном, полученным в результате закраски текущей кистью).

BOOL PatBlt (hDC, nX, nY, nWidth, nHeight, dwROP);

Эта функция может использоваться со всеми растровыми операциями, не применяющими контекст–источник. Из именованных растровых операций это:

 

BLACKNESS — закрасить все черным
DSTINVERT — инвертировать изображение (сделать "негатив")
PATCOPY — закрасить кистью
PATINVERT — закрасить инвертированной кистью
WHITENESS — закрасить все белым

 

Эта функция часто используется для начальной закраски областей (операции BLACKNESS, WHITENESS, PATCOPY) и для выделения фрагментов (DSTINVERT).

Следующая функция, которую мы рассмотрим:

BOOL BitBlt (

hDestDC, nDestX, nDestY, nDestWidth, nDestHeight,

hSrcDC, nSrcX, nSrcY, dwROP);

Она осуществляет передачу изображений между двумя контекстами устройств, при этом передается прямоугольный фрагмент, который на контексте-приемнике и на контексте-источнике имеет одинаковые размеры. При использовании этой функции надо быть достаточно осторожным — для задания координат и размеров используется логическая система координат, и логический размер изображения в обеих системах может быть различным.

Отдельно надо рассмотреть случай, когда один из контекстов является цветным, а другой черно–белым — при этом особым образом осуществляется преобразование цветов:

при переходе от монохромного к цветному цвет, закодированный 1, соответствует цвету фона (задаваемому функцией SetBkColor), а цвет 0 — цвету текста (функция SetTextColor).

при переходе от цветного к монохромному считается, что если цвет точки совпадает с цветом фона, то эта точка кодируется цветом 1, иначе 0.

Самая мощная функция, выполняющая растровые операции:

BOOL StretchBlt (

hDestDC, nDestX, nDestY, nDestWidth, nDestHeight,

hSrcDC, nSrcX, nSrcY, nSrcWidth, nSrcHeight, dwROP);

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

изображение увеличивается, то некоторые строки (столбцы) будут дублироваться;

изображение уменьшается, то некоторые строки (столбцы) будут комбинироваться в одну строку (столбец).

Объединение строк (столбцов) при сжатии может осуществляться различными способами, которые выбираются с помощью функции

UINT SetStretchBltMode (hDC, nMode);

параметр nMode задает режим объединения строк:

 

BLACKONWHITE выполняется операция И (AND). В результате получается, что черный цвет имеет "приоритет" над белым — сочетание черного с белым рассматривается как черный
WHITEONBLACK выполняется операция ИЛИ (OR). При этом "приоритет" принадлежит белому над черным — сочетание черного с белым дает белый
COLORONCOLOR при этом происходит простое исключение строк (столбцов).
HALFTONE 1 только в Win32 API; происходит усреднение цвета объединяемых точек.

 

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...