0

My issue is that the BMP appears to resize properly (in terms of size, that is) - so I don't think I have any problems with changing and updating the Bitmap Info/File-Headers (I probably do...), and therefore I believe (hopefully) I have identified my issue location to the loop starting at "// iterate over infile's scanlines" -- I am trying to follow the "rewrite" method. Perhaps this code snippet will show how hopelessly lost I am here, or maybe I'm at least somewhat close to solving this? Any guidance is greatly appreciated.

// Copies 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 for n
    int n = atoi(argv[1]);
    if (n < 1 || n > 100)
    {
        fprintf(stderr, "Enter n between 1 and 100\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;
    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;
    }

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

    // modify header information for output file
    BITMAPFILEHEADER outptr_bf = bf;
    BITMAPINFOHEADER outptr_bi = bi;

    outptr_bi.biWidth *= n;
    outptr_bi.biHeight *= n;

    int outptr_padding = (4 - (outptr_bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    outptr_bi.biSizeImage = ((outptr_bi.biWidth * sizeof(RGBTRIPLE)) + outptr_padding) * abs(outptr_bi.biHeight);
    outptr_bf.bfSize = outptr_bi.biSizeImage + sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);

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

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

    // iterate over infile's scanlines
    for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
    {
        // declare array to temporarily store each scanline
        RGBTRIPLE* scanline_copy = malloc(outptr_bi.biWidth);

        // iterate over pixels in scanline (for each pixel ...)
        for (int j = 0; j < bi.biWidth; j++)
        {
            // temporary storage
            RGBTRIPLE triple;

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

            // store scanline into the scanline_copy array (write to array n times...)
            for (int l = 0; l < n; l++)
            {
                scanline_copy[l] = triple;
            }
        }

        // write RGB triple to outflie (for n times ...)
        for (int m = 0; m < n; m++)
        {
            // write array to output file
            fwrite(&scanline_copy, sizeof(scanline_copy), 1, outptr);

            // write padding
            for (int k = 0; k < outptr_padding; k++)
            {
                fputc(0x00, outptr);
            }
        }

        free(scanline_copy);

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

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // success
    return 0;
}
3
  • Can't tell where the problem lies from what's posted. Have you verified that the headers are really correct? "Hopefully" isn't good enough. Problems in calculating header values or using the wrong header values can cause problems downstream. So can incorrectly calculated padding. Please edit the question and post the rest of the code so it can be tested. – Cliff B Nov 9 '18 at 20:56
  • As a side note, if you malloc the scanline_copy memory once, before the loop, it can be reused repeatedly and needs only be created and freed once. More efficient. But, kudos for correctly implementing without a memory leak. ;-) – Cliff B Nov 9 '18 at 20:57
  • Thanks @CliffB -- I have edited to include all the code – Greh Nov 11 '18 at 18:58
0

To close this out -- these are the changes I needed to fix it:

(1) moved malloc and free of RGBTRIPLE *scanline_copy outside the loop (per Cliff B's comment for more efficiency);

(2) needed to malloc (sizeof(RGBTRIPLE) * outptr_bi.biWidth) - I was not malloc'ing enough memory in the code posted above;

(3) to "write to array n times" - rather than writing triple to scanline_copy[l] (the index in the for loop), I created a separate int index set to 0 right at the beginning of the "iterate over infile's scanlines" for loop and then wrote triple to scanline_copy[index++] in the same for loop that I originally had it;

(4) corrected fwrite function under "write array to output file" as follows: fwrite(scanline_copy, sizeof(RGBTRIPLE) * outptr_bi.biWidth, 1, outptr);

You must log in to answer this question.

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