비트맵(.bmp) 파일 구조

2022. 1. 6. 16:22C&C++

비트맵의 파일구조는 아래와 같다.

BitmapFileHeader
BitmapInfoHeader
이미지 데이터

 

BitmapFileHeader와 BitmapInfoHeader의 구조

typedef struct tagBITMAPFILEHEADER {
	WORD bfType; //파일의 타입. 문자 BM이 저장된다.
	DWORD bfSize; //파일의 사이즈
	WORD bfReserved1;
	WORD bfReserved2;
	DWORD bfOffBits; //bitmap bits(실제 이미지 데이터)가 시작되는 지점
} BITMAPFILEHEADER, *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

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, * LPBITMAPINFOHEADER, * PBITMAPINFOHEADER;

파일의 규격에 있어서는 신기하게도 구조체의 패딩 규칙이 적용되지 않는다. (pragma pack)

따라서 BITMAPFILEHEADER의 크기는 14 Byte, BITMAPINFOHEADER의 크기는 40 Byte가 된다.

 

이 두가지 구조체 이후에 실제 이미지 데이터가 들어가게 된다.

이미지 데이터는 상하반전된 상태로 들어간다. 

 

이러한 헤더를 이용하여 알파블렌딩을 구현해보자.

sample.bmp와 sample2.bmp의 이미지데이터를 반씩 섞어서, 두 이미지가 마치 섞인 것 처럼 보이게된다.

코드에서 BITMAPFILEHEADER의 bfOffBits를 이용하여 이미지 데이터가 시작되는 부분을 찾고,

그 이후의 데이터를 반씩 합쳐서 알파블렌딩을 구현했다.

#include <iostream>

int main()
{
	//이미지 파일 두 개 읽어오기 
	FILE* fp1;
	FILE* fp2;
	unsigned char* s1;
	unsigned char* s2;
	int fileSize;
	int dataStartPosition;

	fopen_s(&fp1, "sample.bmp", "rb");
	fopen_s(&fp2, "sample2.bmp", "rb");
	if (fp1 == nullptr || fp2 == nullptr)
		exit(1);

	//파일 내부의 헤더 두개와 비트 malloc으로 저장하기

	//크기 구하기
	fseek(fp1, 0, SEEK_END);
	fileSize = ftell(fp1);
	fseek(fp1, 0, SEEK_SET);
	//할당
	s1 = (unsigned char*)malloc(fileSize);
	s2 = (unsigned char*)malloc(fileSize);
	if (s1 == nullptr || s2 == nullptr)
		exit(1);
	//파일 통째로 저장
	fread_s(s1, fileSize, 1, fileSize, fp1);
	fread_s(s2, fileSize, 1, fileSize, fp2);
	//읽기 끝내기
	fclose(fp1);
	fclose(fp2);

	//헤더가 어디서부터 어디까지인지 가져오기 -> 비트맵파일헤더 offset값으로
	dataStartPosition = s1[10];
	//s1에다가 결과값 저장 : 헤더는 그대로 넣고 내용은 절반씩 더해서 넣기
	for (int i = dataStartPosition; i < fileSize; i++)
	{
		s1[i] = (s1[i] >> 1) + (s2[i] >> 1);
	}

	//이미지 파일 생성
	fopen_s(&fp1, "alpha.bmp", "wb");
	if (fp1 == nullptr) exit(1);
	//파일에 작성
	fwrite(s1, 1, fileSize, fp1);
	//종료
	fclose(fp1);
	return 0;
}

'C&C++' 카테고리의 다른 글

[C++] 형 변환 연산  (0) 2022.01.07
C++ 정리  (0) 2022.01.06
[C/C++] 파일 패킹  (0) 2022.01.06
[C/C++] 파일 입출력  (0) 2022.01.06
C언어 문자열 처리  (0) 2022.01.06