0

I am receiving the below when I check Pset4:

:) resize.c and bmp.h exist.
:) resize.c compiles.
:) doesn't resize small.bmp when n is 1
:( resizes small.bmp correctly when n is 2
    Byte 22 of pixel data doesn't match. Expected 0xff, not 0x00
:( resizes small.bmp correctly when n is 3
    Byte 30 of pixel data doesn't match. Expected 0xff, not 0x00
:( resizes small.bmp correctly when n is 4
    Byte 38 of pixel data doesn't match. Expected 0xff, not 0x00
:( resizes small.bmp correctly when n is 5
    Byte 50 of pixel data doesn't match. Expected 0xff, not 0x00
:( resizes large.bmp correctly when n is 2
    Byte 313 of pixel data doesn't match. Expected 0x00, not 0xff
:( resizes smiley.bmp correctly when n is 2
    Byte 55 of pixel data doesn't match. Expected 0xff, not 0x00
:( resizes smiley.bmp correctly when n is 3
    Byte 82 of pixel data doesn't match. Expected 0xff, not 0x00

Here is my code:

// Implements a program resize that enlarges 24-bit uncompressed BMPs by a factor of n

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

#include "bmp.h"

int main(int argc, char *argv[])
{
    // ensure proper usage
    if (argc != 4)
    {
        fprintf(stderr, "Usage: Improper number of command-line arguments\n");
        return 1;
     }

    // Resize by factor of n; 0 < n >= 100
    int n = atoi(argv[1]);

    if (n < 1 || n > 100)
    {
        fprintf(stderr, "Resize of n must be a positive integer and cannot be greater than 100\n");
        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);

    // 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 padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    // Update width and height for new BITMAPHEADER | old = bi.biWidth and bi.biHeight
    bi.biWidth *= n;
    bi.biHeight *= n;

    // Update padding for outfile
    int newPadding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

    // Update BITMAPHEADERINFO: change image size for outfile | old = bi.biSizeImage
    bi.biSizeImage = ((sizeof(RGBTRIPLE) * bi.biWidth) + newPadding) * abs(bi.biHeight);
    // Update BITMAPFILEHEADER: change file size for outfile | old = bi.biSize
    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; i++)
    {
        // iterate over pixels in scanline
        for (int j = 0; j < n; j++)
        {
            // Set pointer to beginning of file
            fseek(inptr, -bi.biWidth * sizeof(RGBTRIPLE) + padding * i, SEEK_SET);

            // Iterate over pixels in scanline
            for (int k = 0; k < bi.biWidth; k++)
            {
                // temporary storage
                RGBTRIPLE triple;

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

                // Iterate over pixels in scanline n times
                for (int l = 0; l < n; l++)
                {
                    // write RGB triple to outfile
                    fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
                }
            }

            // then add it back (to demonstrate how)
            for (int m = 0; m < padding; m++)
            {
                fputc(0x00, outptr);
            }
        }
        // skip over padding, if any
        fseek(inptr, padding, SEEK_CUR);
    }

    // close infile
    fclose(inptr);

    // close outfile
    fclose(outptr);

    // success
    return 0;
}

Any helps is appreciated!

1 Answer 1

0

One thing is

    // Update width and height for new BITMAPHEADER | old = bi.biWidth and bi.biHeight
    bi.biWidth *= n;
    bi.biHeight *= n;

From this point on, bi.biHeight and bi.biWidth represent output dimensions. In lines

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

the outer loop should use input image height. Same later for width.

There are multiple possible fixes. One quick fix would be to use bi.biHeight/n after that, computing the old dimensions from the new one. Or, what I would prefer, save the old width/height to additional variables before you multiply-assign.

The formula in the first fseek is wrong (only positions with SEEK_CUR or SEEK_END could be negative, and you might need a pair of parentheses), and if you use SEEK_SET, you don't need a second fseek. Where would line i begin in the file? It would surely have to skip the headers.

The fseek would have to move you to the correct position within a file. A relative approach (using SEEK_CUR) would have to go back by the bytes read on some lines, and go forward by input padding in others (possibly in multiple steps, like always rewind, but then go forward by a line's pixels plus padding). An absolute approach (with SEEK_SET) would have to set the position to the beginning of the bitmap, plus a number of bytes per input line.

7
  • Thanks, can you expand your answer? What do I need to add/change to reference the input height/width? Do my for loops for i and j need to be updated? Is the fseek to skip padding the only fseek I need in the code? Commented Dec 5, 2018 at 18:10
  • Expanded it a bit.
    – Blauelf
    Commented Dec 6, 2018 at 17:02
  • Thanks! I tried several iterations to make all but the 3 following work: :( resizes small.bmp correctly when n is 2 Byte 22 of pixel data doesn't match. Expected 0xff, not 0x00 :( resizes small.bmp correctly when n is 3 Byte 30 of pixel data doesn't match. Expected 0xff, not 0x00 :( resizes small.bmp correctly when n is 4 Byte 38 of pixel data doesn't match. Expected 0xff, not 0x00. (The updated code is too long to add) Please let me know if you have any further suggestions based on this. Commented Dec 11, 2018 at 3:08
  • The byte's value would for example be different if you 1. wrote wrong number of pixels per line, or 2. somehow messed up with input or output padding (they might be of different size), or 3. implemented a re-read approach (which you did) and fseeked to the wrong position
    – Blauelf
    Commented Dec 11, 2018 at 8:10
  • I revised my fseek code and moved it to right before the close file coding. Can you take a look?: if ((i+1) % n != 0) { fseek(inptr, -(oldWidth * sizeof(RGBTRIPLE) + padding), SEEK_CUR); } Commented Dec 11, 2018 at 16:12

You must log in to answer this question.

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