2017-10-30 22 views
1

현재 CS50 과정을 수강 중인데 크기 조정 문제가 완전히 풀립니다. 할당은 입력 .bmp 파일을 가져 와서 n 배로 확장하고 출력 .bmp 파일에 쓰는 프로그램을 만드는 것입니다. 하지만 내 코드는 단지 입력 이미지를 왜곡시키고 크기를 전혀 변경하지 않습니다. https://imgur.com/1v55tjz 을 내가 크기를 조정하려고 할 때, 그냥이 (여전히 3 × 3)으로 변합니다 : :이 코드는 https://imgur.com/JAKQMfY.bmp 이미지의 크기를 제대로 조절할 수 없음 (CS50 pset 4, 크기 조정, 덜 편안함)

입니다 이 (3 × 3 픽셀, 여기에서 확대) 테스트를 위해 제공되는 BMP입니다 크기 조정 :

#include <stdio.h> 
#include <stdlib.h> 

#include "bmp.h" 

int main(int argc, char *argv[]) 
{ 
    // ensure proper usage 
    if (argc != 4) 
    { 
     fprintf(stderr, "Usage: ./copy infile outfile\n"); 
     return 1; 
    } 

    // remember filenames 
    int n = atoi(argv[1]); 
    char *infile = argv[2]; 
    char *outfile = argv[3]; 

    // open input file 
    FILE *inptr = fopen(infile, "r"); 
    if (inptr == NULL) 
    { 
     fprintf(stderr, "Could not open %s.\n", infile); 
     return 2; 
    } 

    // open output file 
    FILE *outptr = fopen(outfile, "w"); 
    if (outptr == NULL) 
    { 
     fclose(inptr); 
     fprintf(stderr, "Could not create %s.\n", outfile); 
     return 3; 
    } 

    // read infile's BITMAPFILEHEADER 
    BITMAPFILEHEADER bf; 
    fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr); 

    // read infile's BITMAPINFOHEADER 
    BITMAPINFOHEADER bi; 
    fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr); 


    // 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); 
     fprintf(stderr, "Unsupported file format.\n"); 
     return 4; 
    } 

    // create file- and infoheader for output file 
    BITMAPFILEHEADER outBF = bf; 
    BITMAPINFOHEADER outBI = bi; 

    //Scale width and height by n 
    outBI.biWidth *= n; 
    outBI.biHeight *= n; 

    //Calculate padding for input and output file 
    int outPadding = (4 - (outBI.biWidth * sizeof(RGBTRIPLE) % 4) % 4); 
    int inPadding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4; 

    //Calculate biSizeImage and bfSize for output file 
    outBI.biSizeImage = ((sizeof(RGBTRIPLE) * outBI.biWidth) + outPadding * abs(outBI.biHeight)); 
    outBF.bfSize = outBI.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); 

    // write outfile's BITMAPFILEHEADER 
    fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr); 

    // write outfile's BITMAPINFOHEADER 
    fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr); 

    //Instantiate two counters to keep track of whether we have reached the n - 1 times of the recopy method and to be able to fseek to the next line 
    int countIterations = 1; 
    int countPositionInFile = 0; 


    // iterate over infile's scanlines 
    for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++) 
    { 
     countIterations = 1; 
     for(int j = 0; j < n; j++) 
     { 
      // iterate over pixels in scanline 
      for (int k = 0; k < bi.biWidth; k++) 
      { 
       // temporary storage 
       RGBTRIPLE triple; 

       // read RGB triple from infile 
       fread(&triple, sizeof(RGBTRIPLE), 1, inptr); 

       // resize horizontally by writing every pixel in row n times 
       for(int l = 0; l < n; l++) 
       { 
        // write RGB triple to outfile 
        fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr); 
       } 
      } 

      // skip over padding, if any 
      fseek(inptr, inPadding, SEEK_CUR); 

      //Add padding for this line 
      for (int l = 0; l < outPadding; l++) 
      { 
      fputc(0x00, outptr); 
      } 

      if(countIterations == n) 
      { 
       countPositionInFile++; 
      } 

      int newPosition = (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (countPositionInFile * (bi.biWidth + inPadding))); 

      // return the "cursor" to the start of the file 
      fseek(inptr, newPosition, SEEK_SET); 
      countIterations++; 
     } 

    } 

    // close infile 
    fclose(inptr); 

    // close outfile 
    fclose(outptr); 

    // success 
    return 0; 
}  

그리고 이것은 bmp.h 파일입니다

/** 
* BMP-related data types based on Microsoft's own. 
*/ 

#include <stdint.h> 

/** 
* Common Data Types 
* 
* The data types in this section are essentially aliases for C/C++ 
* primitive data types. 
* 
* Adapted from https://msdn.microsoft.com/en-us/library/cc230309.aspx. 
* See http://en.wikipedia.org/wiki/Stdint.h for more on stdint.h. 
*/ 
typedef uint8_t BYTE; 
typedef uint32_t DWORD; 
typedef int32_t LONG; 
typedef uint16_t WORD; 

/** 
* BITMAPFILEHEADER 
* 
* The BITMAPFILEHEADER structure contains information about the type, size, 
* and layout of a file that contains a DIB [device-independent bitmap]. 
* 
* Adapted from https://msdn.microsoft.com/en-us/library/dd183374(v=vs.85).aspx. 
*/ 
typedef struct 
{ 
    WORD bfType; 
    DWORD bfSize; 
    WORD bfReserved1; 
    WORD bfReserved2; 
    DWORD bfOffBits; 
} __attribute__((__packed__)) 
BITMAPFILEHEADER; 

/** 
* BITMAPINFOHEADER 
* 
* The BITMAPINFOHEADER structure contains information about the 
* dimensions and color format of a DIB [device-independent bitmap]. 
* 
* Adapted from https://msdn.microsoft.com/en-us/library/dd183376(v=vs.85).aspx. 
*/ 
typedef struct 
{ 
    DWORD biSize; 
    LONG biWidth; 
    LONG biHeight; 
    WORD biPlanes; 
    WORD biBitCount; 
    DWORD biCompression; 
    DWORD biSizeImage; 
    LONG biXPelsPerMeter; 
    LONG biYPelsPerMeter; 
    DWORD biClrUsed; 
    DWORD biClrImportant; 
} __attribute__((__packed__)) 
BITMAPINFOHEADER; 

/** 
* RGBTRIPLE 
* 
* This structure describes a color consisting of relative intensities of 
* red, green, and blue. 
* 
* Adapted from https://msdn.microsoft.com/en-us/library/dd162939(v=vs.85).aspx. 
*/ 
typedef struct 
{ 
    BYTE rgbtBlue; 
    BYTE rgbtGreen; 
    BYTE rgbtRed; 
} __attribute__((__packed__)) 
RGBTRIPLE; 

나는 사람이 과제와 경험을 가지고 도움이 될 수 있습니다 희망, 나는 TBH 지금 꽤 붙어 느낌,하지만 어쩌면 I'v 그냥 너무 오래 쳐다보고있어. 미리 감사드립니다.

+1

줄 바꿈에 대한 이전 설명을 삭제 했으므로 삭제했습니다. 당신의 문제는 디버깅 질문입니다. C에 관한 질문이 아닙니다. 문제를 해결할 수 있습니다. 첫 번째 단계는 픽셀 값에 관계없이 새로운 크기의 이미지를 만드는 것입니다. 그럴 때, 현명하게 픽셀이 적기 때문에 래스터 생성의 각 루프를 검사 할 수 있습니다. –

답변

1

파일은 바이너리 플래그로 열 수 있습니다 : 당신은 outBIoutBF을 무시하는

FILE *inptr = fopen(infile, "rb"); 
FILE *outptr = fopen(outfile, "wb"); 

, 당신은 새 파일에 기존의 헤더를 작성 :

fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);//old header 
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);//old header 

두 가지 다른 방법이 여기에 사용됩니다 패딩을 계산하려면 :

int outPadding = (4 - (outBI.biWidth * sizeof(RGBTRIPLE) % 4) % 4); 
int inPadding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4; 
                 ^  ^

우연히 만이 아니라 둘 다 옳을 수는 없습니다.

이 경우 우리는 24 비트 맵을 사용하는 당신은 내가이 코드를 알아낼 수 이것은 당신이 fseek(inptr, inPadding, SEEK_CUR);for(...) fputc(0x00, outptr);

와 패딩을 건너 길을 일치합니다

int outPadding = outBI.biWidth % 4; 
int inPadding = bi.biWidth % 4; 

으로 패딩을 계산할 수 있습니다

int newPosition = (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) 
    + (countPositionInFile * (bi.biWidth + inPadding)));<==remove 
fseek(inptr, newPosition, SEEK_SET);<==remove 

그래야합니다. 그걸 제거하고 ftell을 사용하여 줄을 읽기 전에 위치를 저장하고 fseek을 사용하여 그 위치로 돌아갈 수 있습니다.

비트 맵 높이를 아래에서 위로 읽어야하지만이 경우에는 차이가 없습니다.

+0

그런 광범위한 답변을 작성해 주셔서 감사합니다. :)이 모든 것이 많은 도움이되었습니다. 이제 해결되어 해결되었습니다. 고마워요! – sunero4