본문 바로가기
Education/Bit 18th

[최종프로젝트] 비트맵 관련 구조체들

by ★용호★ 2010. 1. 31.

2010년 1월 31일 일요일

비트맵은, 파일로 저장되어 있을 때는 DIB(Device Independent Bitmap)형태이지만

일반적인 방법으로 메모리에 로드하면 DDB(Device Dependent Bitmap)으로 변합니다.

DDB는 GetPixel(), PutPixel() 등의 함수를 이용해 픽셀 데이터를 취급할 수 있지만,

처리속도도 낮고, 배열 처럼 취급하기가 어려워 코딩 자체도 그리 명쾌하지가 않습니다.

 

질문과 같은 목적으로 사용하시려면 파일과 유사한 DIB 형태로 로드하시는 게 좋은데,

이렇게 하면 처리속도도 높고 배열 처럼 취급할 수가 있어 코드가 명쾌하게 됩니다.

비트맵 파일을 DIB로 로드할 때는, 시스템 내부적으로 사용하는 DIBSECTION 구조체를

활용하며, DIB, DDB에 공통으로 사용하는 BITMAP 구조체, 그리고 LoadImage(),

GetObject() 등의 함수를 이용합니다.

 

그 다음 픽셀 데이터를 비교한다든지 하는 일은, 비트맵 파일 구조의 이해가 필요한데

아시다시피 비트맵은 색상표현방법에 따라 여러가지 형태가 있을 수 있습니다.

이 부분에 대해서는, BITMAPFILEHEADER, BITMAPINFO, BITMAPINFOHEADER 및

RGBQUAD, RGBTRIPLE 등의 구조체에 대한 이해가 필요하므로 별도 참조 바라며,

여기서는 몇 가지 필요하다 싶은 것만 사용 예를 들어 보이도록 하겠습니다.

 

[이해가 필요한 구조체들]

typedef struct tagDIBSECTION {
    BITMAP              dsBm;
    BITMAPINFOHEADER    dsBmih;
    DWORD               dsBitfields[3];
    HANDLE              dshSection;
    DWORD               dsOffset;
} DIBSECTION;

 

typedef struct tagBITMAPINFOHEADER{ // bmih
    DWORD  biSize;
    LONG   biWidth;
    LONG   biHeight;
    WORD   biPlanes;
    WORD   biBitCount
    DWORD  biCompression;
    DWORD  biSizeImage;
    LONG   biXPelsPerMeter;
    LONG   biYPelsPerMeter;
    DWORD  biClrUsed;
    DWORD  biClrImportant;
} BITMAPINFOHEADER;

 

typedef struct tagBITMAP {  // bm
    LONG   bmType;
    LONG   bmWidth;
    LONG   bmHeight;
    LONG   bmWidthBytes;
    WORD   bmPlanes;
    WORD   bmBitsPixel;
    LPVOID bmBits;
} BITMAP;

 

typedef struct tagRGBQUAD { // rgbq
    BYTE    rgbBlue;
    BYTE    rgbGreen;
    BYTE    rgbRed;
    BYTE    rgbReserved;
} RGBQUAD;

 

typedef struct tagRGBTRIPLE { // rgbt
    BYTE rgbtBlue;
    BYTE rgbtGreen;
    BYTE rgbtRed;
} RGBTRIPLE;

 

[함수 사용 예]

HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, _T("파일명"), IMAGE_BITMAP, 0, 0,
                        LR_LOADFROMFILE | LR_CREATEDIBSECTION);

 

DIBSECTION dib;

GetObject(hBitmap, sizeof(DIBSECTION), &dib);

 

비트맵 가로 크기 : dib.dsBmih.biWidth 혹은 dib.dsBm.bmWidth

비트맵 세로 크기 : dib.dsBmih.biHeight 혹은 dib.dsBm.bmHeight

한 픽셀을 표현하는 데 필요한 비트 수 : dib.dsBmih.biBitCount 혹은 dib.dsBm.bmBitsPixel

실제 픽셀 데이터 가 있는 곳(포인터) : dib.dsBm.bmBits

 

[픽셀 데이터 취급 시 유의사항]

1. DIB 비트맵의 수직 좌표는 DDB와 반대로, 아래 부분이 0 이고 위로 올라올 수록 y좌표가 커지며

    메모리 상의 주소로 따진다면, 그림의 아랫 부분 데이터가 먼저 오게 됩니다.

 

2. DIB 비트맵에서 수평 한 라인의 데이터 구성할 때는, 수평 픽셀 수 또는 픽셀 데이터 크기와는

    상관 없이 무조건 32비트(4바이트) 단위로 맞춥니다. 그러므로 이미지의 수평 픽셀 수와 픽셀

    데이터의 크기 등으로써 수평 바이트 수를 계산해 두어야 합니다(수직 좌표 이동의 기본 단위가

    되므로...). 코딩할 때 다음과 같은 매크로를 정의해 두고 사용하시면 편리할 겁니다.

 

    #define HBYTES(w, b)  ((((w) * (b) + 31) & ~31) / 8)

    ☞ int nHBytes = HBYTES(dib.dsBmih.biWidth, dib.dsBmih.biBitCount);

 

   이리하여 비트맵 전체의 바이트 크기는 (nHBytes * dib.dsBmih.biHeight) 가 됩니다.

 

3. 픽셀데이터 크기가 바이트(8비트) 단위로 떨어지지 않으면(1bpp, 4bpp 등) 픽셀 하나의 데이터를

   얻어내기가 좀 까다로운데, 보통 비트 쉬프트 기법을 사용해서 처리합니다.

 

4. DIB는 팔레트를 사용하는 경우도 있습니다. 1bpp, 4bpp, 8bpp는 물론, 16bpp도 경우에 따라

   팔레트를 사용하는데, 이런 경우 픽셀데이터는 색상값이 아니라 팔레트(색상테이블)의 인덱스가

   됩니다. 그러므로 픽셀의 색상은 이 인덱스로 해서 색상테이블에서 가져와야 합니다.

   (※ 24bpp, 32bpp 등의 트루컬러 시스템에서는 팔레트가 없고 데이터 자체가 색상임)

댓글