0

Hi i am facing some bug in my program and am unable to figure out. What it should do is this:

for each row
  for (n-1) times
   write pixels ,padding to outfile
   send infile cursor back
  skip over infile padding
  write outfile padding

Any help would be 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: copy infile outfile\n");
    return 1;
}

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

if (n < 1 || n> 100)
{
    fprintf(stderr, "Factor must be between 1 and 100 inclusive\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;
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 (input file)
int inpadding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

bi.biWidth = n * bi.biWidth;
bi.biHeight = n * bi.biHeight;

// determine padding for output file
int outpadding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

bi.biSizeImage = (bi.biWidth + outpadding) * 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);

bi.biHeight = bi.biHeight / n;
bi.biWidth = bi.biWidth / n;

// iterate over infile's scanlines
for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
{
    //resizes height by factor n-1
    for (int l =0; l<n-1; l++)
    {
        // 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);
            // resizes each row by factor n
            for (int k=0; k<n; k++)
            {
                // write RGB triple to outfile
                fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
            }
        }

        // then add it back to outfile
        for (int k = 0; k < outpadding; k++)
        {
            fputc(0x00, outptr);
        }

        //go back to start of line for factoring
        fseek(inptr,-1*(bi.biWidth*sizeof(RGBTRIPLE)),SEEK_CUR);
    }

    //write to output file at least once if factor = 1.
    for (int j = 0; j < bi.biWidth; j++)
    {
        // temporary storage
        RGBTRIPLE triple;
        // read RGB triple from infile
        fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
        // resizes each row by factor n
        for (int k=0; k<n; k++)
        {
            // write RGB triple to outfile
            fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
        }
    }
    // skip over infile padding, if any
    fseek(inptr, inpadding, SEEK_CUR);
}

// close infile
fclose(inptr);

// close outfile
fclose(outptr);

// success
return 0;
}
1

I see two issues. First, there are incorrect values in the headers. Have you used peek to look at the headers of the input and output files to compare?

Next, it looks like the padding is missing for n=1 and some of the padding is missing for n!=1. That should be a big clue. ;-) Did you use xxd to look at the raw data?

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

| improve this answer | |
  • Got it! changed my biSizeImage and added padding for n!=1 and it worked perfectly. Thanks! – Yan Bo Pei May 26 '18 at 8:16
  • I do, however, managed to get it, without totally understanding it. bi.biSizeImage = (bi.biWidth*sizeof(RGBTRIPLE) + outpadding) *(abs(bi.biHeight)); we multiply bi.biWidth by 3 since each pixel is 3 btyes. But why dont we multiply height by 3 as well since height is also in pixels? – Yan Bo Pei May 26 '18 at 8:36
  • biWidth is measured in pixels, which are 3 bytes long, so the width of the row is calculated in bytes by multiplying the pixels by 3. The padding, which is already in bytes is added to that. That total is then multiplied by biHeight, the number of rows, which is already in the correct units. – Cliff B May 26 '18 at 8:43
  • isnt biHeight in pixels? how is this the correct unit? – Yan Bo Pei May 26 '18 at 8:58
  • Perhaps if you step back and look at the big picture for a second. ;-) Also, forget about padding for this discussion too. An image size is measured in biHeight x biWidth pixels. But a pixel is 3 bytes. So, if you're measuring the size of the image in bytes, it would be the size of the image times 3. Also, biWidth is specifically the number of pixels in a row, while biHeight is the actual number of ROWS. Or, think of it as a checkerboard with 8x8 =64 squares. Now, say each square represented a pixel. That means that each square is 3 bytes. 3 bytes x 64 squares, not 3 x 8 x 3 x 8 = 576! – Cliff B May 26 '18 at 9:14

You must log in to answer this question.

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