CS50 Pset4 Resize程序求助:处理像素后文件大小异常波动
Troubleshooting CS50 Pset4 Resize: Unexpected Output File Sizes
Hey there, let's walk through some key areas to investigate for your Resize task issues—BMPs are tricky with their headers, padding, and file pointer management, so these are the most likely spots where things are going off the rails:
Header & Size Calculation Issues
- You're writing the file header before updating its size! Look at your code: you call
fwrite(&bf, ...)first, then modifybf.bfSizeafterward. That means the output file gets the original, unmodified file size instead of the scaled one—this breaks the entire file structure right out the gate, leading to invalid sizes or corrupted data. - Your
bf.bfSizeformula is wrong. The linebf.bfSize = (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(bi.biSizeImage));usessizeof(bi.biSizeImage)—butbi.biSizeImageis already the total size of the pixel data (in bytes). You don't need to take its size; just use the value directly. - Double-check how you're calculating
bi.biSizeImage: make sure you're using the scaled width to compute the new padding, and that the formula accounts for every scanline (including padding) multiplied by the scaled height.
Input File Pointer & Loop Logic
- You're iterating over the scaled height instead of the original height. When you do
for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++),bi.biHeightis already the scaled value. That means you're trying to read way more scanlines than exist in the original file—freadwill start pulling garbage data once it hits the end of the input, which messes up all subsequent writes. You need to save the original width and height before modifying them, then loop over those original values when reading from the input. - Your pixel-reading loop uses the scaled width. The line
for (int j = 0; j < bi.biWidth; j++)uses the scaled width to read pixels from the original file, which is way more than the original scanline has. Again, you need to use the original width here to read only the pixels that actually exist in each input scanline.
Padding & Scanline Writing
- Make sure you're skipping the original padding, not the scaled one. When you call
fseek(inptr, padding, SEEK_CUR), thatpaddingvariable is calculated using the scaled width—you need to compute and use the original padding value here instead, otherwise you'll skip too many (or too few) bytes in the input file. - Double-check that when you write the scaled scanlines n times, you're adding the new scaled padding each time. Your current code does this, but if the padding calculation is wrong (from using original width instead of scaled), this will still break things.
Here's your code for reference:
// 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; }
内容的提问来源于stack exchange,提问作者juansf111
相关产品推荐
相关产品推荐

