[This is CS50 2024] After Week4 - 메모리 #Bottom Up

moonstrnck·2024년 2월 22일

CS50

목록 보기
11/13


[CS50 Practice - #Bottom up]

Bottom Up

Learning Goals

  • 이미지 작업 연습
  • 메타데이터에 대해 알아보기
  • 구조체가 어떻게 유용한지 자세히 알아보세요.

Background

주요 프레젠테이션을 위해 상사에게 제출해야 하는 이미지가 어떻게든 손상되었다고 상상해 보십시오! 조사해 보면 이미지가 대부분 손상되지 않은 것으로 나타났습니다. 단, 이미지를 보면 이제 거꾸로 된 것처럼 보입니다!

디지털 이미지 파일은 어떤 방식으로 배열된 일련의 비트일 뿐이라는 점을 기억하세요. 따라서 24비트 BMP 파일은 기본적으로 비트 시퀀스일 뿐이며 (거의) 24비트마다 일부 픽셀의 색상을 나타냅니다. 그러나 BMP 파일에는 이미지의 높이 및 너비와 같은 정보인 일부 "메타데이터"도 포함되어 있습니다. 해당 메타데이터는 C의 헤더 파일과 혼동하지 않도록 일반적으로 "헤더"라고 하는 두 가지 데이터 구조 형식으로 파일 시작 부분에 저장됩니다. BITMAPFILEHEADER라고 하는 첫 번째 헤더의 길이는 14바이트입니다.(1바이트는 8비트와 같다는 점을 기억하세요.) BITMAPINFOHEADER라고 하는 두 번째 헤더의 길이는 40바이트입니다. 이 헤더 바로 뒤에는 실제 비트맵이 있습니다. 바이트 배열은 픽셀의 색상을 나타냅니다.

당신의 임무는 비트맵의 맨 위 행이 첫 번째 행이고 맨 아래 행이 마지막이 되도록 프로그래밍 방식으로 메타데이터를 편집하는 것입니다. 파일이 더 손상되지 않도록 픽셀을 직접 편집하지 않는 것이 가장 좋습니다!

Hints

  • bmp.h의 BITMAPINFOHEADER 구조체 멤버를 주의 깊게 살펴보세요.
  • 각 구성원에 대한 문서(documentation)를 읽었을 때 무엇을 수정해야 합니까? 어떻게요?

Demo

Demo 보기

Getting Started

  1. GitHub 계정을 사용하여 cs50.dev에 로그인합니다.
  2. 터미널 창 내부를 클릭하고 cd를 실행합니다.
  3. 코드 공간에서 Bottomup.zip이라는 zip을 다운로드하려면
    wget https://cdn.cs50.net/2022/fall/labs/4/bottomup.zip을 실행한 다음 Enter 키를 누르세요. wget과 다음 URL 또는 해당 문제에 대한 다른 문자 사이의 공백을 간과하지 않도록 주의하세요!
  4. 이제 unzip Bottomup.zip을 실행하여 Bottomup이라는 폴더를 만듭니다.
  5. 더 이상 ZIP 파일이 필요하지 않으므로 rm Bottomup.zip을 실행하고 프롬프트에서 "y"를 입력한 후 Enter를 입력하면 됩니다.

Implementation Details

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해준다.

0개의 댓글