I have been working on resize.c(less comfortable) for days (tears hair out). My code is able to resize just fine but the colours of the output image are messed up. I just can't seem to find any logical fault in my code, despite having trawled through CS50 reddit and stackexchange.
Moreover, peek shows that my output matches the staff's implementation. My only guess is that the problem lies with the padding and seek but I am not sure where since the code I have written for them seem logical to me too.
This is how I understand the logic dealing with the infile padding after each row is copied and resized accordingly:
Since the cursor has moved bi.biWidth number of pixels to the right in the infile, one way to resize it vertically is by calling the fseek function to move the cursor back bi.biWidth number of pixels in infile. Hence, there is no need to skip the padding in the original picture until the last vertical resize. At the last vertical resize, using fseek, cursor should skip over infile padding, if any, so that the cursor can move and start iterating infile’s scanlines from the second row of infile, in this case, small.bmp.
Any help and explanation of the reasoning behind would be immensely appreciated!!
Here is my code and the relevant images below:
#include <stdio.h>
#include <stdlib.h>
#include "bmp.h"
int main(int argc, char *argv[])
{
// ensure proper usage
if (argc != 4)
{
fprintf(stderr, "Usage: ./resize n infile outfile\n");
return 1;
}
// validate user input: check resize n
int n = atoi(argv[1]);
if (n < 0 || n > 100)
{
printf("Resize n should be a positive integer less than 100.\n");
return 2;
}
// remember filenames
char *infile = argv[2];
char *outfile = argv[3];
// open input file for reading
FILE *inptr = fopen(infile, "r");
if (inptr == NULL)
{
fprintf(stderr, "Could not open %s.\n", infile);
return 3;
}
// open output file for writing
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;
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;
}
// create copy of original dimensions
int biWidth_original = bi.biWidth;
int biHeight_original = bi.biHeight;
// update image dimensions in BITMAPFILEHEADER in bmp.h file
bi.biWidth *= n;
bi.biHeight *= n;
// determine padding for scanlines (padding is measured in pixels)
int padding_original = (4 - (biWidth_original * sizeof(RGBTRIPLE)) % 4) % 4;
int padding_resize = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
// update image size
bi.biSizeImage = abs(bi.biHeight) * ((abs(bi.biWidth) *
sizeof(RGBTRIPLE)) + padding_resize);
// update file size
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 height of image
for (int i = 0; i < biHeight_original; i++)
{
// scale vertically: write each row to outfile n times
for (int j = 0; j < n; j++)
{
// iterate through pixels in scan line (one loop for one pixel)
for (int k = 0; k < biWidth_original; k++)
{
// temporary storage
RGBTRIPLE triple;
// read RGB triple from infile, one at a time!
fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
// scale horizontally: write each pixel to outfile n times
for (int l = 0; l < n; l++)
{
// write RGB triple to outfile
fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
}
}
// add padding back to outfile
for (int m = 0; m < padding_resize; m++)
{
fputc(0x00, outptr);
}
if (j < n - 1)
{
// reset cursor to start of scanline
fseek(inptr, -(biWidth_original * sizeof(RGBTRIPLE)),
SEEK_CUR);
}
else
{
// If at last vertical line, skip infile padding in order for cursor to move on to next row
fseek(inptr, padding_original, SEEK_CUR);
}
}
}
// close infile
fclose(inptr);
// close outfile
fclose(outptr);
// success
return 0;
}