Just spent 2 days for figuring out how fread()
, fwrite()
and fseek()
works.
I tried to use "Rewrite" method from Zamyla's video for vertycal resizing:
- Remember pixels in array (first written row of outfile)
- Write array as many time as needed (n-1 times more)
Now I'm trying to copy a row of my out file in resize.c
fread()
returns an error, please help me find the reason of it. Thanks!
/**
* resize.c
*
* Computer Science 50
* Problem Set 4
* by Semen Pilyukov
* [email protected]
*
* Copies a BMP piece by piece, just because.
*/
#include <stdio.h>
#include <stdlib.h>
#include "bmp.h"
int main(int argc, char* argv[])
{
/**
* Usage control and header stuff works correctly!
*
*/
// ensure proper usage
if (argc != 4)
{
printf("Usage: ./copy n infile outfile\n");
printf("Usage: n - integer multiplier between 1 and 100 iclusivly\n");
return 1;
}
// remember multiplier filenames
int n = atoi(argv[1]);
char* infile = argv[2];
char* outfile = argv[3];
// ensure proper multiplier
if (n < 1 || n > 100)
{
printf("Usage: ./copy n infile outfile\n");
printf("Usage: n - integer multiplier between 1 and 100 iclusivly\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;
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 headers for output image
BITMAPFILEHEADER outbf = bf;
BITMAPINFOHEADER outbi = bi;
// determine biWidth and biHeight for output image
outbi.biWidth *= n;
outbi.biHeight *= n;
// determine padding for scanlines in inptr
int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
// determine padding for scanlines and writing in outptr
int outpadding = (4 - (outbi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
// determine biSizeImage and bfSize for output image
outbi.biSizeImage = (outbi.biWidth * sizeof(RGBTRIPLE) + outpadding) * abs(outbi.biHeight);
outbf.bfSize = outbi.biSizeImage + sizeof(outbf) + sizeof(outbi);
// write outfile's BITMAPFILEHEADER and BITMAPINFOHEADER
fwrite(&outbf, sizeof(BITMAPFILEHEADER), 1, outptr);
fwrite(&outbi, sizeof(BITMAPINFOHEADER), 1, outptr);
/**
* Here starts the problem part of resizing
*
* 1) Copy fist row with width multiply
* 2) Step back to the start of row in outfile
* 3) Read just written outfile's row (returns an error)
* 4) Write this row (n-1) times more
* Conptrol position in outfile at every step
*
*/
// determine outfile's row size
int outrowsize = outbi.biWidth * sizeof(RGBTRIPLE) + outpadding;
// determine outfile's pixel row size (without padding)
int pixelrowsize = outbi.biWidth * sizeof(RGBTRIPLE);
// Position in out file - where we are now (position - ok)
int pos = ftell(outptr);
// Print parameters for control
printf("outrowsize %i\noutpadding %i\npixelrowsize %i\npos before all %i\n\n", outrowsize, outpadding, pixelrowsize, pos);
// Temporary storage of a whole row. !!! MAYBE HERE IS A PROBLEM
RGBTRIPLE* outrow = malloc(pixelrowsize);
// iterate over infile's scanlines
for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
{
// iterate over pixels in scanline
for (int j = 0; j < bi.biWidth; j++)
{
// temporary storage
RGBTRIPLE triple;
// read RGB triple from infile
fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
// write RGB triple 'n' times to outfile
for (int f = 0; f < n; f++)
fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
}
// Position in out file - where we are now (ok)
pos = ftell(outptr);
printf("before padding %i\n", pos);
// skip over padding, if any
fseek(inptr, padding, SEEK_CUR);
// add outfile's padding
for (int k = 0; k < outpadding; k++)
{
fputc(0x00, outptr);
}
// Check position - ok
pos = ftell(outptr);
printf("after padding %i\n", pos);
// Move to the beginning of row
fseek(outptr, - outrowsize, SEEK_CUR);
// Check position - ok
pos = ftell(outptr);
printf("after lineback %i\n", pos);
// HERE IS THE PROBLEM!
// Read from "outptr" file stream "pixelrowsize" bytes 1 time
// and place it into "outrow" storage
// RETURNS AN ERROR :'-(
if ((fread(outrow, pixelrowsize, 1, outptr) != 1))
printf("read error!\n");
// Check position - DID NOT CHANGED
pos = ftell(outptr);
printf("after pixelline read %i\n", pos);
// Move to the end of row (skip padding)
fseek(outptr, outpadding, SEEK_CUR);
// then copy line of outfile 'n' times
for (int m = 0; m < n - 1; m++)
{
// write copied row to outfile (WRITES SUCCESSFULLY)
// But storage "outrow" is empty, thats way prints black
if ((fwrite(outrow, pixelrowsize, 1, outptr) != 1))
printf("write error!\n");
// Add padding
for (int r = 0; r < outpadding; r++)
{
fputc(0x00, outptr);
}
}
// Check position - it changes, but it wrong because read error
pos = ftell(outptr);
printf("after pixelline write %i\n\n", pos);
}
// nobody likes memory leaks
free(outrow);
// close infile
fclose(inptr);
// close outfile
fclose(outptr);
// that's all folks
return 0;
}
And results:
/home/ubuntu/workspace/pset4/bmp/ $ ./resize 2 small.bmp staff.bmp
outrowsize 20
outpadding 2
pixelrowsize 18
pos before all 54
before padding 72
after padding 74
after lineback 54
read error!
after pixelline read 54
after pixelline write 76
before padding 94
after padding 96
after lineback 76
read error!
after pixelline read 76
after pixelline write 98
before padding 116
after padding 118
after lineback 98
read error!
after pixelline read 98
after pixelline write 120
fseek()
backwards to it. Post the full code so we can debug your program. We can't guess all the missing lines. Please read How to create a Minimal, Complete, and Verifiable example