0

My resize program seems to be working fine on both bitmaps that require padding, and bitmaps that don't. I've compared the results with the staff's solution both visually and using peek, but everything seems identical. I've been scratching my head for a couple of hours over this now, but to no avail.

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

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

//Check if the resize factor is valid
if(!(rfactor > 0 && rfactor < 101)) 
{
    printf("Invalid resize factor %d. Enter value between 1 and 100.\n", rfactor);
    return 4;
}

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

bi.biHeight *= rfactor;
int padding =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
bi.biWidth *= rfactor;

// determine padding for scanlines
int paddingOut =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
bi.biSizeImage = ((bi.biWidth) * sizeof(RGBTRIPLE) + (paddingOut)) * abs(bi.biHeight);
bf.bfSize = (bi.biSizeImage) + 54;

// 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++)
{
    fpos_t position;
    // iterate over pixels in scanline
    for (int j = 0; j < bi.biWidth/rfactor; j++)
    {
        // temporary storage
        RGBTRIPLE triple;
        if (j == 0)
            fgetpos(inptr, &position);
        // read RGB triple from infile
        fread(&triple, sizeof(RGBTRIPLE), 1, inptr);

        // write RGB triple to outfile
        for(int k = 0; k < rfactor; k++) {
            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 < paddingOut; k++)
    {
        fputc(0x00, outptr);
    }

    ///////////////////////////////////////////////////////////////////////
    for(int l = 0; l < rfactor - 1; l++)
    {
        // repeat lines vertically
        for (int j = 0; j < bi.biWidth/rfactor; j++)
        {
            // temporary storage
            RGBTRIPLE triple;
            if(j == 0)
                fsetpos(inptr, &position);
            // read RGB triple from infile
            fread(&triple, sizeof(RGBTRIPLE), 1, inptr);

            // write RGB triple to outfile
            for(int k = 0; k < rfactor; k++) {
                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 < paddingOut; k++)
        {
            fputc(0x00, outptr);
        }
    }
    ///////////////////////////////////////////////////////////////////////
}

// close infile
fclose(inptr);

// close outfile
fclose(outptr);

// that's all folks
return 0;
}

For some reason, repeating the "repeat lines vertically" loop rfactor times, instead of manually copying the code below doesn't seem to work perhaps because I'm not able to 'fgetpos' correctly while doing that. Anyhow, the above code is producing the expected output with the expected headers (as compared against the results produced by the official solution using peek). I'm forgetting something quite basic somewhere, so any clues are appreciated. :)

Here is a screenshot displaying the header information for official as well as my solution for a single pixel image enlarged by me by a factor of 2.

Enlarged smileys

Here is another screenshot displaying the header information and the images (both official one, and the one outputted by my resize.c) for smiley.bmp

Enlarged smileys

Similarly, I've also tried images that require padding, and they too resize fine and match with the headers of official output.

1

Actually, the posted code is not doing many of the things that it should. If tested with rfactor == 1, it works fine, as indicated by :) doesn't resize 1x1-pixel BMP when n is 1. However, when rfactor > 1, it falls apart. Header calculations are incorrect and the image data actually outputs far less data than the image data of the original image file.

My recommendation is to go back and, using a resize factor of 2, get the header data right first, and then get the image data right.

I'm really confused why there are two for loops that are essentially identical and that both output lines of pixels. You should be able to write this program with only one of these loops, with the proper controls on how often each input line should be processed. Anytime you have a significant block of code that is essentially identical to another block, it should be a red flag that the logic is flawed and that the two blocks can be accomplished by only one block.

Hopefully, this helps you to get started again. There's a bit of work and rewrite needed, but you should be able to get through it.

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

2
  • Hi. Sorry if I'm wrong, but can you please check the screenshots I added in my edited question? I can't seem to find any discrepancies in the header data outputted by my version of resize (as compared with the official one). And thanks for the suggestion about using the for loop. :) (I've addressed this issue in my question, using single loop, I somehow couldn't figure out when to get the position, and when to set it. I'd try doing it again once my solution works fine passes check50.) Dec 17 '16 at 13:04
  • No. I can't. Screen shots appear like microfilm. Please remove them and replace them with cut and paste of the actual results. Also, instead of running peek for each file, use two filenames as parameters so that the results are posted side by side and any differences are automatically highlighted. ~cs50/pset4/peek small2x.bmp s2.bmp
    – Cliff B
    Dec 17 '16 at 21:04

You must log in to answer this question.

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