Category Archives: Structure and algorithm

비트맵 파일구조

BMP 파일의 개요

DIB는 Windows API에서 직접 지원된다. DIB 파일의 확장자는 대게 BMP를 쓰며, 간혹가다 DIB인 경우도 있다. 아이콘과 마우스 커서도 약간 형태가 다른 DIB 파일이다.


로그램은 DIB 파일의 처음 14byte를 뺀 나머지 부분을 연속적인 메모리 블록에 로드할 수 있다. 이 경우를 packed
DIB형식의 비트맵이라고 부르기도 한다. windows에서 실행되는 응용 프로그램은 windows 클립보드를 통해서 이미지를
교환하거나 브러쉬를 생성할 때 packed DIB형식을 사용할 수 있다.


러나 DIB는 아무리 설명해도 windows 운영체제에서 지원하지 않는 DIB작업을 수행해야 하는 경우가 너무나 많다. 예를
들어 24bit DIB를 이용해야 하고, 파일의 256 색상 팔레트와 함께 8bit DIB로 변환하고자 한다면 windows는
이 작업을 수행해 주지 않는다. 여기서는 이 범위까지 다룰 것이다.

OS/2 DIB

DIB 파일 형식은 현재도 변하고 있다. 이해를 돕기 위해 초창기 버전인 OS/2 와 호환되는 DIB파일 형식을 살펴보자. DIB 파일에는 4개의 기본 섹션이 있다.

파일 헤더

정보 헤더

RGB 색상 테이블(항상 있는 것은 아니다)

비트맵 픽셀 bit

여기에 사용될 수 있는 구조체들이 wingdi.h에 정의 되어 있다.

packed DIB 파일 형식의 메모리 기반 DIB에는 세 개의 섹션이 있다.

정보 헤더

RGB 색상 테이블(항상 있는 것은 아니다)

비트맵 픽셀 bit

내부 구조는 파일 헤더만 제외하고 완벽하게 동일하다.

먼저 파일헤더부터 알아보자. 전체 크기는 14바이트 이다.


다음으로 BITMAPCOREHEADER 구조체가 이어진다.

typedef struct tagBITMAPINFOHEADER{
        DWORD      biSize;                  // 구조체의 크기
        LONG       biWidth;                  //이미지의 가로 크기
        LONG       biHeight;                 //이미지의 세로 크기
        WORD       biPlanes;               //플레인수, 평면의 개수
        WORD       biBitCount;             //픽셀당 비트 수
        DWORD      biCompression;     //압축 유무
        DWORD      biSizeImage;         //이미지 크기
        LONG       biXPelsPerMeter;    //미터당 가로 픽셀
        LONG       biYPelsPerMeter;    //미터당 세로 픽셀
        DWORD      biClrUsed;            //컬러 사용 유무
        DWORD      biClrImportant;       //중요하게 사용하는 색
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

비트맵 파일 형식의 한계에 의해 65,535 픽셀 이상 크기의 파일은 만들 수 없다.

픽셀당 bit수를 bcBitCount라 할 때 표현할 수 있는 총 색상수는 2^bcCount(=1<<BCCOUNT)가

bit
수가 1, 4, 8인 비트맵의 경우, 다음으로 색상 테이블이 앞에 나온다. 24비트 비트맵의 경우에는 색상 테이블이 없다. 색상
테이블은 2byte 색상 테이블의 구조체 배열이며 각각의 색상들은 3바이트, 즉 24비트를 차지한다.


WINGDI.H에는 색상 테이블이 다음과 같은 구조체가 정의되어있다.


이 구조체는 코어 헤더와 팔레트 색상 테이블을 모두 포함하는 것이다.

예를 들어 8비트 DIB에서는 이 구조체를 다음과 같이 쓸 수 있을 것이다.

가 될 것이다.

DIB
파일의 마지막 섹션은 실제 픽셀 bit로 구성되어 있다. DIB의 행수는 BITMAPCOREHEADER의 bcHeight의 값과
같다. 각 줄은 bcWidth의 값과 같은 수의 픽셀로 구성되어 있다. 그러나 bcWidth*bcBitCount/8와 같은 수의
바이트를 가지고 있진 않다. DIB 파일의 bit 정보는 4byte로 나누어 떨어지게 설계되어 있다. 그것이 32비트
운영체계에서 접근하기가 가장 용이하다. 결론적으로 각 줄은 다음과 같은 byte 수를 가진다.

필요한 경우 줄 오른쪽의 남은 부분은 0으로 채운다.

이상에서 언급한 내용을 정리하면 다음과 같다.

파일 헤더

BITMAPFILEHEADER

정보 헤더

BITMAPCOREHEADER

BITMAPCOREINFO

RGB 색상 테이블
(항상 있는 것은 아니다)

RGBTRIPLE의 배열

비트맵 픽셀 bit


확장된 WindowsDIB


버전은 Windows 3.0이 나오면서 OS/2 호환 DIB와 같이 발표된 것이다. 이 파일은 OS/2 호환 DIB와 마찬가지로
BITMAPFILEHEADER로 시작하지만, 그 다음에 BITMAPCOREHEADER 구조체 대신 BITMAPINFOHEADER
구조체가 나온다.

이 구조체의 처음 부분은 BITMAPCOREHEADER와 완전히 같지 않다. bcWidth와 bcHeight는 WORD형이었지만 이 버전에서는 LONG 형으로 바뀌었다.
LONG(부
호 있는)형으로 표기할 수 있는 가장 큰 이미지의 크기는 WORD(부호 없는) 형과 같다. 달라진 점은 이미지의 크기로 음수를
사용할 수 있게 되었다는 점이다. 마이너스 크기의 비트맵은 위에서 아래로 그려짐을 의미한다. 이러한 DIB를 하향식이라 한다.

새로 추가된 필드는 6개나 되지만, 별로 의미심장한 것은 없다.


선 PelsPerMeter부터 알아보자. biXPelsPerMeter와 biYPelsPerMeter필드는 1m 당 포함된
픽셀수를 나타낸다. Pel은 IBM에서 픽셀을 부를 때 사용한 용어이다. 예를 들어 300DPI의 DIB는 11811이라는 값을
가질 것이다.

biClrUsed는 색상 테이블이 전부 사용되지 않을 경우에 쓰이는 필드이다. 이 필드에 쓰여진 갯수 만큼의 색상이 쓰인다. 만일 이 값이 0이면 모든 색상이 쓰임을 의미한다. 그러므로 8비트 DIB에서 0과 256은 같다.

biClrImportant필드는 그 이름과 달리 그리 중요하지 않다. 이 값은 생상 테이블의 색상 중에서 실제로 사용되는 색의 개수를 의미한다. 대게 0으로 세팅되어 biClrUsed와 같은 값을 가지게 된다.

biCompression 필드는 4개의 상수(BI_RGB, BI_RLE8, BI_RLE4, BI_BITFIELDS) 중의 하나이다.

다음과 같은 값이 가능하다.

1비트 DIB

BI_RGB

4비트 DIB

BI_RGB 또는 BI_RLE4

8비트 DIB

BI_RGB 또는 BI_RLE8

16비트 DIB

BI_RGB 또는 BI_FIELDS

24비트 DIB

BI_RGB

32비트 DIB

BI_RGB 또는 BI_FIELDS

이 값이 BI_RGB인 경우 픽셀 bit는 OS/2 호환 DIB와 같이 저장된다.

만일 16비트나 32비트의 DIB의 경우 OS/2 호환 DIB에서는 정의되어 있지 않으므로, 다음과 같이 읽혀진다.

먼저 16비트 DIB의 경우

항상0

빨강

초록

파랑

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

각 색상의 레벨은 다음과 같다.

눈치가 빠른 사람은 8을 곱한다는 사실을 알았을 것이다. 5비트로는 모든 색상을 나타낼 수 없으므로 8을 곱해 8비트를 만드는 것이다.

32비트 DIB의 경우는 내부적으로 24비트만을 사용하며, 8비트는 0으로 세팅되어있다.

항상0

빨강

초록

파랑

31

30

29

28

27

26

25

24

23

22

21

20

19

18

17

16

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

각 색상의 레벨은 다음과 같다.

이 DWORD는 Window에서 정의된 COLORREF값과 같지 않음에 유의하라. COLORREF 값은 0BGR순이다.

4비트나 8 비트 비트맵은 RLE 방식을 사용해 압축될 수 있다.

RLE8부터 알아보자.

byte1

byte2

byte3

byte4

의미

00

00

·

줄의 끝

00

01

·

이미지의 끝

00

02

dx

dy

dx, dy 만큼 이동

00

03~FF

·

다음 n픽셀 그대로 사용

01~FF

픽셀데이터

·

픽셀을 n번 반복

예를 들어 05 27은 27 27 27 27 27와 같다.

00 06 01 04 03 05 02 05 06은 01 04 03 05 02 05 06와 같다.

00 00을 만나면 현재 해독하고 있는 x, y가 어디든 상관 없이 다음줄로 내려간다.(x=0, y++)

00 02를 만나면 현재 해독하고 있는 x, y에 dx, dy를 더한다.(x+=dx, y+=dy)

00 01을 만나면 무조건 끝낸다.

00 00과 00 02에 의해 이 비트맵 파일은 투명 영역이 가능하다. 이러한 기능은 애니메이션등에 쓰일 수 있다.

RLE4의 경우에는 인코딩은 대체적으로 같지만 byte와 pixel이 1:1로 대응하지 않게 때문에 약간 복잡하다.

byte1

byte2

byte3

byte4

의미

00

00

·

줄의 끝

00

01

·

이미지의 끝

00

02

dx

dy

dx, dy 만큼 이동

00

03∼FF

·

다음 n픽셀 그대로 사용

01∼FF

2개의 픽셀데이터

·

뒤의 정보를 이용하여 n픽셀만큼 반복

예를 들어 07 35는 35 35 35 3이 된다. 만일 이 다음에 05 24 가 나오면 전체의 해독 결과는 35 35 35 32 24 24가 된다.

00 05 23 57 10 00은 23 57 1이 된다.

현재 문서에는 하향식 DIB는 압축할 수 없다고 되어있다.

biCompression값이 BI_FIELDS의 경우 DIB의 BITMAPINFOHEADER 구조체 바로 뒤에는 3개의 DWORD 컬러마스크 값이 이어진다. 순서는 R, G, B순이다. 예를 들면 16비트 DIB에서 다음과 같다.

16비트 DIB이므로 하위 16비트만 설정이 되어있다.

각 컬러값을 얻기 위해서는 이 값을 &연산 한 후 오른쪽 시프트를 하면 된다. 이 때 몇칸 오른쪽으로 이동해야 하는가는 주어지지 않는다. 이 값을 얻기 위해서는 다음과 같은 함수를 사용해야 한다.

결론적으로

이 된다.

biCompression이 BI_RLEx인 경우에 biSizeImage 필드는 DIB 픽셀 데이터의 크기를 byte 단위로 나타낸다.

이 값이 BI_RGB이면, 앞에서 계산했던 대로 줄의 byte 길이에 biHeight를 곱한 값일 수 도 있지만, 대부분 0이다.

이 버전에서의 또 다른 변화는 1,4,8비트 DIB의 경우 색상 테이블이 RGBTRIPLE 구조의 배열이 아니라 RGBQUAD 구조체의 배열이라는 것이다.

이 구조체는 항상 0으로 설정되는 네 번째 필드가 있다.
이렇게 함으로써 이전 버전에서 4바이트를 맞추기 위해 뒤에 붙일 0들을 앞으로 끌어왔다고나 할까?
어쨌든 이전버전이 더 밀도 있고, 이 버전은 쉽다.

마찬가지로 BITMAPCOREINFO에 해당하는 구조체가 여기에서도 제공된다.

typedef struct

{

    BITMAPINFOHEADER bmiHeader;

    RGBQUAD bmiColors[1];

} BITMAPINFO, *PBITMAPINFO

정리하면 다음과 같다.

파일 헤더

BITMAPFILEHEADER

정보 헤더

BITMAPINFOHEADER

BITMAPINFO

RGB 색상 테이블(항상 있는 것은 아니다)

RGBQUAD의 배열

비트맵 픽셀 bit


버전 4

이 버전은 Windows95가 나오면서 발표된 것이다. BITMAPINFOHEADER는 BITMAPV4HEADER로 바뀌었다. 버전 4라는 것은 Windows 4.0(Windows 95)에서 정의되었다는 것이다.

처음 11 필드는 BITMAPINFOHEADER 구조체의 것과 같다. 이어지는 컬러마스크들은 이전 버전의 컬러 마스크들과 같다.
그러나 여기서는 명시적인 필드이다. 마지막 다섯 필드는 WindowsICM에 관한 정보가 들어간다. 이에 대한 설명은 생략한다.

버전 5

이 버전의 DIB는 Windows 98 및 Windows 2000에서 정의되었다.

4개의 필드가 추가되었지만, 3개의 필드가 사용된다. 이 필드들은 ICC 프로필 형식을 위한 것이다. 자세한 셜명은 생략한다.

참고 자료