Поможем написать учебную работу
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Если у вас возникли сложности с курсовой, контрольной, дипломной, рефератом, отчетом по практике, научно-исследовательской и любой другой работой - мы готовы помочь.
Лабораторна робота №6
Тема: Використання GDI інтерфейсу для побудови графіки в ОС Windows.
Мета: Навчитися користуватися засобами GDI.
Теоретичні основи
Основні поняття
Розпочнемо з того, що собою представляє GDI, і яку роль грає у ОС Windows.
GDI розшифровується як Graphics Device Interface, і є інтерфейсом, який Windows використовує для малювання 2d графіки. Також це найповільніший спосіб відображення графіки з тих, що існують, проте найпростіший для розуміння основ. Отже, спершу, поговоримо про основні поняття і терміни в GDI.
Почнемо з того, що GDI зазвичай не використовують для створення "крутих" графічних ефектів, для цього є DIRECTX, OPENGL. Проте, для створення простих ефектів з мінімальними зусиллями GDI цілком підходить.
Поняття графічний контекст
Для висвітлення або відтворення (наприклад, на папері) малюнка потрібен пристрій виводу(малювання). Наприклад, в моніторі зображення відтворює 3 лазерними пушками, які контролюються 4-ма магнітами, дякуючи їм, лазери будуються складні кольори та контори, що ми бачимо на екрані. Також цей "пристрій" може виступати як певний механізм, що оперує деякою палітрою компонентів. Якщо перейти до абстрактного мислення, то таким пристроєм можна назвати руку людини. Це геніальний пристрій, котрий може намалювати все що завгодно, починаючи від простої точки закінчуючи складною фігурою з тінями і у кольоровому супроводі. У технології GDI є свій пристрій малювання, який може реалізувати, практично все, його називають графічним контекстом або контекстом пристрою (DC - "Device Context").
Визначення DC для обєктів типу вікно
У операційній системі Windows будь яке вікно, що відтворюється на екрані є малюнком. Виходячи з попереднього твердження, кожне вікно, це графічний обєкт. Відповідно всі вікна мають свій DC. Щоб ним скористатися, потрібно його визначити (позичити). Це робиться за допомогою функції GetDC.
У функції є один параметр, хендл вікна. Якщо вікна оголошені як діалогові (див. попередню лабораторну), для визначення хенду контрола використовується функція GetDlgItem.
Функція GetDC позичає DC у вікна, тому після використання потрібно повернути DC власнику, тобто вікну. Це робиться за допомогою функції ReleaseDC. Для взяття DC робочого столу параметром функції GetDC має бути "0". Таке значення хендлу працює тільки у вище згаданій функції. В інших випадках може причинити помилку.
GetDC
hWnd // хендл вікна у котрого позичимо DC
Результат: хендл DC
ReleaseDC
hWnd // хендл вікна у кого позичали DC
hDC // хендл DC
Результат: TRUE (1) якщо повернувся DC вікну
Створити DC не можна його можна або позичити або скопіювати за допомогою функції CreateCompatibleDC. Параметр 1, хендл DC з кого копіюємо. Якщо графічний обєкт з якого будемо чорно-білий, то "ново спечений" DC також буле чорно-білим.
Поняття растру та основні функції роботи з ним.
Перед тим як використовувати методи GDI, треба зрозуміти яким чином відтворюється графіка у компютері.
Почнемо з того, що таке растр. Растр - це є сукупність мінімальних одиниць зображення, що розміщено як матриця, де під мінімальною одиницею розуміється піксекль. Піксель це точка, але у компютерній графіці, точна не є круглою, як ми звикли уявляти, а на справді маленький квадратик. Відповідно сукупність пікселів розміщених послідовно ми будемо називати лінією.
Найпростішою і мабуть най повільнішою функцією у GDI є SetPixel.
SetPixel
HDC // хендл DC
X // координата Х
Y // координата Y
crColor // колір у колуванні RGB
Результат: значення встановленого кольору(RGB), або -1 якщо точка розміщена поза зоною видимості
Для взяття інформації про піксель використовується функції GetPixel
GetPixel
HDC // хендл DC
X // координата Х
Y // координата Y
Результат: значення встановленого кольору(RGB) у координатах Х,Y
Під RGB кодування розуміється представлення кольору у вигляді 3 компонентів R червонного, G зеленого та B синього. Кожна компонента займає 1байт, і містить число у діапазоні [0..255]. Це кодування має іншу назву, 24бітний колір (24 bit Color). У ОС Windows використовується 5 типів:
Приклад, градієнт:
Задача: Якщо по вертикалі, в позиції 0 колір буде рівний 0, а в позиції "висота" = 255, то який колір буде в позиції y?
сol = y * 255 / висоту.
;Код 1
.data
hdc1 dd 0
x dd 0
y dd 0
.code
........
.if wParam == 1001
invoke GetDC,hWin
mov hdc1,eax
mov x,0
mov y,0
.while y<270
.while x<500
invoke MulDiv,y,0ffh,270
invoke SetPixel,hdc1,x,y,eax
inc x
.endw
inc y
mov x,0
.endw
invoke ReleaseDC,hWin,hdc1
........
Прапор:
;Код 2
.data
hdc1 dd 0
x dd 0
y dd 0
.code
........
.if wParam == 1001
invoke GetDC,hWin
mov hdc1,eax
mov x,0
mov y,0
.while y<270
.while x<500
; синій зменшується, а червоний та зелений збільшуються
invoke MulDiv,y,0ffh,270
mov ecx,0ffh ; ecx = 255
sub ecx,eax ; ecx "pos gradient"
shl ecx,16 ; ecx -> blue (<< 16)
mov ebx,eax ; ebx= red
shl eax,8 ; eax = green
or eax,ebx ; mix
or eax,ecx
invoke SetPixel,hdc1,x,y,eax
inc x
.endw
inc y
mov x,0
.endw
invoke ReleaseDC,hWin,hdc1
........
Код1 Код2
Мал. 1. Приклад роботи з пікселями
Для малювання прямих використовується функція LineTo
LineTo
hdc // хендл DC
nXEnd, // координата Х кінця малювання прямої
nYEnd // координата Y кінця малювання прямої
Результат: не нуль, в позитивному випадку
Зверніть увагу, колір, тип та товщина лінії залежить від інструменту (Pen), який використовує на час виконання функції DC, якщо є потреба малювати іншим пером, треба підмінити його новим, про це пізніше.
Початкові координати прямої будуть кінцем попередньої функції, тому якщо є потреба під коректувати це значення використовується функція MoveToEx
MoveToEx
hdc // хендл DC
nXNew, // координата Х
nYNew // координата Y
lpPoint // вказівник на структуру POINT де будуть записані старі координати початку малювання прямої. Цей параметр може бути 0 (NULL)
Результат: не нуль, в позитивному випадку
Наступний приклад ілюструє малювання лінії за рухом мишки.
PolylineTo
hdc // хендл DC
*lppt // вказівник на масив структур POINT, в яких буде міститися координати вершин ламаної
cCount // к-сть вершин
Результат: не нуль, в позитивному випадку
Переглянути функції :
Приклад побудови трикутника за допомогою ліній:
.data
Hdc1 dd 0
.code
.....
.if wParam == 1001
invoke GetDC,hWin
mov hdc1,eax
invoke MoveToEx,hdc1,100,100,0
invoke LineTo,hdc1,150,150
invoke LineTo,hdc1,250,100
invoke LineTo,hdc1,100,100
invoke ReleaseDC,hWin,hdc1
.endif
......
За допомогою полі-ліній:
.data
hdc1 dd 0
x POINT <150,150>
POINT <250,100>
POINT <100,100>
.code
........
.if wParam == 1001
invoke GetDC,hWin
mov hdc1,eax
invoke MoveToEx,hdc1,100,100,0
invoke PolylineTo,hdc1,addr x,3
invoke ReleaseDC,hWin,hdc1
.endif
........
Результат:
|
|
|
|
|
|
|
|
|
|
Колір замальовування буде білим, якщо є потреба змінити колір, потрібно підмінити інструмент "щитка" у DC.
Поняття палітри інструментів та оперування з ними.
Для малювання будь-яких обєктів в GDI потрібно скористатися певним інструментом. Будь-який DC системи має у своєму розпорядженні 5 обєкт-інструментів. Це перо, щитка, текстовий шрифт, регіон (область) відтворення та полотно на якому він малює.
Вважається, що первинно DC має стандартний набір. Наприклад, чорна ручка, біла щітка, стандартній шрифт і тд. Для використання у певному DC іншого інструменту, потрібно "підмінити" інструмент. Це здійснюється за допомогою функції SelectObject.
SelectObject
hdc, // хендл DC
gdiobj // хендл обєкт-інструменту, на який хочемо замінити.
Результат: хендл старого інструменту
В один момент часу DC може оперувати тільки ОДНИМ НАБОРОМ ІНСТРУМЕНТІВ. Тобто, водночас він не може використовувати 2 обєкти перо, наприклад. Тому якщо потрібно, у певний момент часу поміняти інструмент, викликаємо функцію (SelectObject), малюємо новим інструментом і при потребі, повертаємо старий таким же методом.
Іноді потрібно видалити старий інструмент, щоб не засмічувати память. Це здійснюється за допомогою функції DeleteObject. Параметр 1, хендл обєкту що знищуємо.
Окрім цього, бувають ситуації коли нам потрібно визначити характеристики певного інструменту. Це здійснюється за допомогою GetObject.
GetObject
Hgdiobj // хендл інструменту
cbBuffer // розмір буфера
lpvObject // вказівник на буфер
Результат: якщо успішно то повертає кількість байт записаних у буфер.
Під буфером розуміється, певна структура, наприклад, якщо хендл пера то структура LOGPEN, для щитки LONGBRUSH і тд.
Для визначення типу інструменту можна скористатися функцією GetObjectType.
Окрім цього, є ще одна важлива і водночас цікава функція, котра керує режимом малювання. SetROP2. Вона цікава тим, що може задавати властивість R2_XORPEN. Для зрозумілості, наприклад, якщо намалювати дві ліні, однакового кольору, одна поверх іншою, друга то витре першу. Принцип логічної операції xor (1 xor 1 = 0). Ця властивість не тільки розповсюджується на лінії, також на готові обєкти. При накладені зображень з різним кольором відбувається вирізання кольору, наприклад, якщо на синьому полотні намалювати прямокутник з білим зафарбуванням, намалюється жовтий.
Створення інструментів.
Перед тим як здійснювати замітину інструменту в DC, потрібно його створити. Розглянемо функції які для цього використовуються. Розглянемо коротко цей список.
Створення пера
Перо є основним інструментом в GDI. Коли малюємо певне зображення ми можемо намалювати її чорними лініями а потім зафарбувати вміст. Але що робити, коли лінії за тонкі або чорний контур є не доречним? Рішенням є використати інший обєкт перо.
В основному є 2 функції для створення інструменту перо це CreatePen та CreatePenIndirect.
CreatePen
fnPenStyle // значення яке визначає стиль пера. Може бути комбіноване.
nWidth // ширина пера
crColor // колір (RGB)
Результат: хендл пера
Функція CreatePenIndirect є сестрою близнючкою функції CreatePen з однією різницею, має тільки 1 параметр. Вказівник на структуру LOGPEN, що містить в собі всі поля вище згаданої сестри.
Створення щитки
Малювання контуру зображення це не відємна риса зображення, але вміст контору залишається "пустим". Можна методом штрихування зафарбувати вміст контуру, але ця дія сповільняє відтворення зображення. Тому для таких цілей в GDI є обєкт щитка. По замовчуванню вона біла. Для створення власної щітки використовується наступні функції.
Створення обєкта шрифт
Найпростішим та най оптимальнішим методом передачі інформації є текст. Для виводу тексту на екран GDI використовує інструмент шрифт. Існує багато функцій роботи з шрифтами, розглядати детально ми їх не будемо, але зупинимося на основній, яка створю простий шрифт.
CreateFont
nHeight, // висота шрифту. Визначається по формулі -MulDiv("Бажана висота", GetDeviceCaps(hDC, LOGPIXELSY), 72);
nWidth, // Висота шрифту
nEscapement, // кут нахилу
nOrientation, // кут базової лінії
fnWeight, // товщина шрифту (0..900) кратне 100. Диф. Хелп.
fdwItalic, // текст буде курсивом ( "0" або "1" )
fdwUnderline, // текст буде підкреслений ( "0" або "1" )
fdwStrikeOut, // текст буде закреслений ( "0" або "1" )
fdwCharSet, // задати набір символів
fdwOutputPrecision, // задати точність виводу літер (одна із констант)
fdwClipPrecision, // задає точність відсічення по границям літер (одна із констант)
fdwQuality, // задає якість виводу даних
fdwPitchAndFamily, // встановлює крок між символами
lpszFace // вказівник на рядок що містить назву шрифта зареєстрованого у системі
Результат: хендл нового шрифта
Приклад створення простого шрифта.
.data
szfont db 'Arial',0
.code
…..
invoke GetDeviceCaps,hdc1,LOGPIXELSY
invoke MulDiv,40,eax,72
neg eax ; -eax
invoke CreateFont,eax,40,0,0,FW_NORMAL,1,0,0,DEFAULT_CHARSET,\
OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,\
DEFAULT_PITCH,addr szfont
……
Також перегляньте наступні функції:
Функції |
Опис |
AddFontMemResourceEx |
Добавляє у систему новий шрифт з області памяті |
AddFontResource |
Добавляє у систему новий шрифт |
AddFontResourceEx |
Добавляє у систему новий шрифт (з розширеними можливостями) |
CreateFont |
Ств. шрифт |
CreateFontIndirect |
Ств. шрифт за допомогою структури LOGFONT |
CreateFontIndirectEx |
Ств. шрифт за допомогою структури LOGFONT (розширене) |
CreateScalableFontResource |
Creates a font resource file for a scalable font. |
DrawText |
Draws formatted text in a rectangle. |
DrawTextEx |
Draws formatted text in rectangle. |
EnumFontFamExProc |
An application definedcallback function used with EnumFontFamiliesEx to process fonts. |
EnumFontFamiliesEx |
Enumerates all fonts in the system with certain characteristics. |
ExtTextOut |
Draws a character string. |
GetAspectRatioFilterEx |
Gets the setting for the aspect-ratio filter. |
GetCharABCWidths |
Gets the widths of consecutive characters from the TrueType font. |
GetCharABCWidthsFloat |
Gets the widths of consecutive characters from the current font. |
GetCharABCWidthsI |
Gets the widths of consecutive glyph indices or from an array of glyph indices from the TrueType font. |
GetCharacterPlacement |
Gets information about a character string. |
GetCharWidth32 |
Gets the widths of consecutive characters from the current font. |
GetCharWidthFloat |
Gets the fractional widths of consecutive characters from the current font. |
GetCharWidthI |
Gets the widths of consecutive glyph indices or an array of glyph indices from the current font. |
GetFontData |
Gets metric data for a TrueType font. |
GetFontLanguageInfo |
Returns information about the selected font for a display context. |
GetFontUnicodeRanges |
Tells which Unicode characters are supported by a font. |
GetGlyphIndices |
Translates a string into an array of glyph indices. |
GetGlyphOutline |
Gets the outline or bitmap for a character in the TrueType font. |
GetKerningPairs |
Gets the character-kerning pairs for a font. |
GetOutlineTextMetrics |
Gets text metrics for TrueType fonts. |
GetRasterizerCaps |
Tells whether TrueType fonts are installed. |
GetTabbedTextExtent |
Computes the width and height of a character string, including tabs. |
GetTextAlign |
Gets the text-alignment setting for a device context. |
GetTextCharacterExtra |
Gets the current intercharacter spacing for a device context. |
GetTextColor |
Gets the text color for a device context. |
GetTextExtentExPoint |
Gets the number of characters in a string that will fit within a space. |
GetTextExtentExPointI |
Gets the number of glyph indices that will fit within a space. |
GetTextExtentPoint32 |
Computes the width and height of a string of text. |
GetTextExtentPointI |
Computes the width and height of an array of glyph indices. |
GetTextFace |
Gets the name of the font that is selected into a device context. |
GetTextMetrics |
Fills a buffer with the metrics for a font. |
PolyTextOut |
Draws several strings using the font and text colors in a device context. |
RemoveFontMemResourceEx |
Removes a font whose source was embedded in a document from the system font table. |
RemoveFontResource |
Removes the fonts in a file from the system font table. |
RemoveFontResourceEx |
Removes a private or non-enumerable font from the system font table. |
SetMapperFlags |
Alters the algorithm used to map logical fonts to physical fonts. |
SetTextAlign |
Sets the text-alignment flags for a device context. |
SetTextCharacterExtra |
Sets the intercharacter spacing. |
SetTextColor |
Sets the text color for a device context. |
SetTextJustification |
Specifies the amount of space the system should add to the break characters in a string. |
TabbedTextOut |
Writes a character string at a location, expanding tabs to specified values. |
TextOut |
Writes a character string at a location. |
Нижче приведений код програми для завантаження власних шрифтів
.date
szPathFont db 'Cheese and Mouse.ttf',0
szfont db 'Cheese and Mouse',0
szTest db 'Hello',0
size_szTest dd $-szTest ; визначити довжину стрічки ($ = поточна адреса змінної)
.code
…..
DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
mov eax,uMsg
.if eax==WM_INITDIALOG
invoke GetDC,hWin
mov hdc1,eax
.elseif eax==WM_COMMAND
.if wParam == 1001 ;натискаємо кнопку
invoke AddFontResource,addr szPathFont ; додаємо новий шрифт в систему
invoke GetDeviceCaps,hdc1,LOGPIXELSY
invoke MulDiv,60,eax,72
neg eax ; -eax
invoke CreateFont,eax,60,0,0,FW_NORMAL,0,0,0,DEFAULT_CHARSET, \
OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,\
DEFAULT_QUALITY,DEFAULT_PITCH,addr szfont
invoke SelectObject,hdc1,eax ; підміняємо в DC новий шрифт
invoke SetTextColor,hdc1,0ffh ; коліт тексту червоний
invoke SetBkMode,hdc1,TRANSPARENT ; фон тексту прозорий
invoke TextOut,hdc1,50,100,addr szTest,size_szTest ; виводимо текст
invoke RemoveFontResource,addr szPathFont ; видаляємо встановлений шрифт
.endif
.elseif eax==WM_CLOSE
invoke ReleaseDC,hWin,hdc1
invoke EndDialog,hWin,0
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
DlgProc endp
…………
Мал. 4. Приклад завантаження власного шрифту
Створення регіональних контурів
Під регіональним контуром розуміється обєкт, що описує певну область як сукупність точок або підмножин областей. Іншими словами регіон описує контур (область) видимості (малювання). Цей інструмент є дуже потрібний для будування специфічних обєктів. Нижче наведений список функцій роботи з регіонами.
Функція |
Опис |
CombineRgn |
Комбінує 2 регіони (перетин, вирізання, обєднання ітд ) |
CreateEllipticRgn |
Ств. регіон у вигляді еліпса |
CreateEllipticRgnIndirect |
Ств. Регіон у вигляді еліпса (за допомогою структури RECT) |
CreatePolygonRgn |
Ств. регіон з полігону точок |
CreatePolyPolygonRgn |
Ств. регіон з полігонних областей точок |
CreateRectRgn |
Ств. регіон прямокутник |
CreateRectRgnIndirect |
Ств. регіон прямокутник з структури RECT |
CreateRoundRectRgn |
Ств. регіон прямокутник з не гострими кутами |
EqualRgn |
Перевіряє 2 регіони на ідентичність. |
ExtCreateRegion |
Ств. регіон на основі спеціальних МЕТА-даних. |
FillRgn |
Зафарбовує регіон певним кольором. |
FrameRgn |
Малює границю доокола регіону |
GetPolyFillMode |
Визначає поточний тип заповнення/замальовування регіону |
GetRegionData |
Повертає масив точок, які описують регіональну область |
GetRgnBox |
Повертає фізичні параметри і записує у структуру RECT |
InvertRgn |
Інвертує колів в певній області |
OffsetRgn |
Переміщує регіон на певне зміщення |
PaintRgn |
Малює регіон на певному DC. |
PtInRegion |
Визначає чи входить точка (X,Y) в задану область регіону |
RectInRegion |
Визначає чи "влазить" прямокутник у область регіону |
SetPolyFillMode |
Встановлює стиль заповнення регіону |
SetRectRgn |
Конвертує регіон у прямокутник не чіткою портую (не гострими кутами) |
Приклад.1
.data
x POINT <150,150>
POINT <250,100>
POINT <100,100>
.code
…….
DlgProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL hr:DWORD
mov eax,uMsg
.if eax==WM_INITDIALOG
invoke GetDC,hWin
mov hdc1,eax
.elseif eax==WM_COMMAND
.if wParam == 1001
invoke CreatePolygonRgn,addr x,3,WINDING ; ств. регіон
mov hr,eax
invoke CreateSolidBrush,00A8A8FFh ; ств. щітку
push eax
invoke FillRgn,hdc1,hr,eax ; замалювали регіон
call DeleteObject ; витерли щітку (хендл вже у стеку)
invoke DeleteObject,hr ; знищуємо регіон
.endif
.elseif eax==WM_CLOSE
invoke ReleaseDC,hWin,hdc1
invoke EndDialog,hWin,0
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
ret
DlgProc endp
……
Приклад 2
.data
x POINT <0,0>
POINT <550,500>
POINT <500,100>
y POINT <0,500>
POINT <250,0>
POINT <500,200>
.code
.elseif eax==WM_COMMAND
.if wParam == 1001
invoke CreatePolygonRgn,addr x,3,1
mov hr1,eax
invoke CreatePolygonRgn,addr y,3,1
mov hr2,eax
invoke CombineRgn,hr1,hr1,hr2,RGN_OR
invoke SetWindowRgn,hWin,hr1,1
.endif
Зафарбовування регіональної області створення форми з "специфічним виглядом"
Мал. 5 регіони
Створення обєкту типу BITMAP (полотно)
BITMAP це бітове поле розміщене у памяті, що містить / описує якесь графічне зображення (піксельне поле). Використовується для обробки зображення перед його малюванням на екрані.
Нижче перераховані функції роботи з бітовим полем.
AlphaBlend |
Здійснення альфа-міксування кольру в бітмапі |
BitBlt |
Малювання/копіювання бітів з одного полотна на інше. |
CreateBitmap |
Створення біт мапу |
CreateBitmapIndirect |
Створення біт мапу на основі структури BITMAP |
CreateCompatibleBitmap |
Ств. біт мапу на основі іншого DC |
CreateDIBitmap |
Ств. апаратно залежний біт мап з апаратно не залежного бітового простору ( масиву бітів) |
CreateDIBSection |
Ств. апаратно залежний біт мап з прямим доступом до памяті бітів малюнка. (DIB-секція) |
ExtFloodFill |
Зафарбовує замкнуту область малюнка певним кольором і стилем |
GetBitmapDimensionEx |
"Витягує" розмір малюнка |
StretchBlt |
Копіювання біт мапу з можливістю його деформування (стиснення/розтягування) |
TransparentBlt |
Копіювання біт мапу з властивістю прозорості |
Завдання: