카테고리 없음

야, BMP (ASCII 문자를 픽셀 데이터로 BMP 만들기)

comalmot_ 2020. 7. 17. 23:32
반응형

안녕하세요, comalmot 입니다.

 

오늘은 BMP 파일 픽셀 데이터에 문자를 넣어 보려고 합니다.

 

우선 BMP 파일이 어떻게 이루어져 있는가 부터 보시겠습니다.

 

일반적인 비트맵 파일의 구조

일반적인 BMP 파일의 구조는 이러합니다.

굉장히 간단하죠?

 

저도 그렇게 생각합니다.. ^^

하지만 너무 어려웠어요.. ㅠㅠ

 

우선 BITMAPFILEHEADER 구조체 부터 보시겠습니다!!!

 

 

 

 

 

 

 

 

 

 

typedef struct BITMAPFILEHEADER     // BMP 비트맵 파일 헤더 구조체

{

    unsigned short bfType;           // BMP 파일 매직 넘버 "BM"

    unsigned int   bfSize;           // 파일 크기

    unsigned short bfReserved1;      // 예약, 0

    unsigned short bfReserved2;      // 예약, 0

    unsigned int   bfOffBits;        // 픽셀 데이터의 시작 위치

} BITMAPFILEHEADER;

bfType 변수에는 문자열 "BM" 이 들어갑니다. 파일의 매직 넘버라고 하는데요, 이는 제가 추후 다른 포스팅으로 찾아뵙도록 하겠습니다.

 

다음은 bfSize 변수입니다. 말 그대로 파일의 크기를 나타내는 것입니다.

 

bfReserved1, bfReserved2는 미래를 위해 예약된 변수라고 하는데, 정확하게는 모르겠네요..

추후 추가 하도록 하겠습니다.

 

bfOffBits는 Pixel Data가 시작하는 부분의 Offset을 저장하는 변수입니다!

 

 

다음은 BITMAPINFOHEADER 입니다!

typedef struct BITMAPINFOHEADER     // BMP 비트맵 정보 헤더 구조체(DIB 헤더)
{
    unsigned int   biSize;           // 현재 구조체의 크기
    int            biWidth;          // 비트맵 이미지의 가로 크기
    int            biHeight;         // 비트맵 이미지의 세로 크기
    unsigned short biPlanes;         
    unsigned short biBitCount;       // 픽셀 하나를 표현하는 비트 수
    unsigned int   biCompression;    // 압축 방식
    unsigned int   biSizeImage;      // 비트맵 이미지의 픽셀 데이터 크기
    int            biXPelsPerMeter;  // 그림의 가로 해상도(미터당 픽셀)
    int            biYPelsPerMeter;  // 그림의 세로 해상도(미터당 픽셀)
    unsigned int   biClrUsed;        
    unsigned int   biClrImportant;   
} BITMAPINFOHEADER

biSize는 현재 구조체의 크기를 의미하는데요, 이때 구조체가 정렬한 바이트 수를 세는 것이 아니라

1바이트로 정렬된 구조체의 바이트 수를 세는 것이므로 sizeof(int)*9 + sizeof(short) * 2 = 40 바이트네요!

biSize는 40 바이트 고정이라고 보시면 될 것 같습니다.

 

다음은 비트맵 이미지의 가로 크기와 세로 크기인데요, 여기서 문제가 되는 것이 비트맵은 width가 4의 배수가 아니면 padding 이라는 작업을 따로 해줘야 합니다.

 

예를 들어, 23 * 50의 이미지가 있다면 23이 4의 배수가 아니므로 4의 배수인 24로 바꿔준 다음 빈공간을 아무 데이터로 채우는 것입니다. 쓰레기값이죠.

 

*추가적으로, 24비트 컬러를 사용한 1920*1080 해상도의 비트맵 이미지의 저장용량은 

1920 * 1080 * 24 = 49,766,400‬ byte 입니다.

그러므로 우리가 넣을 ASCII 데이터에 따라서 파일 용량을 적절히 계산해서

biSizeImage와 bfSize 변수에 제대로 반영을 해 주어야합니다.

 

 

제가 사실 제일 삽질했던 부분은 biSizeImage였습니다. 문장 독해력이 딸리는 건지.. 픽셀 데이터의 크기를 나타내는지 제대로 이해하지 못하고 한창 헤맸습니다.

 

말 그대로 "픽셀 데이터(실제로 RGB 값이 들어가는 부분)"의 전체 크기를 구해서 넣어주시면 됩니다.

 

biBitCount 변수는 픽셀 하나를 표현하는 비트 수 입니다. 24비트, 36비트 컬러 등이 있습니다.

이게 중요한 이유는 비트마다 구조체가 달라집니다.

 

여기서는 24비트 픽셀 구조체만 설명하도록 하겠습니다. 제일 간단하거든요.

 

typedef struct _RGBTRIPLE            // 24비트
{
    unsigned char rgbtBlue;          
    unsigned char rgbtGreen;         
    unsigned char rgbtRed;           
} RGBTRIPLE;

 

24비트 픽셀 구조체는 RGBTRIPLE 구조체를 사용합니다.

변수는 딸랑 네개.. R, G, B 심지어 값을 unsigned char이기 때문에 0 ~ 255의 값을 가집니다.

익숙하지 않나요?

ㅎㅎ

 

데이터를 여기에 쏙쏙!

넣어주면 될 것 같습니다. 그렇죠?

 

소스코드는 나중에 github에 올려놓도록 하겠습니다

(더러운 코드.. ㅠㅠ 미리 양해부탁드리겠습니다.)

 

 

예.. 저는 파일 이름을 입력하고 width와 height, data를 입력하면 자동으로 bmp 파일을 만들어주는 프로그램을 만들었습니다.

빈공간은 임시로!! 순백으로 채워넣었습니다!!

 

이제 파일 데이터도 한번 보겠습니다

 

 

아.. 아쉽게도 뒤에 다른 쓰레기 값이 따라나왔네요.

이 부분은 픽셀 데이터를 임의로 다시 설정해서 따로 출력하는 구문을 작성해야할 것 같습니다!

 

오늘의 포스팅 끝!!!

반응형