BMP 파일을 읽고 쓰는 방법
코딩과 교육/전문코딩 2007. 11. 23. 16:46
비트맵포맷의 구조는 다음과 같다.
기본적으로 디바이스 독립적 영상파일 저장 표준규격은 JPEG, GIF, BMP, TIFF, PCX, PGM 등의 여러 규격이 존재한다. 많이 사용하는 영상 포맷들은 압축 알고리즘을 사용하여 작은 크기로 변환시킨다.
BMP 파일포맷은 압축을 수행하지 않아 파일 크기가 커지는 반면, 파일의 구조가 가장 간단하다.
## 비타맵 파일에 대한 정보(파일헤드)
비트맵파일인지 아닌지를 확인하는 변수가 bfType 이다. BMP파일의 첫 두 바이트는 항상 "BM" 문자가 저장된다. bfOffBits 는 파일 시작부분에서 실제 영상데이터가 존재하는 위치까지 바이트 단위의 거리를 나타낸다. WORD 는 unsigned short, DWORD 는 unsigned long 으로 정의되어 있다.
## 영상 자체에 대한 정보(영상헤드)
비트맵 영상에 대한 크기, 흑백, 칼러정보, 팔레트 크기 정보등을 저장하기 위한 구조체 변수이다.
중요한 정보는 영상파일의 크기를 나타내는 변수 biHeight, biWidth 와 흑백과 칼라여부를 나타내는 biBitCount, 팔레트 크기를 나타내는 biClrUsed 등이다.
biBitCount 가 8이면 흑백영상이거나 2^8 = 256 칼라의 영상이다. 24라면 트루칼라, 16이면 2^16 개의 칼라를 사용하는 영상이다.
## 팔레트
팔레트는 인덱스에 의한 칼라값을 저장하기 위한 구조체이다. 이 구조체를 사용, 팔레트 수만큼 배열을 할당, 저장한다. 256 칼라모드의 경우 팔레트배열 크기는 256이 되고, 16비트 칼라영상의 경우 2^16 개의 팔레트배열 크기를 가지게 된다.
## DIB 와 DDB
DDB 는 Device Dependent Bitmat 의 약자로 디바이스 종속적인 비트맵이고, DIB 는 Device Independent Bitmat 의 약자로 디바이스에 독립적인 비트맵이다. 다시말해서 DIB 는 어느 기종에서 보든 즉, PC 거나, MAC 이거나, 아니면 핸드폰으로 보거나, PDA로 보거나 상관없이 같은 그림과 칼라가 나온다는 의미이다.
## BMP 에서 DIB 사용시 주의사항
비트맵 영상이 저장될 때는 이미지가 거꾸로 저장된다. 즉, 비트맵에서 영상데이타를 영상처리를 위해 사용할 배열로 다시 저장할 때는 거꾸로 뒤집어서 저장해 주어야 한다.
영상의 가로길이는 4바이트의 배수가 된다.
비트맵은 메모리 저장시 가로줄의 크기가 항상 4바이트의 배수가 되어야 한다. 실제 사용 영상의 가로길이는 4바이트의 배수가 아닐 수 있다. 이런 경우 4의 배수바이트로 바꾸어 저장한다. 즉 78 x 80 크기의 BMP 파일은 가로 픽셀 78이 78byte 로 4의 배수가 아니므로 80byte 로 만들고 나머지 2byte 는 쓰레기값으로 처리된다. 실제 저장되는 메모리는 80 x 80 으로 저장된다.
아래는 간단한 소스이다.
#include <stdio.h>
#include <windows.h>
#define WIDTHBYTES(bits) (((bits)+31)/32*4)
#define BYTE unsigned charint main()
{
FILE *infile;
infile = fopen("ImgBW.bmp", "rb");
if(infile==NULL) {printf("No Image File"); return;}// BMP Header Information
BITMAPFILEHEADER hf;
BITMAPINFOHEADER hInfo;
fread(&hf, sizeof(BITMAPFILEHEADER),1,infile);
if(hf.bfType!=0x4D42) exit(1);
fread(&hInfo,sizeof(BITMAPINFOHEADER),1,infile);
if(hInfo.biBitCount!=8) {printf("Bad File Format!!"); return;}// BMP Pallete
RGBQUAD hRGB[256];
fread(hRGB, sizeof(RGBQUAD), 256, infile);// Memory
BYTE *lpImg = new BYTE [hInfo.biSizeImage];
fread(lpImg, sizeof(char), hInfo.biSizeImage, infile);
fclose(infile);int rwsize = WIDTHBYTES(hInfo.biBitCount * hInfo.biWidth);
// Reversed Image
for(int i=0; i<hInfo.biHeight; i++) {
for (int j=0; j<hInfo.biWidth; j++)
lpImg[i*rwsize+j] = 255 - lpImg[i*rwsize+j];
}// Image Output
FILE *outfile = fopen("ImgBWR.bmp", "wb");
fwrite(&hf, sizeof(char), sizeof(BITMAPFILEHEADER), outfile);
fwrite(&hInfo, sizeof(char), sizeof(BITMAPINFOHEADER), outfile);
fwrite(hRGB, sizeof(RGBQUAD), 256, outfile);
fwrite(lpImg, sizeof(char), hInfo.biSizeImage, outfile);
fclose(outfile);delete [] lpImg;
}
256 회색 이미지를 반전 처리한