==================================Outline====================================
비트맵 구조체
----------------------------------------------------------------------------
비트맵 구조체
크기가 가로 400픽셀, 세로 400픽셀인 비트맵 파일을 임의로 생성하여 비트맵파일에 대해서 알아보기로 하자.
![](https://t1.daumcdn.net/cfile/tistory/23759B38563B5E5B06)
![](https://t1.daumcdn.net/cfile/tistory/22179038563B5E5C23)
각 픽셀이 RGB로 표현되기 때문에 이 비트맵 파일의 용량은 (400 * 400) * 3이고, 54byte는 헤더파일이다. 헤더 파일은 실제내용을 간추린 정보를 제공하는데 이것을 ‘오버 헤더’라고 한다.
![](https://t1.daumcdn.net/cfile/tistory/2370FA38563B5E5E30)
비트맵 파일은 픽셀 단위로 데이터를 저장한다. 1byte(8bits)에는 한가지 색에 대한 정보를 가지고 있다. 1픽셀은 3byte로 구성되는데, 각 바이트는 빨(Red), 녹(Green), 파(Blue)로 이루어져 있다.
**빛의 3원색: 빨강, 녹색, 파랑
**색의 3원색: 자주, 노랑, 청록
![](https://t1.daumcdn.net/cfile/tistory/26203D38563B5E6023)
** 빛은 섞을수록 밝아지고 색은 섞을수록 어두워진다.
위에서 만든 비트맵 파일을 헥사뷰를 사용하여 출력해본다. 54byte가 'FF'가 아닌 값으로 표시되고 있음을 알 수 있다.
![](https://t1.daumcdn.net/cfile/tistory/23338838563B5E6221)
54Byte는 비트맵 파일의 헤더부분이며 비트맵 파일에 대한 정보를 담고 있다. 비트맵 파일의 구조체를 살펴보도록 하자.
![](https://t1.daumcdn.net/cfile/tistory/262BF538563B5E6202)
/* 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;
![](https://t1.daumcdn.net/cfile/tistory/227A7938563B5E6430)
/* 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;
비트맵 파일 구조체를 참고하여 구조체 멤버들을 출력해보자.
![](https://t1.daumcdn.net/cfile/tistory/212A893A563B5E6512)
400 * 400 크기의 BMP파일의 경우 한 픽셀당 3byte를 차지하고 그 값을 red, greeb, blue의 정도는 8bit(256) 나누어 표시할 수 있다. 파일의 총 크기는 480054byte이고 54byte는 헤더파일임으로 파일의 시작점에서 54byte 떨어진 지점부터의 데이터를 조작함으로써 BMP파일을 변형시킬 수 있다.
BMP파일을 조작하여 여러 가지 색깔로 변형시켜보자.
**BMP이미지를 수정하여 원본에 덮어 쓰도록 하자.
각 색에 대한 출력 정보는 0 ~ FF로 표현된다. '0'이 가장 낮은 단계이며 'FF'가 가장 높은 단계이다. 가로 픽셀이 400, 세로 픽셀이 400인 비트맵 구조체에서 가로 한 줄의 용량은 400 * 3이다. 좌측 상단에서 우측 하단까지 'for문'을 사용하여 데이터의 값을 입력할 값을 설정해주면 된다.
각 픽셀의 첫 번째 바이트는 blue, 두 번째 바이트는 green, 세 번째 바이트는 red이다. 비트맵 파일의 정보를 수정하여 색이 어떻게 바뀌는지 출력해보자.
![](https://t1.daumcdn.net/cfile/tistory/273ED73A563B5E6724)
![](https://t1.daumcdn.net/cfile/tistory/2551CD3A563B5E6818)
![](https://t1.daumcdn.net/cfile/tistory/2218E23A563B5E6A0A)
![](https://t1.daumcdn.net/cfile/tistory/257FEA3A563B5E6C31)
![](https://t1.daumcdn.net/cfile/tistory/231ED73A563B5E6E13)
소스 코드는 아래와 같다.
/*** 소스 ***/
#include <stdio.h
>#include <fcntl.h
>#include <windows.h
>int main(
int iNum,
char * cpArr[])
{
int iRtn;
int iFd;
BITMAPFILEHEADER stBFHead;
BITMAPINFOHEADER stBIHead;
char cBuf[
16*
16];
unsigned char * ucpBuf;
unsigned int uiCntX;
unsigned int uiCntY;
iFd
= open(cpArr[
1], O_RDWR
|O_BINARY);
if(iFd
== 0)
{
printf(
"파일을 열 수 없습니다.\n");
return -
1;
}
iRtn
= read(iFd,
&stBFHead,
sizeof(BITMAPFILEHEADER));
if(iRtn
== 0)
{
printf(
"파일을 읽을 수 없습니다.\n");
close(iFd);
return -
1;
}
if(
0x4D
42 !
= (stBFHead.bfType) )
{
printf(
"BMP파일이 아닙니다.\n");
close(iFd);
return -
1;
}
iRtn
= lseek(iFd,
sizeof(BITMAPFILEHEADER), SEEK_SET);
if(iRtn !
= sizeof(BITMAPFILEHEADER) )
{
printf(
"읽어들일 부분이 잘못 지정되었습니다.\n");
close(iFd);
return -
1;
}
iRtn
= read(iFd,
&stBIHead,
sizeof(BITMAPINFOHEADER));
if(iRtn
== 0)
{
printf(
"INFO헤더가 존재하지 않습니다.\n");
close(iFd);
return -
1;
}
ucpBuf
= (
void *)malloc(stBIHead.biSizeImage);
if(
0 == ucpBuf)
{
printf(
"사용 가능한 메모리가 부족합니다.\n");
close(iFd);
return -
1;
}
lseek(iFd,
sizeof(BITMAPFILEHEADER)+
sizeof(BITMAPINFOHEADER), SEEK_SET);
iRtn
= read(iFd, ucpBuf, stBIHead.biSizeImage);
if(iRtn
== 0)
{
printf(
"데이터를 읽을 수 없습니다.\n");
close(iFd);
free(ucpBuf);
return -
1;
}
for(uiCntY
=0; uiCntY
< stBIHead.biHeight; ++uiCntY)
{
for(uiCntX
=0; uiCntX
< stBIHead.biWidth; ++uiCntX)
{
ucpBuf[uiCntY * (stBIHead.biWidth *
3) + (uiCntX *
3) +
0]
= 0;
//blue ucpBuf[uiCntY * (stBIHead.biWidth *
3) + (uiCntX *
3) +
1]
= 0;
//green ucpBuf[uiCntY * (stBIHead.biWidth *
3) + (uiCntX *
3) +
2]
= 0xFF;
//red }
}
lseek(iFd,
54, SEEK_SET);
iRtn
= write(iFd, ucpBuf, stBIHead.biSizeImage);
if(iRtn
== 0)
{
printf(
"데이터 쓰기에 실패 했습니다.\n");
close(iFd);
free(ucpBuf);
return -
1;
}
lseek(iFd,
54, SEEK_SET);
iRtn
= read(iFd, cBuf,
16*
16);
close(iFd);
free(ucpBuf);
return 0;
}