0

I have been staring at this code for hours now and can't find what is wrong with it. It makes a new bmp image that is "n" times larger, but there is something wrong with the reading frame because the image is all jumbled up. If anyone can set a fresh set of eyes on it I would appreciate it! Code below...

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

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

    if (n < 1 || !(int)n)
    {
        printf("Must use a positive integer for n! Please try again.\n");
        return 1;
    }



    // 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;
    BITMAPFILEHEADER new_bf;
    fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);

    // copy old header into new one
    new_bf = bf;

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

    // copy old header into new one
    new_bi = 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;
    }

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

    // change file sizing based on resizing parameters

    new_bi.biWidth = bi.biWidth * n;
    new_bi.biHeight = bi.biHeight * n;
    new_bi.biSizeImage = (new_bi.biWidth * sizeof(RGBTRIPLE) + new_padding) * abs(new_bi.biHeight);
    new_bf.bfSize = bi.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

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

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


    // storage
    RGBTRIPLE triple;
    RGBTRIPLE *transfer = malloc(new_bi.biWidth);

    // iterate over infile's scanlines
    for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
    {

        // iterate over pixels in scanline
        for (int k = 0; k < bi.biWidth; k++)
        {

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

            // perform the resizing by augmenting pixels

            for (int m = 0; m < n; m++)
            {
                *(transfer + n*k + m) = triple;
            }
        }

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

        // copy each line "n" times
        for (int j = 0; j < n; j++)
        {
            fwrite(transfer, new_bi.biWidth, 1, outptr);

             // add new padding
            for (int k = 0; k < new_padding; k++)
            {
                fputc(0x00, outptr);
            }
        }
    }

    // free back memory from transfer
    free(transfer);

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // success
    return 0;
}

EDIT: I appreciate your comment. I have tried messing around with the code because I think what you were alluding to was that I needed to add in the sizeof(RGBTRIPLE) into the areas where "transfer" was receiving the scanline from the old file. What I came up with was the code below, but I still can't seem to get it running very well. My current code is as follows...

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

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

    if (n < 1 || !(int)n)
    {
        printf("Must use a positive integer for n! Please try again.\n");
        return 1;
    }



    // 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;
    BITMAPFILEHEADER new_bf;
    fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);

    // copy old header into new one
    new_bf = bf;

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

    // copy old header into new one
    new_bi = 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;
    }

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

    // change file sizing based on resizing parameters

    new_bi.biWidth = bi.biWidth * n;
    new_bi.biHeight = bi.biHeight * n;
    new_bi.biSizeImage = (new_bi.biWidth * sizeof(RGBTRIPLE) + new_padding) * abs(new_bi.biHeight);
    new_bf.bfSize = bi.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

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

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


    // storage
    RGBTRIPLE triple;
    RGBTRIPLE *transfer = malloc(new_bi.biWidth * sizeof(RGBTRIPLE));

    // iterate over infile's scanlines
    for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
    {

        // iterate over pixels in scanline
        for (int k = 0; k < bi.biWidth; k++)
        {

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

            // perform the resizing by augmenting pixels

            for (int m = 0; m < n; m++)
            {
                *(transfer + (n*k + m)* sizeof(RGBTRIPLE)) = triple;
            }
        }

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

        // copy each line "n" times
        for (int j = 0; j < n; j++)
        {
            fwrite(transfer, new_bi.biWidth * sizeof(RGBTRIPLE), 1, outptr);

             // add new padding
            for (int k = 0; k < new_padding; k++)
            {
                fputc(0x00, outptr);
            }
        }
    }

    // free back memory from transfer
    free(transfer);

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // success
    return 0;
}
1

A couple questions for you:

Given that a pixel is represented by an RGBTRIPLE,

  1. How many bytes in a RGBTRIPLE?

  2. Is biWidth measured in bytes or pixels?

If this doesn't push you in the right direction, leave a comment and I'll clue you in. ;-)

[EDIT: following code changes] Well, you went a little too far. Look at this line from the new code:

            *(transfer + (n*k + m)* sizeof(RGBTRIPLE)) = triple;

This line deals with copying an address from one pointer to another. Multiplying the offset by sizeof(RGBTRIPLE) is causing the offset to be 3 times further than necessary. Remember, transfer is an array of RGBTRIPLEs, not an array of bytes.

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

2
  • I edited my post with the revised code that I think you were alluding to, but still can't seem to get it to work. Thank you for the help! Jun 23 '19 at 22:18
  • Woohoo! Its working now. Thank you! Jun 23 '19 at 23:48

You must log in to answer this question.

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