I have corrected my code. Now I have two versions, but both fail to print the
same scanline twice (vertical scaling). No problems with horizontal scaling.
I will be grateful for your help!
Below are two versions I have. If factor = n
, then the first one packs n
lines
in a block, and writes that block n
times. For example, if factor = 2
, then
every two lines
will be printed two times
. I have spent more than a day analyzing
this, but the only problem I see is the fseek
function that takes di.diWidth
as
as parameter. di.diWidth
is changed before the start of loops, hence it seems
logical that n
lines are printed n
times. So, in the second version I changed
di.diWidth
back to its initial value by dividing by the factor
. This version
also produces a bizarre outcome (I have tested both on smiley.bmp
).
What is my mistake? Did my best to come up with the solution, but I don't see
the problem in the logic of the code.
Second version:
#include <stdio.h>
#include <stdlib.h>
#include "bmp.h"
int main(int argc, char* argv[])
{
// ensure proper usage
if (argc != 4)
{
printf("Usage: ./copy value infile outfile\n");
return 1;
}
int factor = atoi(argv[1]);
// ensure positive integers
if (factor < 1 && factor > 100)
{
printf("Incorrect value of n\n");
return 2;
}
// remember filenames
char* infile = argv[2];
char* outfile = argv[3];
// 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;
}
int padding_infile = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
printf("%d %d %d\n", bi.biWidth, bi.biHeight, padding_infile);
bi.biWidth *= factor;
bi.biHeight *= factor;
int biHeight = abs(bi.biHeight);
// determine padding for infile and outfile
int padding_outfile = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
// determine the new image size, including padding
bi.biSizeImage = (bi.biWidth * sizeof(RGBTRIPLE) + padding_outfile) * biHeight;
// update file size
bf.bfSize = bi.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
printf("width %d height %d padding %d imagesize %d file size %d\n", bi.biWidth, bi.biHeight, padding_outfile, bi.biSizeImage, bf.bfSize);
// write outfile's BITMAPFILEHEADER
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);
// write outfile's BITMAPINFOHEADER
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);
// count rows with same pixels
int count = 0;
// iterate over infile's scanlines
for (int i = 0; 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 to outfile repeating each pixel factor times
for (int m = j; m < factor + j; m++)
{
fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
}
}
// add padding to outfile
for (int k = 0; k < padding_outfile; k++)
{
fputc(0x00, outptr);
}
count++;
if (count == factor)
{
// skip over padding, if any
fseek(inptr, padding_infile, SEEK_CUR);
count = 0;
}
else /** if (count > 0 && count < factor) **/
{
fseek(inptr, (-(bi.biWidth / factor) * sizeof(RGBTRIPLE) - padding_infile), SEEK_CUR);
}
}
// close infile
fclose(inptr);
// close outfile
fclose(outptr);
// that's all folks
return 0;
}
First version that prints n
lines n times
:
#include <stdio.h>
#include <stdlib.h>
#include "bmp.h"
int main(int argc, char* argv[])
{
// ensure proper usage
if (argc != 4)
{
printf("Usage: ./copy value infile outfile\n");
return 1;
}
int factor = atoi(argv[1]);
// ensure positive integers
if (factor < 1 && factor > 100)
{
printf("Incorrect value of n\n");
return 2;
}
// remember filenames
char* infile = argv[2];
char* outfile = argv[3];
// 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;
}
int padding_infile = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
printf("%d %d %d\n", bi.biWidth, bi.biHeight, padding_infile);
bi.biWidth *= factor;
bi.biHeight *= factor;
int biHeight = abs(bi.biHeight);
// determine padding for infile and outfile
int padding_outfile = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
// determine the new image size, including padding
bi.biSizeImage = (bi.biWidth * sizeof(RGBTRIPLE) + padding_outfile) * biHeight;
// update file size
bf.bfSize = bi.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
printf("width %d height %d padding %d imagesize %d file size %d\n", bi.biWidth, bi.biHeight, padding_outfile, bi.biSizeImage, bf.bfSize);
// write outfile's BITMAPFILEHEADER
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);
// write outfile's BITMAPINFOHEADER
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);
// count rows with same pixels
int count = 0;
// iterate over infile's scanlines
for (int i = 0; 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 to outfile repeating each pixel factor times
for (int m = j; m < factor + j; m++)
{
fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
}
}
// add padding to outfile
for (int k = 0; k < padding_outfile; k++)
{
fputc(0x00, outptr);
}
count++;
// skip over padding, if any
fseek(inptr, padding_infile, SEEK_CUR);
if (count == factor)
{
count = 0;
}
else /** if (count > 0 && count < factor) **/
{
fseek(inptr, -(bi.biWidth/factor * sizeof(RGBTRIPLE) - padding_infile), SEEK_CUR);
}
}
// close infile
fclose(inptr);
// close outfile
fclose(outptr);
// that's all folks
return 0;
}
Thank you!
EDIT: I have changed a program to add new structures for outfile, and hence now I have
separate values for infile headers and outfile headers. I still get an altered
picture: some pixels are being repeated correctly, others not.
#include <stdio.h>
#include <stdlib.h>
#include "bmp.h"
int main(int argc, char* argv[])
{
// ensure proper usage
if (argc != 4)
{
printf("Usage: ./copy value infile outfile\n");
return 1;
}
int factor = atoi(argv[1]);
// ensure positive integers
if (factor < 1 && factor > 100)
{
printf("Incorrect value of n\n");
return 2;
}
// remember filenames
char* infile = argv[2];
char* outfile = argv[3];
// 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;
}
int padding_infile = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
/**** printf("%d %d %d\n", bi.biWidth, bi.biHeight, padding_infile); ****/
// outfile's BITMAPFILEHEADER
BITMAPFILEHEADER outfile_bf = bf;
// outfile's BITMAPINFOHEADER
BITMAPINFOHEADER outfile_bi = bi;
// update width and height of the outfile
outfile_bi.biWidth = bi.biWidth * factor;
outfile_bi.biHeight = bi.biHeight * factor;
int biHeight = abs(outfile_bi.biHeight);
// determine padding for infile and outfile
int padding_outfile = (4 - (outfile_bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
// determine the new image size, including padding
outfile_bi.biSizeImage = (outfile_bi.biWidth * sizeof(RGBTRIPLE) + padding_outfile) * biHeight;
// update file size
outfile_bf.bfSize = outfile_bi.biSizeImage + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
/**** printf("width %d height %d padding %d imagesize %d file size %d\n", outfile_bi.biWidth, outfile_bi.biHeight, padding_outfile, outfile_bi.biSizeImage, outfile_bf.bfSize); ****/
// write outfile's BITMAPFILEHEADER
fwrite(&outfile_bf, sizeof(BITMAPFILEHEADER), 1, outptr);
// write outfile's BITMAPINFOHEADER
fwrite(&outfile_bi, sizeof(BITMAPINFOHEADER), 1, outptr);
// count rows with same pixels
int count = 0;
// iterate over infile's scanlines
for (int i = 0; i < biHeight; i++)
{
// iterate over pixels in scanline
for (int j = 0; j < outfile_bi.biWidth; j++)
{
// temporary storage
RGBTRIPLE triple;
// read RGB triple from infile
fread(&triple, sizeof(RGBTRIPLE), 1, inptr);
// write RGB triple to outfile repeating each pixel factor times
for (int m = j; m < factor + j; m++)
{
fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
}
}
// add padding to outfile
for (int k = 0; k < padding_outfile; k++)
{
fputc(0x00, outptr);
}
count++;
if (count == factor)
{
// skip over padding, if any
fseek(inptr, padding_infile, SEEK_CUR);
count = 0;
}
else /** if (count > 0 && count < factor) **/
{
fseek(inptr, (-bi.biWidth * sizeof(RGBTRIPLE)), SEEK_CUR);
}
}
// close infile
fclose(inptr);
// close outfile
fclose(outptr);
// that's all folks
return 0;
}