0

I'm running resize.

The headers are right when I check them using peek.

The files look right (smiley, small, even whodunit).

But when I run check50 I get these errors:

:( resizes 1x1-pixel BMP to 2x2 correctly when n is 2
:( resizes 1x1-pixel BMP to 3x3 correctly when n is 3
:( resizes 1x1-pixel BMP to 4x4 correctly when n is 4
:( resizes 1x1-pixel BMP to 5x5 correctly when n is 5
:( resizes 2x2-pixel BMP to 4x4 correctly when n is 2

Any ideas? I notice my file sizes are larger than the staff versions.

Here is my code:

     /**
     * resize.c
     *
     * Computer Science 50
     * Problem Set 4
     *
     * Resizes a 24-bit uncompressed bmp by a factor of n
     */

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

    #include "bmp.h"

    int main(int argc, char* argv[])
    {
        // ensure proper usage
        if (argc != 4 || atoi(argv[1]) > 100 || atoi(argv[1]) < 1)
        {
            printf("Usage: ./resize n infile outfile, where n is greater than 0 and less than or equal to 100\n");
            return 1;
        }

        // remember filenames
        char* infile = argv[2];
        char* outfile = argv[3];
        int n = atoi(argv[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;
        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;
        }

        int inPadding =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4; // Calculates input padding before rewriting header files so I can use it to scan accurately over input file


        // resize BITMAPFILEHEADER
        bi.biHeight = bi.biHeight * n; // Multiply the height by n
        bi.biWidth = bi.biWidth * n; //  Multiplies the width by n

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

       // Determine the SizeImage after the padding is set which requires biWidth be set; normally SizeImage would be right after width
        bi.biSizeImage = bi.biWidth * abs(bi.biHeight) * sizeof(RGBTRIPLE) + padding * abs(bi.biHeight);    
        bf.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + bi.biSizeImage; // concentrates just on the size of the bitmap, subtracting out the headers, multiplies by n to expand number of pixels, multiples by the number of bytes per pixel (the number of bytes per pixel)

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

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


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

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

                    for (int l = 0; l < n; l++)
                    {
                        // write RGB triple to outfile
                        fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
                    }
                }      
                fseek(inptr, inPadding, SEEK_CUR);

                for (int k = 0; k < padding; k++) // Adds padding to each row
                {
                    fputc(0x00, outptr);
                }

                if(m < (n-1))
                {
                    fseek(inptr, -(bi.biWidth/n * sizeof(RGBTRIPLE) + inPadding), SEEK_CUR); // Resets the INPUT file selector location to the beginning of the row
                }
            }
        }

        // close infile
        fclose(inptr);

        // close outfile
        fclose(outptr);

        // that's all folks
        return 0;
    } 

1 Answer 1

0

When you modify the original headers instead of creating a copy and modifying them for output, you run into the risk of forgetting that some of the fields have been modified for the output file and are no longer valid for the input file. In this case, you changed bi.biHeight and then tried to use it to process the input file. So, if you were scaling by a factor of 1, it worked fine. If you use any other scaling factor, you were trying to process beyond the end of the input file.

    bi.biHeight = bi.biHeight * n; // Multiply the height by n

    // iterate over infile's scanlines
    for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)

So, given the code above from your program, if the image had 3 lines and you scaled by 2, then you'd try to process 6 lines in the input file, i.e., i would run from 0 to 5, when it should only run from 0 to 2.

If this answers your question, please click the check mark. Let's keep up with forum maintenance. ;-)

1
  • That was, of course, the answer. Basically divided biHeight by n and voila!
    – Norcim133
    Commented Dec 6, 2015 at 2:14

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .