The task is to rezise a bmp image with a factor. My code works visually, it looks correct when I check the hexadeximal of the rezised picture and the size is correct, but check50 says the picture is too large. I checked the size by downloading the picture and looked at the hexadecimal via the CS50 IDE. I also tried other code from GitHub but that code was also rejected by Check50. What is the error? Thanks in advance!
// Copies a BMP file
#include <stdio.h>
#include <stdlib.h>
#include "bmp.h"
int main(int argc, char *argv[])
{
// ensure proper usage
if (argc != 4)
{
printf("Usage: copy infile outfile\n");
return 1;
}
// remember filenames
int factor = atoi(argv[1]);
char *infile = argv[2];
char *outfile = argv[3];
if(factor < 0 || factor > 100)
{
printf("facor must be between 0 and 100\n");
return 15;
}
// 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);
printf("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);
printf("Unsupported file format.\n");
return 4;
}
//adjust fileheader
BITMAPFILEHEADER bf_out = bf;
BITMAPINFOHEADER bi_out = bi;
//HEIGHT AND WIDTH
bi_out.biWidth = bi.biWidth * factor;
bi_out.biHeight = bi.biHeight * factor;
// determine padding for scanlines
int padding = (4 - (bi_out.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
//IMAGESIZE
bi_out.biSizeImage = bi_out.biHeight * bi_out.biWidth * sizeof(RGBTRIPLE)+ padding;
//BITMAPFILEHEADER
bf_out.bfSize = bi_out.biSizeImage - sizeof(BITMAPFILEHEADER) - sizeof(BITMAPINFOHEADER);
// write outfile's BITMAPFILEHEADER
fwrite(&bf_out, sizeof(BITMAPFILEHEADER), 1, outptr);
// write outfile's BITMAPINFOHEADER
fwrite(&bi_out, sizeof(BITMAPINFOHEADER), 1, outptr);
printf("Original bfSize: %d\n", bf.bfSize);
printf("Resized bfSize: %d\n", bf_out.bfSize);
printf("Bitmapinfoheader: %lu\n", sizeof(BITMAPINFOHEADER));
printf("Bitmapfileheader: %lu\n", sizeof(BITMAPFILEHEADER));
printf("Original biSizeImage: %d\n", bi.biSizeImage);
printf("Resized biSizeImage: %d\n", bi_out.biSizeImage);
printf("Original biWidth: %d\n", bi.biWidth);
printf("Original biHeight: %d\n", bi.biHeight);
printf("Resized biWidth: %d\n", bi_out.biWidth);
printf("Resized biHeight: %d\n", bi_out.biHeight);
// iterate over infile's scanlines
for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
{
// temporary storage
RGBTRIPLE triple[bi.biWidth];
// iterate over pixels in scanline
for (int j = 0; j < bi.biWidth; j++)
{
// read RGB triple from infile
fread(&triple[j], sizeof(RGBTRIPLE), 1, inptr);
}
for(int l = 0; l < factor; l++)
{
for(int o = 0; o < bi.biWidth; o++)
{
for(int g = 0; g < factor; g++)
{
fwrite(&triple[o], sizeof(RGBTRIPLE), 1, outptr);
}
}
for (int k = 0; k < padding; k++)
{
fputc(0x00, outptr);
}
}
}
// close infile
fclose(inptr);
// close outfile
fclose(outptr);
// success
return 0;
}
//BITMAPFILEHEADER
bf_out.bfSize = bi_out.biSizeImage - sizeof(BITMAPFILEHEADER) - sizeof(BITMAPINFOHEADER);
The file size is image size plus the size of the headers. Not minus.
And you can replace this
// temporary storage
RGBTRIPLE triple[bi.biWidth];
// iterate over pixels in scanline
for (int j = 0; j < bi.biWidth; j++)
{
// read RGB triple from infile
fread(&triple[j], sizeof(RGBTRIPLE), 1, inptr);
}
With just a single fread call. No need to loop.
RGBTRIPLE triple[bi.biWidth];
fread(triple, sizeof(RGBTRIPLE), bi.biWidth, inptr);
You also need to calculate padding for the original image and then seek past it after you read into the buffer.
After looking for a solution online I finally managed to find a working code that I also understand. Maybe it will help someone with similar problems. This solution works with while loops instead of for loops and the padding is done outside of the inner loops but despite that the code is pretty much the same.
/**
* resize.c
*
* Computer Science 50
* Problem Set 4
*
* Copies a BMP piece by piece, but also resizes it, just because.
*/
#include <stdio.h>
#include <stdlib.h>
#include "bmp.h"
int main(int argc, char* argv[])
{
// ensure proper usage
if (argc != 4)
{
printf("Usage: ./resize factor infile outfile\n");
return 1;
}
// remember filenames and resize factor
int factor = atoi(argv[1]);
char* infile = argv[2];
char* outfile = argv[3];
// check factor
if (factor < 1 || factor > 100)
{
printf("Factor must be in the range [1-100]\n");
return 1;
}
// 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;
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;
}
// set new width and height dimensions
bi_new.biWidth = bi.biWidth * factor;
bi_new.biHeight = bi.biHeight * factor;
// determine padding for scanlines
int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
int new_padding = (4 - (bi_new.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
// set new file size
bf_new.bfSize = 54 + (bi_new.biWidth * sizeof(RGBTRIPLE) + new_padding) * abs(bi_new.biHeight);
bi_new.biSizeImage = bf_new.bfSize - 54;
// write outfile's BITMAPFILEHEADER
fwrite(&bf_new, sizeof(BITMAPFILEHEADER), 1, outptr);
// write outfile's BITMAPINFOHEADER
fwrite(&bi_new, sizeof(BITMAPINFOHEADER), 1, outptr);
// iterate over infile's scanlines
for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
{
// each row will be printed out factor times
int rowcounter = 0;
while (rowcounter < factor)
{
// iterate over pixels in scanline
for (int j = 0; j < bi.biWidth; j++)
{
// temporary storage
RGBTRIPLE triple;
// each pixel will be printed out factor times
int pixelcounter = 0;
// read RGB triple from infile
fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
// write RGB triple to outfile
while (pixelcounter < factor)
{
fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
pixelcounter++;
}
}
// add new padding
for (int k = 0; k < new_padding; k++)
fputc(0x00, outptr);
// seek back to the beginning of row in input file, but not after iteration of printing
if (rowcounter < (factor - 1))
fseek(inptr, -(bi.biWidth * sizeof(RGBTRIPLE)), SEEK_CUR);
rowcounter++;
}
// skip over padding, if any
fseek(inptr, padding, SEEK_CUR);
}
// close infile
fclose(inptr);
// close outfile
fclose(outptr);
// that's all folks
return 0;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.