WinApi 정복 6장 (그래픽)

2015. 4. 14. 07:09창고

728x90
728x90

1. DC의 정보수정

GDI 오브젝트

GDI 오브젝트는 그래픽 출력에 사용되는 도구들을말한다.

펜, 브러시, 비트맵, 폰트 등등이 모두 GDI 오브젝트이다.

사용자는 그래픽을 출력하기 전에 DC에 원하는 오브젝트를 선택해주고

그래픽을 다른 모양으로 변경할 수 있다.


GDI 오브젝트핸들 타입설명디폴트
HPEN선을 그을 때 사용된다.검정색의 가는 선
브러시HBRUSH면을 채울 때 사용된다.흰색
폰트HFONT문자 출력에 사용되는 글꼴시스템 글꼴
비트맵HBITMAP비트맵 이미지선택되지 않음
팔레트HPALETTE팔레트선택되지 않음
영역HRGN영역선택되지 않음


속성 변경

스톡 오브젝트

윈도우즈가 기본적으로 제공해주는 GDI 오브젝트를 말한다.

생성과 소멸에 직접 관여할 필요가 없다. 아래 함수에서 핸들만 얻어 사용하면 된다.


1
HGDIOBJ GetStockObject( int fnObject ); 
cs


사용되는 인수

fnObject설명
BLACK_BRUSH검정색 브러시
GRAY_BRUSH회색 브러시
NULL_BRUSH투명 브러시
WHITE_BRUSH흰색 브러시
DKGRAY_BRUSH짙은 회색 브러시
LTGRAY_BRUSH옅은 회색 브러시
BLACK_PEN검정색 펜
WHITE_PEN흰색 펜
NULL_PEN투명 펜
ANSI_FIXED_FONT고정폭 폰트
ANSI_VAR_FONT가변폭 폰트
DEFAULT_PALETTE시스템 팔레트


색상

윈도우즈는 색상값을 표현하기 위해 COLORREF라는 데이터형을 사용한다.


typedef DWORD COLORREF; 형태로 정의되어 있다.


부호없는 32비트 크기의 정수형.

8비트씩 빨간색, 초록색, 파란색의 농도를 나타낸다.

상위 8비트는 사용되지 않는다.

각 색상 요소는 1바이트 크기를 가지므로 0~255까지 농도를 표현할 수 있다.


RGB 매크로 정의

1
2
3
4
5
6
7
#define RGB(r,g,b) ((COLORREF)(((BYTE)(r) | ((WORD)((BYTE)(g))<<8)) | (((DWORD)(BYTE)(b))<<16)))
 
#define GetRValue(rgb)      ((BYTE)(rgb))
#define GetGValue(rgb)      ((BYTE)(((WORD)(rgb)) >> 8))
#define GetBValue(rgb)      ((BYTE)((rgb)>>16))
 
 
cs

COLORREF형은 사용하기가 어렵기때문에 RGB 매크로가 정의되어 있다.


선을 그을 때 사용되는 GDI 오브젝트이다.


1
HPEN CreatePen( int fnPenStyle, int nWidth, COLORREF crColor ); 
cs


fnPenStyle

그려질 선의 모양을 정의한다.



nWidth

선의 폭을 지정한다. 디폴트 선의 굵기는 1. 값을 2나 3으로 변경하면 더 두꺼운 선을 그릴 수 있다.

0일 경우 무조건 맵핑 모드에 상관없이 무조건 1픽셀 두께의 선이 만들어진다.


crColor

선의 색상을 지정한다. COLORREF 형이므로 RGB 매크로 함수를 사용하면 된다.


사용순서


브러시

채워지는 면을 채색하는 용도로 사용한다.


1
HBRUSH CreateSolidBrush( COLORREF crColor ); HBRUSH CreateHatchBrush( int fnStyle, COLORREF clrref ); 
cs


인자

설명
HS_BDIAGONAL좌하향 줄무늬
HS_CROSS바둑판 모양
HS_DIACROSS좌하향 및 우하향 줄무늬
HS_FDIAGONAL우하향 줄무늬
HS_HORIZONTAL수평선
HS_VERTICAL수직선


2. 그리기 모드

그리기 모드의 종류

디폴트 그리기 모드는 R2_COPY 모드이다. 그려지는 그림이 기존의 그림을 덮어버린다.


1
2
int SetROP2( HDC hdc, int fnDrawMode );
int GetROP2( HDC hdc ); 
cs


SetROP2 - 그리기 모드를 변경

GetROP2 - 현재 그리기 모드


그리기 모드설명
R2_BLACK항상 검정색이다.
R2_WHITE항상 흰색이다.
R2_NOP아무런 그리기도 하지 않는다.
R2_NOT원래의 그림을 반전시킨다.
R2_COPYPEN원래의 그림을 덮어버리고 새 그림을 그린다.
R2_NOTCOPYPEN새 그림을 반전시켜 그린다.
R2_MERGEPENOR연산으로 두 그림을 합친다.
R2_MASKPENAND연산으로 겹치는 부분만 그린다.
R2_XORPENXOR연산으로 겹치는 부분만 반전시킨다.


Ropmode

선을 그리도록 하되 선이 그려지는 중간 과정을 보여주도록 한다.


변수설명
sx,sy처음 마우스를 누른 위치를 가진다.
oldx,oldy지워져야 할 선의 끝 좌표를 가진다.
ex,ey다시 그려져야 할 선의 끝 좌표를 가진다.
bNowDraw현재 선을 그리고 있는 중인가에 대한 정보를 가진다.


코드(유용하게 쓰일 것 같다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
    static int sx,sy,oldx,oldy;
    int ex,ey;
    static BOOL bNowDraw = FALSE;
    HDC hdc;
    switch(iMessage) {
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    case WM_LBUTTONDOWN:
        sx = LOWORD(lParam);
        sy = HIWORD(lParam);
        oldx = sx;
        oldy = sy;
        bNowDraw = TRUE;
        return 0;
    case WM_LBUTTONUP:
        bNowDraw = FALSE;
        hdc=GetDC(hWnd);
        MoveToEx(hdc,sx,sy,NULL);
        LineTo(hdc,oldx,oldy);
        ReleaseDC(hWnd, hdc);
        return 0;
    case WM_MOUSEMOVE:
        if (bNowDraw) {
            hdc=GetDC(hWnd);
            SetROP2(hdc,R2_NOT);
            MoveToEx(hdc,sx,sy,NULL);
            LineTo(hdc,oldx,oldy);
            ex = LOWORD(lParam);
            ey = HIWORD(lParam);
            MoveToEx(hdc,sx,sy,NULL);
            LineTo(hdc,ex,ey);
            oldx = ex;
            oldy = ey;
            ReleaseDC(hWnd,hdc);
        }
        return 0;
    }
    return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
cs


3. 맵핑 모드

맵핑 모드

주어진 좌표가 화면상의 실제 어디에 해당하는지 결정하는 방법을 말한다.

윈도우즈는 논리 좌표와 물리 좌표 두가지로 나뉜다.

- 논리좌표 : 윈도우즈 내부에서 사용되는 좌표. 실제 위치는 경우에 따라 달라진다.

그래픽 함수들이 사용하는 모든 좌표는 논리 좌표이다.(DC 핸들을 인수로 받는 모든 함수.

- 물리좌표 : 실제 화면에 출력되는 좌표. 픽셀 단위를 말한다. 물리적인 모니터의 픽셀.


이 두가지 좌표의 관계를 정의하는 것이 맵핑 모드이다. 

윈도우즈에서의 맵핑 모드는 논리 좌표를 물리 좌표로 변환하는 방법을 의미한다.

맵핑이란 두가지 사물의 일대일 대응 관계를 정의하는 공식 내지는 함수라 할 수 있다.


맵핑모드 종류

맵핑 모드단위X축 증가Y축 증가
MM_TEXT픽셀오른쪽아래쪽
MM_LOMETRIC0.1mm오른쪽윗쪽
MM_HIMETRIC0.01mm오른쪽윗쪽
MM_LOENGLISH0.01인치오른쪽윗쪽
MM_HIENGLISH0.001인치오른쪽윗쪽
MM_TWIPS1/1440인치오른쪽윗쪽
MM_ISOTROPIC가변가변가변
MM_ANISOTROPIC가변가변가변


디폴트 맵핑 모드는 픽셀 단위인 MM_TEXT이며 나머지는 밀리미터나 인치 등

논리적인 단위를 사용한다. 

1
2
int SetMapMode( HDC hdc, int fnMapMode );
int GetMapMode( HDC hdc ); 
cs


SetMapMode - 맵핑 모드 변경

GetMapMode - 현재 설정된 맵핑 모드를 알고싶을때


윈도우와 뷰포트

맵핑 모드를 제대로 이해하려면 알아야 하는 개념.

윈도우는 논리 좌표가 사용되는 표면을 말하며 그래픽 출력 함수는 윈도우에 그래픽을 출력한다.

뷰포트는 물리 좌표가 사용되는 영역을 말하며 실제로 사용자의 눈에 보이는 좌표 영역이다.


원점이란 좌표의 기준이 되는 점, 즉 (0,0)의 좌표를 말한다.

디폴트로 원점은 맥핑 모드에 관계 없이 화면의 좌상단에 위치한다.

프로그래머의 의도에 따라 변경할 수 있는 함수를 제공한다.


1
2
BOOL SetViewportOrgEx( HDC hdc, int X, int Y, LPPOINT lpPoint );
BOOL SetWindowOrgEx( HDC hdc, int X, int Y, LPPOINT lpPoint )
cs


가변비율

윈도우즈에 포함된 시계 프로그램을 보면 윈도우의 크기에 비해 항상 일정한 


4. 비트맵

Bitmap.dsw

메모리 DC

BitBlt

StretchBit

비트맵 만들기


5. 폰트

CreateFont

1
2
3
4
5
HFONT CreateFont( int nHeight, int nWidth, int nEscapement, 
int nOrientation, int fnWeight, DWORD fdwItalic, 
DWORD fdwUnderline, DWORD fdwStrikeOut, DWORD fdwCharSet, 
DWORD fdwOutputPrecision, DWORD fdwClipPrecision, 
DWORD fdwQuality, DWORD fdwPitchAndFamily, LPCTSTR lpszFace ); 
cs


14개의 인자! 그만큼 글꼴이라는 것이 복잡한 모양을 가질 수 있다는 뜻이다.


인자

인수설명
nHeight폰트의 높이를 논리적인 단위로 지정한다. 이 값이 0일 경우는 디폴트 크기가 사용된다.
hWidth폰트의 폭을 지정하되 이 값이 0이면 nHeight에서 지정한 높이에 따라 폭을 자동으로 결정한다. 즉 이 값이 0이면 폰트의 종횡비(장평)가 일정하다.
nEscapement폰트의 각도를 0.1도 단위로 설정한다. 이 각도는 문자가 출력될 X출과 문자열과의 각도이며 일상적인 360분법의 각도 체계를 사용한다. 즉 세시 방향이 0도로 사용되며 반시계 방향으로 각도가 증가한다.
nOrientation글자 한자와 X축과의 각도를 지정한다. nEscapement는 전체 문자열의 기울기를 지정하는데 비해 이 인수는 개별 문자의 기울기를 설정한다.
nWeight폰트의 무게를 0~1000까지의 값으로 설정한다. 쉽게 말해서 폰트의 두께를 설정한다. 0~1000까지의 값을 지정할 수 있으며 보통 굵기인 FW_NORMAL이 400이다.
bItalic, bUnderline, cStrikeOut기울임체, 밑줄, 관통선 속성을 설정한다. 데이터형이 BYTE이지만 불린형처럼 사용한다. 속성을 주고 싶으면 0 이외의 값(TRUE)를 주고 속성을 주지 않으려면 0(FALSE)를 준다.
nCharSet문자 셋을 설정한다. 여러 가지 값이 있지만 실제 사용될 수 있는 옵션은 ANSI_CHARSET과 OEM_CHARSET가 있다. ANSI_CHARSET가 윈도우즈에서 사용하는 문자셋이고 OEM_CHARSET가 도스에서 사용하는 문자셋이라고 생각하면 된다.
nOutPrecision출력 정확도를 설정한다.
nClipPrecision클리핑 정확도를 설정한다.
nQuality논리적 폰트를 물리적 폰트에 얼마나 근접시킬 것인가를 지정한다.
nPitchAndFamily폰트의 피치와 그룹을 설정한다.
lpszFacename글꼴의 이름을 나타내는 문자열을 설정한다.


Font.dsw

폰트 테스트 예제



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    HFONT font, oldfont;
    char str[]="폰트 Test 1234";
    switch(iMessage) {
    case WM_PAINT:
        hdc=BeginPaint(hWnd, &ps);
        font=CreateFont(50,0,0,0,0,0,0,0,HANGEUL_CHARSET,0,0,0,0,"궁서");
        oldfont=(HFONT)SelectObject(hdc,font);
        TextOut(hdc, 100,100,str,strlen(str));
        SelectObject(hdc,oldfont);
        DeleteObject(font);
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
cs


다른 방법

LOGFONT 구조체를 사용하여 폰트를 정의하고 CreateFontIndirect 함수로 폰트를 만드는 방법도 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    HFONT font, oldfont;
    char str[]="폰트 Test 1234";
    LOGFONT lf;
    switch(iMessage) {
    case WM_PAINT:
        hdc=BeginPaint(hWnd, &ps);
        lf.lfHeight=50;
        lf.lfWidth=0;
        lf.lfEscapement=0;
        lf.lfOrientation=0;
        lf.lfWeight=0;
        lf.lfItalic=0;
        lf.lfUnderline=0;
        lf.lfStrikeOut=0;
        lf.lfCharSet=HANGEUL_CHARSET;
        lf.lfOutPrecision=0;
        lf.lfClipPrecision=0;
        lf.lfQuality=0;
        lf.lfPitchAndFamily=0;
        strcpy(lf.lfFaceName,"궁서");
        font=CreateFontIndirect(&lf);
        oldfont=(HFONT)SelectObject(hdc,font);
        TextOut(hdc, 100,100,str,strlen(str));
        SelectObject(hdc,oldfont);
        DeleteObject(font);
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}
cs


결과는 동일하다.

LOGFONT 구조체의 장점

- 구조체 배열을 이용하여 미리 사용할 폰트 목록 생성

- 맴버중 일부만 변경하여 재사용할 수 있다.


문자열의 색상



글자 회전시키기


728x90
반응형