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;
}
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
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!
My problem starts from the while loop. I have an if condition and inside of the if condition I create a file and write to it. But naturally, I can't use the pointer outside of the condition. I'm new to C and I'm looking for a way to make that pointer global variable like in python. Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include "cs50.h"
//define chunk size
const int chunksize = 512;
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr,"Usage: ./recover image\n");
return 1;
}
// open memory card file
FILE *inptr = fopen(argv[1], "r");
if (inptr == NULL)
{
fprintf(stderr, "Could not open %s.\n", argv[1]);
return 2;
}
//create a variable to store memory size
fseek(inptr, 0L, SEEK_END);
long int memorysize = ftell(inptr);
rewind(inptr);
//find how many chunk does memory card contain
int nofchunks = memorysize / chunksize;
//create a file counter
int nofjpeg = 0;
while(nofchunks > 0)
{
//create a temporary storage
unsigned char chunk[chunksize];
// read a 512 byte chunk from memory card
fread(&chunk, chunksize, 1, inptr);
FILE *outptr = NULL;
//check the chunk if it is a JPEG by looking first 4byte of the chunk
if (chunk[0] == 0xff && chunk[1] == 0xd8 && chunk[2] == 0xff && (chunk[3] & 0xf0) == 0xe0)
{
nofjpeg++;
//create a temporary file name
char filename[8];
if (nofjpeg == 1)
{
//create a new file name
sprintf(filename, "%03i.jpg", nofjpeg);
//open the file in write mode
outptr = fopen(filename, "w");
if (outptr == NULL)
{
fprintf(stderr, "Could not open %s.\n", argv[1]);
return 2;
}
fwrite(&chunk, chunksize, 1, outptr);
}
else
{
//close the previous file
fclose(outptr);
//create a new file name
sprintf(filename, "%03i.jpg", nofjpeg);
//open the file in write mode
outptr = fopen(filename, "w");
if (outptr == NULL)
{
fprintf(stderr, "Could not open %s.\n", argv[1]);
return 2;
}
fwrite(&chunk, chunksize, 1, outptr);
}
}
else if(nofjpeg > 1)
{
fwrite(&chunk, chunksize, 1, outptr);
}
nofchunks--;
}
}
You can see that inside of the first inner if condition I open the file and write to it. And I need to close that file inside the following else condition. You can also see I also use that pointer following the outer if condition.
Declare the file pointer before the if statement but assign it a null value. It is then available after the if statement. Inside the if statement you can assign it a value which will persist after the if statement. Following the if statement you should check to make sure it's not null before de-referencing it.
//check the chunk if it is a JPEG by looking first 4byte of the chunk
FILE *outptr = (FILE*) NULL; // Declare before the if and assign to NULL cast to type FILE*
if (chunk[0] == 0xff && chunk[1] == 0xd8 && chunk[2] == 0xff && (chunk[3] & 0xf0) == 0xe0)
{
nofjpeg++;
//create a temporary file name
char filename[8];
if (nofjpeg == 1)
{
//create a new file name
sprintf(filename, "%03i.jpg", nofjpeg);
//open the file in write mode
outptr = fopen(filename, "w"); // Assign inside the if statement, but don't declare.
if (outptr == NULL)
{
fprintf(stderr, "Could not open %s.\n", argv[1]);
return 2;
}
fwrite(&chunk, chunksize, 1, outptr);
}
else
{
//close the previous file ... this is likely a logical error; it should be NULL at this point, so there's nothing to close.
if (outptr) fclose(outptr); // Check to see if pointer is null before use.
//create a new file name
sprintf(filename, "%03i.jpg", nofjpeg);
//open the file in write mode
outptr = fopen(filename, "w");
if (outptr == NULL)
{
fprintf(stderr, "Could not open %s.\n", argv[1]);
return 2;
}
fwrite(&chunk, chunksize, 1, outptr);
}
}
else if(nofjpeg > 1)
{
// This is likely a logical error; outptr will be NULL here
if (outptr) fwrite(&chunk, chunksize, 1, outptr);
}
nofchunks--;
Finally found the solution!!! (I am using cloud visual studio)
Outside the loop declare it like this: FILE * outptr = (FILE *) outptr ;
And then just use outptr anywhere else (inside the differnt IF statements):
..inside the 1st IF >>>
open the file with: outptr = fopen(filename, "w");
write: fwrite(&chunk, chunksize, 1, outptr);
..inside the last ELSE IF >>>
write: fwrite(&chunk, chunksize, 1, outptr);
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'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.