0

I'm having trouble with pset4's resize.c.

It partly works now! But there are these black vertical lines running through the picture. GDB helped.

This is my code now.

/**
 * resize.c
 *
 * Computer Science 50
 * Problem Set 4
 *
 * Resizes a BMP piece by piece, 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 n 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)
    {
        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;
    }

    // original width, height, and padding
    long inWidth = bi.biWidth;
    long inHeight = bi.biHeight;
    int inPadding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    printf("%d = bfSize\n", bf.bfSize);
    printf("%d = biSize\n", bi.biSizeImage);

    bi.biWidth = bi.biWidth * n;
    bi.biHeight = bi.biHeight * n;

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

    bi.biSizeImage = abs((bi.biWidth * 3 + padding) * bi.biHeight);
    bf.bfSize = bi.biSizeImage + bf.bfOffBits;

    printf("%d = bfSize\n", bf.bfSize);
    printf("%d = biSize\n", bi.biSizeImage);
    printf("%d = sizeof bf\n", sizeof(bf));

    // 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(inHeight); i++)
    {
        // re-copy each scanline n times
        for (int l = 0; l < n; l++)
        {
            // iterate over pixels in scanline
            for (int j = 0; j < inWidth; j++)
            {
                // temporary storage
                RGBTRIPLE triple;

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

                // write RGB triple to outfile n times
                fwrite(&triple, sizeof(RGBTRIPLE), n, outptr);

                for (int k = 0; k < n; k++)
                {
                    printf("[%d] ", triple.rgbtGreen);
                }
            }

            printf("\n");

            if (l != n - 1)
            {
                // restart scanline
                fseek(inptr, -inWidth * sizeof(RGBTRIPLE), SEEK_CUR);
            }

            // add padding
            for (int j = 0; j < padding; j++)
            {
                fputc(0x00, outptr);
            }
        }

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

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // that's all folks
    return 0;
}

1 Answer 1

1

Your mistake is that you calculate the padding

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

but that is the padding you should have on the outfile, and you use both for skipping the padding of the infile (that's where your mistake lies) and adding the padding in the outfile

    // add padding
    for (int j = 0; j < padding; j++)
    {
        fputc(0x00, outptr);
    }
}

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

They are two different paddings.


Edit

First of all, I should say that you should work on your own code a little more, and not ask help for logical problems you have. You have to learn to debug your own code and become better from the process. It's another thing if you get an error you have no idea how to solve, and another to have a code that works, but not quite. Then you should tinker with it yourself, and try to improve it. That's how you build experience.

Tell you the truth, you would have spared valuable time both of us, if you had created new HEADERS for the outfile and not reused those from infile. It might look like a waste of space but you wouldn't have to get so complicated with the inWidth and inHeight variables.

The first problem you have, is this line

if (l != n - 1)
{
    // restart scanline
    fseek(inptr, -bi.biWidth * sizeof(RGBTRIPLE), SEEK_CUR);
}

Since you changed the bi.biWidth in the infile's HEADER, this now represents the width of the outfile, so you rewind the infile's scanline way to far. You should use the infile's original width, not the outfile's.

Then there is something more you should correct. You need to change the declarations for inWidth and inHeight from longs to ints. Else the compiler that checks your code in the CS50 server will give you an error and exit. Not sure why but it does that but it does.

You should also remove all the printf's from your code that you have for debugging.


If this answers your question please accept it by clicking the gray check-mark to the left, so that it becomes green. You can also vote it up by pressing the up arrow above the check-mark. And don't forget to keep coding!

8
  • I defined "inPadding" as: long inPadding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4; before I change the height and width. I change the fseek() call to: fseek(inptr, inPadding, SEEK_CUR); But the program still doesn't work properly.
    – David
    Aug 27, 2015 at 19:12
  • Edit your code above and adjust what new is happening now.
    – ChrisG
    Aug 27, 2015 at 19:51
  • I updated my code above. It still doesn't work.
    – David
    Aug 27, 2015 at 21:21
  • check the edit.
    – ChrisG
    Aug 27, 2015 at 23:27
  • I changed fseek's third second argument from padding to inPadding.
    – David
    Aug 28, 2015 at 1:02

You must log in to answer this question.

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