Будь умным!


У вас вопросы?
У нас ответы:) SamZan.ru

Лекция 4 GDI Контекст устройства

Работа добавлена на сайт samzan.ru: 2016-03-30


Лекция №4. GDI. Контекст устройства.

Другие функции поддержки окон


Часто используемые сообщения


GDI – графический интерфейс устройства

GDI (графический интерфейс устройства) обеспечивает графический вывод на устройства отображения информации.

Соотношение между приложениями, GDI и драйверами устройств отображено на рис. 1.

Рис. 1.

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


GDI
(Graphics Device Interface, Graphical Device Interface) — один из трёх основных компонентов или «подсистем», вместе с ядром и Windows API составляет пользовательский интерфейс (оконный менеджер GDI) Microsoft Windows.

GDI — это интерфейс Windows для представления графических объектов и передачи их на устройства отображения, такие как мониторы и принтеры.

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

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

Простые игры, которые не требуют быстрой графики, могут использовать GDI. Однако GDI не обеспечивает качественной анимации, поскольку в нём нет возможности синхронизации с кадровым буфером. Также, в GDI нет растеризации для отрисовки 3D-графики. Современные игры используют DirectX или OpenGL, что даёт программистам доступ к большему количеству аппаратных возможностей.


GDI
+

С выходом Windows XP появился потомок подсистемы GDI - GDI+, основанной на C++.

GDI+ является улучшенной средой для 2D-графики, в которую добавлены такие возможности, как:

- сглаживание линий (antialiasing),

- использование координат с плавающей точкой,

- градиентная заливка,

- внутренняя поддержка таких графических форматов, как JPEG и PNG,

- лучшая поддержка регионов отсечения с возможностью использовать в них координаты с плавающей точкой (а не 16-битные целые) и применения к ним World Transform,

- преобразования двумерных матриц и т. п.

GDI+ использует ARGB-цвета. Эти возможности используются в пользовательском интерфейсе Windows XP, а их присутствие в базовом графическом слое облегчает использование систем векторной графики, таких как Flash или SVG.

Динамические библиотеки GDI+ могут распространяться вместе с приложениями для использования в предыдущих версиях Windows.

GDI+ схож с подсистемой Quartz 2D у Apple и библиотеками с открытым кодом libart и Cairo.

GDI+ есть не более чем набор дополнительных функций для обычной GDI.

В Windows 7 появился новый API Direct2D, который является почти аналогом GDI+, но реализован «сверху донизу» вплоть до драйвера видеокарты (использует некоторые возможности Direct3D в этом драйвере), и может использовать аппаратное ускорение — т. е. трехмерный видеопроцессор для рисования некоторых двухмерных объектов (antialiasing и т. д.)


Контекст устройства

Для определения атрибутов текста и изображения, которые выводятся на экран или принтер, используется программный объект под названием «контекст устройства» (Device Context, DC). DC, как и большинство объектов GDI, инкапсулирует подробности реализации и данные в себе и к ним нельзя получить прямой доступ.

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

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

Для любого рисования нужен объект HDC (хэндл DC). При выводе на принтер HDC получается вызовом CreateDC. При выводе на экран также можно использовать CreateDC, но это приведет к рисованию поверх всех окон вне их границ, потому обычно для рисования на экране используются вызовы GetDC и BeginPaint, принадлежащие уже не GDI, а USER, и возвращающие контекст, ссылающийся на регион отсечения окна.


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

В набор характеристик контекста устройства входят следующие графические объекты:

1) Перо (pen) для рисования линий;

2) Кисть (brush) для заполнения фона или заливки фигур;

3) Растровое изображение (bitmap) для отображения в указанной области окна;

4) Палитра (palette) для определения набора доступных цветов;

5) Шрифт (font) для вывода текста;

6) Регион (region) для отсечения области вывода.

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


Типы контекстов устройств (контекстов отображения)

Можно выделить следующие типы контекста отображения:

  •  общий контекст устройства

(common display context);

  •  

контекст устройства для класса окна

(class display context);

  •  личный контекст устройства

(private display context);

  •  родительский контекст устройства (parent display context);
  •  контекст устройства для окна (window display context);
  •  контекст физического устройства (device context);
  •  контекст (information context);
  •  контекст для памяти (memory device context);
  •  контекст для метафайла (metafile context).

При работе с графическими изображениями Windows-приложению нужно придерживаться следующей последовательности действий:

  •  получение или создание контекста устройства;
  •  установка необходимых атрибутов в контексте устройства;
  •  выполнение операций рисования;
  •  освобождение либо удаление контекста устройства.

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

Система поддерживает кэш для контекстов устройства (DC), таких как общий, родительский и оконный контекст. Система извлекает контекст устройства из кэша всякий раз, когда приложение вызывает функцию GetDC или BeginPaint; система возвращает контекст устройства (DC) в кэш, когда приложение впоследствии вызывает функцию ReleaseDC или EndPaint.


Общий контекст устройства

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

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

Для получения общего контекста отображения приложение должно вызвать функцию BeginPaint (при обработке сообщения WM_PAINT) или GetDC (при обработке других сообщений). При этом перед регистрацией класса окна в поле стиля класса окна в структуре WNDCLASS не должны использоваться значения CS_OWNDC , CS_PARENTDC или CS_CLASSDC:

wc.style = 0;

Функция BeginPaint возвращает контекст отображения для окна hwnd:

HDC WINAPI BeginPaint(HWND hwnd,

                                             PAINTSTRUCT FAR* lpps);

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

В случае успешного завершения функция возвращает дескриптор контекста дисплея для клиентской области окна. Кроме этого функция заполняет поля структуры PAINTSTRUCT.


Структура PAINTSTRUCT описана в файле windows.h:

typedef struct tagPAINTSTRUCT

{

HDC  hdc;                    // контекст устройства;

BOOL fErase;             // признак стирания фона клиентской области;

RECT rcPaint;            // границы недействительного прямоугольника;

BOOL fRestore;

BOOL fIncUpdate;

BYTE rgbReserved[32];

} PAINTSTRUCT;

hdc – идентификатор полученного контекста отображения, который должен передаваться в качестве параметра функциям интерфейса GDI, выполняющим рисование. Можно использовать также значение идентификатора контекста, возвращенное функцией BeginPaint, так как эти значения одинаковые.

Поле fErase указывает на то, нужно ли перерисовывать фон окна. Если в этом поле находится значение TRUE, фон окна должен быть перерисован. Такая необходимость может возникнуть в том случае, если в классе, на базе которого создано окно, при регистрации не была выбрана кисть для закрашивания фона (поле hbrBackground структуры WNDCLASS).

Поле rcPaint (представляет собой структуру типа RECT) содержит координаты верхнего левого и правого нижнего угла прямоугольника, внутри которого нужно рисовать.


Формат структуры RECT, описанной в файле windows.h имеет вид:

typedef struct tagRECT

{

 int left;

 int top;

 int right;

 int bottom;

} RECT;

При обработке сообщения WM_PAINT приложение должно суметь перерисовать все окно или любую его часть. Сообщение WM_PAINT может попасть в функцию окна в том случае, если все окно или его часть требуют перерисовки. Поле rcPaint в структуре PAINTSTRUCT содержит координаты прямоугольной области, расположенной в окне и требующей перерисовки.

Остальные поля зарезервированы для Windows и не используются приложениями.


Контекст устройства, полученный при помощи функции BeginPaint, необходимо освободить перед завершением обработки сообщения WM_PAINT, вызвав функцию
EndPaint :

void WINAPI EndPaint(HWND hwnd,

                                         const PAINTSTRUCT FAR* lpps);

Функции EndPaint передаются те же параметры, что и функции BeginPaint.

Обычно обработчик сообщения WM_PAINT выглядит следующим образом:

PAINTSTRUCT ps;

HDC hdc;

........

case WM_PAINT:

{

 // Получаем контекст отображения

 hdc = BeginPaint(hwnd, &ps);

// После получения контекста отображения

// можно вызывать функции GDI

 TextOut(hdc, 0, 0, (LPSTR)"String", 6);

       .

       .

// Освобождаем контекст отображения

 EndPaint(hwnd, &ps);

 break;

}

Функции BeginPaint и EndPaint можно использовать только внутри обработчика сообщения WM_PAINT.


Если же необходимо в программе рисовать не во время обработки сообщения WM_PAINT, то приложение должно получить контекст отображения с помощью функции GetDC. Перед выходом из обработчика сообщения следует освободить полученный контекст отображения, вызвав функцию ReleaseDC.

Функция GetDC возвращает контекст отображения для окна с идентификатором hwnd:

HDC WINAPI GetDC(HWND hwnd);

Функция ReleaseDC освобождает контекст отображения hdc, полученный для окна hwnd:

int WINAPI ReleaseDC(HWND hwnd, HDC hdc);


Контекст устройства для класса окна

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

wc.style = CS_CLASSDC;

Все окна, созданные на базе класса, имеющего стиль CS_CLASSDC, будут использовать один общий контекст отображения.

В отличие от общего контекста устройства, приложение, однажды получив контекст устройства для класса окна, может не освобождать его. То есть после функций BeginPaint и GetDC можно не вызывать функции EndPaint и ReleaseDC. Если же приложение вызовет функцию EndPaint или ReleaseDC, они не будут ничего делать и сразу вернут управление.

Для уменьшения вероятности ошибки рекомендуется всегда освобождать контекст отображения.

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

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


Личный контекст устройства

Если указать в стиле класса окна значение CS_OWNDC, то для каждого окна, созданного на базе такого класса, Windows создаст отдельную структуру контекста устройства:

wc.style = CS_OWNDC;

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

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

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

Родительский контекст отображения

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

Для использования родительского контекста отображения в классе, на базе которого создается дочернее окно, перед регистрацией необходимо указать стиль CS_PARENTDC :

wc.style = CS_PARENTDC;


Контекст устройства для окна

Все описанные выше контексты отображения позволяют рисовать только во внутренней области окна (client region).

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

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

Например, необходимо получить контекст отображения, позволяющий рисовать во всем окне приложения:

hdc = GetWindowDC(hwnd);

Освободить указанный контекст отображения можно следующим образом:

ReleaseDC(hwnd, hdc);

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

Это контекст обычно используется при необходимости заменить стандартные элементы окна (заголовок, полосы просмотра и т.п.) на собственные элементы оформления.


Контекст физического устройства

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

Контекст физического устройства не получается, а создается, для чего используется функция CreateDC:

HDC WINAPI CreateDC(

 LPCSTR lpszDriver,                // имя драйвера

 LPCSTR lpszDevice,               // имя устройства

 LPCSTR lpszOutput,               // имя файла или порта вывода

 const void FAR* lpvInitData); // данные для инициализации

Параметр lpszDriver – имя драйвера совпадает с именем файла *.drv, содержащего сам драйвер и расположенного в системном каталоге Windows.

Имя устройства lpszDevice - название устройства, описанное, например, в файле win.ini в разделе [devices].

Параметр lpszOutput - имя файла или порта вывода;

Параметр lpvInitData указывает на структуру данных типа DEVMODE, используемую при инициализации устройства вывода. Если настройки наследуются из Control Panel (панели управления Windows), то данный параметр нужно устанавливать в NULL.


Пример1: Создать контекст устройства для лазерного принтера HP Laserjet I
II, подключенного к порту LPT1:, для этого принтера установлен драйвер hppcl5a.drv:

hdc = CreateDC("hppcl5a", "HP LaserJet III", "LPT1:", NULL);

Пример2: Создать контекст устройства для принтера Epson FX-850, подключенного к порту LPT2:, и работающему через драйвер epson9.drv:

hdc = CreateDC("epson9", "Epson FX-850", "LPT2:", NULL);

Созданный при помощи функции CreateDC контекст устройства следует удалить (но не освободить), вызвав функцию DeleteDC:

BOOL WINAPI DeleteDC(HDC hdc);

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


Контекст для устройства DISPLAY

1 способ: Если требуется получить контекст дисплея, позволяющий приложению рисовать в любом месте экрана, то такой контекст создаётся при помощи функции CreateDC:

hdc = CreateDC("DISPLAY", NULL, NULL, NULL);

Начало системы координат, выбранной в данный контекст, располагается в верхнем левом углу экрана видеомонитора.

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

2 способ: Используя функцию GetDC, указав в качестве параметра значение NULL:

hdc = GetDC(NULL);

Этот контекст следует освободить при помощи функции ReleaseDC, передав ей вместо идентификатора окна значение NULL:

ReleaseDC(NULL, hdc);

3 способ: Используя функцию GetDCEx.


Информационный контекст

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

Информационный контекст создается при помощи функции CreateIC , аналогичной по своим параметрам функции CreateDC:

HDC WINAPI CreateIC(

 LPCSTR lpszDriver,            // имя драйвера

 LPCSTR lpszDevice,            // имя устройства

 LPCSTR lpszOutput,            // имя файла или порта вывода

 const void FAR* lpvInitData); // данные для инициализации

После использования информационный контекст следует удалить, вызвав функцию DeleteDC.


Функция GetDeviceCaps извлекает зависимую от устройства информацию для заданного устройства.

Синтаксис

int GetDeviceCaps(

 HDC hdc,     // дескриптор DC

 int nIndex     // индекс действия

);

Параметры

hdc - Дескриптор DC.

nIndex - Устанавливает элемент для возврата. Этот параметр может быть одним из ниже перечисленных значений.

DRIVERVERSION Версия драйвера устройства.

TECHNOLOGY Технология устройства. Это может быть любое из ниже перечисленных значений.

HORZSIZE Ширина, в миллиметрах, физического экрана.

VERTSIZE Высота, в миллиметрах, физического экрана.

HORZRES Ширина, в пикселях, экрана.

VERTRES Высота, в растровых строках, экрана.

NUMBRUSHES Число зависимых от устройства кистей.

NUMPENS Число зависимых от устройства перьев.

NUMFONTS Число зависимых от устройства шрифтов.

NUMCOLORS Число записей в таблице цветов устройства, если устройство имеет разрядность (глубину) цвета не больше, чем 8 битов на пиксель. Для устройств с большими разрядностями  цвета,  возвращается - (минус) 1. 

ASPECTX Относительная ширина пикселя устройства, которое использовалась для рисования линии.

ASPECTY Относительная высота пикселя устройства, которое использовалась для рисования линии.

ASPECTXY Диагональная ширина пикселя устройства, которое  использовалась для рисования линии.


Контекст для памяти

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

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

Для создания совместимого контекста используется функция CreateCompatibleDC :

HDC WINAPI CreateCompatibleDC(HDC hdc);

Созданный таким образом контекст памяти удаляется при помощи функции DeleteDC.

Алгоритм работы с контекстом в памяти состоит из следующих шагов:

  1.  Получения хэндла контекста устройства (hDC - handle of Device Context) для окна, в которое будет осуществляться вывод изображения.
  2.  Получения хэндла bitmap'а, который будет отображаться в окне.
  3.  Получения совместимого с hDC контекста в памяти (для хранения изображения) с помощью функции CreateCompatibleDC().
  4.  Выбора изображения (hBitmap) как текущего для контекста в памяти (hCompatibleDC).
  5.  Копирования изображения контекста в памяти (hCompatibleDC) на контекст устройства (hDC).
  6.  Удаления совместимого контекста (hCompatibleDC).
  7.  Принятия мер для того, чтобы замещенный bitmap из контекста в памяти не остался в памяти.
  8.  Освобождения контекста устройства (hDC).

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


Притмер 1. Вывод графического изображения из файла в окно на Си:

#include <windows.h>

LRESULT CALLBACK PaintWndProc(HWND,UINT,UINT,LONG);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

{

HWND hMainWnd;  

char szClassName[] = "MyClass";

 MSG msg;

WNDCLASSEX wc;

 

 // Заполняем структуру класса окна

 wc.cbSize        = sizeof(wc);  

wc.style         = CS_HREDRAW | CS_VREDRAW;

wc.lpfnWndProc   = PaintWndProc;

wc.cbClsExtra  = 0;

wc.cbWndExtra    = 0;

wc.hInstance     = hInstance;

wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);

wc.hCursor       = LoadCursor(NULL, IDC_ARROW);

wc.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);

wc.lpszMenuName  = NULL;

wc.lpszClassName = szClassName;

wc.hIconSm       = LoadIcon(NULL, IDI_INFORMATION);

// Регистрируем класс окна

if (!RegisterClassEx(&wc)) {

 MessageBox(NULL, "Cannot register class", "Error", MB_OK);

 return 0;

}

hMainWnd=CreateWindow(szClassName,"Должно быть фото...",

     WS_OVERLAPPEDWINDOW,

     CW_USEDEFAULT,CW_USEDEFAULT,

     CW_USEDEFAULT,CW_USEDEFAULT,

     NULL,NULL,

     hInstance,NULL);

if (!hMainWnd)

{

MessageBox(NULL,"Не могу создать окно","Error",MB_OK);

return 0;

}

// Показываем наше окно

ShowWindow(hMainWnd,nCmdShow);

UpdateWindow(hMainWnd);

// Создаём цикл сообщений

while (GetMessage(&msg,NULL,0,0))

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

return msg.wParam;

}

// Создаём оконную процедуру

LRESULT CALLBACK PaintWndProc(HWND hWnd,UINT Message,

          UINT wParam,LONG lParam)

{

HDC hDC,hCompatibleDC;

PAINTSTRUCT PaintStruct;

HANDLE hBitmap,hOldBitmap;

RECT Rect;

BITMAP Bitmap;

switch(Message)

{

case WM_PAINT:

// Получаем контекст устройства

hDC=BeginPaint(hWnd,&PaintStruct);

// Загружаем bitmap, который будет отображаться в окне

 hBitmap=LoadImage(NULL, "Foto118.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);

// Получаем размерность загруженного bitmapа

GetObject(hBitmap,sizeof(BITMAP),&Bitmap);

// Создаём совместимый с контекстом окна контекст в памяти

hCompatibleDC=CreateCompatibleDC(hDC);

// Делаем загруженный из файла bitmap текущим в совместимом контексте

hOldBitmap=SelectObject(hCompatibleDC,hBitmap);

// Определяем размер рабочей области окна

GetClientRect(hWnd,&Rect);

// Копируем bitmap с совместимого на основной контекст с масштабированием

 StretchBlt(hDC,0,0,Rect.right,Rect.bottom,hCompatibleDC,0,0,Bitmap.bmWidth,Bitmap.bmHeight,SRCCOPY);

// Делаем старый bitmap текущим 

SelectObject(hCompatibleDC,hOldBitmap);

// Удаляем загруженный с диска bitmap

DeleteObject(hBitmap);

// Удаляем совместимый контекст

DeleteDC(hCompatibleDC);

// Освобождаем основной контекст, завершая перерисовку рабочей области окна

EndPaint(hWnd,&PaintStruct);

return 0;

case WM_DESTROY:

PostQuitMessage(0);

return 0;

}

return DefWindowProc(hWnd,Message,wParam,lParam);

}

Для отображения рисунка Foto125.bmp необходимо, чтобы этот файл находился в текущей директории Debug. Можно также указать адрес файла с изображением, если он находится не в текущей директории:

D:\\Задания\\WinAPI\\Graf\\Debug


Пример 2. Вывод графического изображения из файла в окно на ассемблере.

;выводит изображения графического файла в окно

.386

.model flat, stdcall

WM_DESTROY             equ 2

WM_CREATE                equ 1

WM_PAINT                   equ 0Fh

CS_VREDRAW             equ 1h

CS_HREDRAW             equ 2h

CS_GLOBALCLASS     equ 4000h

WS_OVERLAPPEDWINDOW        equ 000CF0000H

style                   equ CS_HREDRAW+CS_VREDRAW+CS_GLOBALCLASS

IDI_APPLICATION            equ 32512

IDC_ARROW                  equ 32512  

SW_SHOWNORMAL     equ 1

WHITE_BRUSH              equ 0

CW_USEDEFAULT        equ 80000000h

extrn            BeginPaint:PROC

extrn            CreateCompatibleDC:PROC

extrn            CreateWindowExA:PROC

extrn            DefWindowProcA:PROC

extrn            DeleteDC:PROC

extrn            DeleteObject:PROC

extrn            DispatchMessageA:PROC

extrn            EndPaint:PROC

extrn            ExitProcess:PROC

extrn            GetClientRect:PROC

extrn            GetMessageA:PROC

extrn            GetModuleHandleA:PROC

extrn            GetObjectA:PROC

extrn            GetStockObject:PROC

extrn            LoadCursorA:PROC

extrn            LoadIconA:PROC

extrn            LoadImageA:PROC

extrn            PostQuitMessage:PROC

extrn            RegisterClassA:PROC

extrn            SelectObject:PROC

extrn            ShowWindow:PROC

extrn            StretchBlt:PROC

extrn            TranslateMessage:PROC

extrn            UpdateWindow:PROC

MSGSTRUCT STRUC

    MSHWND    DD ?     ; идентификатор окна, получающего сообщение

    MSMESSAGE DD ?     ; идентификатор сообщения

    MSWPARAM  DD ?     ; доп. информация о сообщении

    MSLPARAM  DD ?     ; доп. информация о сообщении

    MSTIME    DD ?     ; время посылки сообщения

    MSPT      DD ?     ; положение курсора, во время посылки сообщения

MSGSTRUCT ENDS

WNDCLASS STRUC

    clsStyle      DD ?   ; стиль окна

    clsLpfnWndProc     DD ?   ; указатель на процедуру окна

    clsCbClsExtra  DD ?   ; информация о доп. байтах для данной структуры

    clsCbWndExtra    DD ?   ; информация о доп. байтах для окна

    clsHInstance  DD ?   ; дескриптор приложения

    clsHIcon      DD ?   ; идентификатор иконы окна

    clsHCursor    DD ?   ; идентификатор курсора окна

    clsHbrBackground    DD ?   ; идентификатор кисти окна

    clsLpszMenuName    DD ?   ; имя-идентификатор меню

    clsLpszClassName        DD ?   ; специфицирует имя класса окон

WNDCLASS ENDS

BITMAP struct

  bmType       dd ?

  bmWidth      dd ?

  bmHeight     dd ?

  bmWidthBytes dd ?

  bmPlanes     dw ?

  bmBitsPixel  dw ?

  bmBits       dd ?

BITMAP ends

PAINTSTRUCT STRUC

    hdc    DWORD 0

    fErase DWORD 0

    left   DWORD 0

    top    DWORD 0

    right  DWORD 0

    bottom DWORD 0

    fRes   DWORD 0

    fIncUp DWORD 0

    Reserv DB 32 dup(0)

PAINTSTRUCT ENDS

RECT STRUC

    L DWORD ?

    T DWORD ?

    R DWORD ?

    B DWORD ?

RECT ENDS

LR_LOADFROMFILE  = 010h

SRCCOPY          = 00CC0020h

IMAGE_BITMAP     = 0

.data

newhwnd          dd 0

MSG              MSGSTRUCT <?>

wc               WNDCLASS  <?>

hDC                       dd ?

hCompatibleDC    dd ?

Ps                          PAINTSTRUCT <?>

hBitmap                dd ?

hOldBitmap          dd ?

Rect                      RECT <?>

Bitmap                  BITMAP <?>

hInstance        dd 0

szTitleName      db 'DCDemo', 0

szClassName      db 'ASMCLASS32',0

szImg            db 'IMG2.bmp',0

.code

;-----------------------------------------------------------------------------

start:

       call    GetModuleHandleA,0

       mov     [hInstance],eax

; initialize the WndClass structure

       mov     [wc.clsStyle], CS_HREDRAW + CS_VREDRAW

       mov     [wc.clsLpfnWndProc], offset DCDemoWndProc

       mov     [wc.clsCbClsExtra], 0

       mov     [wc.clsCbWndExtra], 0

       mov     eax, [hInstance]

       mov     [wc.clsHInstance], eax

       call    LoadIconA, 0, IDI_APPLICATION

       mov     [wc.clsHIcon], eax

       call    LoadCursorA, 0 ,IDC_ARROW

       mov     [wc.clsHCursor], eax

       call    GetStockObject, WHITE_BRUSH

       mov     [wc.clsHbrBackground], eax

       mov     [wc.clsLpszMenuName], 0

       mov     [wc.clsLpszClassName], offset szClassName

       call    RegisterClassA, offset wc

       call    CreateWindowExA, 0,offset szClassName,offset szTitleName, \

               WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, \

             CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,0,0, \

               [hInstance], 0

       mov     [newhwnd],eax

       call    ShowWindow, [newhwnd], SW_SHOWNORMAL

       call    UpdateWindow, [newhwnd]

msg_loop:

    PUSH 0

    PUSH 0

    PUSH 0

    PUSH OFFSET MSG

    CALL GetMessageA

    CMP EAX, 0

    JE  END_LOOP

    PUSH OFFSET MSG

    CALL TranslateMessage

    PUSH OFFSET MSG

    CALL DispatchMessageA

    JMP msg_loop

END_LOOP:

; выход из программы (закрыть процесс)

    PUSH [MSG.MSWPARAM]

    CALL ExitProcess

;-----------------------------------------------------------------------------

DCDemoWndProc    proc uses ebx edi esi, hwnd:DWORD, wmsg:DWORD,\

                wparam:DWORD, lparam:DWORD

       cmp     [wmsg], WM_PAINT

       je      wmpaint

       cmp     [wmsg], WM_DESTROY

       je      wmdestroy

       call    DefWindowProcA, [hwnd],[wmsg],[wparam],[lparam]

       jmp     finish

wmpaint:

;==================================================

       ; Получаем контекст устройства

       call    BeginPaint, [hwnd], offset Ps

       mov     [hDC], eax

       ; Загружаем bitmap, который будет отображаться в окне, из файла

       call    LoadImageA, 0,offset szImg,IMAGE_BITMAP, \

               0,0,LR_LOADFROMFILE

       mov     [hBitmap], eax

       ; Получаем размерность загруженного bitmap'а

       call    GetObjectA, [hBitmap], size BITMAP, offset Bitmap

       ; Создаем совместимый с контекстом окна контекст в памяти

       call    CreateCompatibleDC, [hDC]

       mov     [hCompatibleDC], eax

       ; Делаем загруженный из файла bitmap текущим в совместимом контексте

       call    SelectObject, [hCompatibleDC], [hBitmap]

       mov     [hOldBitmap], eax

       ; Определяем размер рабочей области окна

       call    GetClientRect, [hwnd], offset Rect

       ; Копируем bitmap с совместимого на основной контекст

       ; с маштабированием

       call    StretchBlt, [hDC],0,0,[Rect.R],[Rect.B], \

               [hCompatibleDC],0,0,[Bitmap.bmWidth],[Bitmap.bmHeight], \

               SRCCOPY

       ; Вновь делаем старый bitmap текущим

       call    SelectObject, [hCompatibleDC], [hOldBitmap]

       ; Удаляем загруженный с диска bitmap

       call    DeleteObject, [hBitmap]

       ; Удаляем совместимый контекст

       call    DeleteDC, [hCompatibleDC]

       ; Освобождаем основной контекст, завершая перерисовку

       ; рабочей области окна

       call    EndPaint, [hwnd], offset Ps

       mov     eax, 0

       jmp     finish

;====================================================

wmdestroy:

       push    0

       call    PostQuitMessage

       mov     eax, 0

finish:

       ret

DCDemoWndProc          endp

ends

end start

Самостоятельно на практике: Ввести программы из примера 1 и 2. Довести их до рабочего состояния. Разработать программу на ассемблере, которая бы выводила в окно из четырёх различных графических файла четыре различных изображения. Пример:


Контекст для метафайла

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

1) Для создания контекста метафайла используется функция CreateMetaFile:

HDC WINAPI CreateMetaFile(LPCSTR lpszFileName);

Параметр lpszFileName указывает на строку, содержащую путь к имени файла, в который будут записаны команды GDI, или NULL. Если параметр равен NULL, то создается метафайл в оперативной памяти.

2) После выполнения рисования в контексте метафайла следует закрыть метафайл, вызвав функцию CloseMetaFile :

HMETAFILE WINAPI CloseMetaFile(HDC hdc);

Функция закрывает метафайл для контекста hdc и возвращает идентификатор метафайла.

3) Если имеется идентификатор метафайла, то метафайл можно скопировать в обычный дисковый файл, с помощью функции CopyMetaFile :

HMETAFILE WINAPI CopyMetaFile(HMETAFILE hmf,

LPCSTR lpszFileName);

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


4) Можно проиграть метафайл в контексте отображения или контексте устройства, вызвав функцию PlayMetaFile:

BOOL WINAPI PlayMetaFile(HDC hdc, HMETAFILE hmf);

5) При помощи функции DeleteMetaFile можно удалить метафайл:

BOOL WINAPI DeleteMetaFile(HMETAFILE hmf);

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

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

HMETAFILE WINAPI GetMetaFile(LPCSTR lpszFileName);


Использование сообщения WM_PAINT

Сообщение WM_PAINT система посылает окну во всех случаях, требующих перерисовки клиентской области окна, например при наступлении следующих событий:

  1.  Изменились размеры или местоположение окна;
  2.  Клиентская область была полностью или частично закрыта другим окном или выпадающим меню, а теперь закрывающий объект исчез;
  3.  Приложение вызвало одну из функций работы с полосами прокрутки.

Кроме того, приложение может само инициировать посылку сообщения WM_PAINT посредством вызова одной из функций InvalidateRect, InvalidateRgn или UpdateWindow.

Функция UpdateWindow посылает сообщение WM_PAINT непосредственно в оконную процедуру, минуя очередь сообщений приложения.


Использование функций InvalidateRect и InvalidateRgn

Если необходимо сгенерировать сообщение WM_PAINT, то можно воспользоваться функциями InvalidateRect и InvalidateRgn. Функция InvalidateRect имеет следующий прототип:

BOOL InvalidateRect(HWND hWnd, CONST RECT* lpRect, BOOL bErase);

hWnd – дескриптор окна, у которого изменился обновляемый регион. Если этот параметр равен NULL, то система обновляет и перерисовывает все окна приложения, а также посылает сообщения WM_ERASEBKGNB и WM_NCPAINT оконной процедуре до возврата из функции.

lpRect – указатель на строку типа RECT, содержащую клиентские координаты прямоугольника, который добавляется к обновляемому региону. Если этот параметр имеет значение NULL, то к обновляемому региону добавляется вся клиентская область.

bErase – флаг, определяющий будет ли стираться фон обновляемого региона. Если этот параметр равен TRUE, то фон стирается, когда вызывается функция BeginPaint. Если указано значение FALSE, то фон остаётся без изменения. То есть, функция InvalidateRect добавляет прямоугольник в область перерисовки окна hwnd.

Функция InvalidateRgn имеет следующий прототип:

BOOL InvalidateRgn(HWND hWnd, HRGN hRgn, BOOL bErase);

Параметр hRgn содержит дескриптор региона, добавляемого к обновляемому региону. Этот дескриптор можно получить при помощи функций типа CreateRectRgn, CreatePolygonRgn и др. функций.


Функция ValidateRect

Добавляемые для перерисовки прямоугольники накапливаются до обработки сообщения WM_PAINT. В качестве единой области перерисовки Window’s вычисляет один прямоугольник, который охватывает все добавленные прямоугольники.

Функция ValidateRect удаляет прямоугольную область из списка прямоугольников перерисовки. Прототип этой функции:

BOOL ValidateRect(HWND hwnd, CONST RECT *lpRect);

Параметр hwnd указывает на окно, из области перерисовки которого исключается прямоугольник. Если этот параметр равен NULL, Windows перерисовывает все окна – посылает сообщения WM_ERASEBKGND и WM_NCPAINT функциям всех окон.

Параметр lpRect указывает на прямоугольник, который будет удалён из области перерисовки. Если lpRect = NULL, то из области обновления удаляются все прямоугольники.

В случае успешного выполнения функция возвращает ненулевое значение.


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

Операции по обмену блоками бит (bit block transfer, BLT) или тернарные растровые операции (ternary raster operation) – механизм, осуществляющий передачу растровых изображений между различными контекстами устройств.

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

  1.  между битмапом, выбранным в совместимый контекст устройства и реальным устройством на котором необходимо изображение показать;

2) между двумя битмапами;

  1.  с реального устройства в битмап;
  2.  с реального устройства на другое устройство.

GDI содержит 3 функции, осуществляющих такую передачу изображений — PatBlt, BitBlt и StretchBlt:

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);

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

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

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

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


В процессе выполнения растровой операции три исходных изображения (битовых последовательности
p, d, s) комбинируются и получается результирующее изображение. Код выполняемой операции задается параметром dwROP — индексом тернарной растровой операции.

Предположим, что биты, определяющие битмап совместимого контекста обозначают буквой S (source – источник, ресурс), биты заливки – буквой Р (pattern - образец), а биты, на которых будет прорисовываться изображение – буквой D (destination – назначение, место назначения). Операции, которые выполняются с битами S, P, D: а – побитовое И, n – побитовое НЕТ, о – побитовое ИЛИ, х – побитовое исключающее ИЛИ.

Х1   Х2  И     Х1   НЕТ    Х1   Х2  ИЛИ   Х1   Х2  Исключающее ИЛИ          

0      0    0       0         1        0      0       0       0      0               0               

0      1    0       1         0        0      1       1       0      1                1               

1      0    0                            1      0       1       1      0                1               

1      1    1                            1      1       1       1      1                0               

Обозначив знак операции как Ор, то действия с битами можно записать таким образом: PSОр. То есть необходимо взять пиксель паттерны и прорисовываемого битмапа и произвести над ними операцию (бинарная растровая операция). Если в операции участвует три операнда, то получим DPSОр1Ор2 (тернарная растровая операция).


Определить индекс операции PSx
и DPSxx.

P            1  1  1  1  0  0  0  0

S             1  1  0  0  1  1  0  0

D            1  0  1  0  1  0  1  0

PSx         0  0  1  1  1  1  0  0     =0x3c   ????

DPSxx    1  0  0  1  0  1  1  0     = 0x96   ????

DPx        0  1  0  1  1   0  1  0 = 5A         ????

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

Number

Hex ROP

Boolean function

Common Name

0

00000042

0

BLACKNESS

...

0D

000D0B25

PDSnaon

...

Поле «Hex ROP» – индекс тернарной растровой операции (используется в качестве параметра dwROP).

Поле «Boolean function» содержит пояснение к выполняемой операции;

Поле «Common name» — имя растровой операции, если оно назначено.


Основные коды растровых операций приведены в таблице.


Функция
StretchBlt

Скопировать bitmap с совместимого на основной контекст с масштабированием можно с помощью функции StretchBlt(). Эта функция описана следующим образом:

StretchBlt(HDC, int, int, int, int, HDC, int, int, int, int, DWORD);

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

Первый и шестой аргументы функции – хэндлы окна (hDC) и совместимого контекста (hCompatibleDC) соответственно. Одиннадцатый аргумент функции StretchBlt() – это код растровой операции.

Первые пять аргументов описывают тот прямоугольник на экране, в который будет вписан битмап. Ту часть битмапа, которая будет вписана в прямоугольник на экране, описывают следующие пят аргументов.


При масштабировании, используя функцию
StretchBlt возможно два случая:

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

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

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

UINT SetStretchBltMode(hDC, nMode);

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

BLACKONWHITE

выполняется операция И (AND). В результате получается, что черный цвет имеет "приоритет" над белым — сочетание черного с белым рассматривается как черный

WHITEONBLACK

выполняется операция ИЛИ (OR). При этом "приоритет" принадлежит белому над черным — сочетание черного с белым дает белый

COLORONCOLOR

при этом происходит простое исключение строк (столбцов).

HALFTONE 1

только в Win32 API; происходит усреднение цвета объединяемых точек.


Функция
BitBlt 

BOOL BitBlt(hDestDC, nDestX, nDestY, nDestWidth, nDestHeight, hSrcDC, nSrcX, nSrcY, dwROP);

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

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

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

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


Функция PatBlt не может рисовать битовые изображения, но используется для закраски прямоугольных областей экрана. Эта функция имеет имя 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 при ошибке.

PAGE  36




1. тема юридичної підготовки фахівців вУкраїні зазнала Істотних змін 3 підвищенням значення права ужитті суспі
2. Найти определители матриц АВС
3. Реферат- Беларуская музыка.html
4. Вильгельм Оранский
5. Экзогенные процессы в земной коре Подземные воды и льды криолитозоны
6. Роль первого Президента России Б
7. ИСТОРИЯ РЕЛИГИИ 1
8. Экуменизм
9. «Зеленый клин» Юго-Запада
10. тихоокеанский регион- динамизм определяют новые центры роста
11. Створення служби безпеки підприємства
12. Методические рекомендации по выполнению индивидуальных заданий по дисциплине Делопроизводство и корреспо
13. 2012 гг. Школьный этап 78 классы Участник школа класс
14. Deutsche Literturgeschichte Epochen~berblicke1
15. Это распространённый тип рынка наиболее близкий к совершенной конкуренции
16. Вредители и болезни хвойных растений
17. Расчет винта Расчет гребного винта осуществляется при помощи модуля Wint и заключается в опр
18. Медичне страхування
19. Деятельность НИ Толстого в области славистики
20. Іудаїзм