0

Can someone please help me, I am trying to get horizontal resizing working before moving on to adding vertical resizing (as the walkthrough suggests).

My code works to resize smiley.bmp and large.bmp correctly (i.e. when input padding is 0), but when I try and enlarge small.bmp I get the correct size but the picture is random colours.

I have looked at other answered questions but still cant find the issue in my code. Help is much appreciated. Thanks. Here is my code:

// Resizes a BMP file

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

#include "bmp.h"

int main(int argc, char *argv[])
{
    // ensure proper usage
    if (argc != 4)
    {
        fprintf(stderr, "Usage: resize n infile outfile\n");
        return 1;
    }

    // check validity of n

    int n = atoi(argv[1]);

    if (n < 0 || n > 100)
    {
        fprintf(stderr, "Usage: n must be an int between 1 and 100\n");
        return 2;
    }

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

    // open output file
    FILE *outptr = fopen(outfile, "w");
    if (outptr == NULL)
    {
        fclose(inptr);
        fprintf(stderr, "Could not create %s.\n", outfile);
        return 4;
    }

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


    // change file header to output
    bi.biWidth *= n;

    int padding = (4 - ((bi.biWidth) * sizeof(RGBTRIPLE)) % 4) % 4;

    bi.biSizeImage = ((sizeof(RGBTRIPLE) * bi.biWidth) + padding) * abs(bi.biHeight);

    bf.bfSize = (bi.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));


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

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


 // change file header back to input
    bi.biWidth /= n;

    padding = (4 - ((bi.biWidth) * sizeof(RGBTRIPLE)) % 4) % 4;

    bi.biSizeImage = ((sizeof(RGBTRIPLE) * bi.biWidth) + padding) * abs(bi.biHeight);

    bf.bfSize = (bi.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER));


    // iterate over infile's scanlines
    for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
    {
        // change padding back to original
        padding = (4 - ((bi.biWidth) * sizeof(RGBTRIPLE)) % 4) % 4;

        // iterate over pixels in scanline
        for (int j = 0; j < (bi.biWidth * n); 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 k = 0; k < n; k++)
            {
                fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
            }
        }

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

        // work out how much padding is needed in output file
        padding = (4 - ((bi.biWidth * n) * sizeof(RGBTRIPLE)) % 4) % 4;

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

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // success
    return 0;
}
1

I didn't go deep into your program because there's something you need to fix that will have a big effect on what is happening. I think this is more about technique than anything else, based on the overview scan that I did.

You are trying to work with one single variable, padding, and changing it every time you need padding for input and output files. In reality and for efficiency, there really needs to be two separate variables, say inpadding and outpadding, clearly labeled so that you can easily recognize which is which. Calculate them once before starting the image data processing and be done with it. That way, they're only calculated once each instead of every pass through a loop and they won't get corrupted because of an incorrect calculation or the sequence of program flow changes in a way that wasn't anticipated.

Also, get the headers right when n=2 before going on to get the image correct. When you do go on to get the image correct, and like you said, work on the horizontal scaling. If the image looks stretched horizontally but the same height, with the last line repeated over and over to fill out the vertical, that's a really good sign that the horizontal code is correct. Then work on the vertical. ;-)

If you're still blocked after changing the code to have two padding vars, post a new question and go from there.

If this answers your (immediate) question, please click on the check mark to accept. Let's keep up on forum maintenance. ;-)

2
  • Thanks so much for the response. I understand much better now. – ab26221 Jul 18 '18 at 23:56
  • One other tip - use the peek tool to check headers and especially use the xxd tool to look at the raw hex image data. An image shows a bunch of colored blocks, but the hex data will clearly show patterns in the data that should indicate where problems are originating! Happy coding! ;-) – Cliff B Jul 19 '18 at 0:30

You must log in to answer this question.

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