Графический интерфейс GDI в Microsoft Windows (2)

         

Шрифты



Шрифты

Для того чтобы рисовать текст, используются шрифты . Как мы уже говорили в предыдущих томах "Библиотеки системного программиста", операционная система Windows версии 3.1 может работать с растровыми, векторными и масштабируемыми шрифтами. Кроме этого, приложения Windows могут использовать шрифты, встроенные в устройство вывода (обычно это принтерные шрифты).

Растровые шрифты содержат битовые образы всех символов. Для каждого размера шрифта необходимо иметь свой набор символов. Кроме того, различные устройства вывода имеют разное соотношение горизонтальных и вертикальных размеров пиксела, что приводит к необходимости хранить отдельные наборы образов символов не только для разных размеров шрифта, но и для разного соотношения размеров пиксела физического устройства отображения.

Растровые шрифты плохо поддаются масштабированию, так как при этом наклонные линии контура символа принимают зазубренный вид.

Векторные шрифты хранятся в виде набора векторов, описывающих отдельные сегменты и линии контура символа, поэтому они легко масштабируются. Однако их внешний вид далек от идеального. Как правило, векторные шрифты используются для вывода текста на векторные устройства, такие, как плоттер.

Масштабируемые шрифты TrueType впервые появились в Windows версии 3.1 и сильно повлияли на рост популярности этой операционной системы. Шрифты True Type поддаются масштабированию без существенных искажений внешнего вида.



Создание цветовой палитры



Создание цветовой палитры

Процесс создания цветовой палитры несложен. Вначале надо убедиться в том, что bmp-файл содержит таблицу цветов. Если размер таблицы цветов не равен нулю, следует заказать память для структуры LOGPALETTE , заполнить соответствующим образом заголовок и переписать в палитру цвета из таблицы цветов: lpPal->palVersion = 0x300; lpPal->palNumEntries = wNumColors; for (i = 0; i < wNumColors; i++) { lpPal->palPalEntry[i].peRed =lpbmi->bmiColors[i].rgbRed; lpPal->palPalEntry[i].peGreen=lpbmi->bmiColors[i].rgbGreen; lpPal->palPalEntry[i].peBlue =lpbmi->bmiColors[i].rgbBlue; lpPal->palPalEntry[i].peFlags = 0; }

Палитра создается с помощью функции CreatePalette: hPal = CreatePalette(lpPal);





Создание изображений в памяти



Создание изображений в памяти

Другой способ работы с изображениями в формате DDB заключается в создании их непосредственно в оперативной памяти.

Вы должны подготовить массив, содержащий биты изображения, заполнить структуру типа BITMAP, которая описывает изображение, и затем вызвать функцию CreateBitmapIndirect , указав ей в качестве единственного параметра указатель lpbm на заполненную структуру типа BITMAP: HBITMAP CreateBitmapIndirect(BITMAP FAR* lpbm);

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

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

Например, пусть нам надо нарисовать битовое изображение, показанное в увеличенном виде на Рисунок 4.2.



Создание кисти



Создание кисти

Если вам нужна цветная кисть, ее следует создать с помощью функции CreateSolidBrush : HBRUSH WINAPI CreateSolidBrush(COLORREF clrref);

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

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

После использования созданной вами кисти ее следует удалить, не забыв перед этим выбрать в контекст отображения старую кисть. Для удаления кисти следует использовать макрокоманду DeleteBrush : #define DeleteBrush(hbr) DeleteObject((HGDIOBJ)(HBRUSH)(hbr))

Приложение может заштриховать внутреннюю область замкнутой фигуры, создав одну из шести кистей штриховки функцией CreateHatchBrush : HBRUSH WINAPI CreateHatchBrush(int fnStyle, COLORREF clrref);

С помощью параметра clrref вы можете определить цвет линий штриховки.

Параметр fnStyle задает стиль штриховки:



Создание области



Создание области

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



Структура PRINTDLG



Структура PRINTDLG

В качестве параметра функции PrintDlg необходимо передать адрес предварительно подготовленной структуры типа PRINTDLG , описанной в файле commdlg.h: typedef struct tagPD { DWORD lStructSize; HWND hwndOwner; HGLOBAL hDevMode; HGLOBAL hDevNames; HDC hDC; DWORD Flags; UINT nFromPage; UINT nToPage; UINT nMinPage; UINT nMaxPage; UINT nCopies; HINSTANCE hInstance; LPARAM lCustData; UINT (CALLBACK* lpfnPrintHook)(HWND, UINT,WPARAM,LPARAM); UINT (CALLBACK* lpfnSetupHook)(HWND, UINT,WPARAM,LPARAM); LPCSTR lpPrintTemplateName; LPCSTR lpSetupTemplateName; HGLOBAL hPrintTemplate; HGLOBAL hSetupTemplate; } PRINTDLG; typedef PRINTDLG FAR* LPPRINTDLG;

Рассмотрим назначение отдельных полей этой структуры.



Функция возвращает контекст отображения, позволяющий



Таблица 1

КонстантаОписание
DCX_WINDOW Функция возвращает контекст отображения, позволяющий рисовать во всем окне, а не только в его внутренней области
DCX_CACHE Функция получает общий контекст отображения из кеша Windows, даже если окно создано на базе класса стиля CS_OWNDC или CS_CLASSDC
DCX_CLIPCHILDREN Видимые области всех дочерних окон, расположенных ниже окна hwnd, исключаются из области отображения
DCX_CLIPSIBLINGS Видимые области всех окон-братьев (окон, имеющих общих родителей), расположенных выше окна hwnd, исключаются из области отображения
DCX_PARENTCLIP Для отображения используется вся видимая область родительского окна, даже если родительское окно создано с использованием стилей WS_CLIPCHILDREN и WS_PARENTDC. Начало координат устанавливается в левый верхний угол окна hwnd
DCX_EXCLUDERGN Если указан этот флаг, при выводе будет использована область ограничения, заданная параметром hrgnClip
DCX_INTERSECTRGN Используется пересечение области ограничения, заданной параметром hrgnClip, и видимой области полученного контекста отображения
DCX_LOCKWINDOWUPDATE Этот флаг разрешает рисование в окне, заблокированном для рисования функцией LockWindowUpdate . Флаг можно использовать при необходимости рисовать, например, рамку, выделяющую произвольную область экрана
Контекст отображения, полученный функцией GetDCEx, следует освободить после использования при помощи функции ReleaseDC.


Таблица 1

ПолеОписание
bmType Тип битового изображения. Должен быть равен 0
bmWidthШирина битового изображения в пикселах, должна быть больше 0
bmHeightВысота битового изображения в пикселах, должна быть больше 0
bmWidthBytesРазмер памяти, занимаемый одной строкой растра битового изображения. Это значение должно быть четным, так как массив изображения состоит из целых чисел размером 16 бит. Таким образом, произведение bmWidthBytes*8 должно быть кратно 16. Кроме того, это произведение должно быть больше или равно произведению bmWidth*bmBitsPixel
bmPlanesКоличество плоскостей в битовом изображении. В зависимости от типа видеоадаптера и его режима работы для представления цвета одного пиксела может использоваться несколько бит, расположенных в одной или нескольких плоскостях видеопамяти (подробное описание структуры видеопамяти в различных режимах вы можете найти в 3 томе "Библиотеки системного программиста")
bmBitsPixelКоличество битов, используемых для представления цвета пиксела. Если используется несколько плоскостей, то это поле содержит количество бит одной плоскости, используемых для представления цвета пиксела
bmBitsДальний указатель на массив, содержащий биты изображения
Загрузив битовое изображение из ресурсов приложения, вы можете определить его размеры, узнать количество цветовых плоскостей и количество бит в одной плоскости, определяющих цвет пиксела. Кроме этого, вы можете получить указатель на область памяти, содержащую биты изображения.
Для монохромных битовых изображений используется одна плоскость. Для определения цвета пиксела (черный или белый) используется один бит памяти. Размер памяти, занимаемый одной строкой растра битового изображения, кратен величине 16 бит.
Пусть, например, вы подготовили с помощью графического редактора, входящего в состав приложения Resource Workshop, битовое изображение, показанное на Рисунок 4.1. Для наглядности каждая строка растра этого изображения пронумерована.




Таблица 1

СемействоНазвание шрифта Пример текста
Modern CourierШрифт в стиле Modern
Roman TimesШрифт в стиле Roman
Swiss HelveticaШрифт в стиле Swiss
Script Script Cyrillic Шрифт в стиле Script
Decorative Wingdings Dm13m,0=;rative
Приложения Windows могут заказывать шрифт, ссылаясь на название соответствующего семейства, однако в зависимости от состава имеющихся шрифтов Windows может предоставить в ваше распоряжение не тот шрифт, какой бы вам хотелось.
Другая важная характеристика шрифта - это размер букв. Из 11 тома "Библиотеки системного программиста" вы знаете, что для описания вертикального размера букв шрифта используются несколько параметров. Не останавливаясь на тонкостях, отметим, что шрифты, содержащие буквы разного размера, являются разными шрифтами.
Растровые шрифты, которые относятся к одному семейству, но имеют разные размеры букв, хранятся в отдельных файлах. В то же время благодаря возможности масштабирования шрифтов True Type для них нет необходимости в отдельном хранении глифов различных размеров.
GDI может выполнять масштабирование растровых шрифтов, увеличивая (но не уменьшая) размер букв. Результат такого масштабирования при большом размере букв обычно неудовлетворительный, так как на наклонных линиях контура букв образуются зазубрины (Рисунок 1.5 в первой главе).
Векторные шрифты легко поддаются масштабированию, поэтому для хранения шрифта одного семейства, но разного размера, можно использовать один файл.
Вы знаете, что шрифты могут иметь нормальное (normal), жирное (bold) или наклонное (italic) начертание:



Таблица 1

ПолеОписание
dmDeviceNameИмя драйвера принтера
dmSpecVersion Номер версии структуры DEVMODE. Для Windows версии 3.1 это поле содержит значение 0x30a
dmDriverVersionВерсия драйвера
dmSizeРазмер структуры DEVMODE в байтах
dmDriverExtraРазмер в байтах дополнительной структуры данных, которая может находиться в памяти сразу за структурой DEVMODE
dmFieldsНабор флагов, каждый из которых отвечает за свое поле структуры DEVMODE. Если флаг установлен, соответствующее поле инициализируется. возможны следующие значения: DM_ORIENTATION , DM_PAPERSIZE , DM_PAPERLENGTH , DM_PAPERWIDTH , DM_SCALE , DM_COPIES , DM_DEFAULTSOURCE , DM_PRINTQUALITY , DM_COLOR , DM_DUPLEX , DM_YRESOLUTION , DM_TTOPTION
dmOrientationОриентация бумаги. Возможные значения:DMORIENT_PORTRAIT , DMORIENT_LANDSCAPE
dmPaperSizeКод размера бумаги. Например, для бумаги формата A4 используется константа DMPAPIER_A4
dmPaperLengthДлина листа бумаги в десятых долях миллиметра
dmPaperWidthШирина листа бумаги в десятых долях миллиметра
dmScaleКоэффициент масштабирования для печати
dmCopiesКоличество печатаемых копий
dmDefaultSourceКод устройства подачи бумаги, используемого по умолчанию.
dmPrintQualityКод разрешения принтера: DMRES_HIGH , DMRES_LOW , DMRES_MEDIUM , DMRES_DRAFT или положительное число, равное количеству точек на дюйм
dmColorРежим печати для цветного принтера: DMCOLOR_COLOR - цветная печать, DMCOLOR_MONOCHROME - монохромная печать
dmDuplexВозможность печати с двух сторон бумажного листа
dmYResolutionРазрешение принтера по вертикали в точках на дюйм
dmTTOptionСпособ печати шрифтов True Type:DMTT_BITMAP - печать в графическом режиме, обычно используется для матричных принтеров;DMTT_DOWNLOAD - загрузка шрифтов True Type в память принтера, используется для лазерных принтеров, совместимых с принтерами HP LaserJet;DMTT_SUBDEV - замена шрифтов на принтерные шрифты, используется для PostScript-принтеров
Структура DEVNAMES , как мы уже говорили, содержит имя драйвера, имя принтера и имя порта вывода, к которому подключен принтер: typedef struct tagDEVNAMES { UINT wDriverOffset; UINT wDeviceOffset; UINT wOutputOffset; UINT wDefault; } DEVNAMES; typedef DEVNAMES FAR* LPDEVNAMES;
Первые три слова структуры содержат смещения текстовых строк с именами, соответственно, драйвера, принтера и порта вывода. Строки расположены в памяти непосредственно за структурой DEVNAMES. Поле wDefault может содержать флаг DN_DEFAULTPRN , в этом случае все три строки описывают принтер, выбранный по умолчанию.
Вы можете подготовить свои значения для двух описанных выше структур, заказать глобальные блоки памяти и передать их идентификаторы функции PrintDlg, записав в соответствующие поля структуры PRINTDLG.
После возврата из функции PrintDlg необходимо освободить эти блоки памяти, взяв их идентификаторы из полей hDevMode и hDevNames структуры PRINTDLG. Учтите, что функция PrintDlg может изменить значения последних двух полей, поэтому надо освобождать блоки памяти с идентификаторами, взятыми из структуры PRINTDLG после возврата из функции PrintDlg: if(pd.hDevMode != 0) GlobalFree (pd.hDevMode); if(pd.hDevNames != 0) GlobalFree (pd.hDevNames);
Если перед вызовом функции PrintDlg вы указали флаги PD_RETURNDC или PD_RETURNIC, после возврата поле hDC будет содержать, соответственно, идентификатор контекста устройства или идентификатор информационного контекста: if(fResult) return pd.hDC; else return NULL;

Из этой таблицы видны недостатки



Таблица 2

Параметр функции GetDeviceCapsCGA EGAVGA SVGA 800x 600 8514/ASVGA 1024 x 768
HORZRES640 640640 8001024 1024
VERTRES200 350480 600760 768
HORZSIZE240 240208 208280 208
VERTSIZE180 175156 152210 152
ASPECTX5 3836 3610 36
ASPECTY12 4836 3614 36
ASPECTXY13 6151 5114 51
LOGPIXELSX96 9696 96120 96
LOGPIXELSY48 7296 96120 96
Из этой таблицы видны недостатки физической системы координат.
Во-первых, вертикальное (VERTRES) и горизонтальное (HORZRES) разрешение зависит от типа видеоконтроллера.
Во-вторых, физические размеры пикселов (ASPECTX и ASPECTY ), и, что самое главное, отношение высоты и ширины пиксела также зависят от типа видеоконтроллера.
Если приложению требуется нарисовать, например, окружность или квадрат, при использовании физической системы координат придется учитывать форму пикселов, выполняя масштабирование изображения по одной из осей координат. В противном случае вместо окружности и квадрата на экране появятся эллипс и прямоугольник.


Таблица 2

Код растровой операцииЛогическое выражение Описание
SRCCOPY SИсходное изображение копируется в контекст отображения
SRCPAINT S | D Цвет полученного изображения определяется при помощи логической операции ИЛИ над цветом изображения и цветом фона
SRCAND S & DЦвет полученного изображения определяется при помощи логической операции И над цветом изображения и цветом фона
SRCINVERT S ^ DЦвет полученного изображения определяется при помощи логической операции ИСКЛЮЧАЮЩЕЕ ИЛИ над цветом изображения и цветом фона
SRCERASE S & ~D Цвет фона инвертируется, затем выполняется операция И над результатом и цветом исходного изображения
NOTSRCCOPY ~SПосле рисования цвет изображения получается инвертированием цвета исходного изображения
NOTSRCERASE ~(S | D) Цвет полученного изображения получается инвертированием результата логической операции ИЛИ над цветом изображения и цветом фона
MERGECOPY P & S Выполняется логическая операции И над цветом исходного изображения и цветом кисти
MERGEPAINT ~S | DВыполняется логическая операции ИЛИ над инвертированным цветом исходного изображения и цветом фона
PATCOPY PВыполняется копирование цвета кисти
PATPAINT P | ~S | D Цвет кисти комбинируется с инвертированным цветом исходного изображения, при этом используется логическая операция ИЛИ. Полученный результат комбинируется с цветом фона, также с помощью логической операции ИЛИ
PATINVERT P ^ DЦвет полученного изображения определяется при помощи логической операции ИСКЛЮЧАЮЩЕЕ ИЛИ над цветом кисти и цветом фона
DSTINVERT ~DИнвертируется цвет фона
BLACKNESS 0Область закрашивается черным цветом
WHITENESS 1Область закрашивается белым цветом
Остальные коды приведены в документации, которая поставляется вместе с SDK. В более удобном виде все коды растровых операций приведены в приложении к книге "Developing Windows 3.1 Application whit Microsoft C/C++" (автором которой является Brent Rector). Мы не будем воспроизводить полную таблицу для кодов растровых операций, так как во-первых, эти операции редко используются, а во-вторых, таблица занимает много места.
Для рисования битовых изображений можно использовать вместо функции BitBlt функцию StretchBlt , с помощью которой можно выполнить масштабирование (сжатие или растяжение) битовых изображений: BOOL WINAPI StretchBlt( HDC hdcDest, // контекст для рисования int nXDest, // x-координата верхнего левого угла // области рисования int nYDest, // y-координата верхнего левого угла // области рисования int nWidthDest, // новая ширина изображения int nHeightDest, // новая высота изображения HDC hdcSrc, // идентификатор исходного контекста int nXSrc, // x-координата верхнего левого угла // исходной области int nYSrc, // y-координата верхнего левого угла // исходной области int nWidthSrc, // ширина исходного изображения int nHeightSrc, // высота исходного изображения DWORD dwRop); // код растровой операции
Параметры этой функции аналогичны параметрам функции BitBlt, за исключением того, что ширина и высота исходного и полученного изображения должна определяться отдельно. Размеры исходного изображения (логические) задаются параметрами nWidthSrc и nHeightSrc, размеры нарисованного изображения задаются параметрами nWidthDest и nHeightDest.
Возвращаемое значение равно TRUE при успешном завершении или FALSE при ошибке.
Следует упомянуть также еще одну функцию, которая сама по себе не может рисовать битовые изображения, но часто используется для закраски прямоугольных областей экрана. Эта функция имеет имя PatBlt : BOOL WINAPI PatBlt( HDC hdc, // контекст для рисования int nX, // x-координата верхнего левого угла // закрашиваемой области int nY, // y-координата верхнего левого угла // закрашиваемой области int nWidth, // ширина области int nHeight, // высота области DWORD dwRop); // код растровой операции
При использовании этой функции вы можете закрашивать области экрана с использованием следующих кодов растровых операций: PATCOPY, PATINVERT, PATPAINT, DSTINVERT, BLACKNESS, WHITENESS.
Возвращаемое функцией PatBlt значение равно TRUE при успешном завершении или FALSE при ошибке.



Таблица 2

НачертаниеОбразец шрифта
NormalAaBbCcDdEeFfGgHhIiJjKkLl АаБбВвГгДдЕеЖжЗзИиКкЛлМмНн
BoldAaBbCcDdEeFfGgHhIiJjKkLl АаБбВвГгДдЕеЖжЗзИиКкЛлМмНн
ItalicAaBbCcDdEeFfGgHhIiJjKkLl АаБбВвГгДдЕеЖжЗзИиКкЛлМмНнОоПпРр
GDI получает жирное и наклонное начертание растровых шрифтов из нормального при помощи соответствующих алгоритмов утолщения и наклона шрифта. Такие алгоритмы могут быть использованы и для масштабируемых шрифтов True Type, однако лучших результатов можно достигнуть при использовании отдельных файлов шрифтов True Type для нормального, жирного и наклонного начертания.
Еще один часто используемый атрибут оформления строк текста - подчеркивание: Текст с подчеркиванием
Иногда используется шрифт с перечеркнутыми буквами.
GDI выполняет подчеркивание самостоятельно, файлы шрифтов не содержат глифы с подчеркиванием.
Растровые и векторные шрифты хранятся в системном каталоге Windows в файлах с расширением имени fon.
Глифы масштабируемых шрифтов True Type находятся в файлах с расширением имени ttf, причем сами эти файлы могут располагаться в любом каталоге. В процессе регистрации масштабируемого шрифта Windows создает в своем системном каталоге файлы с расширением имени fot, которые содержат ссылки на соответствующие ttf-файлы.
С помощью приложения Control Panel вы можете добавлять или удалять любые шрифты. Следует, однако, учитывать ограничение: в системе можно одновременно использовать не более 253, к тому же для представления жирного и наклонного начертания используются отдельные масштабируемые шрифты. Чрезмерное количество установленных шрифтов может привести к снижению производительности системы.

может быть разный для осей



Таблица 3

Режим отображенияНаправление оси X Направление оси YРазмер одной логической единицы
MM_TEXT ВправоВниз 1 пиксел
MM_LOMETRIC ВправоВверх 0,1 мм
MM_HIMETRIC ВправоВверх 0,01 мм
MM_LOENGLISH Вправо Вверх0,01 дюйм
MM_HIENGLISH Вправо Вверх0,001 дюйм
MM_TWIPS ВправоВверх 1/1440 дюйма
MM_ISOTROPIC Можно выбирать Можно выбиратьПроизвольный, одинаковый для осей Xи Y
MM_ANISOTROPIC Можно выбирать Можно выбиратьПроизвольный, может быть разный для осей X и Y
Как видно из этой таблицы, в режиме отображения MM_TEXT, выбранном в контекст отображения по умолчанию, используется нестандартное (для геометрии, математики и физики) направление оси Y - вниз от начала координат. Мы уже говорили, что такое направление оси Y удобно для отображения текста, поэтому этот режим отображения иногда называют текстовым.
Нетрудно заметить, что в режиме MM_TEXT логическая единица длины полностью соответствует физической, поэтому при рисовании геометрических фигур возможны искажения формы. Эти искажения связаны с тем, что форма пиксела для некоторых видеоконтроллеров может быть отличной от квадратной. Режим MM_TEXT неудобен для рисования фигур.
В режимах MM_LOMETRIC, MM_HIMETRIC, MM_LOENGLISH, MM_HIENGLISH, MM_TWIPS используется более привычное направление осей координат и единицы длины, не зависящие от аппаратного обеспечения устройства вывода.
В режиме MM_ISOTROPIC вы можете выбирать произвольное направление осей координат и произвольный (но одинаковый) масштаб для осей X и Y. Заметим, что произвольное направление координат в нашем случае не подразумевает их произвольного расположения относительно вертикальной и горизонтальной осей - ось X может располагаться только горизонтально, ось Y - только вертикально.
Режим MM_ANISOTROPIC еще более универсален. Он позволяет устанавливать произвольное направление осей координат, произвольный масштаб для осей координат, причем для каждой оси можно установить свой собственный масштаб.
Во всех режимах отображения, кроме MM_TEXT и MM_ANISOTROPIC с разным масштабом для осей X и Y, приложение может не заботиться о "квадратуре пиксела", так как масштаб по осям координат одинаковый и не зависит от особенностей устройства вывода.
Сделаем небольшое пояснение относительно режима отображения MM_TWIPS. В этом режиме используется единица длины twip (от twentieth of a point - двадцатая часть точки, или, в терминах полиграфии, двадцатая часть пункта). Размер одного пункта приблизительно равен 1/72 дюйма, следовательно размер единицы длины twip равен 1/1440 дюйма.
С помощью функции GetMapMode приложение может в любой момент времени определить номер режима отображения, выбранный в контекст отображения hdc: int WINAPI GetMapMode(HDC hdc);


Таблица 3

ПолеОписание
bfType Тип файла. Поле содержит значение 0x4D42 (текстовая строка "BM"). Анализируя содержимое этого поля, приложение может идентифицировать файл как содержащий битовое изображение
bfSizeРазмер файла в байтах. Это поле может содержать неправильное значение, так как в SDK для Windows версии 3.0 поле bfSize было описано неправильно (утверждалось, что это поле содержит размер файла в двойных словах). Обычно содержимое этого поля игнорируется, так как из-за ошибки в документации старые приложения устанавливали в этом поле неправильное значение
bfReserved1Зарезервировано, должно быть равно 0
bfReserved2Зарезервировано, должно быть равно 0
bfOffBitsСмещение битов изображения от начала файла в байтах. Область изображения не обязательно должна быть расположена сразу вслед за заголовками файла или таблицей цветов (если она есть)
В структуре BITMAPFILEHEADER для нас важны два поля - поле bfType, определяющее тип файла, и поле bfOffBits, определяющее смещение битов, из которых формируется изображение. Остальные поля можно проигнорировать. В частности, размер файла нетрудно определить средствами файловой системы MS-DOS.
Сразу после структуры BITMAPFILEHEADER в bmp-файле расположена структура BITMAPINFO (для изображений Windows) или BITMAPCOREINFO (для изображений Presentation Manager).
Структура BITMAPINFO и указатели на нее описаны в файле windows.h следующим образом: typedef struct tagBITMAPINFO { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[1]; } BITMAPINFO; typedef BITMAPINFO* PBITMAPINFO; typedef BITMAPINFO FAR* LPBITMAPINFO;
Структура BITMAPINFOHEADER описывает размеры и способ представления цвета в битовом изображении: typedef struct tagBITMAPINFOHEADER { DWORD biSize; LONG biWidth; LONG biHeight; WORD biPlanes; WORD biBitCount; DWORD biCompression; DWORD biSizeImage; LONG biXPelsPerMeter; LONG biYPelsPerMeter; DWORD biClrUsed; DWORD biClrImportant; } BITMAPINFOHEADER; typedef BITMAPINFOHEADER* PBITMAPINFOHEADER; typedef BITMAPINFOHEADER FAR* LPBITMAPINFOHEADER;
Опишем назначение отдельных полей этой структуры.



Таблица 3

ИдентификаторОписание
SYSTEM_FONT Системный шрифт в кодировке ANSI с переменной шириной букв, используется операционной системой Windows для отображения текста в меню, заголовках окон и диалоговых панелях
SYSTEM_FIXED_FONT Шрифт в кодировке ANSI с фиксированной шириной букв. Использовался в старых версиях операционной системой Windows (до версии 3.0) как системный шрифт
ANSI_VAR_FONT Шрифт в кодировке ANSI с переменной шириной букв
ANSI_FIXED_FONT Шрифт в кодировке ANSI с фиксированной шириной букв
OEM_FIXED_FONT Шрифт в кодировке OEM с фиксированной шириной букв
DEVICE_DEFAULT_FONT Шрифт, который используется для данного устройства по умолчанию. Если устройство не имеет своих шрифтов, используется системный шрифт SYSTEM_FONT
После того как вы получили идентификатор шрифта, этот шрифт можно выбрать в контекст отображения макрокомандой SelectFont : #define SelectFont(hdc, hfont) \ ((HFONT)SelectObject((hdc), (HGDIOBJ)(HFONT)(hfont)))
Первый параметр этой макрокоманды определяет идентификатор контекста отображения, в который выбирается шрифт с идентификатором hfont. Она возвращает идентификатор шрифта, который был выбран в контекст отображения раньше, до вызова SelectFont.
Вам не нужно удалять встроенные шрифты, так же как не нужно удалять встроенные кисти и перья.

Способности устройства рисовать линии. Возвращаемое



Таблица 4

Имя константыОписание
LINECAPS Способности устройства рисовать линии. Возвращаемое значение представляет собой набор битовых масок, установленных в 1, если устройство может само рисовать линии различного типа:LC_INTERIORS устройство может закрашивать внутреннюю область;LC_MARKER маркеры;LC_NONE устройство не может рисовать линии;LC_POLYLINE ломаные линии;LC_POLYMARKER линии polymarker;LC_STYLED устройство может рисовать линии с использованием различных стилей (штриховые, пунктирные, штрих пунктирные и т.д.);LC_WIDE широкие линии;LC_WIDESTILED устройство может рисовать широкие линии с использованием различных стилей (штриховые, пунктирные, штрих-пунктирные и т. д.)
CURVECAPS Способность устройства рисовать различные кривые линии и геометрические фигуры. Возвращаемое значение представляет собой набор битовых масок, установленных в 1, если устройство может само рисовать различные фигуры:CC_CIRCLES окружности;CC_CHORD сегмент эллипса;CC_ELLIPSES эллипсы;CC_INTERIORS устройство может закрашивать внутреннюю область геометрических фигур;CC_NONE устройство не может рисовать кривые линии и геометрические фигуры;CC_PIE секторы эллипса;CC_ROUNDRECT прямоугольники со скругленными углами;CC_STYLED устройство может рисовать рамки с использованием различных стилей (штриховые, пунктирные, штрих-пунктирные и т.д.);CC_WIDE широкие рамки;CC_WIDESTYLED устройство может рисовать широкие рамки с использованием различных стилей (штриховые, пунктирные, штрих-пунктирные и т. д.)
POLYGONALCAPS Способности устройства рисовать многоугольники. Возвращаемое значение представляет собой набор битовых масок, установленных в 1, если устройство может само рисовать многоугольники различного типа:PC_INTERIORS устройство может закрашивать внутреннюю область;PC_NONE устройство не может рисовать многоугольники;PC_RECTANGLE прямоугольники;PC_SCANLINES устройство может выполнять сканирование линий растра;PC_STYLED устройство может рисовать рамки с использованием различных стилей (штриховые, пунктирные, штрих-пунктирные и т. д.);PC_WIDE широкие рамки;PC_WIDESTILED устройство может рисовать широкие рамки с использованием различных стилей (штриховые, пунктирные, штрих-пунктирные и т. д.)PC_WINDPOLYGON многоугольники с заполнением в режиме WINDING
Для приложения не имеет особого значения, кто именно будет рисовать - видеоконтроллер, драйвер или GDI. Запрос на рисование, например, эллипса, будет выполнен, даже если соответствующая операция не поддерживается драйвером. В последнем случае эллипс будет нарисован самим GDI с использованием более примитивных операций, но процесс рисования займет больше времени.
Учитывая сказанное выше, не следует строить работу приложений таким образом, чтобы периодичность вывода или скорость работы приложения зависела от скорости рисования (подобная практика не приветствуется и при создании программ для MS-DOS, вспомните, как ведут себя старые игры, разработанные для процессора 8088, на компьютерах с процессорами i80386 или i486). Современные видеоадаптеры сконструированы таким образом, что большинство основных операций рисования, используемых в операционной системе Windows, выполняются аппаратно. Эти видеоадаптеры иногда называются ускорителями Windows. Скорость рисования для ускорителя Windows может превышать в десятки раз скорость рисования для обычного адаптера VGA или SVGA.
Результат рисования геометрических фигур зависит от установки таких атрибутов контекста, как ширина, цвет и стиль линии (определяются выбранным в контекст отображения пером), способ закраски замкнутых фигур (определяется выбранной в контекст отображения кистью), цвета фона, прозрачностью фона (прозрачный режим TRANSPARENT и непрозрачный режим OPAQUE ), режимом рисования, режимом закрашивания, областью ограничения, режимом отображения, т. е. практически от всех атрибутов контекста отображения. Поэтому при описании функций мы будем попутно описывать способы изменения атрибутов контекста отображения, влияющих на результат их выполнения.
Работа с цветовыми палитрами и битовыми изображениями будут рассмотрены позже в отдельных разделах, так как эти вопросы далеко не тривиальны и поэтому заслуживают отдельного обсуждения.
Итак, перейдем непосредственно к описанию функций рисования геометрических фигур.


Таблица 4

ПолеОписание
biSizeРазмер структуры BITMAPINFOHEADER в байтах
biWidthШирина битового изображения в пикселах
biHeightВысота битового изображения в пикселах
biPlanesКоличество плоскостей в битовом изображении. Содержимое этого поля должно быть равно 1
biBitCountКоличество битов на один пиксел. Может быть равно 1, 4, 8 или 24. Для новых 16- и 32-битовых форматов файлов DIB, используемых в Windows NT, в этом поле могут находиться также значения 16 и 32
biCompressionМетод компрессии. Может принимать одно из следующих значений:BI_RGB - компрессия не используетсяBI_RLE4 - компрессия изображений, в которых для представления пиксела используется 4 бита. При использовании этого метода компрессии содержимое поля biBitCount должно быть равно 4BI_RLE8 - компрессия изображений, в которых для представления пиксела используется 8 бит. При использовании этого метода компрессии содержимое поля biBitCount должно быть равно 8BI_BITFIELDS - другой формат компрессии. Это значение используется для Windows NT. Соответствующая константа описана в файле windows.h, который поставляется вместе со средствами разработки приложений Windows NT
biSizeImageРазмер изображения в байтах. Это поле содержит размер, необходимый для хранения разжатого изображения. Если компрессия не используется (в поле biCompression находится значение BI_RGB), содержимое поля biSizeImage может быть равно 0
biXPelsPerMeterРазрешение устройства вывода по горизонтали в пикселах на метр, необходимое для вывода битового изображения без искажений. Это поле используется не всегда. Если оно не используется, в нем следует установить нулевое значение.
biYPelsPerMeterРазрешение устройства вывода по вертикали в пикселах на метр, необходимое для вывода битового изображения без искажений. Это поле, как и предыдущее, используется не всегда. Если оно не используется, в нем следует установить нулевое значение
biClrUsedРазмер таблицы цветов. Это поле определяет размер массива структур RGBQUAD (Рисунок 4.4), расположенного в файле сразу после структуры BITMAPINFOHEADER. Если в этом поле находится нулевое значение, размер таблицы цветов зависит от количества бит, используемых для представления цвета одного пиксела (поле biBitCount)
biClrImportantКоличество цветов, необходимое для отображения файла без искажений. Обычно в этом поле находится нулевое значение, в этом случае важны все цвета
Сразу после структуры BITMAPINFOHEADER в фале может находиться таблица цветов. Эта таблица содержит массив структур RGBQUAD : typedef struct tagRGBQUAD { BYTE rgbBlue; BYTE rgbGreen; BYTE rgbRed; BYTE rgbReserved; } RGBQUAD; typedef RGBQUAD FAR* LPRGBQUAD;
Поля rgbBlue, rgbGreen и rgbRed содержат RGB-компоненты цветов, поле rgbReserved зарезервировано и должно содержать нулевое значение.
Как мы уже говорили, файл битового изображения может содержать таблицу цветов, а может и не содержать ее. Приведем зависимость размера таблицы цветов в зависимости от значения поля biBitCount (количество бит, используемых для представления одного пиксела):



Таблица 4

КонстантаЗначение
FW_DONTCARE 0
FW_THIN 100
FW_EXTRALIGHT 200
FW_ULTRALIGHT 200
FW_LIGHT 300
FW_NORMAL 400
FW_REGULAR 400
FW_MEDIUM 500
FW_SEMIBOLD 600
FW_DEMIBOLD 600
FW_BOLD 700
FW_EXTRABOLD 800
FW_ULTRABOLD 800
FW_BLACK 900
FW_HEAVY 900
Вы можете использовать любое из указанных значений, однако следует иметь в виду, что многие шрифты содержат описания символов только для веса FW_NORMAL, FW_REGULAR и FW_BOLD.

в контекст отображения по умолчанию



Таблица 5

ЗначениеОписание
BLACK_PEN Перо, рисующее черную линию толщиной в один пиксел (для любого режима отображения). Это перо выбрано в контекст отображения по умолчанию
WHITE_PEN Перо белого цвета. Толщина пера также равна одному пикселу и не зависит от режима отображения
NULL_PEN Невидимое перо толщиной в один пиксел. Используется для рисования замкнутых закрашенных фигур (таких, как прямоугольник или эллипс) в тех случаях, когда контур фигуры должен быть невидимым
После получения идентификатора пера его необходимо выбрать в контекст отображения при помощи макрокоманды SelectPen. Первый параметр этой макрокоманды используется для указания идентификатора контекста отображения, в который нужно выбрать перо, второй - для передачи идентификатора пера.
Макрокоманда SelectPen возвращает идентификатор пера, который был выбран в контекст отображения раньше. Вы можете сохранить этот идентификатор и использовать его для восстановления старого пера.
Однако при помощи встроенных перьев вы не можете нарисовать цветные, широкие, штриховые и штрих-пунктирные линии.
Если вас не устраивают встроенные перья, вы можете легко создать собственные. Для этого нужно воспользоваться функциями CreatePen или CreatePenIndirect.
Функция CreatePen позволяет определить стиль, ширину и цвет пера: HPEN WINAPI CreatePen( int fnPenStyle, // стиль пера int nWidth, // ширина пера COLORREF clrref); // цвет пера
Параметр fnPenStyle определяет стиль линии и может принимать одно из следующих значений, определенных в файле windows.h:


Таблица 5

Значение biBitCount Размер таблицы цветов
12
416
8256
24не используется
Если содержимое поля biClrUsed отлично от нуля, используется таблица цветов уменьшенного размера. В ней описаны только те цвета, которые содержатся в изображении.



Таблица 5

КонстантаЗначениеОписание
ANSI_CHARSET 0 Набор символов в кодировке ANSI
DEFAULT_CHARSET 1 Не используется при отображении шрифтов. Определяется при необходимости запросить шрифт с заданным именем и размером шрифта. Следует использовать с осторожностью, так как если указанного шрифта нет, GDI может выделить шрифт с любым набором символов
SYMBOL_CHARSET 2 Символьный шрифт, такой как, например, Wingdings
SHIFTJIS_CHARSET 128 Шрифт, в котором для представления символов используется двухбайтовая кодировка. Нужен для работы с японской версией Windows
OEM_CHARSET 255 Набор символов в кодировке OEM


PS_SOLID



Таблица 6

Стиль линииВнешний вид Описание
PS_SOLID



Таблица 6

ПолеОписание
bcSizeРазмер структуры BITMAPCOREHEADER в байтах
bcWidthШирина битового изображения в пикселах
bcHeightВысота битового изображения в пикселах
bcPlanesКоличество плоскостей в битовом изображении. Содержимое этого поля должно быть равно 1
bcBitCountКоличество битов на один пиксел. Может быть равно 1, 4, 8 или 24
Таблица цветов в bmp-файле в формате Presentation Manager расположена после структуры BITMAPCOREHEADER и представляет собой массив структур RGBTRIPLE , содержащих RGB-компоненты цвета: typedef struct tagRGBTRIPLE { BYTE rgbtBlue; BYTE rgbtGreen; BYTE rgbtRed; } RGBTRIPLE; typedef RGBTRIPLE FAR* LPRGBTRIPLE;
Зная количество битов, используемых для представления одного пиксела изображения, нетрудно определить количество элементов в таблице цветов: wClrUsed = 1 << bcBitCount;



Таблица 6

КонстантаЗначениеОписание
OUT_DEFAULT_PRECIS 0 Используется точность, заданная по умолчанию
OUT_STRING_PRECIS 1 Выбирается шрифт, для которого соблюдается наибольшее соответствие в размерах символов
OUT_CHARACTER_PRECIS 2 Аналогично OUT_STRING_PRECIS
OUT_STROKE_PRECIS 3 Требуется точное соответствие между запрошенными атрибутами и атрибутами полученного шрифта
OUT_TT_PRECIS 4Выбирается масштабируемый шрифт True Type, даже если есть подходящий растровый или векторный шрифт
OUT_DEVICE_PRECIS 5 Выбирается шрифт устройства вывода
OUT_RASTER_PRECIS 6 Выбирается растровый шрифт
OUT_TT_ONLY_PRECIS 7 Используются только шрифты True Type


Не меняется, т. е. перо



Таблица 7

Режим рисованияФормула Цвет пиксела
R2_COPYPEN PСоответствует (равен) цвету пера
R2_BLACK 0Черный
R2_WHITE 1Белый
R2_NOP D Не меняется, т. е. перо ничего не рисует
R2_NOT ~DПолучается инвертированием цвета подложки, т. е. цвета пиксела до рисования
R2_NOTCOPYPEN ~PПолучается инвертированием цвета пера
R2_MASKPEN P&DКомбинация компонент цветов, имеющихся как в цвете подложки, так и в цвете пера
R2_NOTMASKPEN ~(P&D) Инверсия предыдущего значения
R2_MERGEPEN P|DКомбинация компонент цветов подложки и пера
R2_NOTMERGEPEN ~(P|D) Инверсия предыдущего значения
R2_XORPEN P^DПри определении цвета пиксела выполняется операция "ИСКЛЮЧАЮЩЕЕ ИЛИ" между компонентами цвета подложки и пера
R2_NOTXORPEN ~(P^D)Инверсия предыдущего значения
R2_MASKNOTPEN ~P & D Комбинация цвета подложки и инверсии цвета пера
R2_MASKPENNOT P & ~D Комбинация двух цветов: инверсии цвета подложки и цвета пера
R2_MERGENOTPEN ~P | D Комбинация компонент цветов подложки и инверсии цвета пера
R2_MERGEPENNOT P | ~D Комбинация инверсии цвета подложки и цвета пера
Если изображение и перо черно-белые, результат выполнения описанных выше операций (которые, кстати, называются растровыми операциями ) можно легко предсказать.
В режиме R2_COPYPEN, который установлен в контексте отображения по умолчанию, цвет нарисованной линии будет такой же, как и цвет пера. Для режимов R2_BLACK и R2_WHITE цвет линии будет, соответственно, черный и белый. В режиме R2_NOP вы не увидите нарисованную линию, так как цвет вдоль нее вообще не изменится. Более интересен режим R2_NOT, при использовании которого на черном фоне будет нарисована белая линия, а на белом фоне - черная.
Для цветных изображений перечисленные выше формулы применяются по отдельности к каждой компоненте цвета (всего в Windows используется три компоненты цвета - красная, зеленая и голубая), поэтому для некоторых режимов рисования цвет линии предсказать достаточно трудно. Использование цветовых палитр, которые мы рассмотрим в третьей главе нашей книги, дополнительно усложняет эту задачу.
С помощью функции GetROP2 приложение может определить режим рисования, установленный для контекста отображения hdc: int WINAPI GetROP2(HDC hdc);


Таблица 7

ПолеКритерии проверки
biPlanesДолжно содержать значение 1
biBitCount Может быть равно 1, 4, 8 или 24.Вы можете столкнуться с новыми 16- и 32-битовыми форматами файлов DIB, используемых в Windows NT. Для них в этом поле могут находиться также значения 16 и 32. Если ваше приложение не умеет обрабатывать такие файлы, данную ситуацию следует рассматривать как ошибочную
biCompressionМожет принимать одно из следующих значений: BI_RGB, BI_RLE4, BI_RLE8.При использовании метода компрессии BI_RLE4 содержимое поля biBitCount должно быть равно 4. При использовании метода компрессии BI_RLE8 содержимое поля biBitCount должно быть равно 8.Ваше приложение может ограничиться обработкой bmp-файлов в формате BI_RGB, как это делает, например, приложение Paintbrush
Можно было бы проверить содержимое и других полей структуры BITMAPINFOHEADER, однако это необязательно, так как они не содержат критической информации. Проверка "с пристрастием" может привести к тому, что пользователи будут думать, будто ваше приложение не умеет читать такие файлы, с которыми легко справляются другие приложения.
Итак, подводя итоги, можно выдать следующие рекомендации:
смело игнорируйте bmp-файлы в формате Presentation Manager, а если вы не можете так поступить, преобразуйте их в формат Windows;
в структуре BITMAPINFOHEADER проверяйте только поля biPlanes, biBitCount и biCompression;
так как метод компрессии RLE4 и RLE8 используются редко и не приводит к значительной экономии памяти, ваше приложение может не поддерживать компрессованные bmp-файлы.



Таблица 7

КонстантаОписание
DEFAULT_QUALITY Качество не имеет значения
DRAFT_QUALITY Низкое качество. Допустимо масштабирование шрифтов, синтезирование наклонных, жирных, перечеркнутых и подчеркнутых символов
PROOF_QUALITY Высокое качество. Масштабирование шрифтов не допускается. При этом могут быть получены символы, имеющие размер, немного меньший запрошенного


Бесцветная кисть, которая ничего не



Таблица 8

ЗначениеОписание
BLACK_BRUSH Кисть черного цвета
WHITE_BRUSH Кисть белого цвета
GRAY_BRUSH Серая кисть
LTGRAY_BRUSH Светло-серая кисть
DKGRAY_BRUSH Темно-серая кисть
NULL_BRUSH Бесцветная кисть, которая ничего не закрашивает
HOLLOW_BRUSH Синоним для NULL_BRUSH
Как видно из только что приведенной таблицы, в Windows есть только монохромные встроенные кисти.
Макрокоманда GetStockBrush возвращает идентификатор встроенной кисти.
Прежде чем использовать полученную таким образом кисть, ее надо выбрать в контекст отображения (так же, как и перо). Для этого проще всего воспользоваться макрокомандой SelectBrush : #define SelectBrush(hdc, hbr) \ ((HBRUSH)SelectObject((hdc), (HGDIOBJ)(HBRUSH)(hbr)))
Макрокоманда SelectBrush возвращает идентификатор старой кисти, выбранной в контекст отображения раньше.


Таблица 8

КонстантаОписание
DEFAULT_PITCH Не имеет значения, будет ли шрифт иметь фиксированную или переменную ширину символов
FIXED_PITCH Нужен шрифт с фиксированной шириной символов
VARIABLE_PITCH Нужен шрифт с переменной шириной символов
Вы можете объединить при помощи логической операции ИЛИ эти константы с константами, соответствующими семейству шрифта:

Внешний вид



Таблица 9

Стиль штриховки Внешний вид
HS_BDIAGONAL



Таблица 9

КонстантаОписание
FF_DECORATIVE Шрифт, содержащий маленькие рисунки (пиктограммы). Примером такого шрифта может послужить шрифт Wingdings, поставляемый в составе Windows
FF_DONTCARE Семейство шрифта не имеет значения
FF_MODERN Семейство Modern. Фиксированная ширина символов, могут быть засечки (но могут и не быть)
FF_ROMAN Семейство Roman. Переменная ширина букв, есть засечки
FF_SCRIPT Семейство Script. Рукописный шрифт
FF_SWISS Семейство Swiss. Переменная ширина букв, нет засечек


Область hrgnSrc1, которая не входит



Таблица 10

Значение параметра fnCombineModeСпособ образования области hrgnDest
RGN_AND Пересечение областей hrgnSrc1 и hrgnSrc2
RGN_OR Объединение областей hrgnSrc1 и hrgnSrc2
RGN_XOR Объединение областей hrgnSrc1 и hrgnSrc2 с исключением перекрывающихся областей
RGN_DIFF Область hrgnSrc1, которая не входит в область hrgnSrc2
RGN_COPY Область hrgnSrc1
В зависимости от результата выполнения операции функция CombineRegion может вернуть одно из следующих значений:


Таблица 10

ПолеОписание
lStructSizeРазмер структуры в байтах. Это поле необходимо заполнить перед вызовом функции ChooseFont
hwndOwnerИдентификатор окна, которому будет принадлежать диалоговая панель. Если в поле Flags не указан флаг CF_SHOWHELP, в это поле можно записать значение NULL. Поле заполняется до вызова функции ChooseFont
hDCИдентификатор контекста отображения или информационного контекста для принтера. Если установлен флаг CF_PRINTERFONTS, в списке появятся шрифты, доступные в данном контексте
lpLogFontУказатель на структуру LOGFONT. Приложение может заполнить нужные поля в этой структуре перед вызовом функции ChooseFont. Если при этом будет установлен флаг CF_INITTOLOGFONTSTRUCT, выбранные значения будут использоваться в качестве начальных.
iPointSizeРазмер букв выбранного шрифта в десятых долях пункта. Содержимое этого поля устанавливается после возврата из функции ChooseFont
FlagsФлаги инициализации диалоговой панели. Можно использовать следующие значения:CF_APPLY - разрешается использование кнопки "Apply";CF_ANSIONLY - в списке выбора появляются только шрифты в кодировке ANSI;CF_BOTH - в списке шрифтов появляются экранные и принтерные шрифты;CF_TTONLY - можно выбирать только масштабируемые шрифты True Type;CF_EFFECTS - если указан этот флаг, с помощью диалоговой панели можно определять цвет букв создавать подчеркнутые и перечеркнутые шрифты. В этом случае необходимо перед вызовом функции проинициализировать содержимое полей lfStrikeOut, lfUnderline, rgbColors;CF_ENABLEHOOK - разрешается использовать функцию фильтра адрес которой указан в поле lpfnHook;CF_ENABLETEMPLATE - разрешается использование шаблона диалоговой панели, определяемого содержимым полей hInstance и lpTemplateName;CF_ENABLETEMPLATEHANDLE - флаг указывает, что поле hInstance содержит идентификатор загруженного шаблона диалоговой панели. Содержимое поля lpTemplateName игнорируется;CF_FIXEDPITCHONLY - можно выбрать только шрифты с фиксированной шириной символов:CF_FORCEFONTEXIST - выдается сообщение об ошибке, если пользователь пытается выбрать несуществующий шрифт;CF_INITTOLOGFONTSTRUCT - для инициализации диалоговой панели используется содержимое структуры LOGFONT, адрес которой передается через поле lpLogFont;CF_LIMITSIZE - при выборе шрифта учитывается содержимое полей nSizeMin и nSizeMax;CF_NOFACESEL - отменяется выбор в списке "Font";CF_NOOEMFONTS - нельзя выбирать векторные шрифты, этот флаг аналогичен флагу CF_NOVECTORFONTS;CF_NOSIMULATIONS - запрещается эмуляция шрифтов;CF_NOSIZESEL - отменяется выбор размера шрифта;CF_NOSTYLESEL - отменяется выбор стиля шрифта;CF_NOVECTORFONTS - нельзя выбирать векторные шрифты, этот флаг аналогичен флагу CF_NOOEMFONTS;CF_PRINTERFONTS - в списке появляются только такие шрифты, которые поддерживаются принтером, контекст отображения для которого задан в поле hDC;CF_SCALABLEONLY - можно выбирать только масштабируемые и векторные шрифты;CF_SCREENFONTS - можно выбирать только экранные шрифты;CF_SHOWHELP - в диалоговой панели отображается кнопка "Help";CF_USESTYLE - строка lpszStyle содержит указатель на буфер, который содержит строку описания стиля. Эта строка используется для инициализации списка "Font Style" диалоговой панели "Font";CF_WYSIWYG - можно выбирать только такие шрифты, которые доступны и для отображения на экране, и для печати на принтере. Если установлен этот флаг, следует также установить флаги CF_BOTH и CF_SCALABLEONLY
rgbColorsЦвет символов шрифта, который будет выбран в меню "Colors" диалоговой панели "Fonts" сразу после отображения диалоговой панели. Должен использоваться флаг CF_EFFECTS. Поле заполняется до вызова функции ChooseFont, после возврата из функции поле содержит значение выбранного цвета
lCustDataПроизвольные данные, передаваемые функции фильтра, определенной содержимым поля lpfnHook
lpfnHookУказатель на функцию фильтра, обрабатывающую сообщения, поступающие в диалоговую панель. Для работы с фильтром необходимо в поле Flags указать флаг CF_ENABLEHOOK
lpTemplateNameСтрока, закрытая двоичным нулем, которая содержит идентификатор шаблона диалоговой панели. Для использования этого поля необходимо указать флаг CF_ENABLETEMPLATE
hInstanceИдентификатор модуля, который содержит шаблон диалоговой панели в качестве ресурса. Поле используется только в тех случаях, когда в поле Flags указаны значения CF_ENABLETEMPLATE или CF_ENABLETEMPLATEHANDLE. Поле заполняется до вызова функции ChooseFont
lpszStyleУказатель на буфер, содержащий строку, описывающую шрифт. Если указан флаг CF_USESTYLE, эта строка используется для инициализации списка "Font Style". Размер буфера должен быть не меньше LF_FACESIZE байт
nFontTypeТип выбираемого шрифта. Можно использовать одно из следующих значений:SIMULATED_FONTTYPE - GDI может эмулировать этот шрифт;PRINTER_FONTTYPE - принтерный шрифт;SCREEN_FONTTYPE - экранный шрифт;BOLD_FONTTYPE - жирный шрифт, используется только для шрифтов True Type;ITALIC_FONTTYPE - наклонный шрифт, используется только для шрифтов True Type;REGULAR_FONTTYPE - не жирный и не наклонный шрифт, используется только для шрифтов True Type
nSizeMinМинимальный размер шрифта, который можно выбрать. Для использования этого поля необходимо установить флаг CF_LIMITSIZE
nSizeMaxМаксимальный размер шрифта, который можно выбрать. Для использования этого поля необходимо установить флаг CF_LIMITSIZE
Если пользователь выбрал шрифт, функция ChooseFont возвращает значение TRUE. Если пользователь отказался от выбора, нажав кнопку "Cancel" или клавишу <Esc>, возвращается значение FALSE.

Новая область не является самопересекающейся



Таблица 11

ЗначениеОписание
ERROR Ошибка
NULLREGION Новая область пустая
SIMPLEREGION Новая область не является самопересекающейся (т. е. граница созданной области не пересекает саму себя)
COMPLEXREGION Создана самопересекающаяся область
Для облегчения комбинирования областей в файле windowsx.h определены макрокоманды, предназначенные для копирования, пересечения, объединения и вычитания областей. Все они созданы на базе только что описанной функции CombineRegion : #define CopyRgn (hrgnDst, hrgnSrc) \ CombineRgn(hrgnDst, hrgnSrc, 0, RGN_COPY) #define IntersectRgn (hrgnResult, hrgnA, hrgnB) \ CombineRgn(hrgnResult, hrgnA, hrgnB, RGN_AND) #define SubtractRgn (hrgnResult, hrgnA, hrgnB) \ CombineRgn(hrgnResult, hrgnA, hrgnB, RGN_DIFF) #define UnionRgn (hrgnResult, hrgnA, hrgnB) \ CombineRgn(hrgnResult, hrgnA, hrgnB, RGN_OR) #define XorRgn (hrgnResult, hrgnA, hrgnB) \ CombineRgn(hrgnResult, hrgnA, hrgnB, RGN_XOR)


Таблица 11

КонстантаЗначение
FW_DONTCARE0
FW_THIN100
FW_EXTRALIGHT200
FW_ULTRALIGHT200
FW_LIGHT300
FW_NORMAL400
FW_REGULAR400
FW_MEDIUM500
FW_SEMIBOLD600
FW_DEMIBOLD600
FW_BOLD700
FW_EXTRABOLD800
FW_ULTRABOLD800
FW_BLACK900
FW_HEAVY900
Поля tmItalic, tmUnderlined, tmStruckOut определяют, соответственно, является ли шрифт наклонным, подчеркнутым или перечеркнутым.
Поля tmFirstChar и tmLastChar определяют, соответственно, коды первого и последнего символа, определенных в шрифте.
Если приложение пытается вывести символ, код которого отсутствует в шрифте, вместо него будет выведен символ с кодом, расположенным в поле tmDefaultChar.
Поле tmBreakChar содержит код символа, который используется для переноса слов с одной строки на другую при выравнивании текста.
Поле tmPitchAndFamily содержит код семейства шрифта. В нем могут находится следующие флаги, соответствующие четырем младшим битам:

Векторный шрифт или масштабируемый шрифт



Таблица 12

ЗначениеОписание
TMPF_FIXED_PITCH Шрифт с фиксированной шириной букв
TMPF_VECTOR Векторный шрифт или масштабируемый шрифт True Type
TMPF_TRUETYPE Шрифт True Type
TMPF_DEVICE Шрифт устройства вывода, например, принтерный шрифт
Одновременно может быть установлено несколько флагов с префиксом имени TMPF.
Старшие четыре бита описывают семейство шрифта:

Примером такого шрифта может послужить



Таблица 13

КонстантаОписание
FF_DECORATIVEШрифт, содержащий маленькие рисунки (пиктограммы). Примером такого шрифта может послужить шрифт Wingdings, поставляемый в составе Windows
FF_DONTCAREСемейство шрифта не имеет значения или неизвестно
FF_MODERNСемейство Modern. Фиксированная ширина символов, могут быть засечки (но могут и не быть)
FF_ROMANСемейство Roman. Переменная ширина букв, есть засечки
FF_SCRIPTСемейство Script. Рукописный шрифт
FF_SWISSСемейство Swiss. Переменная ширина букв, нет засечек
В поле tmCharSet находится код используемого набора символов:

Не используется при отображении шрифтов.



Таблица 14

КонстантаЗначениеОписание
ANSI_CHARSET0 Набор символов в кодировке ANSI
DEFAULT_CHARSET1 Не используется при отображении шрифтов. Определяется при необходимости запросить шрифт с заданным именем и размером шрифта. Следует использовать с осторожностью, так как если указанного шрифта нет, GDI может выделить шрифт с любым набором символов
SYMBOL_CHARSET2 Символьный шрифт, такой как Wingdings
SHIFTJIS_CHARSET128 Шрифт, в котором для представления символов используется двухбайтовая кодировка. Нужен для работы с японской версией Windows
OEM_CHARSET255 Набор символов в кодировке OEM
В поле tmOverhang содержится величина, на которую увеличивается ширина символов для синтезированных (эмулированных) шрифтов, например, наклонных или жирных шрифтов, полученных изменением нормального шрифта. Шрифты True Type обычно не используют это поле для наклонных и жирных шрифтов (в нем находится нулевое значение), так как такие шрифты считаются отдельными шрифтами, и не получаются изменением нормального шрифта True Type.
Поля tmDigitizedAspectX и tmDigitizedAspectY содержат значения, которые можно использовать для определения отношения масштабов устройства отображения по горизонтали и вертикали.

Через последний параметр функции EnumFontFamProc



Таблица 15

ЗначениеОписание
DEVICE_FONTTYPE Шрифт устройства вывода
RASTER_FONTTYPE Растровый шрифт
TRUETYPE_FONTTYPE Шрифт True Type
Через последний параметр функции EnumFontFamProc передаются 32-разрядные данные, указанные в параметре lParam функции EnumFontFamilies.
Если приложение собирается продолжить просмотр доступных шрифтов, функция EnumFontFamProc должна возвратить ненулевое значение. Если просмотр должен быть завершен, следует возвратить нуль.

Текущая позиция пера



Текущая позиция пера

Для рисования линий в интерфейсе GDI предназначена функция LineTo, которая использует понятие текущей позиции пера (current pen position ). Функция LineTo рисует линию из точки, соответствующей текущей позиции пера в точку, указанную при помощи параметров. Для установки текущей позиции пера предназначена функция MoveTo .

По умолчанию текущая позиция пера равна значению (0,0), что в системе координат, выбранной по умолчанию, соответствует верхнему левому углу внутренней области окна.

Заметим, что текущая позиция используется интерфейсом GDI только для рисования линий.




Текущая позиция пера

Для рисования прямых линий (и только для этого) в контексте отображения хранятся координаты текущей позиции пера . Для изменения текущей позиции пера в Windows версии 3.1 есть две функции с именами MoveTo и MoveToEx . Для совместимости с 32-разрядными версиями Windows, такими, как Windows NT, в новых приложениях следует использовать функцию MoveToEx: BOOL WINAPI MoveToEx( HDC hdc, // идентификатор контекста отображения int x, // x-координата int y, // y-координата POINT FAR* lppt); // указатель на структуру POINT

Для контекста отображения hdc эта функция устанавливает текущую позицию пера, равную (x,y). В структуру типа POINT, на которую указывает параметр lppt, после возврата из функции будут записаны старые координаты пера.

Функция MoveToEx возвращает TRUE при нормальном завершении или FALSE при ошибке.

Чтобы узнать текущую позицию пера, приложение может использовать функцию GetCurrentPositionEx : BOOL WINAPI GetCurrentPositionEx(HDC hdc, POINT FAR* lppt);

После вызова этой функции текущая позиция пера будет записана в структуру типа POINT, на которую указывает параметр lppt. Функция GetCurrentPositionEx возвращает TRUE при нормальном завершении или FALSE при ошибке.



Установка начальных координат кисти



Установка начальных координат кисти

Начальные координаты кисти (brush origin ) - это атрибут контекста отображения. Он используются для определения координат точки внутри кисти, которая будет служить начальной при закраске внутренней области фигуры или окна. По умолчанию используются координаты (0,0), соответствующие верхнему левому углу кисти (в системе координат, выбранной в контекст отображения по умолчанию).

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

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

Приложение может изменить начальные координаты кисти (сдвинуть кисть) при помощи функций SetBrushOrg и UnrealizeObject.

Прежде всего нужно вызвать функцию UnrealizeObject , передав ей в качестве параметра идентификатор сдвигаемой кисти (только если это не встроенная кисть): BOOL WINAPI UnrealizeObject(HGDIOBJ hbrush);

В этом случае система сбросит координаты кисти после выбора ее в контекст отображения. После сброса надо установить новые значения координат кисти, вызвав функцию SetBrushOrg : DWORD WINAPI SetBrushOrg(HDC hdc, int nx, int ny);

Параметры nx и ny определяют новые значения для начальных координат кисти пикселах (от 0 до 7).

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



Библиотеки системного программиста" представляли собой



Введение

Предыдущие три тома " Библиотеки системного программиста" представляли собой краткое (!) введение в программирование для операционной системы Microsoft Windows. В них мы рассказали вам только о некоторых возможностях, не углубляясь в тонкости графического интерфейса и других подсистем. Мы также отложили рассказ о таких важных понятиях, как многооконный интерфейс MDI, протокол обмена данными между приложениями DDE, системе привязки и вставки объектов OLE.
В книге, которую вы сейчас держите в руках, мы расскажем о графическом интерфейсе GDI (Graphic Device Interface - интерфейс графических устройств), посредством которого графическая операционная система Windows выводит графику и текст на экран, принтер, плоттер и другие аналогичные устройства. В предыдущих томах мы уже упоминали о GDI, однако были рассмотрены только основные моменты, без понимания которых невозможно сделать ни одно приложение (разве что такое, которое не создает окон и ничего не выводит на экран или принтер).
Интерфейс GDI избавляет приложения Windows от необходимости учитывать многие (но не все) аппаратные особенности графических устройств вывода. Например, адресация видеопамяти выполняется по-разному в видеоадаптерах CGA, EGA, VGA, SVGA и, к тому же, структура видеопамяти сильно зависит от используемого режима (подробности вы можете найти третьем томе "Библиотеки системного программиста", который называется "Программирование видеоадаптеров CGA, EGA и VGA"). Однако приложения не работают непосредственно с видеопамятью. Для того чтобы нарисовать линию или написать строку текста, приложения вызывают ту или иную функцию интерфейса GDI, реализованного в виде DLL-библиотеки. Функции GDI также не работают с аппаратурой. Для выполнения нужной графической операции GDI вызывает драйвер устройства вывода, который "знает" о всех особенностях аппаратуры.
Таким образом, с помощью GDI приложения могут организовать вывод текста и графических изображений на некоторое логическое устройство вывода. Функции GDI и драйверы обеспечивают независимость приложений от аппаратуры, поэтому правильно созданное приложение Windows будет корректно работать с любыми видеоадаптерами и принтерами, как существующими на момент разработки приложения, так и с теми, которые появятся в будущем. В этом приложения Windows имеют большое преимущество над программами MS-DOS, вынужденными для повышения производительности работать непосредственно с регистрами видеоконтроллера и видеопамятью.
В первой главе вы познакомитесь с основными понятиями GDI, такими, как контекст отображения и его атрибуты, узнаете об инструментах, которые приложение Windows может использовать для рисования.
Вторая глава посвящена контексту отображения. Вы узнаете о типах контекста, научитесь получать и освобождать контекст отображения и контекст устройства. Мы расскажем вам об использовании режимов отображения, позволяющих работать с различными логическими системами координат. Отдельные разделы этой главы посвящены рисованию геометрических фигур и использованию областей.
В третьей главе мы расскажем о цвете и цветовых палитрах. Вы познакомитесь со статическими и системными цветами, научитесь создавать логическую палитру цветов и следить за изменениями системной палитры цветов. Все это позволит вам рисовать многоцветные изображения. Мы также расскажем об особенностях работы в режимах с высоким цветовым разрешением, таких как True Color.
Четвертая глава - об использовании битовых изображений. Вы узнаете о существовании различных типов битовых изображений и форматов bmp-файлов, содержащих изображения, научитесь рисовать битовые изображения, загруженные из bmp-файлов, а также создавать и использовать логическую палитру на базе таблицы цветов, расположенной в bmp-файле.
Пятая глава посвящена использованию шрифтов, в том числе масштабируемых шрифтов True Type. Будет рассмотрен механизм отображения шрифтов, который используется в процессе выделения шрифтов по запросу приложения. Мы расскажем о том, как выбрать нужный шрифт из числа установленных в системе, как получить различную информацию о шрифте, выбранном в контекст отображения. Несмотря на то что мы не привели полного описания функций GDI, предназначенных для работы с шрифтами True Type (оно занимает слишком много места), пользуясь нашей книгой вы сможете выполнять все основные операции, связанные с использованием шрифтов True Type. Если перед вами стоит задача разработки такого приложения, как редактор шрифтов True Type, вы сможете получить недостающую информацию из документации, которая поставляется вместе с Microsoft SDK for Windows 3.1.
В шестой главе рассмотрены средства, предназначенные для работы с принтером. Теперь ваши приложения смогут печатать текст и графику на любом принтере, установленном в системе. Мы научим вас пользоваться стандартными диалоговыми панелями, предназначенными для печати, выбора принтера и установки параметров принтера, опишем функции GDI, предназначенные для печати.
Мы привели исходные тексты приложений, демонстрирующих использование описанных средств GDI. Вы можете купить дискету, содержащую исходные тексты всех этих приложений.
Для трансляции исходных текстов приложений, приведенных в книге, мы пользовались системой разработки Borland Turbo C++ for Windows версии 3.1. Вы можете также использовать Borland C++ версий 3.1 или 4.0.
Чтобы вы смогли изучить приемы работы с палитрой и использовать режимы с высоким цветовым разрешением, в вашем компьютере должен быть установлен подходящий видеоадаптер и видеомонитор, способный работать в режимах SVGA. Обычный адаптер VGA в Windows предоставляет возможность работы всего лишь с 16 цветами, что недостаточно для многих графических приложений. Механизм цветовых палитр операционной системы Windows используется только в том случае, если в компьютере есть видеоадаптер SVGA, способный отображать 256 цветов. Лучше всего приобрести недорогой видеоадаптер с ускорителем для Windows, который может работать в режиме True Color (примерно 16 млн. цветов). Для отладки приложений, приведенных в этой книге, авторы использовали следующие видеоадаптеры: AVGA3 с видеопроцессором фирмы Cirrus Logic и объемом видеопамяти 1 Мбайт (акселератор для шины ISA стоимостью примерно 100 долларов), Orchid Fahrenheit VA-VLB (акселератор для шины VL-BUS), OAK VGA (адаптер SVGA с объемом видеопамяти 1 Мбайт без ускорителя).
Наш адрес E-mail: frolov@glas.apc.org
Вы можете присылать нам по этому адресу свои замечания и предложения по содержанию книг серий "Библиотека системного программиста" и "Персональный компьютер. Шаг за шагом". Мы их обязательно учтем при подготовке следующих изданий.
Авторы выражают благодарность сотрудникам АО "Диалог-МИФИ" Елене Виноградовой, Олегу Александровичу Голубеву, Наталье Дмитриевой, Оксане Кузьминовой, корректору Виктору Кустову. Появление этой книги стало возможным только благодаря напряженному труду всех этих людей. Мы также благодарим за помощь в работе над книгой Максима Синева и Сергея Ноженко.

Выбор кисти



Выбор кисти

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



Выбор пера



Выбор пера

Для рисования линий приложения Windows могут выбрать одно из трех встроенных перьев, либо создать собственное перо.

Для выбора встроенного пера лучше всего воспользоваться макрокомандами GetStockPen и SelectPen , определенными в файле windowsx.h: #define GetStockPen(i) ((HPEN)GetStockObject(i)) #define SelectPen(hdc, hpen) \ ((HPEN)SelectObject((hdc), (HGDIOBJ)(HPEN)(hpen)))

Макрокоманда GetStockPen возвращает идентификатор встроенного пера, заданного параметром i. Вы можете выбрать для этого параметра одно из следующих значений:



Выбор режима фона



Выбор режима фона

Режим фона влияет на заполнение промежутков между штрихами и точками в штрих-пунктирных, штриховых и пунктирных линиях.

Напомним, что по умолчанию в контексте отображения установлен непрозрачный режим фона OPAQUE . В этом режиме промежутки закрашиваются цветом фона, определенным как атрибут контекста отображения. Приложение может установить прозрачный режим фона TRANSPARENT , в этом случае промежутки в линиях не будут закрашиваться (Рисунок 2.16).



Выбор режима рисования



Выбор режима рисования

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

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

Для выбора режима рисования предназначена функция SetROP2 : int WINAPI SetROP2(HDC hdc, int fnDrawMode);

Параметр hdc предназначен для указания контекста отображения, в котором необходимо установить новый режим рисования, определяемый параметром fnDrawMode.

Функция SetROP2 возвращает код предыдущего режима рисования.

Процесс рисования на экране монитора заключается в выполнении логической операции над цветами точек экрана и цветами изображения. Ниже в таблице мы привели возможные значения для параметра fnDrawMode. Для каждого режима рисования в этой таблице есть формула, с использованием которой вычисляется результат, и краткое описание режима рисования. В формулах цвет пера обозначается буквой P, цвет подложки - D.



Выбор созданного шрифта в контекст отображения



Выбор созданного шрифта в контекст отображения

Если вы заполнили все нужные поля в структуре LOGFONT и затем передали адрес структуры функции CreateFontIndirect, эта функция вернет идентификатор шрифта. Вы должны выбрать шрифт с этим идентификатором в контекст отображения с помощью макрокоманды SelectFont (точно так же, как для встроенных шрифтов): hfontOldFont = SelectFont(hdc, hfont);

Как только в созданном шрифте отпадет необходимость, его следует удалить при помощи макрокоманды DeleteFont , предварительно выбрав в контекст отображения тот шрифт, который был выбран в него раньше: #define DeleteFont(hfont) \ DeleteObject((HGDIOBJ)(HFONT)(hfont))

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

Наиболее важное поле в структуре LOGFONT - поле lfCharSet. Если в этом поле будет установлено нулевое значение, будет выбран шрифт ANSI_CHARACTER, так как значение соответствующей ему константы равно нулю. Понятно, почему это поле самое важное - если приложение запрашивает шрифт OEM_CHARSET, оно предполагает использовать для вывода кодировку OEM. Если бы GDI предоставил приложению шрифт в кодировке ANSI, скорее всего, строку было бы невозможно прочесть. Если же в Windows нет ни одного шрифта с кодировкой OEM, приложение все равно получит какой-нибудь шрифт, однако результат вывода текста может оказаться неудовлетворительным.

Учтите, что растровые шрифты семейств Modern, Roman и Script, которые пришли из Windows версии 3.0, отмечены как имеющие кодировку OEM, хотя в действительности для этих шрифтов используется кодировка ANSI. Это сделано для того, чтобы в процессе выбора GDI вначале использовал масштабируемые шрифты перечисленных семейств, и только в крайнем случае остановил свой выбор на растровых шрифтах.

Следующее по важности поле в структуре LOGFONT - это поле lfPitchAndFamily. Оно имеет большое значение потому, что приложение, запрашивающее шрифт с фиксированной шириной букв, может работать неправильно, если ему будет выделен шрифт с переменной шириной букв.

Далее следует поле lfFaceName, а после него - поле lfFamily.

После сравнения всех описанных полей GDI сравнивает высоту букв шрифта (поле lfHeight), затем в сравнении принимают участие поля lfWidth, lfItalic, lfUnderline, lfStrikeOut.



Выбор встроенного шрифта



Выбор встроенного шрифта

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

Однако в некоторых случаях вам может понадобиться шрифт с фиксированной шириной букв, или шрифт в кодировке OEM. Вы можете получить идентификатор одного из встроенных шрифтов при помощи макрокоманды GetStockFont , описанной в файле windowsx.h: #define GetStockFont(i) ((HFONT)GetStockObject(i))

В качестве единственного параметра этой макрокоманде следует передать идентификатор одного из встроенных шрифтов:



Загрузка bmpфайла и проверка заголовков



Загрузка bmp-файла и проверка заголовков

Вы можете загрузить в оперативную память весь bmp-файл сразу или вначале только заголовки, а затем таблицу цветов и биты изображений. В приложении BMPINFO, рисующем изображения DIB в своем окне, мы использовали первый способ, отведя для загрузки bmp-файла один сплошной блок глобальной памяти.

Составляя программу чтения bmp-файла в память, не следует забывать о том, что размер файла, а следовательно и размер нужного для его загрузки блока памяти, практически всегда превышает 64 Кбайт. Поэтому для чтения такого файла лучше всего использовать функцию _hread , позволяющую прочитать сразу весь файл в один блок памяти любого (теоретически) размера.: _hread(hfDIBFile, lpBuf, *dwFileSize);

Мы уже пользовались этой функцией для перекодировки файла из OEM в ANSI.

Прочитав файл в память, следует убедиться, что его первые два байта содержат значение 0x4d42 ("BM"). Если это так, нужно определить формат bmp-файла. Для этого следует проанализировать содержимое поля biSize, расположенное сразу после заголовка BITMAPFILEHEADER. Для файлов в формате Windows в этом поле должно быть значение 40, что соответствует размеру структуры BITMAPINFOHEADER. Для файлов в формате Presentation Manager в этом поле должно находиться значение 12 (размер структуры BITMAPCOREHEADER).

Ваше приложение может отвергнуть файл в формате Presentation Manager, и это не будет большим недостатком для приложения Windows. В случае необходимости bmp-файлы Presentation Manager могут быть преобразованы в формат Windows, например, с помощью приложения Paintbrush.

Убедившись в том, что вы загрузили bmp-файл в формате Windows, следует проверить содержимое полей структуры BITMAPINFOHEADER.

Следует проверить поля biPlanes, biBitCount и biCompression. Вы можете использовать для проверки следующие критерии:



Загрузка изображений из ресурсов приложения



Загрузка изображений из ресурсов приложения

Самый простой способ использования битовых изображений в приложениях Windows заключается в том, что изображение создается графическим редактором в виде bmp-файла и описывается в файле определения ресурсов приложения при помощи оператора BITMAP: LOGO BITMAP mylogo.bmp

Созданное таким образом битовое изображение можно загрузить в память при помощи функции LoadBitmap : HBITMAP WINAPI LoadBitmap(HINSTANCE hinst, LPCSTR lpszBitmap);

Параметр hinst определяет идентификатор копии приложения, из ресурсов которого нужно загрузить изображение. Идентификатор ресурса изображения задан параметром lpszBitmap. Функция LoadBitmap возвращает идентификатор загруженного изображения или NULL при ошибке.

После использования приложение должно удалить битовое изображение. Для этого лучше всего воспользоваться макрокомандой DeleteBitmap , описанной в файле windowsx.h следующим образом: #define DeleteBitmap(hbm) \ DeleteObject((HGDIOBJ)(HBITMAP)(hbm))

В качестве параметра этой макрокоманде нужно передать идентификатор удаляемого изображения.

Приложение может определить параметры загруженного изображения, вызвав функцию GetObject : int WINAPI GetObject( HGDIOBJ hgdiobj, // идентификатор объекта int cbBuffer, // размер буфера void FAR* lpvObject); // адрес буфера

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

Для нас интересно использование этой функции с целью получения параметров изображения. Идентификатор изображения должен передаваться через параметр hgdiobj. Параметр lpvObject должен указывать на структуру типа BITMAP, в которую будут записаны сведения об изображении. Через параметр cbBuffer следует передать размер структуры BITMAP: BITMAP bm; HBITMAP hBitmap; GetObject(hBitmap, sizeof(BITMAP), (LPSTR) &bm);

Структура BITMAP и указатели на нее описаны в файле windows.h: typedef struct tagBITMAP { int bmType; int bmWidth; int bmHeight; int bmWidthBytes; BYTE bmPlanes; BYTE bmBitsPixel; void FAR* bmBits; } BITMAP; typedef BITMAP* PBITMAP; typedef BITMAP NEAR* NPBITMAP; typedef BITMAP FAR* LPBITMAP;

Опишем назначение отдельных полей этой структуры.



Закрашивание области



Закрашивание области

Для закрашивания области кистью, выбранной в контекст отображения, предназначена функция PaintRgn : BOOL WINAPI PaintRgn(HDC hdc, HRGN hrgn);

Функция FillRgn также закрашивает область, но, в отличие от функции PaintRgn, эта функция использует кисть, идентификатор которой передается ей в качестве параметра hbrush: BOOL WINAPI FillRgn(HDC hdc, HRGN hrgn, HBRUSH hbrush);

С помощью функции FrameRgn вы можете обвести заданную область (закрасить ее границу), используя кисть hbrush: BOOL WINAPI FrameRgn(HDC hdc, HRGN hrgn, HBRUSH hbrush, int nWidth, int nHeight);

Параметры nWidth и nHeight определяют, соответственно, ширину и высоту кисти в пикселах, используемой для рисования границы.

Функция InvertRgn инвертирует цвета в указанной области: BOOL WINAPI InvertRgn(HDC hdc, HRGN hrgn);

Все эти функции возвращают TRUE при успешном завершении или FALSE при ошибке.

Графический редактор битовых изображений Paint Brush, который поставляется вместе с операционной системой Windows, умеет закрашивать внутренние области замкнутых фигур. Для закраски вам достаточно, находясь в соответствующем режиме редактора, указать мышью любую точку внутри фигуры.

Для реализации описанной выше операции в программном интерфейсе GDI предусмотрены функции FloodFill и ExtFloodFill.

Для функции FloodFill необходимо указать идентификатор контекста отображения hdc, координаты точки nX и nY, а также цвет контура clrref, ограничивающего область: BOOL WINAPI FloodFill(HDC hdc, int nX, int nY, COLORREF clrref);

Функция возвращает TRUE при успешном завершении или FALSE при ошибке (ошибка возникает в том случае, когда указанная точка имеет цвет clrref или она лежит вне области ограничения данного контекста отображения).

Для закраски используется кисть, выбранная в контекст отображения.

Функция ExtFloodFill аналогична функции FloodFill: BOOL WINAPI ExtFloodFill(HDC hdc, int nX, int nY, COLORREF clrref, UINT fuFillType);

Эта функция имеет дополнительный параметр fuFillType, определяющий способ закраски области. Параметр может принимать значения FLOODFILLBORDER или FLOODFILLSURFACE . В первом случае закрашивается внутренняя область фигуры, ограниченная контуром, имеющим цвет clrref (как и при использовании функции FloodFill). Во втором случае закрашивается вся область, имеющая цвет clrref.

Функция ExtFloodFill возвращает TRUE при успешном завершении или FALSE при ошибке. Если значение параметра fuFillType равно FLOODFILLBORDER, ошибка может возникнуть из-за тех же причин, что и при выполнении функции FloodFill. Если же значение параметра fuFillType равно FLOODFILLSURFACE, ошибка может возникнуть из-за того, что цвет точки (nX,nY) не равен clrref.



Закрашивание внутренней области окна



Закрашивание внутренней области окна


Напомним, что кисть можно использовать еще и для закрашивания внутренней области окна . Для этого идентификатор кисти следует записать в поле hbrBackground структуры типа WNDCLASS перед регистрацией класса окна: wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);