0

This is extremely frustrating. I've been having header problems for a while, getting various error messages. However, using xxd I can see that when I run resize with n=2, biSizeImage is indeed 120, and biSize is indeed 174, as they should be. newPadding = 2, as it should. So what is wrong with my code? I can't work it out; please help. Posted below is my source code. thanks for any help!!

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

#include "bmp.h"


//todo- modify bitmapfileheader bfsize
//bitmapinfoheader - biSize, biHeight, biWidth
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;
    }



    //declare new BITMAPFILEHEADER on the stack with resized properties
    BITMAPINFOHEADER bin = bi;
    bin.biHeight = bi.biHeight*n;
    bin.biWidth = bi.biWidth*n;

    // determine padding for resized image scanlines
    int newPadding =  (4 - (bin.biWidth * sizeof(RGBTRIPLE)) % 4) % 4; 

    bin.biSizeImage = ((bin.biWidth* sizeof(RGBTRIPLE)) + newPadding)  * abs(bin.biHeight);
    bin.biSize = bin.biSizeImage + 54;

    //declare new BITMAPFILEHEADER on stack
    // write outfile's BITMAPFILEHEADER
    //change bfSize to resize image
    BITMAPFILEHEADER bfn = bf;
    bfn.bfSize = bin.biSize + 54;
    fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);

    // write outfile's BITMAPINFOHEADER
    //bitmapinfoheader - biBitCount, biSize, biHeight, biWidth, biSizeImage

    fwrite(&bin, sizeof(BITMAPINFOHEADER), 1, outptr);

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

    // iterate over infile's scanlines
    for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
    {
        //resize vertically by rewriting each row n times
        for(int y = 0; y < n; y++)
        {
            // iterate over pixels in scanline
            for (int j = 0; j < bi.biWidth; j++)
            {
                // temporary storage
                RGBTRIPLE triple;

                // read RGB triple from infile
                fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
                // write RGB triple to outfile n times
                for (int x = 0; x < n; x++)
                {
                    //takes care of writing extra pixels on scanline
                    fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
                }
            }

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

            // then add it back (to demonstrate how)
            //uses new resized padding amount
            for (int k = 0; k < newPadding; k++)
            {
                fputc(0x00, outptr);
            }
            //fseek in input file back to beginning of scanline
            if (y < n-1)
            {
                fseek(inptr,-((bi.biWidth*sizeof(RGBTRIPLE))+padding),SEEK_CUR);
            }
        }

    }

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // that's all folks
    return 0;
}

1 Answer 1

1

I think maybe the relationship between biSize, biSizeImage, and bfSize is not reflected properly in the code. Here's reference from MSDN:

bfSize: The size, in bytes, of the bitmap file.
~ MSDN BITMAPFILEHEADER structure

and

biSize: The number of bytes required by the structure.
biSizeImage: The size, in bytes, of the image.
~ MSDN BITMAPINFOHEADER structure

Also note the following from the spec:

The first of these headers, called BITMAPFILEHEADER, is 14 bytes long. (Recall that 1 byte equals 8 bits.) The second of these headers, called BITMAPINFOHEADER, is 40 bytes long.
~ CS50 spec for resize

Here's an excerpt from the code above:

bin.biSizeImage = ((bin.biWidth* sizeof(RGBTRIPLE)) + newPadding)  * abs(bin.biHeight);
bin.biSize = bin.biSizeImage + 54;
bfn.bfSize = bin.biSize + 54;

It looks like you are adding 54 bytes to the size of the image to obtain the biSize and adding another 54 bytes to obtain the bfSize. So, in total, you are adding 108 (54 + 54) bytes instead of 54 (14 + 40). Hope that helps.

You must log in to answer this question.

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