흑백 메모리 비트맵과 BitBlt
보통 윈도우에서 그리기를 할 때 메모리 DC(CompatibleDC)와 메모리 Bitmap(CompatibleBitmap)를 사용하여 BitBlt 함수로 드로잉 작업을 한다.
여기서는 BitBlt 함수 개념 정리 내용을 바탕으로 흑백 메모리 비트맵과 BitBlt 함수에 대해서 알아본다.
위의 내용에서 눈여겨 봐 둘 점은 BitBlt 함수는
- 흑백 비트맵을 칼라 비트맵으로 변환할 때, white bit(1)을 배경색으로 변환하고 black bit(0)을 전경색으로 변환한다. 이 때는 대상 DC의 전경색과 배경색이 사용된다.
라는 점이다.
메모리 비트맵을 생성하여 CPaintDC에 출력
- // WTL OnPaint 코드
CPaintDC dc( m_hWnd ) ; - CRect rect ;
dc.GetClipBox( rect ) ;
CDC dcMem ;
dcMem.CreateCompatibleDC( dc ) ;
CBitmap bitmapMem ;
bitmapMem.CreateCompatibleBitmap( dcMem, 100, 100 ) ; // 100x100의 흑색으로 칠해진 흑백 비트맵 생성
dcMem.SelectBitmap( bitmapMem ) ;
dc.BitBlt( 0, 0, rect.Width(), rect.Height(), dcMem, 0, 0, SRCCOPY ) ;
[메모리 비트맵] [출력]
-
전경색인 흑색으로 채워진 비트맵이 생성된다.
-
흑백 비트맵(dcMem)을 칼라 비트맵(dc)으로 변환하나(흑백 비트맵의 흰색->칼라 비트맵의 배경색, 흑백 비트맵의 검정색->칼라 비트맵의 전경색) CPaintDC도 기본 배경색이 흰색이고 전경색이 흑색이다.
-
비트맵 바깥쪽의 흰색 바탕은 윈도우에서 배경색으로 칠해주는 색이다. WM_ERASEBKGND 에서 아무것도 해 주지 않으면 컨토롤의 기본 배경색인 회색 계통의 색이 나타난다.
[참고]
- atlcrack.h를 사용한 OnPaint 함수는 인자로 CDCHandle이 넘어오는데 이 DC는 아무값도 가지고 있지 않다(NULL). 그래서 사용할 수 없다.
- WTL 7.5(? 8.0)에서 부터 사용할 수 있는 CMemoryDC는 생성자에서 인자로 넘겨받는 CPaintDC를 가지고 CreateCompatibleBitmap의 인자로 넘겨주므로 흑백이 아닌 screen과 같은 칼라 포맷을 가진 비트맵이 생성된다.
메모리 비트맵에 글자 찍기
- // WTL OnPaint 코드
CPaintDC dc( m_hWnd ) ;
CRect rect ;
dc.GetClipBox( rect ) ;
CDC dcMem ;
dcMem.CreateCompatibleDC( dc ) ;
CBitmap bitmapMem ;
bitmapMem.CreateCompatibleBitmap( dcMem, 100, 100 ) ; // 100x100의 흑색으로 칠해진 흑백 비트맵 생성
dcMem.SelectBitmap( bitmapMem ) ;
dcMem.TextOut( 0, 0, TEXT("MY TEST") ) ;
dc.BitBlt( 0, 0, rect.Width(), rect.Height(), dcMem, 0, 0, SRCCOPY ) ;
[메모리 비트맵] [출력]
-
메모리 비트맵 생성시 초기에 무조건 전경색인 검정색으로 채워진 비트맵이 생성되고 메모리 DC에 적용한 전경색인 배경색은 그 다음의 그리기 연산을 할 때 적용된다.
-
글자의 배경이 기본 배경색인 흰색, 글자색이 기본 전경색인 흑색으로 출력된다.
CPaintDC의 배경색을 Green으로 변경
- // WTL OnPaint 코드
CPaintDC dc( m_hWnd ) ;
dc.SetBkColor( RGB(0, 255, 0) ) ;
CRect rect ;
dc.GetClipBox( rect ) ;
CDC dcMem ;
dcMem.CreateCompatibleDC( dc ) ;
CBitmap bitmapMem ;
bitmapMem.CreateCompatibleBitmap( dcMem, 100, 100 ) ; // 100x100의 흑색으로 칠해진 흑백 비트맵 생성
dcMem.SelectBitmap( bitmapMem ) ;
dcMem.TextOut( 0, 0, TEXT("MY TEST") ) ;
dc.BitBlt( 0, 0, rect.Width(), rect.Height(), dcMem, 0, 0, SRCCOPY ) ;
[메모리 비트맵] [출력]
-
TextOut 출력시 배경색인 흰색이 CPaintDC의 배경색인 초록색으로 출력된다.
-
TextOut 출력시 전경색인 검정색은 CPaintDC의 전경색인 검정색으로 출력된다.
CPaintDC의 전경색을 Red로 변경
- // WTL OnPaint 코드
CPaintDC dc( m_hWnd ) ;
dc.SetTextColor( RGB(255, 0, 0) ) ;
CRect rect ;
dc.GetClipBox( rect ) ;
CDC dcMem ;
dcMem.CreateCompatibleDC( dc ) ;
CBitmap bitmapMem ;
bitmapMem.CreateCompatibleBitmap( dcMem, 100, 100 ) ; // 100x100의 흑색으로 칠해진 흑백 비트맵 생성
dcMem.SelectBitmap( bitmapMem ) ;
dcMem.TextOut( 0, 0, TEXT("MY TEST") ) ;
dc.BitBlt( 0, 0, rect.Width(), rect.Height(), dcMem, 0, 0, SRCCOPY ) ;
[메모리 비트맵] [출력]
-
TextOut 출력시 전경색인 검정색이 CPaintDC의 전경색인 빨강색으로 출력된다.
-
TextOut 출력시 배경색인 흰색은 CPaintDC의 배경색인 흰색으로 출력된다.
CPaintDC의 배경색을 Green으로, 전경색을 Red로 변경
- // WTL OnPaint 코드
CPaintDC dc( m_hWnd ) ;
dc.SetBkColor( RGB(0, 255, 0) ) ;
dc.SetTextColor( RGB(255, 0, 0) ) ;
CRect rect ;
dc.GetClipBox( rect ) ;
CDC dcMem ;
dcMem.CreateCompatibleDC( dc ) ;
CBitmap bitmapMem ;
bitmapMem.CreateCompatibleBitmap( dcMem, 100, 100 ) ; // 100x100의 흑색으로 칠해진 흑백 비트맵 생성
dcMem.SelectBitmap( bitmapMem ) ;
dcMem.TextOut( 0, 0, TEXT("MY TEST") ) ;
dc.BitBlt( 0, 0, rect.Width(), rect.Height(), dcMem, 0, 0, SRCCOPY ) ;
[메모리 비트맵] [출력]
-
TextOut 출력시 배경색인 흰색은 CPaintDC의 배경색인 초록색으로 출력된다.
-
TextOut 출력시 전경색인 검정색은 CPaintDC의 전경색인 빨강색으로 출력된다.
CPaintDC의 배경색은 Green으로, 전경색을 Red로, 메모리 DC의 배경색을 Black으로, 전경색을 White로 반전
- 원래 메모리 DC의 배경색이 White이고 전경색이 Black이다
- CPaintDC dc( m_hWnd ) ;
dc.SetBkColor( RGB(0, 255, 0) ) ;
dc.SetTextColor( RGB(255, 0, 0) ) ;
CRect rect ;
dc.GetClipBox( rect ) ;
CDC dcMem ;
dcMem.CreateCompatibleDC( dc ) ;
dcMem.SetBkColor( RGB( 0, 0, 0 ) ) ;
dcMem.SetTextColor( RGB( 255, 255, 255 ) ) ;
CBitmap bitmapMem ;
bitmapMem.CreateCompatibleBitmap( dcMem, 100, 100 ) ; // 100x100의 흑색으로 칠해진 흑백 비트맵 생성
dcMem.SelectBitmap( bitmapMem ) ;
dcMem.TextOut( 0, 0, TEXT("MY TEST") ) ;
dc.BitBlt( 0, 0, rect.Width(), rect.Height(), dcMem, 0, 0, SRCCOPY ) ;
[메모리 비트맵] [출력]
-
메모리 비트맵 생성시 초기에 무조건 전경색인 검정색으로 채워진 비트맵이 생성되고 메모리 DC에 적용한 전경색인 배경색은 그 다음의 그리기 연산을 할 때 적용된다.
-
그러므로 전체가 검정색인 비트맵에서 글자를 찍을 때 배경색을 변경된 배경색인 검정색으로 글자색을 변경된 전경색인 흰색으로 찍는다.
-
이 결과 메모리 비트맵에서 검정색 부분은 대상 DC의 전경색인 빨강색으로, 흰색 부분은 대상 DC의 배경색인 초록색으로 출력된다.
CPaintDC의 배경색은 Green, 전경색 Red, 메모리 DC의 전경색과 배경색을 같게
- 메모리 DC의 전경색, 배경색을 모두 White로
- dcMem.SetBkColor( RGB( 255, 255, 255 ) ) ;
- dcMem.SetTextColor( RGB( 255, 255, 255 ) ) ;
[메모리 비트맵] [출력]
- 메모리 DC의 전경색, 배경색을 모두 Black로
- dcMem.SetBkColor( RGB( 0, 0, 0 ) ) ;
- dcMem.SetTextColor( RGB( 0, 0, 0 ) ) ;
[메모리 비트맵] [출력]
메모리 DC의 전경색과 배경색을 흰색과 검정색 이외의 색으로, CPaintDC의 배경색은 Green, 전경색은 Red
여기서 메모리 DC의 전경색 및 배경색을 희색과 검정색 이외의 색으로 지정해 준다면 어떻게 될까?
- 메모리 DC의 배경색을 RGB(255, 255, 0)으로 지정
- // WTL OnPaint 코드
CPaintDC dc( m_hWnd ) ;
COLORREF crBackground = RGB( 0, 255, 0 ) ;
COLORREF crForeground = RGB( 255, 0, 0 ) ;
dc.SetBkColor( crBackground ) ;
dc.SetTextColor( crForeground ) ;
CRect rect ;
dc.GetClipBox( rect ) ;
CDC dcMem ;
dcMem.CreateCompatibleDC( dc ) ;
dcMem.SetBkColor( RGB( 255, 255, 0 ) ) ;
CBitmap bitmapMem ;
bitmapMem.CreateCompatibleBitmap( dcMem, 100, 100 ) ; // 100x100의 흑색으로 칠해진 흑백 비트맵 생성
dcMem.SelectBitmap( bitmapMem ) ;
dcMem.TextOut( 0, 0, TEXT("MY TEST") ) ;
dc.BitBlt( 0, 0, rect.Width(), rect.Height(), dcMem, 0, 0, SRCCOPY ) ;
[메모리 비트맵] [출력]
-
결과는 배경을 흰색으로 지정했을 때와 같다
-
즉 RGB(255, 255, 0)은 흰색으로 계산된다.
- 메모리 DC의 배경색을 RGB(128, 127, 127)로 지정
- // WTL OnPaint 코드
CPaintDC dc( m_hWnd ) ;
COLORREF crBackground = RGB( 0, 255, 0 ) ;
COLORREF crForeground = RGB( 255, 0, 0 ) ;
dc.SetBkColor( crBackground ) ;
dc.SetTextColor( crForeground ) ;
CRect rect ;
dc.GetClipBox( rect ) ;
CDC dcMem ;
dcMem.CreateCompatibleDC( dc ) ;
dcMem.SetBkColor( RGB( 128, 127, 127 ) ) ;
CBitmap bitmapMem ;
bitmapMem.CreateCompatibleBitmap( dcMem, 100, 100 ) ; // 100x100의 흑색으로 칠해진 흑백 비트맵 생성
dcMem.SelectBitmap( bitmapMem ) ;
dcMem.TextOut( 0, 0, TEXT("MY TEST") ) ;
dc.BitBlt( 0, 0, rect.Width(), rect.Height(), dcMem, 0, 0, SRCCOPY ) ;
[메모리 비트맵] [출력]
-
결과는 배경을 검정색으로 지정했을 때와 같다
-
즉 RGB(128, 127, 127)은 검정색으로 계산된다
결과를 보면 알겠지만 흰색과 검정색 이외의 색도 결과적으로 흰색과 검정색으로 변환된다.
이는 현재 메모리 DC는 흑백 비트맵을 장착하고 있다. 그 말은 흰색과 검정색만 표현할 수 있다는 말이다.
그렇다면 흰색과 검정색으로 변환되는 기준은 무엇일까?
SetBkColor에 들어 갈 수 있는 값은 RGB(0, 0, 0)에서 RGB(255, 255, 255)까지의 값이다. 이 사이의 값들 중에서 RGB(0, 0, 0)에 가까운 값은 RGB(0, 0, 0)인 검정색으로 변환되고 RGB(255, 255, 255)에 가까운 값은 RGB(255, 255, 255)인 흰색으로 변환된다.
기준은 RGB 매크로의 인자인 r, g, b 의 최고값인 255, 255, 255를 합하여 검정색과 흰색 두 색으로만 나뉘어지므로 2를 나눈 값이다.
그런데 소수점은 RGB의 값으로 사용할 수 없으므로 r, g, b의 값을 합한 값이 382 이하이면 검정색을 나타내고 383 이상이면 흰색을 나타낸다.
첫 번째 예는 255 + 255 + 0 = 510 이므로 흰색을 나타내고 두 번째 예는 128 + 127 + 127 = 382 이므로 검정색을 나타낸다.
그럼 RGB(129, 127, 127)의 경우는 어떨까? 이 값은 합이 383이므로 흰색을 나타낼 것이다.
- 메모리 DC의 배경색을 RGB(129, 127, 127)로 지정
- // WTL OnPaint 코드
CPaintDC dc( m_hWnd ) ;
COLORREF crBackground = RGB( 0, 255, 0 ) ;
COLORREF crForeground = RGB( 255, 0, 0 ) ;
dc.SetBkColor( crBackground ) ;
dc.SetTextColor( crForeground ) ;
CRect rect ;
dc.GetClipBox( rect ) ;
CDC dcMem ;
dcMem.CreateCompatibleDC( dc ) ;
dcMem.SetBkColor( RGB( 129, 127, 127 ) ) ;
CBitmap bitmapMem ;
bitmapMem.CreateCompatibleBitmap( dcMem, 100, 100 ) ; // 100x100의 흑색으로 칠해진 흑백 비트맵 생성
dcMem.SelectBitmap( bitmapMem ) ;
dcMem.TextOut( 0, 0, TEXT("MY TEST") ) ;
dc.BitBlt( 0, 0, rect.Width(), rect.Height(), dcMem, 0, 0, SRCCOPY ) ;
[메모리 비트맵] [출력]
-
결과는 예상대로 메모리 비트맵의 배경이 흰색으로 나왔다
-
RGB(255, 128, 0)으로 해도 메모리 비트맵의 배경이 흰색이 된다.
-
RGB(254, 128, 0)으로 했을 경우에는 메모리 비트맵의 배경이 검정색이 된다.
결론은 지금껏 보아 왔듯이 다음과 같다.
- 메모리 DC를 인자로 CreateCompatibleBitmap 함수를 호출하면 검정색으로 채워진 흑백 비트맵이 생성된다.
- 흑백 비트맵은 당연히 검정색과 흰색만 나타낼 수 있다.
- BitBlt 함수 사용시 dwRop인자의 영향을 받겠지만 메모리 비트맵의 흰색은 대상 DC의 배경색으로, 검정색으로 대상 DC의 전경색으로 나타난다.
칼라 메모리 비트맵을 흑백 메모리 비트맵으로 Bit-Blit할 때의 칼라 변환은 칼라 메모리 비트맵과 BitBlt를 참조해라.
Tags
History
Last edited on 08/18/2008 10:49 by 개발자를 꿈꾼다
Comments (0)