반응형

안녕하세요.

 

오랜만에 C언어에 대해 글을 씁니다. 

 

오늘은 제목과 같이 #pragma pack(push,1)을 사용하지 않고 구조체만으로 정렬하는 방법에 대해 이어쓰겠습니다.

 

혹시 이해가 안가신다면 전에 글을 읽어주시기 바랍니다.

 

https://coding-yoon.tistory.com/27

 

[C]BMP구조체 : #pragma pack(push, 1) 사용하지 않고 정렬하기

안녕하세요. 오랜만에 C언어에 대해 글을 써봅니다. 여러분들 BMP를 불러올 때 어떻게 하시나요? https://dojang.io/mod/page/view.php?id=703 C 언어 코딩 도장: 81.2 비트맵 구조체 작성하기 비트맵 파일의 구조..

coding-yoon.tistory.com

Lenna.bmp
0.75MB

#include   // strcpy 함수가 선언된 헤더 파일
#include 
#include 
#include 
#pragma warning(disable:4996)
#define _CRT_SECURE_NO_WARNINGS  // strcpy 보안 경고로 인한 컴파일 에러 방지


//pragma pack(push,1)
struct BMPINFO_14  //BMP 파일 구조체
{
//unsigned short bfType;           // BMP 파일 매직 넘버
unsigned int   bfSize;           // 파일 크기
unsigned short bfReserved1;      // 예약
unsigned short bfReserved2;      // 예약
unsigned int   bfOffBits;        // 비트맵 데이터의 시작 위치
};

struct BMP_FILE_44 // BMP 비트맵 정보 구조체
{
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;   // 비트맵을 표현하기 위해 필요한 색상 인덱스 수
};

struct RGB_3 //24비트 비트맵 구조체
{
unsigned char rgbtBlue;          // 파랑
unsigned char rgbtGreen;         // 초록
unsigned char rgbtRed;           // 빨강
};

//#pragma pack(pop)

int main()
{
int i, j, k, ii;

char image[80] = "Lenna.bmp";
char image_copy[80]="Lenna1.bmp";
printf("원본 이미지 : Lenna.bmp\n");
printf("편집 이미지 : Lenna1.bmp\n");

FILE* fp;

//binary read모드
fp = fopen(image, "rb");
if (fp == NULL)
return 1;
/////////////////////////////////BM/////////////////////////////////////
fseek(fp, 0, SEEK_SET);
int buffer = fgetc(fp);
fseek(fp, 1, SEEK_SET);
int buffer1 = fgetc(fp);

if ((buffer != 0x42 || buffer1 != 0x4D) )
{
printf("%x%x", buffer, buffer1);
fclose(fp);
return 3;
}
fseek(fp, 2, SEEK_SET);
////////////////////////////////BM/////////////////////////////////////
//binary write모드
FILE* outfp = fopen(image_copy, "wb");
if (outfp == NULL)
{
fclose(fp);
fprintf(stderr, "생성 불가능 %s.\n", image_copy);
return 2;
}

BMP_FILE_44 bitmapInfoHeader;
BMPINFO_14 bitmapFileHeader;

//
fread(&bitmapFileHeader, sizeof(BMPINFO_14), 1, fp);
fread(&bitmapInfoHeader, sizeof(BMP_FILE_44), 1, fp);
fwrite("BM", 1, 2, outfp);
fwrite(&bitmapFileHeader, sizeof(BMPINFO_14), 1, outfp);
fwrite(&bitmapInfoHeader, sizeof(BMP_FILE_44), 1, outfp);



int biHeight = abs(bitmapInfoHeader.biHeight);
int biWidth = bitmapInfoHeader.biWidth;

int padding = (4 - (biWidth * sizeof(RGB_3)) % 4) % 4; //패딩 처리

//**************************2차동적할당**********************************//
RGB_3** RGB;
RGB = (RGB_3**)malloc(sizeof(RGB_3*) * biHeight);
RGB[0] = (RGB_3*)malloc(sizeof(RGB_3) * biHeight * biWidth);
for (ii = 1; ii < biHeight; ii++)
{
RGB[ii] = RGB[ii - 1] + biWidth;
}
//**************************2차동적할당**********************************//

for (i = 0; i < biHeight; i++)
{
for (j = 0; j < biWidth; j++)
{
fread(&RGB[i][j], sizeof(RGB_3), 1, fp);
}
}

for (i = 0; i < biHeight; i++)
{
for (j = 0; j < biWidth; j++)
{
// 이미지 밝기
int x, y, z;
x = RGB[i][j].rgbtBlue + 75;
y = RGB[i][j].rgbtGreen + 75;
z = RGB[i][j].rgbtRed + 75;
RGB[i][j].rgbtBlue = ((x > 255) ? 255 : x);
RGB[i][j].rgbtGreen = ((y > 255) ? 255 : y);
RGB[i][j].rgbtRed = ((z > 255) ? 255 : z);
}
}

for (i = 0; i < biHeight; i++)
{
for (j = 0; j < biWidth; j++)
{

fwrite(&RGB[i][j], sizeof(RGB_3), 1, outfp);
}
fseek(fp, padding, SEEK_CUR);
for (k = 0; k < padding; k++)
{
fputc(0x00, outfp);
}
}


printf("Complete");



fclose(fp);

fclose(outfp);
free(RGB[0]);
free(RGB);
return 0;

}


이를 실행시켜보면

 

아주 잘읽혀집니다.

 

구조체가 어떻게 정렬하는지는 앞 글에 있고, 조심해야할 점에 대해 적도록 하겠습니다. 

 

Lenna.bmp를 1바이트 정렬없이 읽었으며, 우리가 출력할 Lenna1.bmp를 자세히 보아야 합니다.

 

Lenna1.bmp를 출력하기 위해 Binary Write로 열고 구조체를 사용해야 합니다.

 

하지만 구조체에는 다음과 같이 

 

'BM' 부분이 비어 있게 되어 bmp로 작성할 수 없게 됩니다. 

 

그러면 어떻게 해야 될까요? 

 

아주 간단합니다. 우리가 다시 수동으로 적어주면 됩니다. 이렇게

bitmap 파일 헤더를 읽고,

bitmap 정보 헤더를 읽고,

 

당연히 우리는 bitmap파일헤더에 BM이 존재하지 않기 때문에

 

bmp의 가장 첫 2바이트는 BM이라는거 기억나시죠?

 

fwrite를 통해 BM을 적어주면 됩니다. 

 

그리고 이어서 bitmap파일 헤더, bitmap정보 헤더에 대해 fwrite를 해줍니다. 

 

어떻게 보면 당연한 이야기일 수 있겠지만, 저는 파일 입출력 구조에 대해 이해를 못했을 땐, 왜 이렇게 사용하는지 조차

 

이해가 가지 않았습니다. 파이썬을 하면 이런거 할 일은 없지만, 파일 구조에 대해 공부할 땐 bmp만한게 없는 것 같습니다.

 

 

728x90
반응형

+ Recent posts