1

I'm having a hard time understanding pset4's resize. Although I understand the theory, it's difficult for me to turn it into a program.

I do understand that the scan line's total width must be a multiple of four, and I presume that it's the same formula used from copy.c.

I've watched the video, and I'm attempting to use the recopy method. In the video, Zamyla states that fseek is used to reset the file indicator. In my code, I've put another fseek after I add padding, but I suspect this isn't the proper place. If so, where would I put it?

Any other help for my code would also be greatly appreciated (especially towards the loops).

Here's my code.

/**
 * copy.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 n infile outfile\n");
        return 1;
    }

    // remember arguments
    int n = atoi(argv[1]);
    char* infile = argv[2];
    char* outfile = argv[3];

    if (n < 1 || n > 100) {
        printf("n must be between 1 - 100 \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);
        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;
    }

    // update headers
    BITMAPFILEHEADER new_bf = bf;
    BITMAPINFOHEADER new_bi = bi;

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

    int new_padding = ((4 - (new_bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4);

    printf("%i, %i\n", bi.biWidth, new_bi.biWidth);

    new_bi.biSizeImage = (new_bi.biWidth * abs(new_bi.biHeight) * 2) * sizeof(RGBTRIPLE) + new_padding;
    new_bf.bfSize = new_bi.biSizeImage + sizeof(bf) + sizeof(bi);

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

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

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

    printf("%i\n", new_padding);

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

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

                for (int l = 0; l < n; l++)
                {
                    // write RGB triple to outfile
                    fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
                }

            }

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

            // adds padding if needed
            for (int k = 0; k < new_padding; k++)
            {
                fputc(0x00, outptr);
            }

            // reset to beginning of line
            fseek(inptr, -(bi.biWidth * sizeof(RGBTRIPLE)), SEEK_CUR);           
        }
    }

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // that's all folks
    return 0;
}

When I run ./resize 5 small.bmp student.bmp, the result is this:

My result

2
  • You definitely have some mistakes in the new headers. See this answer for more info, especially about biSizeImage and bfSize.
    – ChrisG
    Aug 11, 2016 at 8:25
  • Thanks for your help. Since my new_bi.biSizeImage is the same as large.bmp's bi.biSizeImage, I'm assuming my formula used is now correct.
    – Lyxpudox
    Aug 11, 2016 at 17:27

1 Answer 1

1

According to MSDN

biSizeImage

The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps.

If biCompression is BI_JPEG or BI_PNG, biSizeImage indicates the size of the JPEG or PNG image buffer, respectively.

Let's say you have an image with 3x3 pixels, and you want to enlarge it by a factor of 2. So your new biWidth == 6 and biHeight == 6.

But 6 is not a multiple of 4, so we have to add some padding, in this case, we need two bytes of padding to reach a total of 8 bytes per line.

So the biSizeImage is:

  • 6 pixels per line, with 3 bytes each, we have 6 * 3 == 18 bytes
  • 2 padding bytes per line, with 1 byte each, so we now have 18 + 2 == 20 bytes
  • 6 lines total, so we have 6 * 20 == 120 bytes

so biSizeImage should be 120.

What you have is:

new_bi.biSizeImage = (new_bi.biWidth * abs(new_bi.biHeight) * 2) * sizeof(RGBTRIPLE) + new_padding;

find the differences and correct your math (and what exactly does that 2 represent in the parentheses?).

Keep in mind there are probably more mistakes in your code.

2
  • Thanks for your help. Using this answer and your other answer really helped me to understand it. My picture is starting to look almost like large.bmp, so I'm assuming that I'm almost finished.
    – Lyxpudox
    Aug 12, 2016 at 17:00
  • Just one final question - what's the purpose of another fseek on inptr?
    – Lyxpudox
    Aug 12, 2016 at 17:13

You must log in to answer this question.

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