0

Currently doing resize (less) problem on the CS50 course and can't understand why this code is not working as it should.

It will resize the large.bmp and the smiley.bmp but not the small.bmp correctly.

The small.bmp will show yellow pixels instead of the green on some of the images. So if the resize value was 2 the image would look like this:

enter image description here

And a resize value of 4 looks like:

enter image description here

Any help would be greatly appreciated!

Results for cs50/problems/2019/x/resize/less generated by check50 v3.0.9

:) resize.c and bmp.h exist.

:) resize.c compiles.

:) doesn't resize small.bmp when n is 1

:( resizes small.bmp correctly when n is 2 expected 0x0, not 0xdb in byte 35 of pixel data

:( resizes small.bmp correctly when n is 3 expected 0x0, not 0xdb in byte 49 of pixel data

:( resizes small.bmp correctly when n is 4 expected 0x0, not 0xdb in byte 63 of pixel data

:( resizes small.bmp correctly when n is 5 expected 0x0, not 0xdb in byte 81 of pixel data

:) resizes large.bmp correctly when n is 2

:) resizes smiley.bmp correctly when n is 2

:) resizes smiley.bmp correctly when n is 3

// Resizes a BMP file

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


#include "bmp.h"

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

    // remember filenames and scale
    char *infile = argv[2];
    char *outfile = argv[3];
    int scale = argv[1][0] - 48;

    // check scale factor is positive integer
    if (argv[1][0] == '-' || argv[1][1] != '\0')
    {
        fprintf(stderr, "Scale factor must a positive integer.\n");
        return 2;
    }

    for (int x = 48; x < 58; x++)
    {
        if (x == argv[1][0])
        {
            break;
        }
        if (x == 9)
        {
            fprintf(stderr, "Scale factor must a positive integer.\n");
            return 2;
        }
    }


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

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

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

    // find original padding
    int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;


    // change the BITMAPINFOHEADER info and determine scaled padding for scanlines
    int orgBiWidth = bi.biWidth;
    int orgBiHeight = bi.biHeight;
    bi.biWidth *= scale;
    bi.biHeight *= scale;
    int scaledPadding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
    bi.biSizeImage = ((sizeof(RGBTRIPLE) * bi.biWidth) + scaledPadding) * abs(bi.biHeight);

    // change the BITMAPFILEHEADER info
    bf.bfSize = bi.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);

    // iterate over infile's scanlines
    for (int i = 0; i < abs(bi.biHeight); i++)
    {
        RGBTRIPLE array[orgBiWidth];

        if (i == 0 || i % scale == 0)
        {
            // iterate over pixels in scanline
            for (int j = 0; j < orgBiWidth; j++)
            {
                // temporary storage
                RGBTRIPLE triple;

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

                // write RGB trible to array
                array[j] = triple;

                // write RGB triple to outfile
                for (int x = 0; x < scale; x++)
                {
                    fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
                }
            }

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

            // then add it back
            for (int k = 0; k < scaledPadding; k++)
            {
                fputc(0x00, outptr);
            }
        }

        else
        {
            for (int y = 0; y < orgBiWidth; y++)
            {
                for (int z = 0; z < scale; z++)
                {
                    fwrite(&array[y], sizeof(RGBTRIPLE), 1, outptr);
                }
            }

            for (int k = 0; k < scaledPadding; k++)
            {
                fputc(0x00, outptr);
            }

        }
    }

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // success
    return 0;
}

1 Answer 1

1

Your problem is where RGBTRIPLE array[orgBiWidth]; is declared. It's declared within the loop, so when the current iteration is over, this memory is marked unused, and part of it will be reused before entering the next iteration, where the next array is declared in the same position (so it seems to persist between iterations). To fix this, simply move this declaration out of your loop.

There are two additional issues.

First, variable orgBiHeight is never used. You don't need it, because you do this i % scale thing. Unused variables cause a warning, which with -Werror prevents compilation.

Second, and in my opinion worse, your code should definitely fail for not accepting all integer factors 0<scale≤100. Also, it does not reject 0. Don't reinvent the wheel, pick a solution like atoi or strtol to parse a string as integer (the former is much simpler, the latter allows you to check for non-integer input, which is not explicitly required).

You must log in to answer this question.

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