1
/**
 * resize.c
 *
 * Computer Science 50
 * Problem Set 4
 *
 * Copies 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: ./copy infile outfile\n");
        return 1;
    }

    // remember filenames
    char* infile = argv[2];
    char* outfile = argv[3];
    int n=0;

    //resize factor from 0 to 100
    do
    {
        n =atoi(argv[1]);
    }
    while(n<0 || n>100);

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

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

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

    int infile_width = bi.biWidth;
    int infile_height = bi.biHeight;

    // determine padding for scanlines
    int infile_padding =  (4 - (infile_width * sizeof(RGBTRIPLE)) % 4) % 4;

    int outfile_width = infile_width*n;
    int outfile_height = infile_height*n;
    int outfile_padding =  (4 - (outfile_width * sizeof(RGBTRIPLE)) % 4) % 4;

    bi.biSizeImage = abs(outfile_height)*( sizeof(RGBTRIPLE) * outfile_width  + outfile_padding);
    bf.bfSize = bi.biSizeImage + 54;

    // iterate over infile's scanlines
    for (int i = 0; i < abs(infile_height); i++)
    {
        for(int l = 0; l < n; l++)
        {
            fseek(inptr, (((infile_width*3 + infile_padding)*i)+54) , SEEK_SET);
            // iterate over pixels in scanline
            for (int j = 0; j < infile_width; j++)
            {
                // temporary storage
                RGBTRIPLE triple;

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

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

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

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // that's all folks
    return 0;
}
0

I found some lines you might want to change. The line numbers I mention are based on the code you provided, for example:

int main(int argc, char* argv[])    // Line #  15

int outfile_width = infile_width*n; // Line #  83

Move the bi and bf writing (lines 71-74) below the section where you set all your bi and bf related variables (put them somewhere below line 86 and above your loop on line 91). If you write them before you set these changes, the changes won't get written to your output file. Also, set bi.biWidth and bi.biHeight with your new values:

Instead of this:

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

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

int infile_width = bi.biWidth;
int infile_height = bi.biHeight;

// determine padding for scanlines
int infile_padding =  (4 - (infile_width * sizeof(RGBTRIPLE)) % 4) % 4;

int outfile_width = infile_width*n;
int outfile_height = infile_height*n;
int outfile_padding =  (4 - (outfile_width * sizeof(RGBTRIPLE)) % 4) % 4;

bi.biSizeImage = abs(outfile_height)*( sizeof(RGBTRIPLE) * outfile_width  + outfile_padding);
bf.bfSize = bi.biSizeImage + 54;

You might want that block of code to be something like this (changes are emphasized with asterisks):

int infile_width = bi.biWidth;
int infile_height = bi.biHeight;

// determine padding for scanlines
int infile_padding =  (4 - (infile_width * sizeof(RGBTRIPLE)) % 4) % 4;

int outfile_width = infile_width*n;
int outfile_height = infile_height*n;
int outfile_padding =  (4 - (outfile_width * sizeof(RGBTRIPLE)) % 4) % 4;

// ****************** SET bi.biWidth AND bi.biHeight
bi.biWidth = outfile_width;
bi.biHeight = outfile_height;

bi.biSizeImage = abs(outfile_height)*( sizeof(RGBTRIPLE) * outfile_width  + outfile_padding);
bf.bfSize = bi.biSizeImage + 54;

//  ********************
// MOVE THE WRITE LINES BELOW YOUR CHANGES SO THEY TAKE EFFECT.
// write outfile's BITMAPFILEHEADER
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);

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

This is not enough to get the image correctly resized but it is necessary before doing anything else. I could see this needed to be changed doing these lines:

Using the staff's implementation

~cs50/pset4/resize 7 small.bmp small7s.bmp

Using your version

./resize 7 small.bmp small7m.bmp

Comparing your version with the staff's version

 ~cs50/pset4/peek small7s.bmp small7m.bmp

Looking at the lines that show in red.

You should get all green lines with peek after doing the changes I suggested.

I will keep debugging your resize, since I still don't get a clean resized image. Although the BITMAPFILEHEADER and BITMAPINFOHEADER now content correct resized information.

UPDATE

Given

fwrite(ptr, size, n_items, stream)

ptr is the address of the content, stream is the file to write it to, and size is the size of items to write. n_items is not the amount of times to repeat the process. n_items is the amount of elements fwrite is going to look into ptr to write n_items elements size size into stream.

So if we say

fwrite(&triple, 1, 2, outptr)

We are saying take 2 1 byte-sized pieces of data from triple into outptr.

If we do

fwrite(&triple, 3, n, outptr)

We are not saying write n times 3-byte sized elements. We are just saying take n elements of size 3 bytes from triple. Since triple only has one of those, you only write one instead of n. And all that black horizontal space we were seeing in every row is probably fwrite taking adjacent memory from triple that was 0s and therefore black (0x000000).

7
  • Thanks for showing the error.After replacing fwrite(&triple, sizeof(RGBTRIPLE), n, outptr) with for(int m = 0; m < n; m++) { fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr); } the code works perfectly.
    – qwerty
    Nov 16 '16 at 14:42
  • However I don't understand the difference between both fwrite(&triple, sizeof(RGBTRIPLE), n, outptr) and for(int m = 0; m < n; m++) { fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr); }.Both are same but the code only works with the second one.
    – qwerty
    Nov 16 '16 at 14:44
  • WOW! I can't believe it. I was working on it seeing no errors debugging your code back and forth. I said " let me check if he or she has seen the answer". And it did not occur to me to do that. I just did it and it works perfect as you said. BUT I did not wanted to edit your line because it looks so clever! I actually liked the n instead of the 1. I am also clueless as to why it does not work with n. Nov 16 '16 at 14:46
  • Yes.It's true the code works but I can't understand why it doesn't work with fwrite(&triple,sizeof(RGBTRIPLE),n,outptr).I am not able to concentrate on recover without understanding this.Do you know why it doesn't work with the first one?
    – qwerty
    Nov 16 '16 at 14:54
  • Oh wait, maybe I do know. Read my update. Nov 16 '16 at 22:29

You must log in to answer this question.

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