투명 비트맵 처리해주는 법
출처:
http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=51&MAEULNo=20&no=1062&ref=558작성자: 박일(will78@nownuri.net)
1. 개요
비트맵의 바탕을 투명처리 해 주는 기법에 대해 설명하겠습니다. 의외로 소스는
많은데 실제적으로 그 소스에 대한 설명이 잘 되어 있는 문서는 찾기 힘들더군요. 우선 우
리는 화면에 뿌려줄 Bitmap을 Resource 에 가지고 있고, 투명화 되기를 원하는 영역은 한
가지 특정한 색으로 칠해져 있다는 것을 가정합니다. 또한 대상은 실질적으로 Bitmap과 DC
를 이용해서 이미지가 어떻게 뿌려진다는 정도의 개념을 알고 있다고 생각하겠습니다.
2. 대략적인 개념 이해와 필요한 함수 설명
CDC::SetBkColor
CDC::BitBlt
비트맵을 투명화할 때 꼭 필요한 함수입니다. SetBkColor 함수는 대상 비트맵
의 배경색을 결정해주는 함수이고 BitBlt는 DC든 CBitmap 이든 서로간의 데이터를 복사해
줌으로서 출력해주는 함수입니다. (음... 글빨이 참 없죠? -.-a...) 즉, 우리가 CDC
memDC; 라고 선언한 후 memDC 에 그림을 저장하고 이것을 GetClientDC this(dc); 와 같
이 얻은 화면용 DC에 단순히 데이터를 뿌려주기만 하면 그림이 화면에 나타나는 것입니다.
개념적으로는 CDC는 메모리 포인터를 만드는데 그 중 GetClientDC this(dc); 이런 녀석
이나 OnPaint(pDC) 같은 녀석은 모니터에 보여지고 있는 데이터의 메모리 포인터라고 생각
합시다.
우리는 이미 출력하고자 하는 비트맵에서 투명화하고 싶은 비트맵의 색깔을 정했
습니다.(밑의 코드에는 빨간색(RGB(255,0,0)이 될 것입니다. ) 이것은 마치 영화의 특수효
과 중 블루 스크린을 이용해서 뒤에 다른 배경을 붙이는 것과 같습니다. 이제 투명화 하는
데 필요한 mask 비트맵을 만들어야 합니다. mask 비트맵은 투명으로 사라질 곳은 흰 색으
로 나오고 출력되어야 하는 비트맵은 검은 색으로 나오는 흑백 비트맵입니다. 그리고 우리
는 mask 비트맵과 미리 저장해 놓은 배경 비트맵, 실제 출력하기를 원하는 비트맵, 이 3
개의 비트맵을 AND, OR 연산을 통해서 투명비트맵을 만들 것입니다.
3. 코드 보기...
서론이 너무 길었네요.. -.-;; 밑에 소스와 나름대로 자세하게 적은 주석이 있습
니다. 코드의 진행을 한 번에 알 수 있게 하기 위해 최대한 모든 소스를 한 함수에 담았습
니다. 천천히 읽어보시고 모르겠다 싶은 부분은 지적해 주십시오.
BOOL CTransBitmap::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
#define WHITE RGB(255,255,255)
#define RED RGB(255,0,0)
#define BLACK RGB(0,0,0)
if(m_nFirst == TRUE)
{
//////////////////////////////////////////////////////////////
// 배경을 저장한다.
CRect rcClient;
GetClientRect(&rcClient);
m_dcBkg.CreateCompatibleDC(pDC);
m_bmpBkg.CreateCompatibleBitmap(pDC, rcClient.Width(),
rcClient.Height());
CBitmap *m_pbmpBkgOld = m_dcBkg.SelectObject(&m_bmpBkg);
m_dcBkg.BitBlt(0, 0, rcClient.Width(), rcClient.Height(),
pDC, 0, 0, SRCCOPY);
//////////////////////////////////////////////////////////////
// 출력하기를 원하는 비트맵 DC 생성
m_pBitmapDC = new CDC;
m_pBitmapDC->CreateCompatibleDC(pDC);
CBitmap *pOldSrcBitmap = m_pBitmapDC->SelectObject
(m_pBitmap1);
m_nFirst = FALSE;
}
//////////////////////////////////////////////////////////////
// 비트맵을 사용하기 위해 따로 다른 메모리에 복사한다.
CDC SrcDC;
CBitmap srcBmp;
SrcDC.CreateCompatibleDC(pDC);
srcBmp.CreateCompatibleBitmap(pDC, m_nWidth, m_nHeight);
SrcDC.SelectObject(&srcBmp);
SrcDC.BitBlt( 0, 0, m_nWidth, m_nHeight, m_pBitmapDC, 0, 0, SRCCOPY )
;
///////////////////////////////////////////////////////////////
// masking 을 하기 위한 DC 생성. mask 비트맵은 흑백을 사용한다.
CDC maskDC;
CBitmap maskBmp;
maskDC.CreateCompatibleDC(&SrcDC);
// 흑백 비트맵 생성...
maskBmp.CreateBitmap(m_nWidth, m_nHeight, 1, 1, NULL);
CBitmap *pOldMaskBmp = maskDC.SelectObject(&maskBmp);
// 원하는 색을 배경색으로 지정하고 BitBlt 하면
// 원본 데이타 중 지우고 싶은 곳은 흰색, 다른 곳은 검은 색으로 나타나는
// Mask 가 완성된다.
// 즉 SetBkColor은 칼라를 흑백으로 변환할때
// 배경(흰색)으로 처리되어야 하는 색을 정해주는 함수다.
// 배경을 제외한 다른 색은 모두 검은 색으로 표현된다.
SrcDC.SetBkColor( RED );
maskDC.BitBlt( 0, 0, m_nWidth, m_nHeight, &SrcDC, 0, 0, SRCCOPY);
// 원본 데이타와 mask 데이타를 겹쳐서 원하는 그림만 뽑아내
// SrcDC 에 저장한다.
// 투명처리 하고 싶은 영역은 검은 색으로 출력된다.
// 이것은 SetBkColor 함수를 통해서 가능한데 이번에는 위와는 다르게
// 흑백(maskDC) 에서 칼라(SrcDC) 로의 변환이다.
// 이때에는 흑백 비트맵의 흰색(1) 부분은
// 대상 칼라 비트맵의 배경색으로 바뀌고
// 검은색(0) 부분은 대상 칼라 비트맵의 Foreground color 로 바뀐다.
// BitBlt 는 이렇게 maskDC를 칼라 비트맵으로 변환시킨 후에
// SrcDC랑 AND 연산을 하게 된다.
// 결과적으로 maskDC에서 흰색이던 부분은 BitBlt 를 통해
// 검은 색으로 바뀌고,
// 검은 색은 0이므로 SrcDC와 AND 를 하면 SrcDC 도
// 같은 위치의 비트맵이 검은 색으로 바뀐다.
// 흰 색은 1이므로 AND 연산을 하면 그대로 SrcDC 의 원래 그림이 남는다.
// 이 세 줄의 코드가 끝나면
// SrcDC는 없앨려던 배경이 검은 색으로 칠해진 비트맵이 된다.
SrcDC.SetBkColor( BLACK );
SrcDC.SetTextColor( WHITE );
SrcDC.BitBlt( 0, 0, m_nWidth, m_nHeight, &maskDC, 0, 0, SRCAND);
/////////////////////////////////////////////////////////////////
// 최종 그림을 저장하기 위한 DC
CDC memDC;
CBitmap memBmp;
memDC.CreateCompatibleDC(pDC);
memBmp.CreateCompatibleBitmap(pDC, m_nWidth, m_nHeight);
CBitmap *pOldMemBmp = memDC.SelectObject(&memBmp);
// 최종 합치기
// 일단 배경을 복사한다.
memDC.BitBlt(0, 0, m_nWidth, m_nHeight, &m_dcBkg, 0, 0, SRCCOPY);
// masking 과 배경을 AND 연산해 투명처리된 그림이 찍힐 부분은
// 검은색으로 칠해진 배경을 출력해 준다.
// 이번에는 대상 비트맵의 배경색을 흰색으로 처리했으므로
// maskDC의 흰색은 흰색, 검은 색은 검은 색...
// 즉 마스크 DC는 변한 것이 없다.
// 그 후에 AND 연산을 하므로 배경 비트맵은 우리가 그 위에 출력하고자 하는
// 비트맵 부분만 검은 색으로 칠해진 비트맵이 된다.
memDC.SetBkColor( WHITE );
memDC.BitBlt(0, 0, m_nWidth, m_nHeight, &maskDC, 0, 0, SRCAND);
// 이제 원하는 이미지 빼고는 검은 색 처리된 비트맵을 OR 연산으로 붙여준다.
// OR 연산을 하면 검은 색은 0이므로 무시된다.
// 배경은 그림부분이 0(검은색)이고 그림은 배경부분이 0(검은색)이므로
// OR 연산 후에는 우리가 원하는 배경이 투명화 된 그림을 얻는다.
memDC.BitBlt(0, 0, m_nWidth, m_nHeight, &SrcDC, 0, 0, SRCPAINT);
// 최종적인 결과를 화면에 뿌려준다.
pDC->BitBlt( 0, 0, m_nWidth, m_nHeight, &memDC, 0, 0, SRCCOPY );
memDC.SelectObject(pOldMemBmp);
return CStatic::OnEraseBkgnd(pDC);
}
4. MSDN 의 중요한 부분
CDC::SetBkColor
virtual COLORREF SetBkColor( COLORREF crColor );
If destination, source, and pattern bitmaps do not have the same
color format, the BitBlt function converts the source and pattern bitmaps to
match the destination. The foreground and background colors of the destination
bitmap are used in the conversion.
When the BitBlt function converts a monochrome bitmap to color, it
sets white bits (1) to the background color and black bits (0) to the
foreground color. The foreground and background colors of the destination
device context are used. To convert color to monochrome, BitBlt sets pixels
that match the background color to white and sets all other pixels to black.
BitBlt uses the foreground and background colors of the color device context to
convert from color to monochrome.
SRCAND Combines pixels of the destination and source bitmaps using the
Boolean AND operator.
SRCCOPY Copies the source bitmap to the destination bitmap.
SRCPAINT Combines pixels of the destination and source bitmaps using the
Boolean OR operator.
끝....