|
보 고 일 자 |
2015.03.17(화) |
|
책임자 |
양 진 모 |
|
확 인 |
|
|
비 트 맵
<기술문서>
SunmoonBit 29기
양진모
목차
1) 비트맵 이란?
2) 메모리 DC
3) Bit Block Transfer
4) StretchBlt
5) 레스터 연산
6) 비트맵 출력하기
1. 비트맵 (Bitmap)
*픽셀(Pixel)은 Picture와 Element의 합성 조어로 이미지를 구성하는 최소 단위인 점을 뜻한다.
같은 면적 안에 픽셀이 많이 있을수록 그림이 더욱 선명하고 정교해지기도 하지만 많은 종류에 색상을 가지고 한 픽셀 마다 색상을 주면 우리는 더욱더 선명하고 정교한 그림을 볼 수 있다.
이 픽셀 하나하나에는 색상 정보를 넣는 공간을 비트라고 한다.
*비트(Bit)는 Binary digit의 약칭으로 2진수 숫자라는 뜻이며 1bit에는 2진수의 숫자인 0과 1이라는 두 값만 가질 수 있다.
즉, 색상 정보를 1bit에 넣는다면 색이 두 가지뿐이니 흑과 백 밖에 표현할 수 없는 것이어서 다양한 색상 정보를 가지고 그림을 표현하기 위해서는 픽셀 한 개당 4bit, 8bit, 16bit, 24bit 등을 필요한 만큼 할당해 준다. (4bit = 2^4 = 16, 8bit = 2^8 = 256, 16bit = 2^16 = 65,536)
*비트맵(Bitmap)은 이러한 비트(픽셀)들로 이루어진 2차원 배열이다. 작은 점들로써 그림을 이루는 이미지 파일 형식. GIF, JPEG, PNG, TIFF, BMP, PCT, PCX등 확장자로 저장되며, 보통 폰트나 이미지에서 사용된다.
비트맵을 저장하는 디스크 파일은 보통 픽셀에 해당하는 비트들로 이루어진 블락(blocks)에 대한 정보들을 가지는데 픽셀 당 비트의 수, 각 행(row)의 픽셀 수, 배열의 행(row)의 수 등의 정보를 가진다. 또한, 컬러 테이블(color table) 을 가지는데, (컬러 테이블은 color palette 라고도 불린다.) 비트맵에 표현 되는 숫자와 실제 색깔과의 맵핑 관계를 나타낸다.
(링크 1: http://msdn.microsoft.com/en-us/library/at62haz6.aspx)
(링크 2: http://msdn.microsoft.com/en-us/library/dd162461(v=VS.85).aspx)
2. 메모리 DC (Memory Device Context)
요약: 그림의 Draw 속도를 빠르게 하기 위해 사용.
본문: 특정 영역에 여러 번 많은 과정을 거쳐서 그림을 그려주게 된다면, 한번에 하나씩 화면에 그리는 것보다는, 화면과 같은 모습을 하고 있는 화면에 그림을 그린 후, 최종적으로 완성된 것을 화면에 그리는 것이 훨씬 빠를 것입니다. 즉, 메모리를 사용하면 훨씬 빠르다는 것이죠. 이렇게 메모리상에 존재하는 DC를 이용하여 화면을 그려주는 것을 메모리DC라고 합니다.
(링크: http://msdn.microsoft.com/en-us/library/dd145049(v=VS.85).aspx)
방법: 현재 화면의 DC와 같은 DC를 만들어서 그 DC에 특정 bitmap을 셋팅해준 다음 그 bitmap에 그림을 그려주고 다시 그 그림을 원래의 화면 DC에 한번에 그려주는 원리입니다.
|
// 화면과 관련된 DC 를 얻습니다. CClientDC dc(this); // Client 영역의 크기를 구합니다. CRect rcClient; GetClientRect(&rcClient); // 메모리 DC 에 사용될 Bitmap CBitmap Bitmap; CBitmap* pbmOld = NULL; // 메모리 DC 변수 선언 CDC dcMem; // 현재 화면과 닮은꼴인 메모리 DC 생성 dcMem.CreateCompatibleDC(&dc); // 메모리 DC 의 전체 화면을 담을 수 있는 크기의 bitmap 생성 Bitmap.CreateCompatibleBitmap(&dc,rcClient.right,rcClient.bottom); // 메모리 DC 의 bitmap 을 새로운 bitmap 을 생성합니다. pbmOld = dcMem.SelectObject(&Bitmap); // 그림을 하얗게 칠하기 dcMem.PatBlt(0, 0,rcClient.right, rcClient.bottom, WHITENESS); // 이제 메모리 DC 에 그림을 그립니다. // 원래 있는 화면 dc 에 메모리 dc를 사용하여 그림을 그립니다. dc.BitBlt(0,0,rcClient.right,rcClient.bottom, &dcMem, 0, 0, SRCCOPY); // 마무리 작업 // 객체 delete dcMem.SelectObject(pbmOld); dcMem.DeleteDC(); |
3. Bit Block Transfer
메모리DC에 그린(저장한) 것을 장치에 뿌려주는 함수.
하나의 DC에 있는 비트맵을 다른 DC로 복사하는 비트맵 전송함수.
(링크: http://msdn.microsoft.com/en-us/library/dd183370(v=VS.85).aspx)
BOOL BitBlt(
HDC hDC, //비트맵이 복사될 핸들 DC
int XDest, int YDest, //출력할 좌표 값
int nWidth, int nHeignt, //출력할 비트맵 가로 세로 값
HDC hSrcDC, //소스 비트맵의 핸들 DC
int XSrc, int ySrc, //비트맵을 잘라내기 시작할 비트맵 내부의 좌표
DWORD dwROP); //소스영역을 대상영역에 복사한다.
<보충 설명>
XSrc, YSrc : 복사될 비트맵의 좌측 상단 좌표이며 복사처와 마찬가지로 논리적 좌표값. 이 값이 0일 경우 전체 비트맵을 복사. 복사원의 폭과 높이는 복사처의 nWidth, nHeight가 적용된다.
dwROP : ROP코드, 즉 브러쉬와 복사원, 복사처의 비트맵 색상이 논리 연산될 방법을 지정한다. 모두 256개의 가능한 값이 있지만 실제로 의미를 갖는 것은 다음 15개이며 매크로 상수가 정의되어 있다.
Bitblt함수에서 가장 중요한 것은 2개의 DC는 반드시 호환(Compatible, Plane(색상면), bpp(픽셀당 비트)가 동일)되어야 한다.
ESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT ps; HDC hdcDisplay, hdcClient; static int cxClient, cyClient; switch(msg) { case WM_MOVE: InvalidateRect(hWnd, 0, TRUE); return 0; case WM_SIZE: cxClient = LOWORD(lParam); cxClient = HIWORD(lParam); return 0; case WM_ERASEBKGND: return TRUE; case WM_PAINT: hdcDispaly = CreateDC(TEXT("DISPLAY"), 0, 0, 0); hdcClient = BeginPaint(hWnd, &ps); Bitblt(hdcClient, 0, 0, cxClient, cyClient, hdcDispaly, 0, 0, SRCCOPY); DeleteDC(hdcDisplay); EndPaint(hWnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hWnd, msg, wParam, lParam); } |
4. StretchBlt
복사하면서 이미지의 크기를 늘리거나 줄이려는 경우에 사용.
BOOL StretchBlt(
HDC hdcDest, //비트맵이 복사될 핸들 DC
int nXOriginDest, int nXOriginDest, //출력할 비트맵의 좌표 값
int nWidthDest, int nHeightDest, //출력할 비트맵의 가로 세로 값
HDC hdcSrc, //소스 비트맵의 핸들 DC
int nXOriginSrc, int nXOriginSrc, //소스 비트맵의 좌표 값
int nWidthSrc, int nHeightSrc, //소스 비트맵의 가로 세로 값
DWORD dwROP); //소스영역을 대상영역에 복사한다.
|
HDC hdcDisplay, hdcClient; static int cxClient, cyClient; switch(msg) { case WM_SIZE: cxClient = LOWORD(lParam); cxClient = HIWORD(lParam); return 0; case WM_LBUTTONDOWN: SetCapture(hWnd); return 0; case WM_LBUTTONUP: if(GetCapture() == hWnd) ReleaseCapture(); return 0; case WM_MOUSEMOVE: if(GetCapture() == hWnd) { POINT pt; GetCursorPos(&ps); hdcDispaly = CreateDC(TEXT("DISPLAY"), 0, 0, 0); hdcClient - GetDC(hWnd); StretchBlt(hdcClient, 0, 0, cxClient, cyClient, hdcDispaly, pt.x, pt.y, 100, 100, SRCCOPY); DeleteDC(hdcDisplay); ReleaseDC(hWnd, hdcClient); } return 0; |
5. 레스터 연산
레스터 연산은 새로 그려져야 할 그림에 이미 그려져 있는 그림과 합성되어 그려질 것인가 하는 것. 256개의 레스터 연산이 제공되며, 아래 표에서 S는 복사원(Source), D는 복사처(Destination), P는 패턴(Pattern)를 의미한다. 이 외의 ROP코드가 필요할 경우에는 상수를 직접 사용해야 한다.
매크로 상수 |
상수 |
연산식 |
|
BLACKNESS |
0x00000042 |
0 |
|
DSTINVERT |
0x00550009 |
~D |
|
MERGECOPY |
0x00C000CA |
D&S |
|
MERGEPAINT |
0x00BB0226 |
~S|D |
|
NOTSRCCOPY |
0x00330008 |
~S |
|
NOTSRCERASE |
0x001100A6 |
~(S|D) |
|
PATCOPY |
0x00F00021 |
P |
|
PATINVERT |
0x005A0049 |
P^D |
|
PATPAINT |
0x00FB0A09 |
P|~(S|D) |
|
SRCAND |
0x008800C6 |
S&D |
|
SRCCOPY |
0x00CC0020 |
S |
|
SRCERASE |
0x00440328 |
S&~D |
|
SRCINVERT |
0x00660046 |
S^D |
|
SRCPAINT |
0x00EE0086 |
S|D |
|
WHITENESS |
0x00FF0062 |
1 |
6. 비트맵 출력하기
HDC CreateCompatibleDC(HDC hdc); //메모리DC를 만들 때 사용.
인수로 화면 DC를 주면 이 화면DC와 동일한 특성을 가지는 DC를 메모리에 만들어 그 핸들 값을 리턴.
HBITMAP LoadBitmap(
HINSTANCE hInstance, //비트맵 리스소를 가진 핸들 인스턴스
LPCTSTR lpBitmapName); //비트맵 리소스의 이름
읽어온 비트맵을 SelectObject함수로 메모리DC에 선택하면 메모리DC의 표면에는 리소스에서 읽어온 비트맵이 그려진다. 마지막으로 고속 복사 함수를 사용하면 화면에 출력 된다.
|
case WM_LBUTTONDOWN: { HDC hdc = GetDC(hWnd); //화면 DC와 호환(동일색상)되는 메모리DC를 얻음. HDC memDC = CreateCompatibleDC(hdc); HBITMAP hBitmap = LoadBitmap(GetModuleHandle(0), MAKEINTSOURCE(IDB_BITMAP1)); BITMAP bm; GetObject(memDC, hBitmap); TextOut(memDC, 5, 5, TEXT("LoadBitmap으로 출력"), 15); //비트맵으로 출력 //메모리DC -> 화면DC POINTS pt = MAKEPOINTS(lParam); Bitblt(hdc, pt.x, pt.y, bm.bmWidth, bm.bmHeight, memDC, 0, 0, SRCCOPY); DeleteDC(memDC); //메모리 제거 ReleaseDC(hWnd, hdc); DeleteObject(hBitmap); } return 0; case WM_RBUTTONDOWN: { HDC hdc = GetDC(hWnd); //화면 DC와 호환(동일색상)되는 메모리DC를 얻음. HDC memDC = CreateCompatibleDC(hdc); HBITMAP hBitmap = (BITMAP)LoadImage(0, //리소스에서 로드할때만 사용 TEXT("3.bmp"), IMAGE_BITMAP, 0, 0, //커서, Icxxxxxxxxxxxxxxonload시만 사용 LR_LOADFROMFILE); BITMAP bm; GetObject(hBitmap, sizeof(bm), &bm); SelectObject(memDC, hBitmap); //메모리DC에 비트맵 선택 TextOut(memDC, 5, 5, TEXT("LoadBitmap으로 출력"), 13); //비트맵으로 출력 //메모리DC -> 화면DC POINTS pt = MAKEPOINTS(lParam); Bitblt(hdc, pt.x, pt.y, bm.bmWidth, bm.bmHeight, memDC, 0, 0, SRCCOPY); DeleteDC(memDC); //메모리 제거 ReleaseDC(hWnd, hdc); DeleteObject(hBitmap); } return 0; |
7. 실행화면