0

below is my code for resize.c in pset4 and i could not figure out where the error / logic problem is.

Few changes to the code are as below:
1) I used atoi to convert n to a int.
2) Changed values of bi and bf before writing to output file so the output file has the correct data in the headers.
3) Repeat the copying of rows n times before adding padding.
4) Repeat the copying of height n times. The size of my output image seems to be correct (i assume my output header files are alright) but i dont see any logic errors with my for loops.
5) Any help is appreciated. Thank You!

// 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;
}
bi.biWidth = n * bi.biWidth;
bi.biHeight = n * bi.biHeight;

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

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

// iterate over infile's scanlines
for (int i = 0, biHeight = abs(bi.biHeight); i < ((biHeight)/n); i++)
{
    //resizes height by factor n
    for (int l =0; l<n; l++)
    {
        // iterate over pixels in scanline
        for (int j = 0; j < (bi.biWidth/n); j++)
        {
            // temporary storage
            RGBTRIPLE triple;
            // resizes each row by factor n
            for (int k =0; k<n; k++)
            {
                // read RGB triple from infile
                fread(&triple, sizeof(RGBTRIPLE), 1, inptr);

                // write RGB triple to outfile
                fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
            }
        }

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

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

// close infile
fclose(inptr);

// close outfile
fclose(outptr);

// success
return 0;
}
0

I see at least 2 problems with this code:

  • you use the same padding value for input and output file (it can be different)
  • you trying to read from input file more lines, than it contains (n * input_heghth lines)
1
  • Thanks for the help, understood why padding values are different and how they should be read and written.
    – Yan Bo Pei
    May 26 '18 at 6:47
1

You seem to read and write at the same pace. Read a pixel, write a pixel. This approach can work only if you use fseek to read the same stuff multiple times. The alternative is reading once, remembering (e.g. storing a full input line in an array, or at least remembering the last read pixel so you have to fseek only between output lines, not within), and performing reading and writing at different nesting levels. Like you would like to skip input padding once per input line, but write output padding once per output line (and those numbers are probably different most of the time).

Like for example

for each input line:
    read input line into array
    skip input padding
    repeat n times:
        write horizontally resized line
        write output padding

Read and write operations on different levels (abstracted away the inner loops, but those are equivalent).

Also, input and output padding might be different. It's there to ensure any line length is divisible by 4 bytes. A 3 pixel input line has 3 bytes of padding (from 9 to 12 bytes), with a scaling factor of 1, 2, 3, 4 that results in output padding of 3 (9->12), 2 (18->20), 1 (27->28), 0 (36->36) bytes.

1
  • Thanks! Im trying to do it without the array at the moment. Will try to do it with array afterwards! Your explanation is very clear!
    – Yan Bo Pei
    May 26 '18 at 6:49

You must log in to answer this question.

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