1

i've been struggling with this for days now. Could someone plz point out what i am doing wrong? It resizes pictures without padding properly, but despite introducing new_padding for resized picture, code is not working for small.bmp

I would greatly apreciate any tips.

int main(int argc, char* argv[])
{
// ensure proper usage

if (argc != 4)
{
    printf("Usage: ./copy infile outfile\n");
    return 1;
}

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


if (size < 1 || size > 100)
{
    printf("%d not within 0-100 range \n", size);
    return 2;
}

// open input file 
FILE* inptr = fopen(infile, "r");
if (inptr == NULL)
{

    printf("Could not open %s.\n", infile);
    return 3;
}

// open output file
FILE* outptr = fopen(outfile, "w");
if (outptr == NULL)
{
    fclose(inptr);
    fprintf(stderr, "Could not create %s.\n", outfile);
    return 4;
}
// read infile's BITMAPFILEHEADER
BITMAPFILEHEADER bf;
BITMAPFILEHEADER bf_new;
fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);
bf_new = bf;


// read infile's BITMAPINFOHEADER
BITMAPINFOHEADER bi;
BITMAPINFOHEADER bi_new;

fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr);
bi_new = bi;
// 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_new.biWidth *= size; 
bi_new.biHeight *= size; 
int padding =  (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
int new_padding =  (4 - (bi_new.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;

int a = bi.biSizeImage - padding * abs(bi.biHeight);
bi_new.biSizeImage = (a * size * size) + new_padding * abs(bi_new.biHeight); 
bf_new.bfSize = bi_new.biSizeImage + 54;
// write outfile's BITMAPFILEHEADER
fwrite(&bf_new, sizeof(BITMAPFILEHEADER), 1, outptr);

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

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

// iterate over infile's scanlines


for (int i = 0, biHeight = abs(bi_new.biHeight); i < biHeight; i++)
{ 
    if (i % size != 0)
    {
        fseek(inptr, -bi.biWidth * sizeof(RGBTRIPLE), SEEK_CUR);
    } 
    // 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
        for (int z = 0; z < size; z++)
        {
            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 < new_padding; k++)
    {
        fputc(0x00, outptr);
    } 



}

// close infile
fclose(inptr);

// close outfile
fclose(outptr);

// that's all folks
return 0;
}
0

1 Answer 1

5

A subtle problem. You probably realized that it had something to do with padding, but couldn't track it down. The problem is that you forgot to account for the padding of the input file when repositioning the file pointer after processing each line of pixels. Look at the code block at the beginning of the for loop that resets the pointer (btw, very creative. First time I've seen it done with %. Nice!):

if (i % size != 0)
{
    fseek(inptr, -bi.biWidth * sizeof(RGBTRIPLE), SEEK_CUR);
} 

Now, consider what happens at the end of the loop:

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

When the loop goes back to the top for the next pass, the first fseek doesn't go back to the beginning of the line. Instead it goes to the beginning + padding size. The result is a corrupted image.

The fix is easy.

fseek(inptr, -(bi.biWidth * sizeof(RGBTRIPLE) + padding), SEEK_CUR);

I made this change and it passed check50 100%.

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

7
  • Thank you so much for this! I was losing my mind, now i finally get it :)
    – Mags
    Commented Aug 28, 2015 at 16:42
  • This doesn't appear to work for n (or var size) > 1 on small.bmp. Without pasting my entire code here, there's no way to tell but I wonder if I'm missing something else, or if this solution is incomplete...
    – user10167
    Commented Mar 14, 2016 at 21:05
  • Can you please explain the fseek portion above the read pixel portion? Commented Jun 12, 2016 at 4:44
  • can't we just do fwrite(&triple, sizeof(RGBTRIPLE), n, outptr); instead of looping from 0 till n to write each pixel horizontally in the output file? Commented Jun 12, 2016 at 4:45
  • no, you can't. The fwrite function is this: fwrite( starting_address, size_of_source_elements, number of source elements, target). The third parameter specifies how many consecutive source elements from the source to write, not how many times to write the same source element.
    – Cliff B
    Commented Jun 12, 2016 at 4:57

You must log in to answer this question.

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