Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
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
Archives
Today
Total
관리 메뉴

codingfarm

6. 그래픽 - 폰트 본문

Windows/윈도우즈 API

6. 그래픽 - 폰트

scarecrow1992 2021. 12. 25. 18:40

0. 개요

  • 폰트도 펜이나 브러쉬처럼 GDI 오브젝트이다.
  • 폰트 오브젝트를 만들고 DC로 전송한 후 문자열을 출력하면, DC에 선택된 폰트를 사용하여 문자열이 출력된다.

 

 

1. CreateFont

  • 폰트의 생성에 쓰이는 함수
  • 반환되는 핸들을 HFONT형의 변수에 대입한다
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
HFONT CreateFontW(
  [in] int     cHeight,
  [in] int     cWidth,
  [in] int     cEscapement,
  [in] int     cOrientation,
  [in] int     cWeight,
  [in] DWORD   bItalic,
  [in] DWORD   bUnderline,
  [in] DWORD   bStrikeOut,
  [in] DWORD   iCharSet,
  [in] DWORD   iOutPrecision,
  [in] DWORD   iClipPrecision,
  [in] DWORD   iQuality,
  [in] DWORD   iPitchAndFamily,
  [in] LPCWSTR pszFaceName
);
cs

인수가 매우 많다. 그만큼 글꼴이라는게 복잡한 모양을 가질 수 있다는 뜻이다.

각 인수의 의미는 아래와 같다.

인수 설명
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 글꼴의 이름을 나타내는 문자열을 설정한다.

출처 : http://soen.kr/

인수 갯수 못지않게 하나하나의 의미도 복잡하다. 눈여겨 볼만한 인수는 문자의 크기를 지정하는 nHeight와 글꼴 모양을 지정하는 lpszFace 정도이다.

 

 

2. 폰트 생성

일반적인 GDI 오브젝트와 사용법 자체는 거의 동일하다.

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <windows.h>
#include <tchar.h>
 
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("Menu");
 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance
    , LPSTR lpszCmdParam, int nCmdShow)
{
    HWND hWnd;
    MSG Message;
    WNDCLASS WndClass;
    g_hInst = hInstance;
 
    WndClass.cbClsExtra = 0;
    WndClass.cbWndExtra = 0;
    WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    WndClass.hInstance = hInstance;
    WndClass.lpfnWndProc = (WNDPROC)WndProc;
    WndClass.lpszClassName = lpszClass;
    WndClass.lpszMenuName = NULL;
    WndClass.style = CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&WndClass);
 
    hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, (HMENU)NULL, hInstance, NULL);
    ShowWindow(hWnd, nCmdShow);
    
    while (GetMessage(&Message, 000)) {
        TranslateMessage(&Message);
        DispatchMessage(&Message);
    }
    return Message.wParam;
}
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    HFONT font, oldfont;
    WCHAR str[] = L"폰트 Test 1234";
    switch (iMessage) {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        font = CreateFont(500000000, HANGEUL_CHARSET, 0000, L"궁서");
        oldfont = (HFONT)SelectObject(hdc, font);
        TextOut(hdc, 100100, str, wcslen(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

 

CreateFont 함수로 폰트 GDI 오브젝트를 생성하는 방법 대신 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;
    TCHAR str[] = TEXT("폰트 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;
        wcscpy(lf.lfFaceName, TEXT("궁서"));
        font = CreateFontIndirect(&lf);
        oldfont = (HFONT)SelectObject(hdc, font);
        TextOut(hdc, 100100, str, wcslen(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

출력 결과는 앞의 코드와 동일하다.

 

Indirect 함수

Win32 API에서는 함수명 뒤에 Indirect가 붙은 함수들이 여러 개 있는데, 이들은 구조체의 포인터를 인수로 취하는 특징을 지니고 있다. (CreatePenIndirect, CreateBrushIndirect ...)

 

3. 텍스트의 색상

폰트 오브젝트 외에 출력되는 문자열에 영향을 주는 여러가지 함수가 있다.

SetTextAlign, SetTextColor, SetBkColor, SetBkMode 함수등이 있다.

뒤의 3가지 함수를 살펴보겠다.

1
2
3
COLORREF SetTextColor( HDC hdc, COLORREF crColor );
COLORREF SetBkColor( HDC hdc, COLORREF crColor );
int SetBkMode( HDC hdc, int iBkMode );
cs

사용법 자체는 굉장히 직관적이고 쉬우므로 추가 설명은 필요없을것이다.

다만 SetBKMode 함수의 2번째 매개변수인 iBkMode는 아래 2가지 인수를 사용한다.

인수 설명
OPAQUE 불투명한 배경을 사용한다. 그래서 배경 색상에 의해 뒷쪽의 그림이 지워진다. 이 모드가 디폴트이다.
TRANSPARENT 투명한 배경색상을 사용한다. 그래서 문자를 출력한 후에도 배경이 바뀌지 않는다. 즉 문자 사이 사이의 여백에 있는 원래 배경이 지워지지 않는다.

대표적인 사용법은 아래와 같다.

 

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <windows.h>
#include <tchar.h>
 
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("Menu");
 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance
    , LPSTR lpszCmdParam, int nCmdShow)
{
    HWND hWnd;
    MSG Message;
    WNDCLASS WndClass;
    g_hInst = hInstance;
 
    WndClass.cbClsExtra = 0;
    WndClass.cbWndExtra = 0;
    WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    WndClass.hInstance = hInstance;
    WndClass.lpfnWndProc = (WNDPROC)WndProc;
    WndClass.lpszClassName = lpszClass;
    WndClass.lpszMenuName = NULL;
    WndClass.style = CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&WndClass);
 
    hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, (HMENU)NULL, hInstance, NULL);
    ShowWindow(hWnd, nCmdShow);
    
    while (GetMessage(&Message, 000)) {
        TranslateMessage(&Message);
        DispatchMessage(&Message);
    }
    return Message.wParam;
}
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    HFONT font, oldfont;
    WCHAR str[] = L"폰트 Test 1234";
    HBRUSH MyBrush, OldBrush;
    switch (iMessage) {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        MyBrush = CreateHatchBrush(HS_CROSS, RGB(00255));
        OldBrush = (HBRUSH)SelectObject(hdc, MyBrush);
        Rectangle(hdc, 5050400200);
        SelectObject(hdc, OldBrush);
 
        font = CreateFont(300000000, HANGEUL_CHARSET, 0000, L"궁서");
        oldfont = (HFONT)SelectObject(hdc, font);
        SetTextColor(hdc, RGB(25500));
        SetBkColor(hdc, RGB(2552550));
        TextOut(hdc, 100100, str, wcslen(str));
        SetBkMode(hdc, TRANSPARENT);
        TextOut(hdc, 100150, str, wcslen(str));
 
        SelectObject(hdc, oldfont);
        DeleteObject(MyBrush);
        DeleteObject(font);
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
cs

 

 

4. 글자 회전

CreateFont의 세번째 인수인 nEscapement를 변경하면 문자열이 출력되는 각도를 바꿀 수 있다.

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <windows.h>
#include <tchar.h>
 
 
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("Menu");
 
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance
    , LPSTR lpszCmdParam, int nCmdShow)
{
    HWND hWnd;
    MSG Message;
    WNDCLASS WndClass;
    g_hInst = hInstance;
 
    WndClass.cbClsExtra = 0;
    WndClass.cbWndExtra = 0;
    WndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    WndClass.hInstance = hInstance;
    WndClass.lpfnWndProc = (WNDPROC)WndProc;
    WndClass.lpszClassName = lpszClass;
    WndClass.lpszMenuName = NULL;
    WndClass.style = CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&WndClass);
 
    hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, (HMENU)NULL, hInstance, NULL);
    ShowWindow(hWnd, nCmdShow);
    
    while (GetMessage(&Message, 000)) {
        TranslateMessage(&Message);
        DispatchMessage(&Message);
    }
    return Message.wParam;
}
 
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) {
    HDC hdc;
    PAINTSTRUCT ps;
    int i;
    WCHAR str[] = L"                   Beautiful Korea";
    HFONT MyFont, OldFont;
    switch (iMessage) {
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        for (i = 0; i < 900; i += 100)
        {
            MyFont = CreateFont(500, i, 0, FW_NORMAL, FALSE, FALSE, FALSE,
                ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
                DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
                L"Times New Roman");
            OldFont = (HFONT)SelectObject(hdc, MyFont);
            TextOut(hdc, 0450, str, wcslen(str));
            SelectObject(hdc, OldFont);
            DeleteObject(MyFont);
        }
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
cs

 

CreateFont의 세번째 인수에0~900까지 100단위로 즉, 10deg 단위로 증가시키며 문자열을 출력한다.

 

 

 

 

'Windows > 윈도우즈 API' 카테고리의 다른 글

7-1. 컨트롤 - 버튼  (0) 2021.12.26
7. 컨트롤  (0) 2021.12.25
6. 그래픽 - 비트맵  (0) 2021.05.05
6. 그래픽 - 그리기 모드  (0) 2021.05.05
6. 그래픽 - DC의 정보 수정  (0) 2021.05.04
Comments