일반적으로 MFC에서 그림을 그릴 땐 dc, 즉 device context를 얻어온 후 MFC에서 제공하는 api를 사용한다. 이렇게 할 경우 원하는 모양을 비교적 자유롭게 그릴 수 있지만 CPU 오버헤드도 커지고, 그림을 쉽게 변경할 수 없다.
이럴때 사용하면 좋은 것이 BITMAP이다.
typedef struct tagBITMAPINFO { BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[1]; } BITMAPINFO, *PBITMAPINFO;
비트맵의 자세한 내용은 (http://minimonk.tistory.com/tag/BITMAPINFO)에서 확인할 수 있다.
이번 포스팅에선 이 비트맵을 실제로 사용하는 과정을 설명하겠다. 이 포스팅을 따라 하다보면 zoom과 focus이동이 가능한 비트맵을 사용할 수 있을 것이다.
0. 비트맵을 그릴 장소에 PictureControl을 그린다.
1. 비트맵을 사용하기 위한 변수를 선언하자.
BITMAPINFO inputBitmapInfo; //비트맵
unsigned char *inputRGBbuffer; //RGB 이미지 버퍼
int inputStageTop, inputStageBottom, inputStageRight, inputStageLeft;
int inputStageWidth, inputStageHeight;
int inputWidthPerRegion, inputHalfWidthPerRegion;
double inputStageXoffset, inputStageYoffset, inputStageZoom;
2. OnInitDialog()에서 선언한 변수를 초기화 한다.
inputWidthPerRegion = 그리고자 하는 비트맵의 폭과 너비
inputHalfWidthPerRegion = inputWidthPerRegion/2;
// 1. 비트맵 정보 초기화
inputBitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
inputBitmapInfo.bmiHeader.biWidth = inputWidthPerRegion;
inputBitmapInfo.bmiHeader.biHeight = inputWidthPerRegion;
inputBitmapInfo.bmiHeader.biPlanes = 1;
inputBitmapInfo.bmiHeader.biBitCount = 32;
inputBitmapInfo.bmiHeader.biCompression = BI_RGB;
inputBitmapInfo.bmiHeader.biSizeImage = (inputWidthPerRegion)*(inputWidthPerRegion)*4;
inputBitmapInfo.bmiHeader.biXPelsPerMeter = 0;
inputBitmapInfo.bmiHeader.biYPelsPerMeter = 0;
inputBitmapInfo.bmiHeader.biClrUsed = 0;
inputBitmapInfo.bmiHeader.biClrImportant = 0;
// 2. 이미지 버퍼에 메모리를 할당한다.
inputRGBbuffer = (unsigned char *)malloc(inputWidthPerRegion*inputWidthPerRegion*4);
memset(inputRGBbuffer, 255, inputWidthPerRegion*inputWidthPerRegion*4);
// 3. 그림을 그릴 영역의 크기를 받아온다. (IDC_STATIC_INPUT은 picture box이다.)
CStatic *inputPictureBox = (CStatic *)GetDlgItem(IDC_STATIC_INPUT);
RECT stage_input_rect;
inputPictureBox->GetClientRect(&stage_input_rect);
// 4. 마진을 추가한다.
int input_rect_margin = 10;
stage_input_rect.bottom += input_rect_margin;
stage_input_rect.right += input_rect_margin;
stage_input_rect.top += input_rect_margin;
stage_input_rect.left += input_rect_margin;
// 5. stage의 위치를 저장한다. 이 위치에 실제로 그린다.
inputStageTop = stage_input_rect.top;
inputStageBottom = stage_input_rect.bottom;
inputStageRight = stage_input_rect.right + 0;
inputStageLeft = stage_input_rect.left + 0;
inputStageWidth = inputStageRight - inputStageLeft;
inputStageHeight = inputStageBottom - inputStageTop;
inputStageXoffset = 0, inputStageYoffset = 0;
inputStageZoom = 1;
3. 그림을 그리기 위한 타이머를 선언하자.
타이머는class wizard로 선언한다.
void CHTMDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
DrawStuff();
CDialogEx::OnTimer(nIDEvent);
}
4. 타이머 안에서 그림을 그릴 함수를 정의하자.
void CHTMDlg::DrawStuff()
{
CClientDC dc(this); // device context for painting
for(int i=0;i<inputWidthPerRegion;i++)
{
for(int j=0;j<inputWidthPerRegion;j++)
{
for (int k = 0; k<4; k++)
{
inputRGBbuffer[ i*inputWidthPerRegion*4 + j*4 + k ] = (int)(rand()%255); // 랜덤한 색
}
}
}
::SetStretchBltMode(dc.m_hDC, COLORONCOLOR);
::StretchDIBits(dc.m_hDC
, inputStageLeft, inputStageTop, inputStageWidth, inputStageHeight
, (int)( inputHalfWidthPerRegion*(1-inputStageZoom) + inputStageXoffset + 0.5 )
, (int)( inputHalfWidthPerRegion*(1-inputStageZoom) + inputStageYoffset + 0.5 )
, (int)( (inputWidthPerRegion*inputStageZoom) + inputStageXoffset + 0.5)
, (int)( (inputWidthPerRegion*inputStageZoom) + inputStageYoffset + 0.5 )
, inputRGBbuffer, &inputBitmapInfo, DIB_RGB_COLORS, SRCCOPY);
}
5. 실행하면 다음과 같이 나온다.
'Enginius > C / C++' 카테고리의 다른 글
MFC에서 CString 사용하기. (0) | 2012.04.27 |
---|---|
[퍼옴] MFC에서 시리얼 통신 프로그램 작성하기. (2) | 2012.04.24 |
MFC에서 랜덤 숫자 사용하기. (0) | 2012.04.16 |
console로 print할 때 주의사항 (0) | 2012.03.26 |
linked list class (0) | 2012.03.23 |