2

Apologies that I cannot be more specific here, I've been through my code with the debugger multiple times and have reviewed other examples online but I'm stuck on PSET3 resize. I think I'm saving correctly to an array, writing it to the outfile and using the fseek function correctly but my output larger.bmp file is not correct. Any help would be greatly appreciated, very frustrated right now. My code below:

#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>
#include "bmp.h"

int main(int argc, char *argv[])
{
// checking for three command lines only
if (argc != 4)
{
    printf("./resize n infile outfile\n");
    return 1;
}

// checking that the second command line is a number
for(int i = 0, n = strlen(argv[1]); i < n; i++)
{
    if (isalpha(argv[1][i]))
    {
        printf("./resize n infile outfile\n");
        return 1;
    }
}

// creating the variables
int n = atoi(argv[1]);
char *infile = argv[2];
char *outfile = argv[3];

// checking the second command line is between 0 and 100
if (n > 100 || n < 0)
{
    printf("./resize n infile outfile\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);
    printf("Could not create %s.\n", outfile);
    return 3;
}
// read infile's BITMAPFILEHEADER
BITMAPFILEHEADER bf, bfr;
fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);
bfr = bf;

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

// multiply height and width by n
bir.biWidth = bi.biWidth * n;
bir.biHeight = bi.biHeight * n;

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

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

// total size of file and image
bir.biSizeImage = ((sizeof(RGBTRIPLE) * bir.biWidth) + outpadding) * abs(bir.biHeight);
bfr.bfSize = bir.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

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

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

// initiate array
RGBTRIPLE *scanlinearray = malloc(sizeof(RGBTRIPLE) * bir.biWidth);

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

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

            // write RGB triple to array n times
            for (int l = 0; l < n; l++)
            {
                scanlinearray[l] = triple;
            }

        }

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

        // for n times

        for (int j = 0; j < n; j++)
        {
            // write array to outfile
            fwrite(scanlinearray, sizeof(RGBTRIPLE), bir.biWidth, outptr);

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

        }

}

// free array
free(scanlinearray);

// close infile
fclose(inptr);

// close outfile
fclose(outptr);

// success
return 0;
}

Thanks!

1 Answer 1

2

Error is with this code:

            // write RGB triple to array n times
            for (int l = 0; l < n; l++)
            {
                scanlinearray[l] = triple;
            }

This will write the triple to the first n array elements. This happens for every triple, always the same array elements. So what you experience as green and black is just the content of the memory malloced, the content you never changed.

There are multiple ways to handle this. One is to add a starting index that adds n for each input pixel, like scanlinearray[l + k * n] = triple;. Another would be to have some int index = 0; within the outermost loop (so it's reset for each input line), and then scanlinearray[index++] = triple;.

To elaborate a bit on the index++: It increments index, but the postfix version (++ after the variable) evaluates to the pre-increment value. Prefix version evaluates to post-increment value. So in this case, we increment index but use the old value in this step. You could separate it if you want, using scanlinearray[index] on one line and then index++;, or ++index;, or index += 1; on the next. Or index++ in the for loop, like for (int l = 0; l < n; l++, index++) (note that's a comma between the two increment expressions, not a semicolon).

3
  • Very helpful, thank you.
    – ChCook
    Commented Feb 6, 2019 at 16:13
  • I ended up with the same problem and the suggestions don't work for me but instead produce this picture (dropbox.com/s/dvklom7c6yyle5c/test_share.bmp?dl=0). I seem unable to figure out why, however. Do you have a hint, @Blauelf?
    – Ivo
    Commented Feb 15, 2019 at 9:17
  • @Ivo Check whether you differentiate between input padding and output padding. Looks like you write the input padding of 3 bytes while output padding happens to be 0 bytes.
    – Blauelf
    Commented Feb 15, 2019 at 9:57

You must log in to answer this question.

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