주요 프레젠테이션을 위해 상사에게 제출해야 하는 이미지가 어떻게든 손상되었다고 상상해 보십시오! 조사해 보면 이미지가 대부분 손상되지 않은 것으로 나타났습니다. 단, 이미지를 보면 이제 거꾸로 된 것처럼 보입니다!
디지털 이미지 파일은 어떤 방식으로 배열된 일련의 비트일 뿐이라는 점을 기억하세요. 따라서 24비트 BMP 파일은 기본적으로 비트 시퀀스일 뿐이며 (거의) 24비트마다 일부 픽셀의 색상을 나타냅니다. 그러나 BMP 파일에는 이미지의 높이 및 너비와 같은 정보인 일부 "메타데이터"도 포함되어 있습니다. 해당 메타데이터는 C의 헤더 파일과 혼동하지 않도록 일반적으로 "헤더"라고 하는 두 가지 데이터 구조 형식으로 파일 시작 부분에 저장됩니다. BITMAPFILEHEADER라고 하는 첫 번째 헤더의 길이는 14바이트입니다.(1바이트는 8비트와 같다는 점을 기억하세요.) BITMAPINFOHEADER라고 하는 두 번째 헤더의 길이는 40바이트입니다. 이 헤더 바로 뒤에는 실제 비트맵이 있습니다. 바이트 배열은 픽셀의 색상을 나타냅니다.
당신의 임무는 비트맵의 맨 위 행이 첫 번째 행이고 맨 아래 행이 마지막이 되도록 프로그래밍 방식으로 메타데이터를 편집하는 것입니다. 파일이 더 손상되지 않도록 픽셀을 직접 편집하지 않는 것이 가장 좋습니다!
Hints
bmp.h의 설명에 따라 BITMAPFILEHEADER 및 BITMAPINFOHEADER가 포함된 URL을 가져옵니다. BITMAPINFOHEADER 구조체의 멤버를 자세히 살펴보세요. 해당 정보를 사용하여 이미지를 상향식에서 하향식으로 변경하는 약간의 코드를 Bottomup.c에 작성합니다. 문제의 코드는 그다지 복잡할 필요가 없습니다. 특히 자신이 하는 일을 알고 있다면 더욱 그렇습니다!
이미지 파일에 메타데이터가 필요한 이유는 무엇입니까?
// Copies a BMP file
#include <stdio.h>
#include <stdlib.h>
#include "bmp.h"
int main(int argc, char *argv[])
{
// Ensure proper usage
if (argc != 3)
{
printf("Usage: copy infile outfile\n");
return 1;
}
// Remember filenames
char *infile = argv[1];
char *outfile = argv[2];
// Open input file
FILE *inptr = fopen(infile, "r"); // r: 파일 읽기
if (inptr == NULL)
{
printf("Could not open %s.\n", infile);
return 2;
}
// Open output file
FILE *outptr = fopen(outfile, "w"); //w: 파일 열고 편집하기, 파일 없다면 생성
if (outptr == NULL)
{
fclose(inptr);
printf("Could not create %s.\n", outfile);
return 3;
}
// Read infile's BITMAPFILEHEADER
BITMAPFILEHEADER bf;
fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr); // bf:
// Read infile's BITMAPINFOHEADER
BITMAPINFOHEADER bi;
fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr);
printf("biHeight: %i\n", bi.biHeight); // console
// Ensure infile is (likely) a 24-bit uncompressed BMP 4.0
if (bf.bfType != 0x4d42 || bf.bfOffBits != 54 || bi.biSize != 40 ||
bi.biBitCount != 24 || bi.biCompression != 0)
{
fclose(outptr);
fclose(inptr);
printf("Unsupported file format.\n");
return 4;
}
bi.biHeight = - bi.biHeight; //
// Write outfile's BITMAPFILEHEADER
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);
// Write outfile's BITMAPINFOHEADER
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);
// Determine padding for scanlines
int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
// Iterate over infile's scanlines
for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++) // bi.biHeight = -1152
{
// Iterate over pixels in scanline
for (int j = 0; j < bi.biWidth; j++)
{
// Temporary storage
RGBTRIPLE triple;
// Read RGB triple from infile
fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
// Write RGB triple to outfile
fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
}
// Skip over padding, if any
fseek(inptr, padding, SEEK_CUR);
// Then add it back (to demonstrate how)
for (int k = 0; k < padding; k++)
{
fputc(0x00, outptr);
}
}
// Close infile
fclose(inptr);
// Close outfile
fclose(outptr);
// Success
return 0;
}
biSize
구조에 필요한 바이트 수입니다.
biWidth
비트맵의 너비(픽셀)입니다.
biCompression 이 BI_JPEG 또는 BI_PNG인 경우 biWidth 멤버는 각각 압축 해제된 JPEG 또는 PNG 이미지 파일의 너비를 지정합니다.
biHeight
비트맵의 높이(픽셀)입니다. biHeight 가 양수 이면 비트맵은 상향식 DIB이고 원점은 왼쪽 아래 모서리입니다. biHeight 가 음수 인 경우 비트맵은 하향식 DIB이고 해당 원점은 왼쪽 위 모서리입니다.
biHeight 가 음수(하향식 DIB를 나타냄) 인 경우 biCompression은 BI_RGB 또는 BI_BITFIELDS여야 합니다. 하향식 DIB는 압축할 수 없습니다.
biCompression이 BI_JPEG 또는 BI_PNG인 경우 biHeight 멤버는 각각 압축 해제된 JPEG 또는 PNG 이미지 파일의 높이를 지정합니다.
출처: https://learn.microsoft.com/en-us/previous-versions//dd183376(v=vs.85)
biHeight 값을 확인하면 음수임을 알 수 있다. top-down DIB을 나타낸다. 이를 거꾸로 돌리려면 bottom-up DIB로 변형해주어야하므로 biHeight * -1해준다.

