I'm currently taking the CS50 course, and I'm completely stuck on the resize problem (less comfortable). The assignment is to make a program that takes an input .bmp file, scales it n times and writes that to an output .bmp file. But my code just kinda distorts the input image and doesn't change the size at all. This is the bmp that is supplied for testing (3x3 pixels, just zoomed in here): https://imgur.com/1v55tjz And when I attempt to resize it, it just turns to this (still 3x3): https://imgur.com/JAKQMfY
This is the code for resizing:
#include <stdio.h>
#include <stdlib.h>
#include "bmp.h"
int main(int argc, char *argv[])
{
// ensure proper usage
if (argc != 4)
{
fprintf(stderr, "Usage: ./copy infile outfile\n");
return 1;
}
// remember filenames
int n = atoi(argv[1]);
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;
}
// 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 file- and infoheader for output file
BITMAPFILEHEADER outBF = bf;
BITMAPINFOHEADER outBI = bi;
//Scale width and height by n
outBI.biWidth *= n;
outBI.biHeight *= n;
//Calculate padding for input and output file
int outPadding = (4 - (outBI.biWidth * sizeof(RGBTRIPLE) % 4) % 4);
int inPadding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
//Calculate biSizeImage and bfSize for output file
outBI.biSizeImage = ((sizeof(RGBTRIPLE) * outBI.biWidth) + outPadding * abs(outBI.biHeight));
outBF.bfSize = outBI.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);
//Instantiate two counters to keep track of whether we have reached the n - 1 times of the recopy method and to be able to fseek to the next line
int countIterations = 1;
int countPositionInFile = 0;
// iterate over infile's scanlines
for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
{
countIterations = 1;
for(int j = 0; j < n; j++)
{
// iterate over pixels in scanline
for (int k = 0; k < bi.biWidth; k++)
{
// temporary storage
RGBTRIPLE triple;
// read RGB triple from infile
fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
// resize horizontally by writing every pixel in row n times
for(int l = 0; l < n; l++)
{
// write RGB triple to outfile
fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
}
}
// skip over padding, if any
fseek(inptr, inPadding, SEEK_CUR);
//Add padding for this line
for (int l = 0; l < outPadding; l++)
{
fputc(0x00, outptr);
}
if(countIterations == n)
{
countPositionInFile++;
}
int newPosition = (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + (countPositionInFile * (bi.biWidth + inPadding)));
// return the "cursor" to the start of the file
fseek(inptr, newPosition, SEEK_SET);
countIterations++;
}
}
// close infile
fclose(inptr);
// close outfile
fclose(outptr);
// success
return 0;
}
And this is the bmp.h file:
/**
* BMP-related data types based on Microsoft's own.
*/
#include <stdint.h>
/**
* Common Data Types
*
* The data types in this section are essentially aliases for C/C++
* primitive data types.
*
* Adapted from https://msdn.microsoft.com/en-us/library/cc230309.aspx.
* See http://en.wikipedia.org/wiki/Stdint.h for more on stdint.h.
*/
typedef uint8_t BYTE;
typedef uint32_t DWORD;
typedef int32_t LONG;
typedef uint16_t WORD;
/**
* BITMAPFILEHEADER
*
* The BITMAPFILEHEADER structure contains information about the type, size,
* and layout of a file that contains a DIB [device-independent bitmap].
*
* Adapted from https://msdn.microsoft.com/en-us/library/dd183374(v=vs.85).aspx.
*/
typedef struct
{
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} __attribute__((__packed__))
BITMAPFILEHEADER;
/**
* BITMAPINFOHEADER
*
* The BITMAPINFOHEADER structure contains information about the
* dimensions and color format of a DIB [device-independent bitmap].
*
* Adapted from https://msdn.microsoft.com/en-us/library/dd183376(v=vs.85).aspx.
*/
typedef struct
{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} __attribute__((__packed__))
BITMAPINFOHEADER;
/**
* RGBTRIPLE
*
* This structure describes a color consisting of relative intensities of
* red, green, and blue.
*
* Adapted from https://msdn.microsoft.com/en-us/library/dd162939(v=vs.85).aspx.
*/
typedef struct
{
BYTE rgbtBlue;
BYTE rgbtGreen;
BYTE rgbtRed;
} __attribute__((__packed__))
RGBTRIPLE;
I hope someone has experience with this assignment and can help, I feel pretty stuck right now tbh, but maybe I've just been staring at it for too long. Thanks in advance!
Files should be opened with binary flags:
FILE *inptr = fopen(infile, "rb");
FILE *outptr = fopen(outfile, "wb");
You are ignoring outBI
and outBF
, you are writing the old header in to new file:
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);//old header
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);//old header
Two different methods is used here to calculate the padding:
int outPadding = (4 - (outBI.biWidth * sizeof(RGBTRIPLE) % 4) % 4);
int inPadding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
^ ^
They can't both be right, except by accident. In this case we are using 24-bitmaps you can calculate padding as
int outPadding = outBI.biWidth % 4;
int inPadding = bi.biWidth % 4;
This will match the way you skip the padding with fseek(inptr, inPadding, SEEK_CUR);
and for(...) fputc(0x00, outptr);
I couldn't figure out this code:
int newPosition = (sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER)
+ (countPositionInFile * (bi.biWidth + inPadding)));<==remove
fseek(inptr, newPosition, SEEK_SET);<==remove
That's should be (bi.biWidth * 3)
Or you could just remove that and use ftell
to save the position before starting to read the line, and use fseek
to go back to that position.
Bitmap height should be read from bottom to top, but in this case it doesn't make a difference.
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.