47952 (597372), страница 11
Текст из файла (страница 11)
HRGN CreatePolyPolygonRgn (lpPoints, lpCounts, nPolyCount, nPolyFillMode);
Аргументы этих функций подобны аргументам функций, осуществляющих рисование аналогичных фигур, поэтому рассматривать их здесь не будем. Параметр nPolyFillMode аналогичен соответствующему атрибуту контекста устройства — режиму заполнения многоугольников.
В результате вызова одной из функций Create...Rgn создается специальный объект, описывающий регион, а нам возвращается хендл этого объекта.
Как и всякий объект GDI регион удаляется с помощью функции DeleteObject.
Одной из самых интересных особенностей регионов является возможность комбинирования нескольких регионов в один, более сложный. Это делается с помощью функции:
int CombineRgn (hrgnDest, hrgnSrc1, hrgnSrc2, nMode);
Данная функция позволяет выполнить определенную параметром nMode операцию над двумя (или одним) исходными регионами и результат записать в третий регион. При этом новый регион не создается, вы должны предварительно создать какой-либо регион и его хендл передать в качестве hrgnDest. В этом регионе будет размещен результат выполнения операции. Такое, на первый взгляд странное, правило позволяет несколько уменьшить количество создаваемых объектов.
Итак, с помощью функции CombineRgn, мы можем выполнять различные операции, задавая номер нужной операции в параметре nMode:
| RGN_AND | — получить пересечение двух регионов (точки, входящие в оба региона одновременно) |
| RGN_OR | — получить объединение регионов (точки, входящие хотя бы в один из двух регионов) |
| RGN_XOR | — получить объединение без перекрывающихся областей |
| RGN_DIFF | — получить часть первого региона, не входящую во второй регион |
| RGN_COPY | — скопировать первый регион (второй регион не используется) |
При этом функция возвращает информацию о том, какой регион получен:
| SIMPLEREGION | — если итоговый регион состоит из не перекрывающихся примитивов |
| COMPLEXREGION | — если примитивы, входящие в итоговый регион, перекрываются |
| NULLREGION | — итоговый регион пустой (не имеет общих точек) |
| ERROR | — возникла ошибка (например, недостаточно памяти) |
В заголовочном файле windowsx.h включено несколько макросов, основанных на функции CombineRgn:
int CopyRgn (hrgnDest, hrgnSrc); 2
int IntersectRgn (hrgnDest, hrgnSrc1, hrgnSrc2); 2
int SubtractRgn (hrgnDest, hrgnSrc1, hrgnSrc2); 2
int UnionRgn (hrgnDest, hrgnSrc1, hrgnSrc2); 2
int XorRgn (hrgnDest, hrgnSrc1, hrgnSrc2); 2
Существует еще одна функция, которая может изменить тип региона, она позволяет заменить указанный вами любой регион на регион прямоугольной формы:
void SetRectRgn (hrgnSrc, lpRect);
Таким образом, применяя функции создания регионов и их комбинируя мы можем описать области очень сложной формы. Теперь нам надо разобраться с основными способами применения регионов.
Во–первых, мы можем применять регионы как абстрактные объекты, и выполнять над ними какие-либо операции, например перемещение, аналогично операциям над прямоугольниками:
int OffsetRgn (hrgnSrc, nDeltaX, nDeltaY);
или проверять совпадение регионов:
BOOL EqualRgn (hrgnSrc1, hrgnSrc2);
Кроме того мы можем проверить принадлежность точки или прямоугольника региону:
BOOL PtInRegion (hrgnSrc, nX, nY);
BOOL RectInRegion (hrgnSrc, lpRect);
И еще одна функция позволяет получить прямоугольник, описанный вокруг указанного региона:
int GetRgnBox (hrgnSrc, lpRect);
Во–вторых, регионы могут отображаться на контексте устройства, например для закраски областей или обведения контура области сложной формы:
BOOL InvertRgn (hDC, hrgnSrc);
BOOL PaintRgn (hDC, hrgnSrc);
BOOL FillRgn (hDC, hrgnSrc, hbrBrush);
BOOL FrameRgn (hDC, hrgnSrc, hbrBrush, nFrameWidth, nFrameHeight);
Функция InvertRgn осуществляет операцию BITWISE NOT над всеми точками, входящими в указанный регион; она аналогична функции InvertRect. Функция PaintRgn закрашивает регион текущей кистью. Она подобна функции FillRgn, которая закрашивает регион указанной вами, а не текущей, кистью. Самая интересная функция — FrameRgn, которая проводит вокруг региона каемку указанной ширины и указанной кистью. То есть эта функция аналогична функции FrameRect, за исключением того, что область может быть сложной формы и вы можете задать ширину каемки, причем как по горизонтали, так и по вертикали.
Рисунок 14. Применение регионов для закраски и областей и обведения области контуром.
В–третьих, еще один из способов применения регионов связан с обработкой сообщения WM_PAINT. Ранее мы говорили о том, что сообщение WM_PAINT генерируется, когда у окна появляется неверный прямоугольник.
Это не совсем точно — вместо неверного прямоугольника обычно используется регион. Аналогично прямоугольникам, у вас есть две функции, одна из которых объявляет неверный регион, а другая указывает, что регион стал верным:
void InvalidateRgn (hWnd, hrgnSrc, fEraseBkgnd);
void ValidateRgn (hWnd, hrgnSrc);
Если сообщение WM_PAINT генерируется в результате появления неверного региона, то полученный с помощью функции BeginPaint контекст устройства может применяться только для рисования внутри неверного региона.
В–четвертых, регион, являясь объектом GDI, может быть выбран в контекст устройства. Регион, выбранный в контекст устройства, определяет область этого контекста, на которой возможно рисование. При этом он является как бы "маской" через которую видно рисуемое изображение.
Рисунок 15. Исходное изображение (слева), регион (в центре) и нарисованное изображение (справа). Светло–серым цветом показан неизменяемый данным рисунком фон.
Для того, что бы выбрать регион в контекст устройства, вы должны воспользоваться функцией
int SelectClipRgn (hDC, hrgnSrc);
Эта функция возвращает целое число, указывающее тип выбранного региона (SIMPLEREGION, COMPLEXREGION, NULLREGION). При выборе региона в контекст устройства он копируется, поэтому вы можете удалить его или использовать иным образом сразу после выбора в контекст устройства.
Кроме функции SelectClipRgn вы можете воспользоваться функцией SelectObject с той же целью. При этом функция SelectObject будет использоваться точно также, как и функция SelectClipRgn, и вернет не хендл предыдущего региона, а тип выбранного вами.
Растровые изображения и метафайлы
В Windows существует возможность хранить изображения в виде картинок, сохраняющих рисунок в виде информации о цветах отдельных точек. Такие изображения иногда называются растровыми, так как информация о цвете точек группируется по строкам растра изображения, или битмапами (bitmap), иногда термин bitmap даже переводят дословно — битовая карта. В ранних версиях Windows битмапы точно соответствовали образу в графической памяти устройства, на которое осуществлялся вывод. При этом информация о передаче цветов соответствовала в точности формату цветовой памяти устройства. Такие битмапы получили название зависимых от устройства битмапов (device–depended bitmap, DDB)
Так, например, для четырехцветных видеоадаптеров CGA каждый пиксель кодировался двумя последовательными битами в видеопамяти — такой–же была организация битмапов, отображаемых на дисплее. А если использовался 16ти–цветный адаптер EGA, в котором для задания каждого пикселя требовалось задать 4 бита лежащих в различных цветовых плоскостях (planes), то и битмап создавался аналогично — каждая строка растра была представлена 4 раза, для каждой цветовой плоскости по разу. Несомненным достоинством таких изображений была простота их отображения на конечном устройстве и высокая скорость вывода.
Но были и недостатки — главный из них — цвет конкретной точки определяется непосредственно настройками аппаратуры и остается независим от самого растрового изображения. То есть попытка отобразить одно и то же изображение при различных настройках (допустим, при различных используемых палитрах), приводила к искажению цветов исходного изображения. Помимо этого при попытке отобразить одно и тоже изображение на разных устройствах требовалось преобразовывать информацию о кодировании цветов — что опять же требовало дополнительных данных о назначении цветов в обоих устройствах.
Все это привело к тому, что был разработан новый стандарт хранения растровых изображений — так называемые независимые от устройства битмапы (device–independed bitmap, DIB). Этот битмап отличается от DDB как фиксированным способом кодирования цвета каждой точки — последовательной группой бит — так и наличием информации о назначении цветов — так называемой палитры (palette) — или иной информации, позволяющей определить точное назначение цветов каждой точки.
Начиная с Windows 3.x все битмапы, представленные в виде файлов или ресурсов приложения, являются независимыми от устройства битмапами (DIB), в то время как после загрузки в память приложения эти битмапы могут быть представлены как в виде независимых от устройства, так и в виде зависимых — смотря по способу загрузки и использования.
Говоря о битмапах надо выделить несколько обсуждаемых аспектов, решаемых для каждого вида битмапов своим способом;
получение битмапа
формирование или коррекция изображения
отображение битмапа
сохранение независимых от устройства битмапов в файлах
Для зависимых и для независимых от устройства битмапов эти задачи решаются разными методами с привлечением разных функций и инструментов. Использовать один вид битмапов в функциях, предназначенных для работы с другим видом битмапов, невозможно. В последующих разделах эти задачи будут обсуждены более подробно, здесь же будет намечена общая схема решения этих задач для каждого вида битмапов. В некоторых случаях битмапы можно применять другими способами — например для создания кистей, передачи изображения через буфер обмена (clipboard) и так далее.
Помимо растровых изображений (зависимых и независимых от устройства битмапов) в Windows предусмотрен еще один способ сохранения изображений — сохранение рисунка в метафайлах.
Обзор зависимых от устройства битмапов (DDB)
Зависимый от устройства битмап (DDB) является объектом GDI и работа с ним осуществляется также, как и обычными объектами GDI — перьями, кистями и прочим. Говоря об идентификации зависимого от устройства битмапа говорят о его хендле — хендле объекта GDI. Более того, так как независимые от устройства битмапы не являются объектами GDI, то они также не имеют специфичных хендлов. Как только в тексте упоминается некоторый хендл битмапа (HBITMAP), то можно однозначно утверждать, что подразумевается зависимый от устройства битмап, DDB.
Более того, зависимые от устройства битмапы в реальной жизни представлены именно как объекты GDI, так как во всех современных версиях Windows изображения хранятся в виде независимых от устройства битмапов. То есть любой сохраняемый на диске (в виде файла или ресурсов приложения) битмап — всегда независимый от устройства, и только после его загрузки в память в виде объекта GDI он станет зависимым от устройства битмапом.
Конечно, независимые от устройства битмапы могут быть загружены в память непосредственно, однако часто для представления в памяти используются именно DDB, так как его отображение выполняется быстрее и он как правило занимает меньше ресурсов.
Получение битмапа;
Для получения хендла битмапа вы можете либо создать новый объект и получить его хендл, либо загрузить уже имеющееся изображение. Так как во всех современных версиях Windows битмапы реально хранятся в виде независимых от устройства, то для загрузки изображения в виде DDB надо осуществить преобразование независимого битмапа в зависимый. Это делается либо автоматически — при загрузке битмапа из ресурсов приложения, либо это надо осуществить непосредственно в вашем приложении.
Формирование или коррекция битмапа;
Для рисования на битмапе создается контекст устройства, ассоциированный с данным битмапом, после чего все функции GDI, применяемые к этому контексту, реально взаимодействуют с битмапом и формируют его изображение. Для выполнения этой задачи предназначен совместимый контекст устройства (compatible DC, memory DC), который предназначен именно для этого.
Отображение битмапа на контексте устройства;
В конце концов все и затевается ради возможности отобразить битмап в окошке или на листе бумаги. GDI не содержит специальных функций для отображения DDB. Вместо этого вы должны ассоциировать битмап с контекстом устройства (как и для рисования), а затем осуществить передачу изображения с одного контекста на другой — для этого в GDI содержится специальный набор функций, называемых функциями передачи растровых изображений или, дословно, функциями для передачи блоков бит (Bit Block Transfer, BLT — произносится «блит »)
Обзор независимых от устройства битмапов (DIB)















