#include <windows.h>
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); HINSTANCE g_hInst;
LPCTSTR lpszClass = TEXT("BitMapOutput"); // 창 제목
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow) // WinMain , API Main 함수 { // nCmdShow 인자의 갯수가 온다 HWND hWnd; // Window Handler // LPSTR 는 char * 배열 C의 main 의 2번째 인자 MSG Message; WNDCLASS WndClass; /* 1. 윈도우 구조체 생성 ( Class ) */ g_hInst = hInstance;
/* 2.1 구조체에 값을 넣어 스타일을 변화시켜준다 */ 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; WndClass.lpszClassName = lpszClass; WndClass.lpszMenuName = NULL; WndClass.style = CS_HREDRAW|CS_VREDRAW; /* 2.2 앞에 모든 Class 값을 등록시켜주는 함수 */ RegisterClass(&WndClass);
/* 3. 창 만들기 */ hWnd=CreateWindow(lpszClass,lpszClass,WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT, NULL,(HMENU)NULL,hInstance,NULL); /* 4. 창을 화면에 출력 하는 함수 */ ShowWindow(hWnd,nCmdShow);
/* 5. 창에서 일어나는 메세지 처리 (클릭, 닫기 등등..) */ while(GetMessage(&Message,NULL,0,0)) { TranslateMessage(&Message); DispatchMessage(&Message); } return (int)Message.wParam; }
/* 마우스나 키보드를 움직이면 OS 에서 자동으로 호출 */ /* 메세지 처리는 여기서 처리된다 */ LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) { static BITMAPFILEHEADER *stpBitmap; static BITMAPINFOHEADER *stpBitInfoHd; HANDLE hFile; DWORD dwRead; static unsigned char ucBuff[sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)]; static unsigned char *ucBitmap; unsigned char *ucpData;
unsigned char Color; unsigned int uiX; unsigned int uiY; PAINTSTRUCT ps; HDC hdc; static unsigned int uiX_Size; static unsigned int uiY_Size; static unsigned int uiPad;
switch(iMessage) { case WM_CREATE: hFile = CreateFile(TEXT("12345.bmp"), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
ReadFile(hFile, ucBuff, sizeof(ucBuff) , &dwRead, NULL); stpBitmap = (BITMAPFILEHEADER *)ucBuff; stpBitInfoHd = (BITMAPINFOHEADER *)(ucBuff+sizeof(BITMAPFILEHEADER)); ucBitmap = (unsigned char *)malloc(stpBitInfoHd->biSizeImage); /* 가로 , 세로 사이즈 */ uiX_Size = stpBitInfoHd->biWidth; // 점 300개 * 3byte /* 패딩(padding)에 의한 용량변화를 그림에서 깨지지않게 보정하기위해서, 밑에 설명 보충 */ uiPad = uiX_Size%4; uiY_Size = stpBitInfoHd->biHeight;
/*파일에서 비트맵 데이터가 있는 위치만큼 포인터를 이동시킨다*/ SetFilePointer(hFile, stpBitmap->bfOffBits , NULL, FILE_BEGIN); ReadFile(hFile, ucBitmap , stpBitInfoHd->biSizeImage , &dwRead, NULL);
CloseHandle(hFile);
return 0; case WM_PAINT: hdc = BeginPaint(hWnd,&ps); /* 그림의 처음 주소 */ ucpData = ucBitmap; /* Bitmap 은 그림이 뒤집혀서 저장되어있으므로 Y 사이즈(아래쪽)에서 X 사이즈 한줄씩 그리는 형식으로 반복문을 돌린다 */ for(uiY=uiY_Size; uiY>0 ; uiY--) { for(uiX=0; uiX<uiX_Size ; uiX++) { //SetPixel(hdc,uiX,uiY,RGB(*(ucpData+2),*(ucpData+1),*ucpData));
Color = ((*(ucpData+2) + *(ucpData+1) + *ucpData )/ 3); /* RGB 값 각각을 더하여 평균을 내서 출력을 하면 회색화면이 뜸 2번 사진*/
SetPixel(hdc,uiX_Size+uiX,uiY,RGB(Color,Color,Color)); ucpData = ucpData+3; } ucpData = ucpData + uiPad; }
/* 그림의 위치와 방향을 바꿔서 */ ucpData = ucBitmap;
for(uiY=uiY_Size; uiY>0 ; --uiY) { for(uiX=uiX_Size; uiX>0 ; --uiX) { SetPixel(hdc,uiX_Size+uiX,uiY,RGB(*(ucpData+2),*(ucpData+1),*ucpData)); ucpData = ucpData+3; } ucpData = ucpData + uiPad; }
ucpData = ucBitmap;
for(uiY=0; uiY<uiY_Size ; ++uiY) { for(uiX=0; uiX<uiX_Size ; ++uiX) { //SetPixel(hdc,uiX,uiY_Size+uiY,RGB(*(ucpData+2),*(ucpData+1),*ucpData)); /* RGB 값을 바꾸면 색을 다양하게 출력가능 1번 사진*/
SetPixel(hdc,uiX,uiY_Size+uiY, RGB(~(*(ucpData+2)) , ~(*(ucpData+1)), ~(*ucpData))); /* 값을 바꾼 경우 3번 사진 */
ucpData = ucpData+3; /* 한 픽셀 당 3byte 를 가지므로 포인터를 3만큼 이동 */ } ucpData = ucpData + uiPad; } ucpData = ucBitmap;
for(uiY=0; uiY<uiY_Size ; ++uiY) { for(uiX=uiX_Size; uiX>0 ; --uiX) { SetPixel(hdc,uiX_Size+uiX,uiY_Size+uiY,RGB(*(ucpData+2),*(ucpData+1),*ucpData)); ucpData = ucpData+3; } ucpData = ucpData + uiPad; } EndPaint(hWnd,&ps); return 0; case WM_DESTROY: free(ucBitmap); PostQuitMessage(0); return 0; } return(DefWindowProc(hWnd,iMessage,wParam,lParam)); }
▷ 비트맵을 그릴때 WM_PAINT 에서 for 문을 돌려서 SetPixel() 을 이용해 그리는 것이 확인되는데,
▶ 밑의 비트맵 아날라이즈 소스를 포팅하여 반대로 WinAPI 로 그려보는 작업이다. 여기서 주의할 점은 한 픽셀의 크기는 3 Byte 이다. 그래서 용량이 3의 배수로 정확히 떨어지지 않으면 그림이 깨지거나, RGB 값이 이상하게 출력이되어서 색이 변하는 것을 목격(?) 할 수 있다. 이러한 이유는 성능상의 이유 때문인데,
32 비트 기계는 4 바이트로 정렬된 데이터를 좀 더 효율적으로 처리할 수 있기 때문에 추가되는 바이트를 더해서 처리를 한다.
죄송합니다. 고의가 아니에요 ;) ..
|