Win32 API

2013.10.23_ API _ Bitmap 분석해보기

성엽이 2013. 10. 23. 09:27


 WinAPI ( Bitmap Analyze )

 #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 바이트로 정렬된 데이터를 좀 더 효율적으로 처리할 수 있기 때문에 추가되는 바이트를 더해서 처리를 한다.


      

죄송합니다. 고의가 아니에요 ;) ..


      

Bitmap Analyze Source

// Bitmap Analyze , Bitmap 구조 및 구조체 참조

#include <stdio.h>

#include <Windows.h>
void HexaView(unsigned char *ucP, unsigned int isize);

int main()
{
  BITMAPFILEHEADER  *stpBitmap;
  BITMAPINFOHEADER  *stpBitInfoHd;  
  RGBQUAD      *stpRGBQUAD;
  HANDLE  hFile;
  unsigned char ucBuff[256];
  DWORD  dwRead;  

  hFile = CreateFile("12345.bmp", GENERIC_READ, 0, NULL, OPEN_EXISTING, 
      FILE_ATTRIBUTE_NORMAL, NULL);
  
  ReadFile(hFile, ucBuff, 256 , &dwRead, NULL);  

  HexaView(ucBuff, 256);
  
  stpBitmap = (BITMAPFILEHEADER *)ucBuff;

  printf("------------BitMap Analyze------------\n");
  printf("▷ Bitmap Header ◁\n");

  printf("bfType    : [%c%c]\n", *ucBuff, *(ucBuff+1));
  printf("bfSize     : [%u] Bytes\n",stpBitmap->bfSize);
  printf("bfReserved1  : [%d]\n",stpBitmap->bfReserved1);
  printf("bfReserved2  : [%d]\n",stpBitmap->bfReserved2);
  printf("bfOffBits  : [%u] Bytes\n",stpBitmap->bfOffBits);

  printf("--------------------------------------\n");
  printf("▷ Bitmap Info Header ◁\n");  

  stpBitInfoHd = (BITMAPINFOHEADER *)(ucBuff+sizeof(BITMAPFILEHEADER));

  printf("biSize    : [%u] Bytes\n", stpBitInfoHd->biSize);
  printf("biWidth    : [%u] Bytes\n",stpBitInfoHd->biWidth);
  printf("biHeight  : [%u] Bytes\n",stpBitInfoHd->biHeight);
  printf("biPlanes  : [%d] 개\n",stpBitInfoHd->biPlanes);
  printf("biBitCount  : [%d] 개\n",stpBitInfoHd->biBitCount);
  printf("biCompression  : [%u] \n",stpBitInfoHd->biCompression);
  printf("biSizeImage    : [%u] Bytes\n",stpBitInfoHd->biSizeImage);
  printf("biXPelsPerMeter  : [%lu] meter\n",stpBitInfoHd->biXPelsPerMeter);
  printf("biYPelsPerMeter  : [%lu] meter\n",stpBitInfoHd->biYPelsPerMeter);
  printf("biClrUsed  : [%u] 개\n",stpBitInfoHd->biClrUsed);
  printf("biClrImportant  : [%u] 개\n",stpBitInfoHd->biClrImportant);

  printf("--------------------------------------\n");
  printf("▷ Bitmap RGBQUAD ◁\n");  

  stpRGBQUAD = (RGBQUAD *)(ucBuff + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
      + sizeof(BITMAPINFO));

  printf("rgbBlue    : [%d] \n",stpRGBQUAD->rgbBlue);
  printf("rgbGreen    : [%d] \n",stpRGBQUAD->rgbGreen);
  printf("rgbRed    : [%d] \n",stpRGBQUAD->rgbRed);
  printf("rgbReserved  : [%d] \n",stpRGBQUAD->rgbReserved);

  putchar('\n');
    
  printf("%02x %02x %02x \n", *(ucBuff + stpBitmap->bfOffBits), *((ucBuff+1)+ stpBitmap->bfOffBits),*((ucBuff+2) + stpBitmap->bfOffBits));

  CloseHandle(hFile);   

  return 0;
}

void HexaView(unsigned char *ucP, unsigned int isize)
{
  int iCnt;
  int iloop;
  
  printf("----------------------------------------"
     "----------------------------------\n");
  printf("Address  \t\t\tHexa\t\t\t      ASCII\n"); 
  printf("\t ");

  
  for(iCnt=0 ; iCnt <= 15 ; iCnt++)
  {
    printf("%02X ", iCnt);
  }

  putchar('\n');

  printf("----------------------------------------"
     "----------------------------------\n");
  
  if0 == isize%16 )
  {
    isize = isize / 16;  
  }
  else
  {
    isize = (isize/16) + 1;    
  }
  
  for(iloop=0; iloop < isize; iloop++)
  {
    printf("%08X ", ucP); 
  
    for( iCnt=0 ; iCnt <= 15 ; iCnt++)
    {
      printf("%02X ", *(ucP+iCnt));
    }

    for( iCnt=0 ; iCnt <= 15 ; iCnt++ )
    {
      if(0 == *(ucP+iCnt))
      {
        printf(".");
      }
      else if32 > *(ucP+iCnt))
      {
        printf(".");
      }
      else if127 < *(ucP+iCnt))
      {
        printf(".");      
      }
      else
      {
        printf("%c", *(ucP+iCnt)); 
      }
    }
    putchar('\n');
    ucP = ucP + 16;
  }
}




 

▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽

 

 File

 

bitmap_test.c


bitmap_test.exe


BitmapAnalize.c

손연재:)



비트맵임의로 정했음.


Bitmap_analize.zip


△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△

 

 

▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽▽

참고사이트 :

http://zzoyu.tistory.com/50

http://blog.naver.com/PostView.nhn?blogId=mystyle1057&logNo=110149823976

http://screwsliding.tistory.com/entry/Bitmap-%EC%9D%BC%EA%B5%AC%EC%A1%B0

http://minimonk.tistory.com/300

http://yagi815.tistory.com/242

△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△△