I'm doing a course at the moment and one task is to create a program to resize 24 bit bitmap images by modifying some code they provide (which simply copies an image). The resizing itself was not a problem, but when I run a memory leak check with Valgrind I keep getting the message below. I can't for the life of me figure out where I'm going wrong and would appreciate some pointers (pun definitely intended) as to where the leak is, but nothing more.
Also, if you could let me know how good my code is, or ways I could improve at programming in general it would be greatly appreciated.
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include "bmp.h"
int main(int argc, char* argv[])
{
// ensure proper usage
if (argc != 4)
{
printf("Usage: ./copy n infile outfile\n");
return 1;
}
// remember factor and filenames
int n = atoi(argv[1]);
char* infile = argv[2];
char* outfile = argv[3];
// check if scale factor is valid (i.e. between 1 and 100)
if ((n < 1) || (n > 100))
{
printf("Invalid scale factor, enter value between 1 and 100 inclusive\n");
return 2;
}
// open input file
FILE* inptr = fopen(infile, "r");
if (inptr == NULL)
{
printf("Could not open %s.\n", infile);
return 3;
}
// open output file
FILE* outptr = fopen(outfile, "w");
if (outptr == NULL)
{
fclose(inptr);
fprintf(stderr, "Could not create %s.\n", outfile);
return 4;
}
// read infile's BITMAPFILEHEADER
BITMAPFILEHEADER bf;
fread(&bf, sizeof(BITMAPFILEHEADER), 1, inptr);
// read infile's BITMAPINFOHEADER
BITMAPINFOHEADER bi;
fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr);
// create headers for outfile
BITMAPFILEHEADER bfout = bf;
BITMAPINFOHEADER biout = bi;
// change output's header info w.r.t. n, the scale factor
biout.biWidth *= n;
biout.biHeight *= n;
biout.biSizeImage *= n * n;
bfout.bfSize = sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER) +
biout.biSizeImage;
// 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 5;
}
// write outfile's BITMAPFILEHEADER
fwrite(&bfout, sizeof(BITMAPFILEHEADER), 1, outptr);
// write outfile's BITMAPINFOHEADER
fwrite(&biout, sizeof(BITMAPINFOHEADER), 1, outptr);
// determine padding for scanlines
int paddingIn = (4 - (bi.biWidth * sizeof(RGBTRIPLE) % 4)) % 4;
int paddingOut = (4 - (biout.biWidth * sizeof(RGBTRIPLE) % 4)) % 4;
// iterate over infile's scanlines
for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
{
//create buffer and set to row's pixels
RGBTRIPLE* buffer = malloc(bi.biWidth * sizeof(RGBTRIPLE));
fread(buffer, sizeof(RGBTRIPLE), bi.biWidth, inptr);
// for each infile scanline, copy n times
for (int j = 0; j < n; j++)
{
// iterate over pixels in scanline
for (int k = 0; k < bi.biWidth; k++)
{
// copy pixel n times
for (int l = 0; l < n; l++)
fwrite(&buffer[k], sizeof(RGBTRIPLE), 1, outptr);
}
// then add padding to Outfile (if needed)
for (int k = 0; k < paddingOut; k++)
fputc(0x00, outptr);
}
// move past padding on infile
fseek(inptr, paddingIn, SEEK_CUR);
// free the buffer
free(buffer);
}
// close infile
fclose(inptr);
// close outfile
fclose(outptr);
// that's all, folks
return 0;
}
You are analysing resize, which is a binary executable on your system.
If you call a program without ./ in front of it, the shell will search for a program with this name in every directory which is entered in the PATH variable (echo $PATH to see it), but not in the current directory.
You have to call your program with ./resize, so it will look in the . directory (your current directory) and will start your program.
The output Usage: resize [-u] [-c] [-s [rows cols]] does not match your code.
Related
I have read all documentation provided in bmp file, and I came to know that height is to be changed to negative, but I don't know how to do it, can anyone figure out what exact code I need to write plz explain in detail
// Copies a BMP file
#include <stdio.h>
#include <stdlib.h>
#include "bmp.h"
int main(int argc, char *argv[])
{
// Ensure proper usage
if (argc != 3)
{
printf("Usage: copy infile outfile\n");
return 1;
}
// Remember filenames
char *infile = argv[1];
char *outfile = argv[2];
// Open input file
FILE *inptr = fopen(infile, "rb+");
if (inptr == NULL)
{
printf("Could not open %s.\n", infile);
return 2;
}
// Open output file
FILE *outptr = fopen(outfile, "wb");
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;
}
// Write outfile's BITMAPFILEHEADER
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);
// Write outfile's BITMAPINFOHEADER
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);
// Determine padding for scanlines
int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
// 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 to outfile
fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
}
// Skip over padding, if any
fseek(inptr, padding, SEEK_CUR);
// Then add it back (to demonstrate how)
for (int k = 0; k < padding; k++)
{
fputc(0x00, outptr);
}
}
// Close infile
fclose(inptr);
// Close outfile
fclose(outptr);
// Success
return 0;
}
I tried writing bi.biheight = - bi.biheight before fwrite, but it wont work
how to write fwrite function to change height to negative
The problem was to turn the BMP image 180 degrees, To do this I am aware that that I must change the value of biHeight to the opposite sign as the input image's biheight. But I am unable to figure out how to do so. Could Somebody please help me understand how I can perform this task.
I have tried this:
bi.biHeight = (abs(bi.biHeight));
// Copies a BMP file, this is the distribution code I have to work on.
#include <stdio.h>
#include <stdlib.h>
#include "bmp.h"
int main(int argc, char *argv[])
{
// Ensure proper usage
if (argc != 3)
{
printf("Usage: copy infile outfile\n");
return 1;
}
// Remember filenames
char *infile = argv[1];
char *outfile = argv[2];
// 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;
}
// Write outfile's BITMAPFILEHEADER
fwrite(&bf, sizeof(BITMAPFILEHEADER), 1, outptr);
// Write outfile's BITMAPINFOHEADER
fwrite(&bi, sizeof(BITMAPINFOHEADER), 1, outptr);
// Determine padding for scanlines
int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
// 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 to outfile
fwrite(&triple, sizeof(RGBTRIPLE), 1, outptr);
}
// Skip over padding, if any
fseek(inptr, padding, SEEK_CUR);
// Then add it back (to demonstrate how)
for (int k = 0; k < padding; k++)
{
fputc(0x00, outptr);
}
}
// Close infile
fclose(inptr);
// Close outfile
fclose(outptr);
// Success
return 0;
}
I've been making the program from CS50'x about reversing the .WAV files. Seems to work fine, however the cs50's check finds an error. Don't know where it is, the code seems to be alright and there I can't find any problem.
I tried to change 'i' - iterator in for-loop but when set as = infile_size - block_size the file won't be converted / reversed.
My code below:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "wav.h"
int check_format(WAVHEADER header);
int get_block_size(WAVHEADER header);
int main(int argc, char *argv[])
{
// Ensure proper usage
// TODO #1
// check if command-line arguments = argv[0], argv[1], argv[2] = 3 in sum
if (argc != 3)
{
if (argc < 3)
{
printf("not enough command-line args\n");
}
else
{
printf("too much command-line args\n");
}
return 1;
}
// remember filenames
char *infile = argv[1];
char *outfile = argv[2];
// open input file for reading
FILE *inptr = fopen(infile, "r");
if (inptr == NULL)
{
printf("could not open the infile\n");
return 1;
}
// read header into an array
WAVHEADER header;
fread(&header, sizeof(header), 1, inptr);
// use check_format to ensure WAV format
check_format(header);
// open output file for writing
FILE *outptr = fopen(outfile, "w");
if (outptr == NULL)
{
printf("couldn't open the outfile\n");
fclose(inptr);
return 1;
}
// write header to file
fwrite(&header, sizeof(header), 1, outptr);
// use get_block_size to calculate size of block
int block_size = get_block_size(header);
printf("block_size: %i\n", block_size);
if (block_size < 0)
{
printf("block_size with no size\n");
return 1;
}
// write reversed audio to file
// 1. declare an array to store each block of audio
char *buffer = malloc(block_size * sizeof(char));
if (buffer == NULL)
{
printf("no memory location");
return 1;
}
// get the size of the input file
fseek(inptr, 0, SEEK_END);
long int infile_size = ftell(inptr);
printf("file_size: %li\n", infile_size);
// iterate through the input file audio data
for (long int i = infile_size; i >= 0; i -= block_size)
{
// move the file indicator to the start
fseek(inptr, i, SEEK_SET);
// read from inptr each size
fread(buffer, sizeof(char), block_size, inptr);
// write in outfile
fwrite(buffer, sizeof(char), block_size, outptr);
}
// free
free(buffer);
// close files:
fclose(inptr);
fclose(outptr);
}
int check_format(WAVHEADER header)
{
// TODO #4
if (header.format[0] == 'W' && header.format[1] == 'A' && header.format[2] == 'V' && header.format[3] == 'E')
{
printf("This is the type .wav\n");
return 0;
}
else
{
printf("File is not the type .wav\n");
return 1;
}
}
int get_block_size(WAVHEADER header)
{
// TODO #7
// check if channels are mono or audio
if (header.numChannels == 1 || header.numChannels == 2)
{
int block_size;
block_size = header.numChannels * (header.bitsPerSample / 8);
return block_size;
}
else
{
printf("Not supported\n");
return 1;
}
}
Thanks in advance!
I'm learning to code using the CS50 Harvard lectures. Can't get past the Resize problem-set. Specifically, i can't figures out how to resize vertically. Here's the code:
int main(int argc, char *argv[])
{
// ensure proper usage
if (argc != 4)
{
fprintf(stderr, "Usage: ./resize f infile outfile\n");
return 1;
}
// remember filenames
char *infile = argv[2];
char *outfile = argv[3];
//check if f is float
if (strcmp(argv[1], "0") == 0)
{
fprintf(stderr, "f cannot be 0\n");
return 1;
}
float f = atof(argv[1]);
if (f == 0)
{
fprintf(stderr, "error while reading float\n");
return 1;
}
// open input file
FILE *inptr = fopen(infile, "r");
if (inptr == NULL)
{
fprintf(stderr, "Could not open %s.\n", infile);
return 1;
}
// open output file
FILE *outptr = fopen(outfile, "w");
if (outptr == NULL)
{
fclose(inptr);
fprintf(stderr, "Could not create %s.\n", outfile);
return 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;
}
int inpad = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
//bi.biWidth *= f;
bi.biHeight *= f;
// determine outpad for scanlines
int outpad = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4;
bi.biSizeImage = (((sizeof(RGBTRIPLE) * bi.biWidth) + inpad) * abs(bi.biHeight));
bf.bfSize = bi.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);
for (int i = 0, biHeight = abs(bi.biHeight); i < biHeight; i++)
{
RGBTRIPLE triple;
fread(&triple, sizeof(RGBTRIPLE), bi.biWidth, inptr);
for (int j = 0; j < f; j++)
{
fwrite(&triple, sizeof(RGBTRIPLE), bi.biWidth, outptr);
//add padding
for (int k = 0; k < outpad; k++)
{
fputc(0x00, outptr);
}
}
// skip over padding, if any
fseek(inptr, inpad, SEEK_CUR);
}
// close infile
fclose(inptr);
// close outfile
fclose(outptr);
//test of success
printf("inpad:%d\noutpad:%d\n", inpad, outpad);
return 0;
}
After reading one line of the infile the infile padding changes to -1 and outfile to -256.
I wrote a very simple file corruptor for fun, but to my surprise, the "corrupted" file ends up being smaller in size than the original.
Here is the corruption function that is supposed to replace bytes but not to delete them:
void
corruptor(char *inputname, int percent)
{
FILE *input;
FILE *output;
int filesize;
char *outputname = append_name(inputname);
// Duplicate file
cp(outputname, inputname);
// Open input and output
input = fopen(inputname, "r");
if (input == NULL)
{
printf("Can't open input, errno = %d\n", errno);
exit(0);
}
output = fopen(outputname, "w+");
if (output == NULL)
{
printf("Can't open output, errno = %d\n", errno);
exit(0);
}
// Get the input file size
fseek(input, 0, SEEK_END);
filesize = ftell(input);
// Percentage
int percentage = (filesize * percent) / 100;
srand(time(NULL));
for (int i = 0; i < percentage; ++i)
{
unsigned int r = rand() % filesize;
fseek(output, r, SEEK_SET);
unsigned char corrbyte = rand() % 255;
fwrite(&corrbyte, 1, sizeof(char), output);
printf("Corrupted byte %d\n", r);
}
fclose(input);
fclose(output);
}
output = fopen(outputname, "w+");
This deletes the contents of the file, To open the file for reading and writing without deleting the contents, use mode "r+".