0

I've gone through my code, and I've progressed now to the point that the outfile finally scaled correctly, but now the colors are off for some reason, and I have no idea why (Infile and Outfile BMPs shown below my code). I'm not even sure how different colored pixels can be written to the outfile, if I am simply reading and writing pixels from one file to another. Any hints? Here is my code:

/**
 * Copies a BMP piece by piece, just because.
 */

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

#include "bmp.h"

int main(int argc, char *argv[])
{
    // convert argv[1] to integer
    int n = atoi(argv[1]);
    // ensure proper usage
    if(argc !=4)
    {
        fprintf(stderr,"Usage: ./resize n small.bmp large.bmp");
        return 1;
    }
     // ensure n <= 100
    if(n > 100)
    {
        fprintf(stderr, "n must be <= 100.");
        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);



    // redefine some stuff after resizing
    bi.biWidth *= n;
    bi.biHeight *= n;
    bi.biSizeImage = ((sizeof(RGBTRIPLE) * bi.biWidth)+((4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4))*abs(bi.biHeight);
    bf.bfSize *= (n*n)*sizeof(RGBTRIPLE)+(4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

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


    int inPadding = (4 - ((bi.biWidth/n) * sizeof(RGBTRIPLE)) % 4) % 4;

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

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

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



    // iterate over infile's scanlines
    for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight/n; i++)
    {
        // vertically scale "n" times
        for (int y=0;y<n;y++)
        {

            // 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 (horizontal scaling)
                for(int k = 0; k<n; k++)
                {
                    fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
                }

            }

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

                // return infile cursor to start of current scanline

                fseek(inptr, i*((bi.biWidth)/n) + (i)*(inPadding), SEEK_SET);

        }
            // move on to next scanline
            fseek(inptr, ((bi.biWidth)/n) + (inPadding), SEEK_CUR);
    }


    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // success
    return 0;
}

enter image description here

Outfile

1 Answer 1

1

It all has to do with padding and repositioning with fseek.

If the code isn't repositiioning correctly, the code won't be aligned with the beginning of a line of pixels. When that happens the padding gets used as if it were part of a pixel. Think about this. A red pixel looks like 00ff00. Now, say that the code is copying two pixels, but the file pointer gets pointed at the padding, which is 2 bytes. Instead of 00ff00 00ff00 which is two green pixels, you'd get 0000ff 0000ff. Instead of green, you get red. If the misalignment moves around, you can get many different colors. You were getting R,G,B, and Cyan, Magenta and Yellow!

First, you have an error in the headers. Fix that first, it'll be easiest. Next, your code to reposition the input file pointer is flawed. It's not going back to where it should and sometimes when it should. I'll leave it to you to work on this for a while to see if you can sort it out now that you know what's happening.

I'll also add this advice. Peek and xxd are your friends. Don't look at the images, look at the raw data in the file. Compare your output to the output from the staff example code. Look for patterns. Look for where things are vs. where they should be. Work on resize factor of n=1 until it works perfectly and then work on n=2.

One final suggestion. The code modifies the initial header values to produce the output file headers. But then, the code makes frequent calculations to recover input header values. It's a much better practice to save the input values needed to be used later in separate vars, and then alter the original headers. Or, copy the headers to preserve the originals and modify the copies. That way, you have both sets of headers available. Wasting a little memory is preferable to making the same calculations over and over. It eliminates opportunities for coding errors and eliminates confusion over why the calculations are being done. Doesn't it make more sense to have bi.biWidth and biout.biWidth instead of bi.biWidth/n??

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

You must log in to answer this question.

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