0

I am currently struggling to understand why my images has more bytes than the staff example given. Comparing the actual sizes of the two .bmp files I find that: student.bmp - 1062 bytes. staff.bmp - 486 bytes.

Check50 Error checks:

:) resize.c and bmp.h exist.
:) resize.c compiles.
:( doesn't resize small.bmp when n is 1
Image has more bytes than expected.
:( resizes small.bmp correctly when n is 2
Image has more bytes than expected.
:( resizes small.bmp correctly when n is 3
Image has more bytes than expected.
:( resizes small.bmp correctly when n is 4
Image has more bytes than expected.
:( resizes small.bmp correctly when n is 5
Image has more bytes than expected.
:( resizes large.bmp correctly when n is 2
Image has more bytes than expected.
:( resizes smiley.bmp correctly when n is 2
Image has more bytes than expected.
:( resizes smiley.bmp correctly when n is 3
Image has more bytes than expected.

I can't seem to understand why this happens and would appreciate any help as to why this happens. Here follows my code for resize.c:

// Resizes a BMP file
#include <stdio.h>
#include <stdlib.h>
#include <cs50.h>
#include "bmp.h"
#include <math.h>
int main(int argc, char *argv[])
{
// ensure proper usage
if (argc != 4)
{
    fprintf(stderr, "Usage: resize factor infile outfile\n");
    return 1;
}

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

// open input file
FILE *inptr = fopen(infile, "r");
if (inptr == NULL)
{
    fprintf(stderr, "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, bf_resized;
fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);
bf_resized = bf;

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

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

//Initialize the factor by which the image needs to be resized
int n = atoi(argv[1]);

//Check if the user inputs a factor between 1-100
if (n <= 0 || n > 100)
{
    printf("Factor needs to be between 1-100\n");
    return 5;
}

//Ensure Height is always positive
bi.biHeight = abs(bi.biHeight);

//Resize Width and Height
bi_resized.biWidth  = floor(bi_resized.biWidth * n);
bi_resized.biHeight = ceil(bi_resized.biHeight * n);

//Calculate padding
int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) %4) % 4;
//Calculate resized padding
int resizedPadding = (4 - (bi_resized.biWidth * sizeof(RGBTRIPLE)) %4) % 4;
// Calculate size of Bitmap File Header
bf_resized.bfSize = 54 + bi_resized.biWidth * abs(bi_resized.biHeight) * 3 + abs(bi_resized.biHeight) *  resizedPadding;
// Calculate size of Bitmap info header
bi_resized.biSizeImage = ((((bi_resized.biWidth * bi_resized.biBitCount) + 31) & ~31) / 8) * abs(bi_resized.biHeight);
// write outfile's BITMAPFILEHEADER
fwrite(&bf_resized, sizeof(BITMAPFILEHEADER), 1, outptr);
// write outfile's BITMAPINFOHEADER
fwrite(&bi_resized, sizeof(BITMAPINFOHEADER), 1, outptr);
RGBTRIPLE triple;
RGBTRIPLE scanLine[bi_resized.biWidth];
int pixel = 0;
int counter = 0;
// iterate over infile's scanlines
for (int i = 0; i < bi.biHeight + n; i++)
{
    //Start at the line's first pixel
    pixel = 0;
    // iterate over pixels in scanline
    for (int j = 0; j < bi.biWidth; j++)
    {
        // read pixel from infile
        fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
        //Repeat the pixel n times to scale horizontally and store it in scanLine array
        counter = 0;
        while (counter < n)
        {
            scanLine[pixel] = triple;
            ++pixel;
            ++counter;
        }
    }
    // Skip over padding, if any
    fseek(inptr, padding, SEEK_CUR);
    //Print the array horizontally with the padding into the output file pointer
    for (int j = 0; j < n; j++)
    {
        fwrite(scanLine, sizeof(RGBTRIPLE), bi_resized.biWidth,outptr);
        // Add a new padding
        for (int l = 0; l < resizedPadding; l++)
        fputc(0x00, outptr);
    }
}
// close infile
fclose(inptr);
// close outfile
fclose(outptr);
return 0;
}
2

Not related to problem: Move your integer conversion and test for n being in range up, before opening a file, but after test for argc. No need to do any work if you won't resize.

Also not related: If you're working with integers only, floor and ceil make little sense. Don't exactly hurt either.

A mistake, but not the one mentioned: The new height should have the same sign as the old one, so do the abs after calculating new height.

Related to the problem: i < bi.biHeight + n looks a bit fishy, especially the + n. You are reading bi.biHeight + n rows in a file of only bi.biHeight rows.

2
  • That worked perfectly. I literally just removed the + n and also removed the floor and ceil, because it was unnecessary. Also moved the integer conversion and test for n up and now everything works. I have been struggling for some time with this hahaha Nov 2 '18 at 17:19
  • 1
    Sometimes that's the problem, you are too close. Getting a night's sleep, or taking another person's perspective by rubber-duck debugging often helps.
    – Blauelf
    Nov 2 '18 at 17:25

You must log in to answer this question.

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