I wonder if someone could point me in the right direction on this problem (no answers, just hints on what the issue is). The idea of the problem is to resize a BMP image in accordance to an integer provided as a command argument. If the number is 2, the file will be twice the size in pixels.
I tested the code I created to update the headers, and the size of the file was correct when I runned it. However, after attempting to resize the pixels, the size fo the file increased dramaticaly or reduced to about 50 bytes in some occasion. Not sure what the mistake is.
This is the code:
// resizes 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: resize integer (1-100) infile outfile\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;
}
int n= atoi(argv[1]);
// 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;
}
// modify bitmapinfoheader for height an width
bi.biWidth = bi.biWidth*n;
bi.biHeight = bi.biHeight*n;
// determine padding for scanlines
int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
// modify bisizeimage
bi.biSizeImage = (((bi.biWidth*(sizeof(RGBTRIPLE)))+padding)*abs(bi.biHeight));
// write outfile's BITMAPFILEHEADER
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);
// modify bfsize before writing it
bf.bfSize = (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(bi.biSizeImage));
// 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++)
{
// temporary storage for a triple
RGBTRIPLE triple;
// temporary storage for scanline
RGBTRIPLE scanline[bi.biWidth];
//array position counter
int arraypos = 0;
// iterate over pixels in scanline
for (int j = 0; j < bi.biWidth; j++)
{
// read RGB triple from infile
fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
//write to array n times
for (int l = 0; l < n; arraypos++, l++)
{
scanline[arraypos] = triple;
}
}
for (int m = 0; m < n; m++)
{
// write array to outfile
fwrite(&scanline, sizeof(scanline), 1, outptr);
// Add padding)
for (int k = 0; k < padding; k++)
{
fputc(0x00, outptr);
}
}
// skip over padding, if any
fseek(inptr, padding, SEEK_CUR);
}
// close infile
fclose(inptr);
// close outfile
fclose(outptr);
// success
return 0; }
bf.bfSize = (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +
sizeof(bi.biSizeImage));
sizeof(bi.biSizeImage)
is just sizeof(int)
. This is supposed to be the file size, so you need bi.biSizeImage
itself.
Another problem is that you change the width and height, but you don't save the old width and height. If the new width and height are larger then you hit end of file.
Change as follows, also add error checks for fread
int width_save = bi.biWidth;
int height_save = bi.biHeight;
bi.biWidth *= n;
bi.biHeight *= n;
//calculate width in bytes
int wb_in = ((width_save * 24 + 31) / 32) * 4;
int wb_out = ((bi.biWidth * 24 + 31) / 32) * 4;
bi.biSizeImage = wb_out * abs(bi.biHeight);
bf.bfSize = 54 + bi.biSizeImage;
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);
RGBTRIPLE *line_in = malloc(wb_in);
RGBTRIPLE *line_out = malloc(wb_out);
for(int i = 0; i < abs(height_save); i++)
{
fread(line_in, 1, wb_in, inptr);
for(int a = 0; a < width_save; a++)
for (int b = 0; b < n; b++)
line_out[a * n + b] = line_in[a];
for(int a = 0; a < n; a++)
fwrite(line_out, 1, wb_out, outptr);
}