0

I am stuck since I have no idea what is wrong with my code. I believe my resizing code is correct. I think I'm not changing the headers correctly, which is giving me this image:

pset4 resize output

Also, i think it doesn't resize after i give a resize value of bigger than 20. It outputs Incorrect file type, which makes me even more suspectible of the file headers.

The CS50's peek line:

./resize 4 small.bmp student.bmp
~cs50/pset4/resize 4 small.bmp staff.bmp
~cs50/pset4/peek student.bmp staff.bmp

outputs all correct (green).

The other problem is that sometimes it resizes sometimes it keeps the same size even after inputting different value.

This code is a mess, and I've been stuck on resize for well over a week now. I've looked through some help here but couldn't come up with a solution. Any help is aprreciated.

    /**
 * Copies a BMP piece by piece, just because.
 */

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

#include "bmp.h"

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

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

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

    // open output file (larger.bmp)
    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;
    }

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

    // add another variable for headers
    BITMAPINFOHEADER bi_out = bi;
    BITMAPFILEHEADER bf_out = bf;

    // change members' sizes before writing
    bi_out.biWidth *= resize;

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

    bi_out.biHeight *= resize;
    bi_out.biSizeImage = ((sizeof(RGBTRIPLE) * bi_out.biWidth) + paddingChanged) * abs(bi_out.biHeight);
    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);

    // (recopy method) (Zamyla's pseudocode) FOR EACH ROW
    // iterate over infile's scanlines
    for (int i = 0, y = abs(bi_out.biHeight); i < y; i++)
    {
        // FOR n-1 TIMES
        // write same lines n times
        for (int m = 0, x = resize - 1; m < x; m++)
        {
            // WRITE PIXELS TO OUTFILE
            // iterate over pixels in scanline
            for (int j = 0; j < bi_out.biWidth; j++)
            {
                // temporary storage
                RGBTRIPLE triple;

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

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

            // WRITE PADDING TO OUTFILE
            for (int k = 0; k < paddingChanged; k++)
            {
                fputc(0x00, outptr);
            }

            // SEND INFILE COURSOR BACK
            fseek(inptr, 0, SEEK_SET);
        }

        // ADD PIXELS TO OUTFILE
        for (int j = 0; j < bi_out.biWidth; j++)
        {
            // temporary storage
            RGBTRIPLE triple;

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

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

        // ADD PADDING TO OUTFILE
        for (int k = 0; k < paddingChanged; k++)
        {
            fputc(0x00, outptr);
        }

        // SKIP OVER INFILE PADDING
        fseek(inptr, padding, SEEK_CUR);
    }

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // success
    return 0;
}

UPDATE: The problems were:

  1. I was using too many iterations on the for() loops. I changed bi_out.biWidth and bi_out.biHeight to bi.biWidth and bi.biHeight inside these loops.
  2. My fseek() line was incorrect. I changed it to fseek(inptr, -(long)bi.biWidth * (long)sizeof(RGBTRIPLE), SEEK_CUR); and it is finally working now.

1 Answer 1

1

In your for loops, use bi.biHeight, not bi_out.biHeight. Together with your nested loops, you'll get to bi_out.biHeight lines written in total.

Same for width, which has its own two nested loops.

Instead of resetting to start of the file

fseek(inptr, 0, SEEK_SET);

do like

fseek(inptr, -bi.biWidth * sizeof(RGBTRIPLE), SEEK_CUR);

to reset to the start of the line.

An alternative could be to read the line, saving it to an array, and writing it resize times.

8
  • I've changed the biHeight and biWidth in the for loops as you said. I've also assigned your fseek formula to long int since it gives me runtime error the way you wrote it. Now, only 1/3 of the box is colored green (starting from top). There's something else I might be doing wrong. Aug 14, 2017 at 11:55
  • bi.biWidth is probably a uint32_t, so negating it could have strange consequences. Maybe -(bi.biWidth * sizeof(RGBTRIPLE)) would work, or -(int)bi.biWidth * sizeof(RGBTRIPLE).
    – Blauelf
    Aug 14, 2017 at 12:15
  • bi.biWidth is a int32_t. I tried both of them but none of them worked. However, my assigning of your first formula to a long int variable and then using that variable in fseek() worked fine. Aug 14, 2017 at 12:49
  • I got it working with -(long)bi.biWidth * (long)sizeof(RGBTRIPLE). Interesting. -bi.biWidth is int32_t, sizeof(RGBTRIPLE) is size_t, which here is probably the same as uint64_t. So this means the the int32_t will be converted to uint64_t first (a very large positive number), and the result won't fit into uint64_t.
    – Blauelf
    Aug 14, 2017 at 13:19
  • Yes, that formula does seem to work now but the output is still the same. Only 1/3 of the box is green, even after changing biWidth, biHeight and fseek(). Aug 14, 2017 at 13:45

You must log in to answer this question.

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