* 이 자료를 퍼 가셔서 타사이트나 블로그에 게재 시 출처를 명시해 주시기 바랍니다.
본 사이트에 게재된 모든 내용 및 자료는 상업적인 용도로 이용할 수 없습니다.
본 사이트에 게재된 모든 내용 및 자료는 상업적인 용도로 이용할 수 없습니다.
이 자료들은 저희 사이트에서 제공하는 [ 알짜배기 ] 프로그램을 이용하시면 좀더 편리하게 볼수 있습니다.
알짜배기 프로그램 받기 : http://www.tipssoft.com/bulletin/tb.php/QnA/8406
비트맵은 크게 DDB(Device-Dependent Bitmap) 나 DIB(Device-Independent Bitmap) 형식으로 나눌수 있습니다.
DDB 형식은 현재 시스템의 이미지 출력장치가 사용가능한 형태로 구성된 Bitmap을 의미하고
DIB는 출력장치와 상관없이 독립적인 형태로 저장된 Bitmap을 의미합니다. 흔히, DIB 는 확장자가 *.bmp 로
저장된 이미지 파일이고 이 파일을 읽어서 현재 시스템에서 출력하기 위해 재구성된 비트맵정보가 DDB 입니다.
DDB 형식은 현재 시스템의 이미지 출력장치가 사용가능한 형태로 구성된 Bitmap을 의미하고
DIB는 출력장치와 상관없이 독립적인 형태로 저장된 Bitmap을 의미합니다. 흔히, DIB 는 확장자가 *.bmp 로
저장된 이미지 파일이고 이 파일을 읽어서 현재 시스템에서 출력하기 위해 재구성된 비트맵정보가 DDB 입니다.
"tipssoft.bmp" --> "CBitmap 객체를 이용해서 읽어들임"
( DIB 형식 ) ( DDB 형식)
( DIB 형식 ) ( DDB 형식)
컴퓨터 시스템마다 출력장치가 동일하지 않고 운영체제에 설정된 출력방식도 사용자가 설정(색상수, 해상도) 하기에
따라서 달라지기 때문에, DDB 형식의 정보를 그대로 파일에 저장하게되면 다른 시스템에서 해당 파일을 읽어서
출력하는 경우, 제대로 출력하지 못하는 경우가 발생할수 있습니다. 따라서 파일에 비트맵을 저장하는 경우
다른 시스템이나 운영체제에서도 이 이미지정보를 읽어서 출력할수 있도록 이미지의 이미지패턴정보 뿐만아니라
비트맵의 속성정보를 포함하는 DIB 형식으로 저장해야 합니다.
따라서 달라지기 때문에, DDB 형식의 정보를 그대로 파일에 저장하게되면 다른 시스템에서 해당 파일을 읽어서
출력하는 경우, 제대로 출력하지 못하는 경우가 발생할수 있습니다. 따라서 파일에 비트맵을 저장하는 경우
다른 시스템이나 운영체제에서도 이 이미지정보를 읽어서 출력할수 있도록 이미지의 이미지패턴정보 뿐만아니라
비트맵의 속성정보를 포함하는 DIB 형식으로 저장해야 합니다.
일반적으로 비트맵은 1, 4, 8, 16, 24, 32 비트형식의 색상을 사용할수 있습니다. 예를들어, 비트맵의 색상이
16비트 형식이라고 하면 1점의 색상이 16비트(2바이트) 크기로 표현된다는 뜻입니다. 따라서 한점을 표현하는
색상이 크면 클수록 비트맵의 용량은 커지게 됩니다. 과거에는 비트맵의 용량을 줄이기 위해서 8비트 형식의
비트맵을 많이 사용했지만 컴퓨터 시스템의 발전으로 인해서 현재는 24비트 또는 32비트 형식을 많이 사용하고
있습니다.
16비트 형식이라고 하면 1점의 색상이 16비트(2바이트) 크기로 표현된다는 뜻입니다. 따라서 한점을 표현하는
색상이 크면 클수록 비트맵의 용량은 커지게 됩니다. 과거에는 비트맵의 용량을 줄이기 위해서 8비트 형식의
비트맵을 많이 사용했지만 컴퓨터 시스템의 발전으로 인해서 현재는 24비트 또는 32비트 형식을 많이 사용하고
있습니다.
"흑백 비트맵"(1비트 형식) -> "256 색상 비트맵"(8비트 형식) -> "트루컬러 비트맵"(24 또는 32비트 형식)
비트맵은 그 형식상 용량이 크기때문에 DIB 형식으로 저장할때 "RLE4, RLE8"과 같은 압축형식을 제공합니다.
하지만, 이 압축방법이 매우 단순하여 이미지가 단순한 색상형태가 아닌 사진과 같은 이미지 정보라면
압축을 기대하기가 어렵습니다. 따라서 요즘 컴퓨터 시스템에서는 단순한 형태의 이미지가 거의없기 때문에
DIB 파일중에서 압축형식으로 저장된것은 찾아보기가 어렵습니다.
하지만, 이 압축방법이 매우 단순하여 이미지가 단순한 색상형태가 아닌 사진과 같은 이미지 정보라면
압축을 기대하기가 어렵습니다. 따라서 요즘 컴퓨터 시스템에서는 단순한 형태의 이미지가 거의없기 때문에
DIB 파일중에서 압축형식으로 저장된것은 찾아보기가 어렵습니다.
DIB (*.bmp) 파일은 역사가 오래되었기 때문에 그 저장 방식이나 형식이 여러번 업데이트 되었고 그 결과
버전별로 또는 운영체제별로 다양한 형식이 존재하였습니다. 하지만, 각 버전별 호환성이 문제가되어
대부분 사용되지 않고 현재는 Windows Version3 방식을 가장 많이 사용하고 있습니다.
버전별로 또는 운영체제별로 다양한 형식이 존재하였습니다. 하지만, 각 버전별 호환성이 문제가되어
대부분 사용되지 않고 현재는 Windows Version3 방식을 가장 많이 사용하고 있습니다.
( 지금은 OS/2를 많이 사용하지 않지만 한때 OS/2 에서 이 형식을 따르지 않는 DIB를 많이 사용하여
비트맵이 호환되지 않는 경우가 많았습니다. )
비트맵이 호환되지 않는 경우가 많았습니다. )
현재 가장 많이 사용하는 DIB 형식의 구조를 살펴보면 아래와 같습니다.

1. 파일 정보
DIB 파일의 가장 선두에 존재하는 정보로써 현재 파일이 비트맵 파일인지를 구별하기 위해서 사용하는
정보입니다. 이 정보는 BITMAPFILEHEADER 구조체 형식으로 정의되어 있으며 이 구조체는 windows.h 헤더
파일에 정의되어 있습니다. 구조체의 내용은 아래와 같습니다.
typedef struct tagBITMAPFILEHEADER {
WORD bfType; // 2 Bytes. 각각의 바이트에 'B','M'이 저장되어 있다.
DWORD bfSize; // 4 Bytes. 파일의 전체 크기가 저장되어 있다.
WORD bfReserved1; // 2 Bytes. 예약 공간 - 사용하지 않음.
WORD bfReserved2; // 2 Bytes. 예약 공간 - 사용하지 않음.
DWORD bfOffBits; // 4 Bytes. 실제 이미지가 들어있는 위치(offset)가 저장되어있다.
// 전체 정보중에서 이 위치부터 순수한 이미지 정보이다.
} BITMAPFILEHEADER
정보입니다. 이 정보는 BITMAPFILEHEADER 구조체 형식으로 정의되어 있으며 이 구조체는 windows.h 헤더
파일에 정의되어 있습니다. 구조체의 내용은 아래와 같습니다.
typedef struct tagBITMAPFILEHEADER {
WORD bfType; // 2 Bytes. 각각의 바이트에 'B','M'이 저장되어 있다.
DWORD bfSize; // 4 Bytes. 파일의 전체 크기가 저장되어 있다.
WORD bfReserved1; // 2 Bytes. 예약 공간 - 사용하지 않음.
WORD bfReserved2; // 2 Bytes. 예약 공간 - 사용하지 않음.
DWORD bfOffBits; // 4 Bytes. 실제 이미지가 들어있는 위치(offset)가 저장되어있다.
// 전체 정보중에서 이 위치부터 순수한 이미지 정보이다.
} BITMAPFILEHEADER
파일의 확장자가 *.bmp 라고해서 꼭 비트맵 파일이라고 할수는 없습니다. 사용자가 임의로 파일을 만든 후,
그 확장자를 bmp로 수정할수도 있기 때문입니다. 따라서 DIB 형식의 파일을 사용하는 프로그램에서는
해당 파일이 비트맵파일임을 확신하기 위해서 아래와 같은 사항을 확인해야 합니다.
그 확장자를 bmp로 수정할수도 있기 때문입니다. 따라서 DIB 형식의 파일을 사용하는 프로그램에서는
해당 파일이 비트맵파일임을 확신하기 위해서 아래와 같은 사항을 확인해야 합니다.
1.1 파일의 선두 두바이트가 "BM" 이라는 문자로 시작하는지 확인한다.
FILE *p_file = fopen("tipssoft.bmp", "rb");
if(p_file != NULL){
char buff[2] = {0, 0};
if(p_file != NULL){
char buff[2] = {0, 0};
// 선두 2바이트의 정보를 얻는다.
fread(buff, 2, 1, p_file);
if(buff[0] == 'B' && buff[1] == 'M'){
// 이 파일은 비트맵 파일임.
} else {
// 이 파일은 비트맵 파일이 아님.
}
fclose(p_file);
}
또는 BITMAPFILEHEADER 구조체 크기만큼 정보를 읽어서 bfType 값이 0x4D42 값인지 확인한다.
FILE *p_file = fopen("tipssoft.bmp", "rb");
if(p_file != NULL){
BITMAPFILEHEADER temp_header;
if(p_file != NULL){
BITMAPFILEHEADER temp_header;
fread(&temp_header, sizeof(temp_header), 1, p_file);
if(temp_header.bfType == 0x4D42){
// 이 파일은 비트맵 파일임.
// 0x42 -> 'B'의 아스키 코드값. 0x4D -> 'M'의 아스키 코드값.
// 윈도우즈 운영체제는 "Little-endian" 형식의 바이트정렬기술을 사용하기 때문에
// WORD 형식으로 정보가 저장되면 뒤집어져서 표현된다.
} else {
// 이 파일은 비트맵 파일이 아님.
}
fclose(p_file);
}
1.2 "BM" 이라는 문자열 뒤에 4바이트를 읽어서 파일의 크기와 일치하는지 확인한다.
FILE *p_file = fopen("tipssoft.bmp", "rb");
if(p_file != NULL){
// 파일의 끝으로 이동한다.
fseek(p_file, 0, SEEK_END);
// 마지막 위치가 파일의 크기이다.
int file_size = ftell(p_file);
// 파일의 처음으로 이동한다.
fseek(p_file, 0, SEEK_SET);
if(p_file != NULL){
// 파일의 끝으로 이동한다.
fseek(p_file, 0, SEEK_END);
// 마지막 위치가 파일의 크기이다.
int file_size = ftell(p_file);
// 파일의 처음으로 이동한다.
fseek(p_file, 0, SEEK_SET);
char buff[2] = {0, 0};
// 선두 2바이트의 정보를 얻는다.
fread(buff, 2, 1, p_file);
if(buff[0] == 'B' && buff[1] == 'M'){
int temp_size = 0;
fread(&temp_size, 4, 1, p_file);
if(temp_size == file_size){
// 이 파일은 비트맵 파일임.
} else {
// 이 파일은 비트맵 파일이 아님.
}
} else {
// 이 파일은 비트맵 파일이 아님.
}
fclose(p_file);
}
또는 BITMAPFILEHEADER 구조체 크기만큼 정보를 읽어서 bfSize 값이 현재 파일크기와
일치하는지 확인한다.
일치하는지 확인한다.
FILE *p_file = fopen("tipssoft.bmp", "rb");
if(p_file != NULL){
// 파일의 끝으로 이동한다.
fseek(p_file, 0, SEEK_END);
// 마지막 위치가 파일의 크기이다.
int file_size = ftell(p_file);
// 파일의 처음으로 이동한다.
fseek(p_file, 0, SEEK_SET);
if(p_file != NULL){
// 파일의 끝으로 이동한다.
fseek(p_file, 0, SEEK_END);
// 마지막 위치가 파일의 크기이다.
int file_size = ftell(p_file);
// 파일의 처음으로 이동한다.
fseek(p_file, 0, SEEK_SET);
BITMAPFILEHEADER temp_header;
fread(&temp_header, sizeof(temp_header), 1, p_file);
if(temp_header.bfType == 0x4D42){
if(temp_header.bfSize == (UINT)file_size){
// 이 파일은 비트맵 파일임.
} else {
// 이 파일은 비트맵 파일이 아님.
}
} else {
// 이 파일은 비트맵 파일이 아님.
}
fclose(p_file);
}
if(temp_header.bfType == 0x4D42){
if(temp_header.bfSize == (UINT)file_size){
// 이 파일은 비트맵 파일임.
} else {
// 이 파일은 비트맵 파일이 아님.
}
} else {
// 이 파일은 비트맵 파일이 아님.
}
fclose(p_file);
}
1.3 위 두가지 외에도 BITMAPFILEHEADER 구조체의 bfReserved1 값과 bfReserved2 값이 0인지
체크하는 방법도 있지만 DIB 형식을 확장해서 사용하는 경우에 이 영역을 사용하는 경우도
있기 때문에 잘 체크하지 않는다.
"파일 정보" 다음에 존재하는 "이미지 헤더정보"에 대해서는 다음 강좌에서 진행하도록 하겠습니다. ^^;;
* 이 자료를 퍼 가셔서 타사이트나 블로그에 게재 시 출처를 명시해 주시기 바랍니다.
본 사이트에 게재된 모든 내용 및 자료는 상업적인 용도로 이용할 수 없습니다.
본 사이트에 게재된 모든 내용 및 자료는 상업적인 용도로 이용할 수 없습니다.
이 자료들은 저희 사이트에서 제공하는 [ 알짜배기 ] 프로그램을 이용하시면 좀더 편리하게 볼수 있습니다.
알짜배기 프로그램 받기 : http://www.tipssoft.com/bulletin/tb.php/QnA/8406
이 강좌에서는 Step1에 이어서 DIB 형식의 비트맵 파일이 어떻게 구성되어 있는지 알아보도록 하겠습니다.
Step1에서 DIB 파일의 선두에는 이 파일이 정말 비트맵형식의 파일인지 체크할수 있는 "파일 정보"가
BITMAPFILEHEADER 라는 구조체 형식으로 들어있다고 설명했습니다. 이 강좌에서는 "파일 정보" 다음 위치에
존재하는 "이미지 헤더정보"에 대해서 알아보도록 하겠습니다.
Step1에서 DIB 파일의 선두에는 이 파일이 정말 비트맵형식의 파일인지 체크할수 있는 "파일 정보"가
BITMAPFILEHEADER 라는 구조체 형식으로 들어있다고 설명했습니다. 이 강좌에서는 "파일 정보" 다음 위치에
존재하는 "이미지 헤더정보"에 대해서 알아보도록 하겠습니다.
2. 이미지 헤더정보
"이미지 헤더정보"는 "파일 정보" 다음에 위치하고 있습니다. "이미지 헤더정보" 영역에는 현재 이미지의
폭, 높이, 색상수, 압축방식과 같은 그림의 전반적인 형식에 대한 정보가 저장됩니다.
폭, 높이, 색상수, 압축방식과 같은 그림의 전반적인 형식에 대한 정보가 저장됩니다.
현재 컴퓨터 시스템과 운영체제의 발전으로 비트맵을 표현하는 방법이 다양해져서 "파일 정보"처럼
그 정보가 특정한 구조체로 이루어진것이 아니라 용도나 버전에 따라서 "이미지 헤더정보"를 표현하는
구조체가 여러가지 형태로 나누어져 있습니다.
그 정보가 특정한 구조체로 이루어진것이 아니라 용도나 버전에 따라서 "이미지 헤더정보"를 표현하는
구조체가 여러가지 형태로 나누어져 있습니다.
2.1 BITMAPCOREHEADER 구조체
typedef struct tagBITMAPCOREHEADER { // bmch
DWORD bcSize; // 구조체의 크기 ( 16 바이트 )
WORD bcWidth; // 이미지의 폭
WORD bcHeight; // 이미지의 높이
WORD bcPlanes; // 현재는 무조건 1 사용. ( 색상을 표현하는데 필요한 Plan의 갯수 )
WORD bcBitCount; // 1 점을 표현하는데 필요한 비트수 ( 1, 4, 8, 24 )
} BITMAPCOREHEADER;
이 구조체는 가장 단순한 형태의 "이미지 헤더정보"를 표현하는 구조체로써 압축에 대한 표현을
할수 없고 색상수도 4가지 밖에 지원하지 않습니다.
DWORD bcSize; // 구조체의 크기 ( 16 바이트 )
WORD bcWidth; // 이미지의 폭
WORD bcHeight; // 이미지의 높이
WORD bcPlanes; // 현재는 무조건 1 사용. ( 색상을 표현하는데 필요한 Plan의 갯수 )
WORD bcBitCount; // 1 점을 표현하는데 필요한 비트수 ( 1, 4, 8, 24 )
} BITMAPCOREHEADER;
이 구조체는 가장 단순한 형태의 "이미지 헤더정보"를 표현하는 구조체로써 압축에 대한 표현을
할수 없고 색상수도 4가지 밖에 지원하지 않습니다.
이 구조체의 특징을 보면 bcSize 라는 항목이 구조체 선두에 나오는데 이 항목이 필요한 이유는
비트맵 파일을 열어서 정보를 읽어야 하는데 현재 이 파일이 어떤 형식의 "이미지 헤더정보"를
사용하는지 알수 없기 때문에 구조체 정보를 읽기전에 4바이트(bcSize)를 읽어서 그 크기로
어떤 종류의 구조체가 사용되었는지 체크하기 위함입니다. 예를 들어, bcSize 값이 16이라면
해당 DIB 파일은 "이미지 헤더정보"를 BITMAPCOREHEADER 구조체로 사용했다고 생각하시면 됩니다.
FILE *p_file = fopen("tipssoft.bmp", "rb");
if(p_file != NULL){
// 파일의 끝으로 이동한다.
fseek(p_file, 0, SEEK_END);
// 마지막 위치가 파일의 크기이다.
int file_size = ftell(p_file);
// 파일의 처음으로 이동한다.
fseek(p_file, 0, SEEK_SET);
BITMAPFILEHEADER temp_header;
fread(&temp_header, sizeof(temp_header), 1, p_file);
if(temp_header.bfType == 0x4D42){
if(temp_header.bfSize == (UINT)file_size){
// 이 파일은 비트맵 파일임.
DWORD temp_size = 0;
// 이미지 헤더정보의 크기를 얻는다.
fread(&temp_size, sizeof(DWORD), 1, p_file);
if(temp_size == 16){
// 크기가 16이라면 BITMAPCOREHEADER 구조체가 사용되었다는 뜻이다. 따라서
// BITMAPCOREHEADER 크기만큼 읽어야하는데 이미 bcSize에 해당하는 정보를
// 읽었기 때문에 파일 포인트가 DWORD 만큼 진행했으니 이를 보정하기 위해서
// sizeof(DWORD)만큼 파일 포인터를 앞으로 이동시킨다.
fseek(p_file, long(sizeof(DWORD))*(-1), SEEK_CUR);
비트맵 파일을 열어서 정보를 읽어야 하는데 현재 이 파일이 어떤 형식의 "이미지 헤더정보"를
사용하는지 알수 없기 때문에 구조체 정보를 읽기전에 4바이트(bcSize)를 읽어서 그 크기로
어떤 종류의 구조체가 사용되었는지 체크하기 위함입니다. 예를 들어, bcSize 값이 16이라면
해당 DIB 파일은 "이미지 헤더정보"를 BITMAPCOREHEADER 구조체로 사용했다고 생각하시면 됩니다.
FILE *p_file = fopen("tipssoft.bmp", "rb");
if(p_file != NULL){
// 파일의 끝으로 이동한다.
fseek(p_file, 0, SEEK_END);
// 마지막 위치가 파일의 크기이다.
int file_size = ftell(p_file);
// 파일의 처음으로 이동한다.
fseek(p_file, 0, SEEK_SET);
BITMAPFILEHEADER temp_header;
fread(&temp_header, sizeof(temp_header), 1, p_file);
if(temp_header.bfType == 0x4D42){
if(temp_header.bfSize == (UINT)file_size){
// 이 파일은 비트맵 파일임.
DWORD temp_size = 0;
// 이미지 헤더정보의 크기를 얻는다.
fread(&temp_size, sizeof(DWORD), 1, p_file);
if(temp_size == 16){
// 크기가 16이라면 BITMAPCOREHEADER 구조체가 사용되었다는 뜻이다. 따라서
// BITMAPCOREHEADER 크기만큼 읽어야하는데 이미 bcSize에 해당하는 정보를
// 읽었기 때문에 파일 포인트가 DWORD 만큼 진행했으니 이를 보정하기 위해서
// sizeof(DWORD)만큼 파일 포인터를 앞으로 이동시킨다.
fseek(p_file, long(sizeof(DWORD))*(-1), SEEK_CUR);
BITMAPCOREHEADER image_header;
fread(&image_header, sizeof(BITMAPCOREHEADER), 1, p_file);
// image_header의 값을 이용하여 이미지의 크기나 색상수를 확인한다.
fread(&image_header, sizeof(BITMAPCOREHEADER), 1, p_file);
// image_header의 값을 이용하여 이미지의 크기나 색상수를 확인한다.
}
} else {
// 이 파일은 비트맵 파일이 아님.
}
} else {
// 이 파일은 비트맵 파일이 아님.
}
fclose(p_file);
}
} else {
// 이 파일은 비트맵 파일이 아님.
}
} else {
// 이 파일은 비트맵 파일이 아님.
}
fclose(p_file);
}
2.2 BITMAPINFOHEADER 구조체
typedef struct tagBITMAPINFOHEADER{ // bmih
DWORD biSize; // 구조체의 크기 ( 40 바이트 )
LONG biWidth; // 이미지의 폭
LONG biHeight; // 이미지의 높이
WORD biPlanes; // 현재는 무조건 1 사용. ( 색상을 표현하는데 필요한 Plan의 갯수 )
WORD biBitCount; // 1 점을 표현하는데 필요한 비트수 ( 1, 4, 8, 16, 24, 32 )
DWORD biCompression; // 압축 형식 : 0 -> BI_RGB, 1 -> BI_RLE8, 2 -> BI_RLE4,
// 3 -> BI_BITFIELDS
// 윈도우즈 98 이상의 운영체제에서 사용되는 비트맵에서는
// BI_JPEG (4) 값이 추가적으로 사용됩니다.
DWORD biSizeImage; // 이미지 데이터의 크기
LONG biXPelsPerMeter; // X축 방향에서 미터당 출력점의 갯수
LONG biYPelsPerMeter; // Y축 방향에서 미터당 출력점의 갯수
DWORD biClrUsed; // 색상 테이블에 등록된 색상 인덱스의 수
DWORD biClrImportant; // 비트맵을 표현하는데 필요한 색상 인덱스의 수
} BITMAPINFOHEADER;
이 구조체는 압축된 형태의 비트맵형식을 표현할수 있으며 좀더 다양한 색상수를 제공합니다. 2.1에서와
동일한 방법으로 "이미지 헤더정보"에서 선두 4바이트를 읽어서 그 크기가 40바이트이면 해당 DIB 파일이
BITMAPINFOHEADER 구조체 형식을 사용했다고 판단하면 됩니다.
DWORD biSize; // 구조체의 크기 ( 40 바이트 )
LONG biWidth; // 이미지의 폭
LONG biHeight; // 이미지의 높이
WORD biPlanes; // 현재는 무조건 1 사용. ( 색상을 표현하는데 필요한 Plan의 갯수 )
WORD biBitCount; // 1 점을 표현하는데 필요한 비트수 ( 1, 4, 8, 16, 24, 32 )
DWORD biCompression; // 압축 형식 : 0 -> BI_RGB, 1 -> BI_RLE8, 2 -> BI_RLE4,
// 3 -> BI_BITFIELDS
// 윈도우즈 98 이상의 운영체제에서 사용되는 비트맵에서는
// BI_JPEG (4) 값이 추가적으로 사용됩니다.
DWORD biSizeImage; // 이미지 데이터의 크기
LONG biXPelsPerMeter; // X축 방향에서 미터당 출력점의 갯수
LONG biYPelsPerMeter; // Y축 방향에서 미터당 출력점의 갯수
DWORD biClrUsed; // 색상 테이블에 등록된 색상 인덱스의 수
DWORD biClrImportant; // 비트맵을 표현하는데 필요한 색상 인덱스의 수
} BITMAPINFOHEADER;
이 구조체는 압축된 형태의 비트맵형식을 표현할수 있으며 좀더 다양한 색상수를 제공합니다. 2.1에서와
동일한 방법으로 "이미지 헤더정보"에서 선두 4바이트를 읽어서 그 크기가 40바이트이면 해당 DIB 파일이
BITMAPINFOHEADER 구조체 형식을 사용했다고 판단하면 됩니다.
// 2.1과 동일한 코드는 생략하겠습니다.
if(temp_header.bfSize == (UINT)file_size){
// 이 파일은 비트맵 파일임.
DWORD temp_size = 0;
// 이미지 헤더정보의 크기를 얻는다.
fread(&temp_size, sizeof(DWORD), 1, p_file);
if(temp_size == 40){
// 크기가 40이라면 BITMAPINFOHEADER 구조체가 사용되었다는 뜻이다. 따라서
// BITMAPINFOHEADER 크기만큼 읽어야하는데 이미 biSize에 해당하는 정보를
// 읽었기 때문에 파일 포인트가 DWORD 만큼 진행했으니 이를 보정하기 위해서
// sizeof(DWORD)만큼 파일 포인터를 앞으로 이동시킨다.
fseek(p_file, long(sizeof(DWORD))*(-1), SEEK_CUR);
if(temp_header.bfSize == (UINT)file_size){
// 이 파일은 비트맵 파일임.
DWORD temp_size = 0;
// 이미지 헤더정보의 크기를 얻는다.
fread(&temp_size, sizeof(DWORD), 1, p_file);
if(temp_size == 40){
// 크기가 40이라면 BITMAPINFOHEADER 구조체가 사용되었다는 뜻이다. 따라서
// BITMAPINFOHEADER 크기만큼 읽어야하는데 이미 biSize에 해당하는 정보를
// 읽었기 때문에 파일 포인트가 DWORD 만큼 진행했으니 이를 보정하기 위해서
// sizeof(DWORD)만큼 파일 포인터를 앞으로 이동시킨다.
fseek(p_file, long(sizeof(DWORD))*(-1), SEEK_CUR);
BITMAPINFOHEADER image_header;
fread(&image_header, sizeof(BITMAPINFOHEADER), 1, p_file);
// image_header의 값을 이용하여 이미지의 크기나 색상수를 확인한다.
fread(&image_header, sizeof(BITMAPINFOHEADER), 1, p_file);
// image_header의 값을 이용하여 이미지의 크기나 색상수를 확인한다.
}
} else {
// ... 생략 ...
} else {
// ... 생략 ...
2.3 BITMAPV4HEADER 구조체
typedef struct {
DWORD bV4Size;
LONG bV4Width;
LONG bV4Height;
WORD bV4Planes;
WORD bV4BitCount;
DWORD bV4V4Compression;
DWORD bV4SizeImage;
LONG bV4XPelsPerMeter;
LONG bV4YPelsPerMeter;
DWORD bV4ClrUsed;
DWORD bV4ClrImportant;
DWORD bV4RedMask;
DWORD bV4GreenMask;
DWORD bV4BlueMask;
DWORD bV4AlphaMask;
DWORD bV4CSType;
CIEXYZTRIPLE bV4Endpoints;
DWORD bV4GammaRed;
DWORD bV4GammaGreen;
DWORD bV4GammaBlue;
} BITMAPV4HEADER, FAR *LPBITMAPV4HEADER, *PBITMAPV4HEADER;
DWORD bV4Size;
LONG bV4Width;
LONG bV4Height;
WORD bV4Planes;
WORD bV4BitCount;
DWORD bV4V4Compression;
DWORD bV4SizeImage;
LONG bV4XPelsPerMeter;
LONG bV4YPelsPerMeter;
DWORD bV4ClrUsed;
DWORD bV4ClrImportant;
DWORD bV4RedMask;
DWORD bV4GreenMask;
DWORD bV4BlueMask;
DWORD bV4AlphaMask;
DWORD bV4CSType;
CIEXYZTRIPLE bV4Endpoints;
DWORD bV4GammaRed;
DWORD bV4GammaGreen;
DWORD bV4GammaBlue;
} BITMAPV4HEADER, FAR *LPBITMAPV4HEADER, *PBITMAPV4HEADER;
이 구조체는 윈도우즈 95 나 윈도우즈 NT 4.0에서 추가된 비트맵 특성을 반영하기 위해서 추가된
"이미지 헤더정보" 구조체 입니다.
"이미지 헤더정보" 구조체 입니다.
2.4 BITMAPV5HEADER 구조체
typedef struct {
DWORD bV5Size;
LONG bV5Width;
LONG bV5Height;
WORD bV5Planes;
WORD bV5BitCount;
DWORD bV5Compression;
DWORD bV5SizeImage;
LONG bV5XPelsPerMeter;
LONG bV5YPelsPerMeter;
DWORD bV5ClrUsed;
DWORD bV5ClrImportant;
DWORD bV5RedMask;
DWORD bV5GreenMask;
DWORD bV5BlueMask;
DWORD bV5AlphaMask;
DWORD bV5CSType;
CIEXYZTRIPLE bV5Endpoints;
DWORD bV5GammaRed;
DWORD bV5GammaGreen;
DWORD bV5GammaBlue;
DWORD bV5Intent;
DWORD bV5ProfileData;
DWORD bV5ProfileSize;
DWORD bV5Reserved;
} BITMAPV5HEADER, FAR *LPBITMAPV5HEADER, *PBITMAPV5HEADER;
DWORD bV5Size;
LONG bV5Width;
LONG bV5Height;
WORD bV5Planes;
WORD bV5BitCount;
DWORD bV5Compression;
DWORD bV5SizeImage;
LONG bV5XPelsPerMeter;
LONG bV5YPelsPerMeter;
DWORD bV5ClrUsed;
DWORD bV5ClrImportant;
DWORD bV5RedMask;
DWORD bV5GreenMask;
DWORD bV5BlueMask;
DWORD bV5AlphaMask;
DWORD bV5CSType;
CIEXYZTRIPLE bV5Endpoints;
DWORD bV5GammaRed;
DWORD bV5GammaGreen;
DWORD bV5GammaBlue;
DWORD bV5Intent;
DWORD bV5ProfileData;
DWORD bV5ProfileSize;
DWORD bV5Reserved;
} BITMAPV5HEADER, FAR *LPBITMAPV5HEADER, *PBITMAPV5HEADER;
이 구조체는 윈도우즈 98 이상 또는 윈도우즈 NT 5.0 이상에서 추가된 비트맵 특성을 반영하기 위해서 추가된
"이미지 헤더정보" 구조체 입니다.
2.3 과 2.4 항목에 있는 두 구조체에 추가된 정보는 실제적으로 비트맵 프로그램에서 일반적으로 다루는 항목들이
아니기 때문에 거의 사용하지 않고 그 내용이 단순하지 않아서 이 강좌에서는 구조체의 형식만 언급하도록 하겠습니다.
"이미지 헤더정보" 구조체 입니다.
2.3 과 2.4 항목에 있는 두 구조체에 추가된 정보는 실제적으로 비트맵 프로그램에서 일반적으로 다루는 항목들이
아니기 때문에 거의 사용하지 않고 그 내용이 단순하지 않아서 이 강좌에서는 구조체의 형식만 언급하도록 하겠습니다.
현재 비트플랜(Bit Plan)값들이 1만 제공되는 이유는 비트 플랜이라는 개념이 예전 EGA/VGA 초창기
시절 16색상을 표현하기 위해 사용하던 개념입니다. 16색상을 표현하는데 4개의 비트플랜을 사용했습니다.
하지만, 윈도우즈 시스템이 일반화되면서 윈도우즈 시스템은 16색을 포기한지 오래되었으며 안전모드도
최소 256색 이상에서 제공되기 때문에 16색은 기준색에서 소외되기 시작했으며 현재는 거의
사용되지 않습니다. 따라서 비트플랜값은 대부분 1만 사용하신다고 보시면 됩니다. 가끔 예전에
만들었던 16색 비트맵 파일을 사용하는 경우, 비트플랜값이 4가 나올수는 있지만 이런경우는 이제
예외로 포함시킬 필요는 없을것 같습니다. ^^;;
현재 "이미지 헤더정보" 구조체들이 비트플랜 항목을 가지고 있는 이유는 이전에 만들어진 비트맵파일들과
호환성을 유지하기 위해서일뿐 다른 의미는 없습니다.
다음 강좌에서 계속하겠습니다.
* 이 자료를 퍼 가셔서 타사이트나 블로그에 게재 시 출처를 명시해 주시기 바랍니다.
본 사이트에 게재된 모든 내용 및 자료는 상업적인 용도로 이용할 수 없습니다.
본 사이트에 게재된 모든 내용 및 자료는 상업적인 용도로 이용할 수 없습니다.
이 자료들은 저희 사이트에서 제공하는 [ 알짜배기 ] 프로그램을 이용하시면 좀더 편리하게 볼수 있습니다.
알짜배기 프로그램 받기 : http://www.tipssoft.com/bulletin/tb.php/QnA/8406
이 강좌에서는 Step2에 이어서 DIB 형식의 비트맵 파일이 어떻게 구성되어 있는지 알아보도록 하겠습니다.
Step2 강좌에서는 "이미지 헤더" 정보가 저장되는 형식에 대해서 설명을 했습니다. 이 강좌에서는
"이미지 헤더" 다음에 위치하는 "색상 테이블(팔레트 정보)"와 그 다음 위치에 배열되는 "점단위의 실제
이미지 정보"에 대해서 알아보도록 하겠습니다.
Step2 강좌에서는 "이미지 헤더" 정보가 저장되는 형식에 대해서 설명을 했습니다. 이 강좌에서는
"이미지 헤더" 다음에 위치하는 "색상 테이블(팔레트 정보)"와 그 다음 위치에 배열되는 "점단위의 실제
이미지 정보"에 대해서 알아보도록 하겠습니다.
3. 색상 테이블 정보 - 팔레트 정보
"색상 테이블" 정보는 과거 출력장치가 기계적인 특성이나 메모리의 한계성 때문에 제한된 수의 색상만
출력할수 있었는데, 이런 제한된 색상수에서도 좀더 효과적인 색상을 출력할수 있도록 필요한 색상을
자신이 선택할수 있는 기술이였습니다. 즉, 16가지 색상을 사용할수 있는 환경이라면 이 16가지 색상이
고정된 것이 아니라 사용자가 많은 색상들중에서 16가지 색상을 선택해서 "색상 테이블"을 만들고
이 16가지 색상을 사용할수 있다는 뜻입니다.
출력할수 있었는데, 이런 제한된 색상수에서도 좀더 효과적인 색상을 출력할수 있도록 필요한 색상을
자신이 선택할수 있는 기술이였습니다. 즉, 16가지 색상을 사용할수 있는 환경이라면 이 16가지 색상이
고정된 것이 아니라 사용자가 많은 색상들중에서 16가지 색상을 선택해서 "색상 테이블"을 만들고
이 16가지 색상을 사용할수 있다는 뜻입니다.
따라서 "이미지 헤더" 정보에서 BitCount 값이 4 또는 8인 경우에는 해당 비트맵이 "색상 테이블"을 사용
하는지 체크해야합니다. ( High Color[16 비트 색상], True Color[24, 32 비트 색상]에서는 색상이 거의
대부분 지원되기 때문에 "색상 테이블"이 사용되지 않습니다.)
"색상 테이블"은 크게 3가지 형식로 구성되는데 RGBQUAD 구조체 형식, RGBTRIPLE 구초제 형식 그리고
사용하지 않는 형식입니다.
하는지 체크해야합니다. ( High Color[16 비트 색상], True Color[24, 32 비트 색상]에서는 색상이 거의
대부분 지원되기 때문에 "색상 테이블"이 사용되지 않습니다.)
"색상 테이블"은 크게 3가지 형식로 구성되는데 RGBQUAD 구조체 형식, RGBTRIPLE 구초제 형식 그리고
사용하지 않는 형식입니다.
3.1 RGBQUAD 구조체
typedef struct tagRGBQUAD { // rgbq
BYTE rgbBlue; // 파란색
BYTE rgbGreen; // 녹색
BYTE rgbRed; // 붉은색
BYTE rgbReserved; // 예약 영역 ( 일반적으로 0 값 )
} RGBQUAD;
BYTE rgbBlue; // 파란색
BYTE rgbGreen; // 녹색
BYTE rgbRed; // 붉은색
BYTE rgbReserved; // 예약 영역 ( 일반적으로 0 값 )
} RGBQUAD;
일반적으로 윈도우즈에서 사용하는 비트맵은 RGBQUAD 구조체 형식으로 "색상 테이블"이 저장됩니다.
따라서 해당 비트맵이 "색상 테이블"를 사용한다면 현재 비트맵의 색상수만큼 위 구조체 형태의
정보가 "이미지 헤더"정보 다음에 위치합니다.
따라서 해당 비트맵이 "색상 테이블"를 사용한다면 현재 비트맵의 색상수만큼 위 구조체 형태의
정보가 "이미지 헤더"정보 다음에 위치합니다.
윈도우즈에서 사용하는 비트맵이라는 것은 "이미지 헤더" 정보가 BITMAPINFOHEADER 구조체 형식으로
저장되었는지 체크해보면 알수 있고, BITMAPINFOHEADER 구조체의 biBitCount 값이 4 또는 8 이라면
"색상 테이블"이 사용된다고 판단하시면 됩니다.
저장되었는지 체크해보면 알수 있고, BITMAPINFOHEADER 구조체의 biBitCount 값이 4 또는 8 이라면
"색상 테이블"이 사용된다고 판단하시면 됩니다.
3.2 RGBTRIPLE 구조체
typedef struct tagRGBTRIPLE { // rgbt
BYTE rgbtBlue; // 파란색
BYTE rgbtGreen; // 녹색
BYTE rgbtRed; // 붉은색
} RGBTRIPLE;
BYTE rgbtBlue; // 파란색
BYTE rgbtGreen; // 녹색
BYTE rgbtRed; // 붉은색
} RGBTRIPLE;
IBM OS/2 라는 운영체제에서 사용하는 비트맵은 RGBTRIPLE 구조체 형식으로 "색상 테이블"이
저장됩니다. 따라서 해당 비트맵이 "색상 테이블"를 사용한다면 현재 비트맵의 색상수만큼
위 구조체 형태의 정보가 "이미지 헤더"정보 다음에 위치합니다.
저장됩니다. 따라서 해당 비트맵이 "색상 테이블"를 사용한다면 현재 비트맵의 색상수만큼
위 구조체 형태의 정보가 "이미지 헤더"정보 다음에 위치합니다.
3.1 에서처럼 "이미지 헤더"가 BITMAPCOREHEADER 구초제 형식으로 저장되어있다면 IBM OS/2 형식의
비트맵이라고 판단하시면 됩니다.
비트맵이라고 판단하시면 됩니다.
3.3 색상 테이블 사용하지 않음
BitCount 가 16, 24, 32인 경우 "색상 테이블"이 필요없기 때문에 "색상 테이블"정보가
"이미지 헤더" 다음에 존재하지 않습니다.
"이미지 헤더" 다음에 존재하지 않습니다.
4. 점단위의 실제 이미지 정보
"색상 테이블" 정보 다음위치에 실제 이미지 정보가 저장되어 있습니다. 하지만, 이 순서가 꼭 지켜진다고
보장할수 없기 때문에 이미지 파일의 가장 처음에 위치하는 "파일 정보"에서 bfOffBits 값을 체크하여
"실제 이미지 정보"의 위치를 판단하는게 좋습니다. ( 가끔씩 "색상 테이블"의 크기가 변칙적으로 사용되거나
"색상 테이블" 영역에 다른 용도의 정보가 저장되는 경우도 있기 때문입니다. )
보장할수 없기 때문에 이미지 파일의 가장 처음에 위치하는 "파일 정보"에서 bfOffBits 값을 체크하여
"실제 이미지 정보"의 위치를 판단하는게 좋습니다. ( 가끔씩 "색상 테이블"의 크기가 변칙적으로 사용되거나
"색상 테이블" 영역에 다른 용도의 정보가 저장되는 경우도 있기 때문입니다. )
이미지 정보는 줄단위로 저장되며 각 줄당바이트수는 아래와 같이 계산할수 있습니다.
줄당바이트수 = ( ( "폭" * BitCount + 7 ) / 8 + 3) / 4;
위와 같이 공식이 복잡한 이유는 2 또는 4 비트 색상의 비트맵인 경우, 한줄에 사용된 점의 갯수가 8로
나누어 떨어지지 않는 경우 때문에 그렇습니다. 예를들어, 4비트 색상의 경우 1점이 4비트씩 공간을
차지하는데 한줄에 사용된 점의 갯수가 2, 4, 6,... 개라면 8로 나누어 떨어지지만 3, 5, 7, ... 개라면
나누어 떨어지지 않기 때문에 모든 BitCount에 따른 일반화된 공식을 적용하기 위해서 위와 같이 복잡한
공식이 나오게 된것입니다.
나누어 떨어지지 않는 경우 때문에 그렇습니다. 예를들어, 4비트 색상의 경우 1점이 4비트씩 공간을
차지하는데 한줄에 사용된 점의 갯수가 2, 4, 6,... 개라면 8로 나누어 떨어지지만 3, 5, 7, ... 개라면
나누어 떨어지지 않기 때문에 모든 BitCount에 따른 일반화된 공식을 적용하기 위해서 위와 같이 복잡한
공식이 나오게 된것입니다.
사실, 16, 24, 32 비트 색상의 경우, 그 값자체가 8의 배수이기 때문에 위와 같은 복잡한 공식을
사용할 필요는 없습니다. 하지만 하위 호환성을 유지하기 위해서 계산할때 위 공식을 사용하는게 좋습니다.
사용할 필요는 없습니다. 하지만 하위 호환성을 유지하기 위해서 계산할때 위 공식을 사용하는게 좋습니다.
5. RLE4, RLE8 압축 방식 - Run Length Encoding
비트맵 파일은 아주 간단한 방식의 압축방법을 제공하는데 그 방법이 RLE(Run Length Encoding) 방식입니다.
이 방식에 대해서 간단하게 설명하면 아래와 같이 정보가 있다고 가정하겠습니다.
이 방식에 대해서 간단하게 설명하면 아래와 같이 정보가 있다고 가정하겠습니다.
11111111111122222222222333333333
1이 12개 2가 11개 3이 9개가 있습니다. 각 정보가 1바이트씩 차지한다면 32바이트의 공간을 차지하게
됩니다. 하지만, 숫자가 반복한다는 것을 이용하여 연속된 정보로 1 12 2 11 3 9 라고 표현하고 연속된
두개의 정보가 1개의 쌍으로 정보를 표현하도록 한다면 6바이트로 위 정보를 모두 표현할수 있습니다.
됩니다. 하지만, 숫자가 반복한다는 것을 이용하여 연속된 정보로 1 12 2 11 3 9 라고 표현하고 연속된
두개의 정보가 1개의 쌍으로 정보를 표현하도록 한다면 6바이트로 위 정보를 모두 표현할수 있습니다.
좀더 바이트를 줄인다면 실제로 반복되는 정보가 16개 이상 나올활률이 낮기 때문에 16개 이상 반복
하더라도 16개까지만 반복을 처리하도록 한다면 해당 정보는 4비트(2^4 = 16)에 저장할수 있고 6바이트로
표현하던 정보를 아래와 같이 3바이트로 줄여서 표현할수 있습니다.
0x1C 0x2B 0x39 ( 16진법으로 표현했습니다. B -> 11, C -> 12 입니다. )
RLE8은 8비트 형식의 이미지에 사용하던 압축방법이고 RLE4는 4비트 형식의 이미지에 사용하는
압축방법입니다. RLE8에 대해서 설명을 드리면 RLE8이 8비트 형식의 이미지를 다루기 때문에 한점이
1 바이트를 차지하게 됩니다.
압축방법입니다. RLE8에 대해서 설명을 드리면 RLE8이 8비트 형식의 이미지를 다루기 때문에 한점이
1 바이트를 차지하게 됩니다.
0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x02,0x02,0x022,0x02,0x02,0x02,
0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03
0x02,0x02,0x02,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03
위에서 설명한것처럼 0x01이 12개 0x02가 11개 0x03이 9개가 있습니다. RLE 형식은 반복된 횟수가
먼저나오고 그 뒤에 반복된 숫자가 나오기 때문에 위 정보를 아래와 같이 표현합니다.
먼저나오고 그 뒤에 반복된 숫자가 나오기 때문에 위 정보를 아래와 같이 표현합니다.
0x0C 0x01 0x0B 0x02 0x09 0x03
RLE의 형식에서 반복된 횟수가 먼저 나오도록 한 이유는 압축방법상 횟수가 0이 나올수 없기 때문에
0x00라는 값이 나올수 없다는것을 이용하여 반복횟수에 0x00가 명시되면 이 정보를 다른 용도로
사용하기 위함입니다. 즉,
0x00라는 값이 나올수 없다는것을 이용하여 반복횟수에 0x00가 명시되면 이 정보를 다른 용도로
사용하기 위함입니다. 즉,
0x00 0x00 이라고 명시되면 이 정보는 이미지상에서 다음라인으로 정보가 넘어감을 의미하고
0x00 0x01 이라고 명시되면 이 정보는 이미지의 끝을 의미하고
0x00 0x02 이라고 명시되면 이 정보는 현재 위치에서 다른 위치로 이동함을 의미합니다. 이 경우는
그 다음 두개의 쌍을 다음 위치의 좌표로 사용하며 동일한 색상의 정보가 많이 반복하는
경우에 그것을 효과적으로 표현하기 위함입니다.
0x00 0x01 이라고 명시되면 이 정보는 이미지의 끝을 의미하고
0x00 0x02 이라고 명시되면 이 정보는 현재 위치에서 다른 위치로 이동함을 의미합니다. 이 경우는
그 다음 두개의 쌍을 다음 위치의 좌표로 사용하며 동일한 색상의 정보가 많이 반복하는
경우에 그것을 효과적으로 표현하기 위함입니다.
0x00 0x02 0x20 0x05
라고 표현하면 현재 색상이 이미지상의 좌표(0x20, 0x05)까지 반복됨을 의미합니다.
이러한 압축방법은 압축알고리즘도 매우 간단하고 표현하기도 쉽습니다. 하지만, 색상이 점단위로 달라진다면
오히려 압축을 사용하지 않는게 더 좋습니다. ㅡ.ㅡ;;
이미지 자체가 단순하지 않은 사진이나 그라데이션형태로 구성되어있다면 이런 압축을 선택하지 않는게
더 좋습니다. 따라서 요즘은 이 압축방법을 거의 사용하지 않습니다. 보통 웹이나 일반 응용 프로그램에서도
Gif 나 Jpeg 파일을 사용하기 편하게 되면서 압축이 필요하다면 이 방법을 사용하지 비트맵에서 제공하는
압축방법을 사용하지는 않습니다.
더 좋습니다. 따라서 요즘은 이 압축방법을 거의 사용하지 않습니다. 보통 웹이나 일반 응용 프로그램에서도
Gif 나 Jpeg 파일을 사용하기 편하게 되면서 압축이 필요하다면 이 방법을 사용하지 비트맵에서 제공하는
압축방법을 사용하지는 않습니다.
'프로그래밍' 카테고리의 다른 글
VS2010 프로젝트속성 디렉토리 한방에추가하기 (0) | 2013.06.18 |
---|---|
SVN 사용방법및 관리 (0) | 2013.06.10 |
BMP 구조4 (0) | 2013.05.14 |
스마트 포인터 (0) | 2013.05.14 |
Hexagon (0) | 2013.05.14 |