본문 바로가기
Education/Bit 18th

[최종프로젝트] BITMAP 분석

by ★용호★ 2010. 2. 1.

Bitmap에 관하여

이번에는 BITMAP에 대해서 철저하게 까보자.
BITMAP은 Window에서 폭넓게 사용하는 이미지형식으로써 데이터한개단위당 픽셀한개로 이루어진 간단한(과연 간단할까?) 이미지형식이다.



DDB : Device Dependent Bitmap (장치 종속적인 비트맵)
DIB : Device Independent Bitmap (장치에 비종속적인 비트맵)
DDB는 윈도우 3.0이전버전부터 사용되온 비트맵의 방식인데 이미지의 크기, 색상에 대한 기본정보, 해당 이미지 데이터로 구성되어진다. 장치에 종속적이기 때문에 다른 장치에 가서 같은 색상의 색이 보여지리라고는 기대할수 없다. 이와는 반대로 DIB는 윈도우즈 3.0부터 지원하기 시작했으며, 색상테이블과 해상도 정보등 추가정보를 지니므로, 다른 장치에서도 같은 색상의 이미지를 출력해낼수 있게 되었다.

설명하기 좋게끔.. DDB에 대해서 구조체를 소개한다.

typedef struct tagBITMAP{ //bm
   LONG bmType;       // 비트맵의 타입 0으로 고정
   LONG bmWidth;       // 비트맵의 폭
   LONG bmHeight;     // 비트맵의 높이
   LONG bmWidthBytes; // 한줄에 해당하는 바이트의 수
   WORD bmPlanes;     // 색상면의 수
   WORD bmBitsPixel;   // 한 픽셀을 표시하기 위해 필요한 Byte수
   LPVOID bmBits;     // 비트맵의 실제 데이터
} BITMAP;

이 DDB 구조체는 Win32 프로그램에서 HBITMAP으로 지칭되는 Bitamp을 가리킨다. 항상 DDB형태여야지만, DC에 선택이 될수 있다. LoadBitmap()같은 함수를 이용하면 내부적으로 DDB형태로 자동 변환된다. 실제 이와 같은 내용을 보고싶으면, GetObject()함수를 이용하여 LoadBitmap()시에 딸려나온 핸들을 넘겨주어 선택하면 가져올수 있을듯.. (하지만, 내가 여기에 기록하고자 하는것은 DIB이므로 생략)


BITMAPFILEHEADER
비트맵 파일 자체정보
BITMAPINFOHEADER
크기,색상포맷에 관련한정보, 기타 장치 독립성에 대한 정보
RGBQUAD
Color Table에 관련한 정보
PIXEL DATA
실제 데이터내용


대충 BITMAP은 위와 같은 형식을 가지고 있다. 대강 설명하면 BITMAPFILEHEADER의 정보가 제일먼저 저장되고 바로다음에 BITMAPINFOHEADER의 정보가 기술되어있으며, 뒤로 RGBQUAD에 해당하는 R,G,B값의 ColorTable이 따라나오며, 마지막으로 픽셀의 데이터(index값) 이 나온게 된다는 소리다.


BITMAP의 분석에 쓰이는 구조체에 대해서 알아보도록 하자. 일단은 구조체의 선언부분이다.

/* BITMAPFILEHEADER 구조체 */
typedef struct tagBITMAPFILEHEADER{ //bmfh
   WORD bfType;         // 파일의 형태, 0x42, 0x4d (BM) 이어야함
   WORD bfSize;         // 비트맵 파일의 크기 (Byte단위)
   WORD bfReserved1;   // 예약. 0으로 설정  
   WORD bfReserved2;  // 예약2. 0으로설정
   DWORD bfOffBits;     // 실제 비트맵데이터까지의 오프셋값
   // 실제로는 bfOffBits = BITMAPFILEHEADER크기 + BITMAPINFOHEADER크기 + RGBQUAD 구조체배열의크기 이다. (그림을 봐야 이해할수 있을것이다)
} BITMAPFILEHEADER;

/* BITMAPINFOHEADER 구조체 */
typedef struct tagBITMAPINFOHEADER{ //bmfh
   DWORD biSize;         // 이 구조체의 크기. 구조체 버전확인할수 있다.
   LONG biWidth;        // 비트맵의 가로 픽셀수
   LONG biHeight;       // 비트맵의 세로 픽셀수
   WORD biPlanes;      // 플레인의 갯수 반드시 1이어야함
   WORD biBitCount;     // 한 픽셀이 구성되는 비트의수
   DWORD biCompression; // 압축방법. BI_RGB일땐 비압축 BI_RLE8, BI_RLE4인경우 run length encode방법으로 압축
   DWORD biSizeImage;   // 이미지의 크기. 압축이 안되어있을때는 0
   LONG biXPelsPerMeter; // 가로 해상도
   LONG biYPelsPerMeter; // 세로 해상도
   DWORD biClrUsed;  // 색상테이블을 사용하였을때 실제 사용되는 색상수
   DWORD biClrImportant; // 비트맵을 출력하는데 필수 색상수
} BITMAPINFOHEADER;

/* RGBQUAD구조체 */
typedef struct tagRGBQUAD{ //rgbq
   BYTE rgbBlue;       // Blue Value
   BYTE rgbGreen;     // Green Vlaue
   BYTE rgbRed;       // Red Value
   BYTE rgbReserved; // 실제 사용하지 않음. 0
} RGBQUAD;

* BITMAPFILEHEADER는 BITMAP FILE에 대한 정보를 가진다.
* BITMAPINFOHEADER는 BITMAP의 특성에 대한 정보를 가진다.
* RGBQUAD는 BITMAP의 Color에 대한 정보를 가진다.

주의사항 RGBQUAD는 4Byte로 이루어지는데. 순서대로 R,G,B로 저장되지 않는다. Blue, Green, Red, 안쓰는 바이트. 순으로 저장되므로 이점 유의해야한다.


또다른 구조체이긴 하지만, 쉽게 BITMAP에 해당하는 정보를 가지기 위해서는 BITMAPINFO라는 구조체를 선언하면 된다. 이 BITMAPINFO는 BITMAPFILEHEADER하고, Data만 제거한 버젼이라고 생각하면 된다.

사실.. 그림을 그려주기 위해서는 BITMAPINFOHEADER와
RGBQUAD그리고 픽셀데이터만 있으면, 할수 있지만, 픽셀데이터는 딴것을 쓰고, BITMAPINFO만 따로 필요하기 때문이다. 자세한 것은 setDIBitsToDevice()나 StretchDIBits()함수의 원형을 자세히 살펴보면 안다.

/*BITMAPINFO 구조체*/
typedef struct tagBITMAPINFO{ //bmi
   BITMAPINFOHEADER bmiHeader;
   RGBQUAD   bmiColors[1];
} BITMAPINFO;


이 구조체에는 BITMAPINFO와 RGBQUAD구조체로 이루어져있다. 썰렁하지 않은가? 주의할점은 RGBQUAD 부분에 bmiColors[1];로 선언되어있다는 것이다. 왜냐? color가 몇 bit인가에 따라서 color의 쓸수 있는 색상수가 틀려지며, 8bit중에서도 100개의 color만 쓰는 이미지가 있는둥하여 첫번째 RGBQUAD의 포인터만 가지게 되는 것이다.
그럼 두번째 RGBQUAD는 어떻게 가져올까? 간단하게 sizeof(RGBQUAD)만큼 더해서(포인터는 더하면 다음것을 가리킨다) 가져오면 된다.


BITMAP의 Type은 다음과 같이 7가지 정도로 나눌수 있겠다.

*1Bit Bitmap : 2^0 으로 총 2가지의 색을 지닌다. 정말로 흑백이다.
*2Bit Bitmap : 2^2 으로 총 4가지의 색을 지닌다. 아직도 흑백이다.
*4Bit Bitmap : 2^4 으로 총 16가지의 색을 지닌다. 이제는 흑백TV수준이다.
*8Bit Bitmap : 2^8 으로 총 256가지의 색을 지닌다. 적당한 크기와 적당한 칼라수를 가지고 있는관계로 임베디드 시스템처럼 크지않은 메모리에 자주 쓰인다. 기본이다.
*16Bit Bitmap : 2^16으로 총 65,536가지의 색을 지닌다. 임베디드보다는 큰 메모리를 지니며, 256색으로는 도저히 안되겠다 싶을때 쓰는 색이다.
*24Bit Bitmap : 2^24으로 총 16,777,216가지의 색을 지닌다. 하이컬러라고 부른다. 컬러TV정도는 되겠다.
*32Bit Bitmap : 2^32으로 총 4,294,967,296가지의 색을 지닌다. 이것이 TRUE Color이다.

이중에서 8Bit 이하의 BITMAP은 Color Table이라는 것을 가지며, 이는 색상을 가진 구조체라고 할수 있고, 위의 BITMAP구조중 RGBQUAD 라고 생각할수 있다.
물론 16Bit 이상의 BITMAP들은 ColorTable를 사용하지 않는다. 이유는 다음과 같다.

1) Bitmap 파일을 이미지 한픽셀의 정보를 각각 가지고 있다. 예를 들면 이미지 첫번째 픽셀은 RGB(123, 0, 0) 을 가지고, 두번째 픽셀은 RGB(2,32,45) 를 가진다는 식으로 말이다. ( R:red, G:green, B:blue)

2) Bitmap 파일의 한픽셀의 대한 정보를 위의 내용처럼 전부를 저장하려면 크기가 커지는 관계로 조금더 효율적인 방식을 생각해 내었다.

3) RGBQUAD 라는 색상구조체( color Table)에 미리 이 이미지에서 쓰인 모든 색을 정의한다. 고로 RGBQUAD라는 곳에는 총 256개 정도의 정보가 저장된다.

4) PIXEL DATA라는 구조체에는 Color Table의 Index (몇번째로 선언된 색) 이라는 값만 가지고 있다.

5) 이렇게 하면, 저장해야할 RGB의 정보(나름대로 큼)를 중복하여 저장하지 않아도 되므로, 파일의 크기를 효율적으로 적게 할수 있다.

6) 고로 8bit Bitmap에서는 위와 같은 구조를 가지게 된것이다.

7) 하지만 8Bit 이상의 비트맵을 생각해 보자. 32비트 같은 BITMAP은 한픽셀을 32Bit를 사용하므로 위의 구조가 맞지 않다. 고로 Color Table을 사용하지 않고, Pixel Data자체가 RGB를 사용한다.

[출처] [펌] [BITMAP] 분석|작성자 슈우웅

댓글