일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- two pointer
- MYSQL
- union find
- String
- DP
- Trie
- 다익스트라
- SQL
- 스토어드 프로시저
- Dijkstra
- 이진탐색
- Brute Force
- Two Points
- Stored Procedure
- Hash
- 그래프
- binary search
- Today
- Total
codingfarm
6. 그래픽 - 비트맵 본문
1. 비트맵 출력
비트맵
- 컴퓨터 분야에서 디지털 이미지를 저장하는 데 쓰이는 이미지 파일 포맷 또는 메모리 저장 방식의 한 형태
- 화면 상의 각 점들을 직교좌표계를 사용하여 화소 단위로 나타냄
- 가로 곱하기 세로 만큼의 픽셀 정보를 다 저장해야 하기 때문에 벡터 방식의 이미지나 텍스트 자료에 비해 상대적으로 용량이 크고 처리 속도가 느림
- GDI 오브젝트로 취급됨
- 파일저장형식 : JPEG, GIF, PNG
winapi는 gdi+를 추가하지 않으면 PNG를 출력할 수 없다.
윈도우에 비트맵 출력하기
비트맵을 선택하고 가져오기를 눌러, PC에 저장된 파일 중 리소스로 쓸 BMP 파일을 가져온다.
우리는 아래의 파일을 쓸것이다.
추가된 리소스의 ID를 확인한 후 아래 코드를 작성한다.
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
|
#include <windows.h>
#include "resource.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("RopMode");
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, NULL, 0, 0)) {
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return Message.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) {
HDC hdc, MemDC;
PAINTSTRUCT ps;
HBITMAP MyBitmap, OldBitmap;
switch (iMessage) {
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
MemDC = CreateCompatibleDC(hdc);
MyBitmap = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP1));
OldBitmap = (HBITMAP)SelectObject(MemDC, MyBitmap);
BitBlt(hdc, 0, 0, 123, 160, MemDC, 0, 0, SRCCOPY);
SelectObject(MemDC, OldBitmap);
DeleteObject(MyBitmap);
DeleteDC(MemDC);
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
|
cs |
2. 메모리 DC
메모리 DC
docs.microsoft.com/ko-kr/windows/win32/gdi/memory-device-contexts
정의
- 응용 프로그램에서 출력을 실제 장치에 전송 하는 대신 메모리에 저장할 수 있도록 한다.
- 비트맵 이미지를 메모리에 저장 가능하게끔 메모리 일부를 가상 장치 취급 할 수 있는 장치
- 응용 프로그램은 CreateCompatibleDC 함수를 호출 하 여 메모리 DC를 만들 수 있습니다.
- Createbitmap, CreateBitmapIndirect또는 CreateCompatibleBitmap 함수를 사용하여 비트맵을 생성하거나 LoadBitmap 함수로 리소스로 등록된 비트맵을 가저온다. SelectObject 함수를 호출 하여 메모리 DC가 비트맵을 선택하게끔 한다.
특성
- 화면DC와 동일한 특성을 지님(색상수, 색상면이 같음)
- 화면DC에서 사용할 수 있는 모든 출력(선, 면, 원...)을 적용할 수 있음
- 화면 DC에서 불가능한 여러 기능도 작동 가능
- 비트맵도 일종의 GDI 오브젝트지만 화면 DC에는 선택할 수 없으며, 메모리 DC만이 비트맵을 선택할 수 있음
메모리 DC 생성
CreateCompatibleDC 함수로 생성
HDC CreateCompatibleDC( HDC hdc );
hdc : 화면 DC의 handle (주로 BeginPaint의 반환값을 사용)
화면 DC와 동일한 특성을 가지는 Dc를 메모리에 만들어 그 핸들을 리턴한다.
화면DC와 호환되기 위해선 동일한 특성을 지녀야 한다.
- 색상수, 색상면이 같다
- 화면이 흑백이면 메모리 DC도 흑백이어야 함
- 화면이 256색상이면 메모리 DC도 256색상 이어야 함
메모리 DC를 만든 후에는 LoadBitmap 함수로 비트맵을 읽어오고, SelectObject 함수를 사용하여 메모리 DC에 선택한다.
HBITMAP LoadBitmap( HINSTANCE hInstance, LPCSTR lpBitmapName );
비트맵 리소스를 가진 인스턴스의 핸들(hInstance)과 비트맵 리소스의 이름(lpBitmapName)을 전달하면, 지정된 비트맵의 핸들을 반환한다.
이때 lpBitmapName은 resource.h에 있는 비트맵 리소스의 ID 매크로 상수를 보낸다.
3.BitBlt
이제 BitBlt함수로 메모리 DC에 저장된 비트맵 이미지를 화면으로 고속 복사하면 된다.
이 함수는 DC간의 영역끼리 고속 복사를 수행한다.
BOOL BitBlt( HDC hdc, int x, int y, int cx, int cy, HDC hdcSrc, int x1, int y1, DWORD rop );
복사 대상이 되는 DC(hdc, 화면 DC; BeginPaint)와 복사될 DC(hdcSrc, 메모리 DC; CreateCompatibleDC)를 전달한다. 그리고 복사될 DC의 복사 시작 지점(x1, y1)와 복사 너비 및 높이(cx, cy) 그리고 창내에서 그림이 그려지기 시작할 좌표(x, y)를 래스터 연산 방법(rop)과 함께 전달하면 이 정보에 맞추어 고속 복사가 진행된다.
가령
BitBlt(hdc, 128, 128, 300, 300, MemDC, 100, 100, SRCCOPY);
|
cs |
위 정보를 바탕으로 화면을 그리면
마지막 매개변수 dwRop는 래스터 연산방법을 지정한다.
값 | 설명 |
BLACKNESS | 대상영역을 검정색으로 가득 채운다. |
DSTINVERT | 화면을 반전시킨다. |
MERGECOPY | 소스 비트맵과 대상 화면을 AND 연산한다. |
MERGEPAINT | 소스 비트맵과 대상 화면을 OR 연산한다. |
SRCCOPY | 소스 영역을 대상 영역에 복사한다 |
WHITENESS | 대상 영역을 흰색으로 채운다. |
4. StretchBlt
docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-stretchblt
DC간에 비트맵을 전송하는데 확대 및 축소가 가능케 한다
BOOL StretchBlt(
HDC hdcDest,
int xDest,
int yDest,
int wDest,
int hDest,
HDC hdcSrc,
int xSrc,
int ySrc,
int wSrc,
int hSrc,
DWORD rop
);
hdcSrc가 가리키는 메모리 DC에 있는 이미지의 좌표 (xSrc, ySrc)에서 wSrc, hSrc만큼의 영역을
hdcDest가 가리키는 화면 DC의 좌표 (xDest, yDest)에서 wDest, hDest의 영역에 비례시켜 복사한다.
StretchBlt(hdc, 0, 0, 1024, 1024, MemDC, 0, 0, 512, 512, SRCCOPY);
|
cs |
가령 위처럼 쓰면, 화면을 2배의 크기로 복사하여 출력하게 된다.
문제점
지금까지 Bitmap 예제는 비트맵을 출력하는 기본적인 방법과 절차에 대해서는 잘 설명하고 있지만, 몇가지 문제점이 있다.
1. WM_PAINT안에 모든 코드를 작성해 넣음
모든 파일은 읽기위해 "열기 $\rightarrow$ 읽기 $\rightarrow$" 의 과정을 고치며 이는 GDI 오브젝트도, 비트맵도 마찬가지다.
그렇기에 속도 효율을 최대로 내기 위해 파일을 열고 닫는 과정을 최소화 해야만 한다.
그런데 WM_PAINT안에 이 파일을 열고, 읽고, 닫는 모든 과정을 다 넣을 경우, 그리기를 할때마다 호출되는 WM_PAINT 메시지의 특성상 속도의 효율이 매우 떨어지는 셈이다.
원칙적으로 비트맵은 WM_CREATE에서 미리 읽어두고, WM_PAINT에서만 출력하고, WM_DESTROY에서 해제하는것이 최적일것이다.
2.비트맵의 출력이 매우 번거롭다
비트맵 하나를 출력하기 위해 메모리 D를 만들고 해제하는 과정을 일일이 거쳐야한다.그러므로 이를 최소화할 수 있는 래퍼 함수를 만들어 쓰는것이 보다 효율적이다.
#include <windows.h>
#include "resource.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("RopMode");
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, NULL, 0, 0)) {
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return Message.wParam;
}
void DrawBitmap(HDC hdc, int x, int y, HBITMAP hBit) {
HDC MemDC;
HBITMAP OldBitmap;
int bx, by;
BITMAP bit;
MemDC = CreateCompatibleDC(hdc);
OldBitmap = (HBITMAP)SelectObject(MemDC, hBit);
GetObject(hBit, sizeof(BITMAP), &bit);
bx = bit.bmWidth;
by = bit.bmHeight;
BitBlt(hdc, x, y, bx, by, MemDC, 0, 0, SRCCOPY);
SelectObject(MemDC, OldBitmap);
DeleteDC(MemDC);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) {
HDC hdc;
PAINTSTRUCT ps;
static HBITMAP MyBitmap;
switch(iMessage) {
case WM_CREATE:
MyBitmap = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP1));
return 0;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
DrawBitmap(hdc, 0, 0, MyBitmap);
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
DeleteObject(MyBitmap);
PostQuitMessage(0);
return 0;
}
return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}
|
cs |
요약
- 비트맵 : 이미지를 직교좌표계를 활용하여 저장하는 방식
- 메모리 DC : 시스템 메모리에 bitmap 데이터를 저장 가능하게끔 가상화 하는 DC
- 비트맵을 윈도우에 출력하는 과정
- CreateCompatibleDC : 메모리 DC 생성
- Createbitmap 혹은 LoadBitmap 함수로 비트맵 이미지를 생성 혹은 가져온다
- SelectObject 함수로 메모리 DC가 비트맵을 선택하게끔 한다
- BitBlt 함수로 이미지를 윈도우에 출력
'Windows > 윈도우즈 API' 카테고리의 다른 글
7. 컨트롤 (0) | 2021.12.25 |
---|---|
6. 그래픽 - 폰트 (0) | 2021.12.25 |
6. 그래픽 - 그리기 모드 (0) | 2021.05.05 |
6. 그래픽 - DC의 정보 수정 (0) | 2021.05.04 |
5. 리소스 - 문자열 테이블(string table) (0) | 2021.05.01 |