0

I have corrected my code. Now I have two versions, but both fail to print the

same scanline twice (vertical scaling). No problems with horizontal scaling.

I will be grateful for your help!

Below are two versions I have. If factor = n, then the first one packs n lines

in a block, and writes that block n times. For example, if factor = 2, then

every two lines will be printed two times. I have spent more than a day analyzing

this, but the only problem I see is the fseek function that takes di.diWidth as

as parameter. di.diWidth is changed before the start of loops, hence it seems

logical that n lines are printed n times. So, in the second version I changed

di.diWidth back to its initial value by dividing by the factor. This version

also produces a bizarre outcome (I have tested both on smiley.bmp).

What is my mistake? Did my best to come up with the solution, but I don't see

the problem in the logic of the code.

Second version:

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

#include "bmp.h"

int main(int argc, char* argv[])
{
    // ensure proper usage
    if (argc != 4)
    {
        printf("Usage: ./copy value infile outfile\n");
        return 1;
    }
    int factor = atoi(argv[1]);

    // ensure positive integers
    if (factor < 1 && factor > 100)
    {
        printf("Incorrect value of n\n");
        return 2;
    }
    // remember filenames
    char* infile = argv[2];
    char* outfile = argv[3];

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

    int padding_infile =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
    printf("%d %d %d\n", bi.biWidth, bi.biHeight, padding_infile);

    bi.biWidth *= factor;
    bi.biHeight *= factor;

    int biHeight = abs(bi.biHeight);

    // determine padding for infile and outfile
    int padding_outfile =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    // determine the new image size, including padding
    bi.biSizeImage = (bi.biWidth * sizeof(RGBTRIPLE) + padding_outfile) * biHeight;

    // update file size
    bf.bfSize = bi.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

    printf("width %d height %d padding %d imagesize %d file size %d\n", bi.biWidth, bi.biHeight, padding_outfile, bi.biSizeImage, bf.bfSize);

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

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

    // count rows with same pixels
    int count = 0;

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

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

            // write RGB triple to outfile repeating each pixel factor times
            for (int m = j; m < factor + j; m++)
            {
                fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
            }
        }
        // add padding to outfile
        for (int k = 0; k < padding_outfile; k++)
        {
            fputc(0x00, outptr);
        }

        count++;

        if (count == factor)
        {
            // skip over padding, if any
            fseek(inptr, padding_infile, SEEK_CUR);
            count = 0;
        }
        else /** if (count > 0 && count < factor) **/
        {
            fseek(inptr, (-(bi.biWidth / factor) * sizeof(RGBTRIPLE) - padding_infile), SEEK_CUR);
        }
    }

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // that's all folks
    return 0;
}

First version that prints n lines n times:

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

#include "bmp.h"

int main(int argc, char* argv[])
{
    // ensure proper usage
    if (argc != 4)
    {
        printf("Usage: ./copy value infile outfile\n");
        return 1;
    }
    int factor = atoi(argv[1]);

    // ensure positive integers
    if (factor < 1 && factor > 100)
    {
        printf("Incorrect value of n\n");
        return 2;
    }
    // remember filenames
    char* infile = argv[2];
    char* outfile = argv[3];

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

    int padding_infile =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
    printf("%d %d %d\n", bi.biWidth, bi.biHeight, padding_infile);

    bi.biWidth *= factor;
    bi.biHeight *= factor;

    int biHeight = abs(bi.biHeight);

    // determine padding for infile and outfile
    int padding_outfile =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    // determine the new image size, including padding
    bi.biSizeImage = (bi.biWidth * sizeof(RGBTRIPLE) + padding_outfile) * biHeight;

    // update file size
    bf.bfSize = bi.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

    printf("width %d height %d padding %d imagesize %d file size %d\n", bi.biWidth, bi.biHeight, padding_outfile, bi.biSizeImage, bf.bfSize);

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

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

    // count rows with same pixels
    int count = 0;

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

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

            // write RGB triple to outfile repeating each pixel factor times
            for (int m = j; m < factor + j; m++)
            {
                fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
            }
        }
        // add padding to outfile
        for (int k = 0; k < padding_outfile; k++)
        {
            fputc(0x00, outptr);
        }

        count++;

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

        if (count == factor)
        {
            count = 0;
        }
        else /** if (count > 0 && count < factor) **/
        {
            fseek(inptr, -(bi.biWidth/factor * sizeof(RGBTRIPLE) - padding_infile), SEEK_CUR);
        }
    }

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // that's all folks
    return 0;
}

Thank you!

EDIT: I have changed a program to add new structures for outfile, and hence now I have

separate values for infile headers and outfile headers. I still get an altered

picture: some pixels are being repeated correctly, others not.

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

#include "bmp.h"

int main(int argc, char* argv[])
{
    // ensure proper usage
    if (argc != 4)
    {
        printf("Usage: ./copy value infile outfile\n");
        return 1;
    }
    int factor = atoi(argv[1]);

    // ensure positive integers
    if (factor < 1 && factor > 100)
    {
        printf("Incorrect value of n\n");
        return 2;
    }
    // remember filenames
    char* infile = argv[2];
    char* outfile = argv[3];

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

    int padding_infile =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
    /**** printf("%d %d %d\n", bi.biWidth, bi.biHeight, padding_infile); ****/

    // outfile's BITMAPFILEHEADER
    BITMAPFILEHEADER outfile_bf = bf;

    // outfile's BITMAPINFOHEADER
    BITMAPINFOHEADER outfile_bi = bi;

    // update width and height of the outfile
    outfile_bi.biWidth = bi.biWidth * factor;
    outfile_bi.biHeight = bi.biHeight * factor;

    int biHeight = abs(outfile_bi.biHeight);

    // determine padding for infile and outfile
    int padding_outfile =  (4 - (outfile_bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    // determine the new image size, including padding
    outfile_bi.biSizeImage = (outfile_bi.biWidth * sizeof(RGBTRIPLE) + padding_outfile) * biHeight;

    // update file size
    outfile_bf.bfSize = outfile_bi.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

    /**** printf("width %d height %d padding %d imagesize %d file size %d\n", outfile_bi.biWidth, outfile_bi.biHeight, padding_outfile, outfile_bi.biSizeImage, outfile_bf.bfSize); ****/

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

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

    // count rows with same pixels
    int count = 0;

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

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

            // write RGB triple to outfile repeating each pixel factor times
            for (int m = j; m < factor + j; m++)
            {
                fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
            }
        }
        // add padding to outfile
        for (int k = 0; k < padding_outfile; k++)
        {
            fputc(0x00, outptr);
        }

        count++;

        if (count == factor)
        {
            // skip over padding, if any
            fseek(inptr, padding_infile, SEEK_CUR);
            count = 0;
        }
        else /** if (count > 0 && count < factor) **/
        {
            fseek(inptr, (-bi.biWidth * sizeof(RGBTRIPLE)), SEEK_CUR);
        }
    }

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // that's all folks
    return 0;
}

1 Answer 1

1

The biWidth field is the width of the image.

    // iterate over pixels in scanline
    for (int j = 0; j < outfile_bi.biWidth; j++)

So why are you using the outfile's biWidth to control reading the data from the infile?

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

1
  • oh!!! It took me a few days of staring at the code, writing and re-writing, moving pieces of code, creating redundant loops, naming, renaming, deleting, playing a computer on many sheets of paper, and all because of this tiny mistake, which somehow eluded being spotted. THANK you so much for your help!
    – Vitale
    Commented Jan 22, 2016 at 8:52

You must log in to answer this question.

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