简体   繁体   中英

Problem with bfSize (Pset3, task resize, CS50)

The task is to rezise a bmp image with a factor. My code works visually, it looks correct when I check the hexadeximal of the rezised picture and the size is correct, but check50 says the picture is too large. I checked the size by downloading the picture and looked at the hexadecimal via the CS50 IDE. I also tried other code from GitHub but that code was also rejected by Check50. What is the error? Thanks in advance!

    // Copies a BMP file

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

#include "bmp.h"

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

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

    if(factor < 0 || factor > 100)
    {
        printf("facor must be between 0 and 100\n");
        return 15;
    }

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

    // open output file
    FILE *outptr = fopen(outfile, "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);

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

    //adjust fileheader
    BITMAPFILEHEADER bf_out = bf;
    BITMAPINFOHEADER bi_out = bi;

    //HEIGHT AND WIDTH
    bi_out.biWidth = bi.biWidth * factor;
    bi_out.biHeight = bi.biHeight * factor;

    // determine padding for scanlines
    int padding = (4 - (bi_out.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    //IMAGESIZE
    bi_out.biSizeImage = bi_out.biHeight * bi_out.biWidth * sizeof(RGBTRIPLE)+ padding;

    //BITMAPFILEHEADER
    bf_out.bfSize = bi_out.biSizeImage - sizeof(BITMAPFILEHEADER) - sizeof(BITMAPINFOHEADER);


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

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

    printf("Original bfSize: %d\n", bf.bfSize);
    printf("Resized bfSize: %d\n", bf_out.bfSize);
    printf("Bitmapinfoheader: %lu\n", sizeof(BITMAPINFOHEADER));
    printf("Bitmapfileheader: %lu\n", sizeof(BITMAPFILEHEADER));
    printf("Original biSizeImage: %d\n", bi.biSizeImage);
    printf("Resized biSizeImage: %d\n", bi_out.biSizeImage);
    printf("Original biWidth: %d\n", bi.biWidth);
    printf("Original biHeight: %d\n", bi.biHeight);
    printf("Resized biWidth: %d\n", bi_out.biWidth);
    printf("Resized biHeight: %d\n", bi_out.biHeight);

    // iterate over infile's scanlines
    for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
    {
        // temporary storage
        RGBTRIPLE triple[bi.biWidth];
        // iterate over pixels in scanline
        for (int j = 0; j < bi.biWidth; j++)
        {
            // read RGB triple from infile
            fread(&triple[j], sizeof(RGBTRIPLE), 1, inptr);
        }
        for(int l = 0; l < factor; l++)
        {
            for(int o = 0; o < bi.biWidth; o++)
            {
                for(int g = 0; g < factor; g++)
                {
                    fwrite(&triple[o], sizeof(RGBTRIPLE), 1, outptr);
                }
            }
            for (int k = 0; k < padding; k++)
            {
                fputc(0x00, outptr);
            }
        }
    }

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // success
    return 0;
}
//BITMAPFILEHEADER
bf_out.bfSize = bi_out.biSizeImage - sizeof(BITMAPFILEHEADER) - sizeof(BITMAPINFOHEADER);

The file size is image size plus the size of the headers. Not minus.

And you can replace this

// temporary storage
RGBTRIPLE triple[bi.biWidth];
// iterate over pixels in scanline
for (int j = 0; j < bi.biWidth; j++)
{
    // read RGB triple from infile
    fread(&triple[j], sizeof(RGBTRIPLE), 1, inptr);
}

With just a single fread call. No need to loop.

RGBTRIPLE triple[bi.biWidth];
fread(triple, sizeof(RGBTRIPLE), bi.biWidth, inptr);

You also need to calculate padding for the original image and then seek past it after you read into the buffer.

After looking for a solution online I finally managed to find a working code that I also understand. Maybe it will help someone with similar problems. This solution works with while loops instead of for loops and the padding is done outside of the inner loops but despite that the code is pretty much the same.

/**
 * resize.c
 *
 * Computer Science 50
 * Problem Set 4
 *
 * Copies a BMP piece by piece, but also resizes it, just because.
 */

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

#include "bmp.h"

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

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

    // check factor
    if (factor < 1 || factor > 100)
    {
        printf("Factor must be in the range [1-100]\n");
        return 1;
    }

    // open input file 
    FILE* inptr = fopen(infile, "r");
    if (inptr == NULL)
    {
        printf("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;
    BITMAPFILEHEADER bf_new;
    fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);

    bf_new = bf;

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

    bi_new = bi;

    // 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;
    }

    // set new width and height dimensions
    bi_new.biWidth = bi.biWidth * factor;
    bi_new.biHeight = bi.biHeight * factor;

    // determine padding for scanlines
    int padding =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
    int new_padding =  (4 - (bi_new.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    // set new file size
    bf_new.bfSize = 54 + (bi_new.biWidth * sizeof(RGBTRIPLE) + new_padding) * abs(bi_new.biHeight);
    bi_new.biSizeImage = bf_new.bfSize - 54;


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

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

    // iterate over infile's scanlines
    for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
    {
        // each row will be printed out factor times
        int rowcounter = 0;

        while (rowcounter < factor)
        {

            // iterate over pixels in scanline
            for (int j = 0; j < bi.biWidth; j++)
            {
                // temporary storage
                RGBTRIPLE triple;

                // each pixel will be printed out factor times
                int pixelcounter = 0;

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

                // write RGB triple to outfile
                while (pixelcounter < factor)
                {
                    fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
                    pixelcounter++;
                }
            }

            // add new padding
            for (int k = 0; k < new_padding; k++)
                fputc(0x00, outptr);

            // seek back to the beginning of row in input file, but not after iteration of printing
            if (rowcounter < (factor - 1))
                fseek(inptr, -(bi.biWidth * sizeof(RGBTRIPLE)), SEEK_CUR);

            rowcounter++;
        }

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

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // that's all folks
    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM