I'm having trouble writing a code that turns an RGB image (in this case a .ppm file) into an image in grayscale (.pgm output file).
The code:
int i;
typedef struct {
unsigned char r, g, b;
} rgb;
FILE *fd;
FILE *gr;
rgb *img;
unsigned width, height;
fd = fopen("rocks.ppm", "r");
fscanf(fd, "%d %d\n", &width, &height);
img = calloc(3, width * height);
fread(img, 3, width * height, fd);
unsigned char *gray;
double len = width * height;
gray = calloc(1, len);
for (i = 0; i < len; i++) {
gray[i] = img[i].r * 0.2126 + img[i].g * 0.7152 + img[i].b * 0.0722;
}
fclose(fd);
gr = fopen("rocks_gray.pgm", "w");
fprintf(gr, "P5\n%d %d\n255\n", width, height);
fwrite(gray, 1, len, gr);
fclose(gr);
When I compile and run the code the image file created comes out completely black, and I can't put my finger on the problem.
Any help would be deeply appreciated.
The problem is here: fscanf(fd, "%d %d\n", &width, &height);
The ppm file starts with P6 so the fscanf() fails to convert anything and returns 0, leaving width and height unchanged, hence uninitialized, causing the rest of the program to have undefined behavior.
You should change the fscanf() and check the return value.
More generally, you should always check for errors that may cause undefined behavior and report the problem with a meaningful error message.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct {
unsigned char r, g, b;
} rgb;
int main() {
const char *input_file = "rocks.ppm";
FILE *fd = fopen(input_file, "rb");
if (fd == NULL) {
perror(input_file);
return 1;
}
unsigned width, height;
char newline[2];
// Accept binary pixmaps:
// P6 <whitespace> width <whitespace> height <whitespace> 255 <single space> <raster>
if (fscanf(fd, "P6 %u %u 255%1[ \t\r\n\v\f]", &width, &height, newline) != 3) {
fprintf(stderr, "%s: invalid source format\n", input_file);
fclose(fd);
return 1;
}
unsigned len = width * height;
rgb *img = calloc(len, 3);
if (img == NULL) {
fprintf(stderr, "cannot allocate memory for %u pixels\n", len);
fclose(fd);
return 1;
}
if (fread(img, 3, len, fd) != len) {
fprintf(stderr, "%s: cannot read %u pixels\n", input_file, len);
fclose(fd);
return 1;
}
fclose(fd);
unsigned char *gray = calloc(len, 1);
if (gray == NULL) {
fprintf(stderr, "cannot allocate memory for %u gray scales\n", len);
return 1;
}
for (unsigned i = 0; i < len; i++) {
// using non standard gray scale conversion
gray[i] = img[i].r * 0.2126 + img[i].g * 0.7152 + img[i].b * 0.0722;
}
const char *output_file = "rocks_gray.pgm";
FILE *gr = fopen(output_file, "wb");
if (gr == NULL) {
perror(output_file);
return 1;
}
fprintf(gr, "P5\n%u %u\n255\n", width, height);
fwrite(gray, 1, len, gr);
fclose(gr);
return 0;
}
Related
I am "attempting" to store P3 PPM files using C but I'm not all that experienced with it so I've hit a brick wall. I was wondering if anyone could help me in accomplishing my task. Thank you.
I would like to keep them as struct PPM and struct PPM * getPPM(File * fd) but the contents can be altered.
I also don't know how to store the comments and would like to do that too.
Basically I am trying to store the data as follows:
P3
#comment.1
. . .
#comment.n
width height
max
r1 g1 b1
r2 g2 b2
r3 g3 b3
. . .
Edit:
I have done the changes for it to compile correctly and now I am trying to pass argv so that the file may read argv[1] to get the file name. When I do so i receive a Segmentation error.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//Holds the data
struct data {int r,g,b;};
struct PPM {char code[4]; char comments; int width; int height; int max; struct data *Data;};
//Gets the PPM data
struct PPM* GetPPM(FILE * fd, argv)
{
char readChars[256] = {0};
//Allocates memory for PPM
struct PPM *image = (struct PPM *)calloc(1, sizeof(struct PPM));
int i;
fgets(image->code, sizeof(image->code), fd);
fd = fopen(argv[1], "r");
//Checks if file is type P3
if((image->code[0] != 'P') && (image->code[0] != '3'))
{
return NULL;
}
image->code[2] = '\0';
//Checks for comments then continues around the loop until there's no more
fgets(readChars, sizeof(readChars), fd);
while(readChars[0] == '#')
{
fgets(readChars, sizeof(readChars), fd);
}
//Checks for PPM width, height and max
sscanf(readChars, "%d %d", &image->width, &image->height);
fgets(readChars, sizeof(readChars), fd);
sscanf(readChars, "%d", &image->max);
image->Data = (struct data*)malloc(image->width * image->height * sizeof(struct data));
i = 0;
while(fgets(readChars, sizeof(readChars), fd));
{
sscanf(readChars, "%d %d %d", &(image->Data[i].r), &(image->Data[i].g), &(image->Data[i].b));
++i;
}
fclose(fd);
return image;
}
//Deallocates memory
void freePPM(struct PPM *image)
{
free(image->Data);
free(image);
}
//Displays PPM
void showPPM(struct PPM *image)
{
int i = 0;
int totalpixels = image->width * image->height;
printf("%s\n", image->code);
printf("%d %d\n", image->width, image->height);
printf("%d\n", image->max);
for(i = 0; i < totalpixels; ++i)
{
printf("%d %d %d\n", image->Data[i].r, image->Data[i].g, image->Data[i].b);
}
}
int main(int argc, char ** argv)
{
struct PPM *image = GetPPM(argv);
showPPM(image);
freePPM(image);
return 0;
}
There are some error in declaring structures and the way data is read. Check how the data is read in the following code and come back here if you want more clarity.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct data {int r,g,b;};
struct PPM {char code[4]; char comments; int width; int height; int max; struct data *Data;};
struct PPM* GetPPM(FILE * fd)
{
char readChars[256] = {0};
struct PPM *image = (struct PPM *)calloc(1, sizeof(struct PPM));
int i;
fgets(image->code, sizeof(image->code), stdin);
if((image->code[0] != 'P') && (image->code[0] != '3'))
{
return NULL;
}
image->code[2] = '\0';
fgets(readChars, sizeof(readChars), stdin);
while(readChars[0] == '#')
{
fgets(readChars, sizeof(readChars), stdin);
}
sscanf(readChars, "%d %d", &image->width, &image->height);
fgets(readChars, sizeof(readChars), stdin);
sscanf(readChars, "%d", &image->max);
image->Data = (struct data*)malloc(image->width * image->height * sizeof(struct data));
i = 0;
while(fgets(readChars, sizeof(readChars), stdin))
{
sscanf(readChars, "%d %d %d", &(image->Data[i].r), &(image->Data[i].g), &(image->Data[i].b));
++i;
}
return image;
}
void FreePPM(struct PPM *image)
{
free(image->Data);
free(image);
}
void PrintPPM(struct PPM *image)
{
int i = 0;
int totalpixels = image->width * image->height;
printf("%s\n", image->code);
printf("%d %d\n", image->width, image->height);
printf("%d\n", image->max);
for(i = 0; i < totalpixels; ++i)
{
printf("%d %d %d\n", image->Data[i].r, image->Data[i].g, image->Data[i].b);
}
}
int main()
{
struct PPM *image = GetPPM(stdin);
PrintPPM(image);
FreePPM(image);
return 0;
}
I'm trying to change the bytes corresponding to file size in the header of a .wav file, which are the 4th and 40th bytes. Currently, I am copying the entire header to a buffer, attempting to edit it there and then writing it to a destination file, but it doesn't seem to work.
int main(int argc, char * argv []){
int delay = atoi(argv[1]);
FILE * source = fopen(argv[2], "rb");
FILE * destination = fopen(argv[3], "wb");
void * header = malloc(44); // size of a wav file header
fread(header, sizeof(header), 1, source);
// my attempt at changing the 4nd and 40th bytes
sizeptr1 = (unsigned int *)(header + 4);
sizeptr2 = (unsigned int *)(header + 40);
*sizeptr1 = *sizeptr1 + delay;
*sizeptr2 = *sizeptr2 + delay
fwrite(header, sizeof(header), 1, destination);
return 0;
}
What would the most efficient way to change these bytes and write the new header to the output file be?
A byte array is easiest, if you are sure which bytes you want to change. For example the 4th byte is at buffer[3].
#include <stdio.h>
#include <stdlib.h>
#define BUFFSIZE 1024
#define HEADSIZE 44
int main(int argc, char * argv []) {
int delay;
size_t bytes;
FILE * source = NULL;
FILE * destination = NULL;
unsigned char buffer[BUFFSIZE];
if (argc < 4) return 0; // check enough args
delay = atoi(argv[1]);
if (NULL == (source = fopen(argv[2], "rb")))
return 0;
if (NULL == (destination = fopen(argv[3], "wb")))
return 0;
// copy & alter buffer
if (HEADSIZE != fread(buffer, 1, HEADSIZE, source))
return 0;
buffer[4] = delay;
buffer[40] = delay;
if (HEADSIZE != fwrite(buffer, 1, HEADSIZE, destination))
return 0;
// copy rest of file
while ((bytes = fread(buffer, 1, BUFFSIZE, source)) != 0) {
if (bytes != fwrite(buffer, 1, bytes, destination))
return 0;
}
if (0 == fclose(destination))
printf("Success\n");
fclose (source);
return 0;
}
This is one way of editing bytes in a file, check if it will works for you.
int
ChangeHeaderByte(
const char* fileName,
unsigned int pos[],
unsigned int val[],
unsigned int size
)
{
unsigned int i = 0;
unsigned int temp = 0;
FILE * fileHandle = fopen(fileName, "r+");
if (fileHandle == 0) {
fprintf(stderr,"Error: %s : %d : Failed to open file ' %s '\n",
__func__,__LINE__,fileName);
return (1);
}
for ( i = 0; i < size ; ++i )
{
if ( fseek(fileHandle, pos[i] - (unsigned int)1, SEEK_SET) == 0 )
{
if ( fread(&temp,sizeof(unsigned int),1,fileHandle) == 1 )
{
if ( fseek(fileHandle, pos[i] - (unsigned int)1 , SEEK_SET) == 0 )
{
val[i] += temp;
fwrite(&val[i], sizeof(unsigned int), 1, fileHandle);
}
else
{
fprintf(stderr,"Error: %s : %d : fseek() failed on file ' %s '\n",
__func__,__LINE__,fileName);
return (1);
}
}
else
{
fprintf(stderr,"Error: %s : %d : fread() failed on file ' %s '\n",
__func__,__LINE__,fileName);
return (1);
}
} else {
fprintf(stderr,"Error: %s : %d : fseek() failed on file ' %s '\n",
__func__,__LINE__,fileName);
return (1);
}
}
fclose(fileHandle);
return (0);
}
int main(void)
{
const unsigned int size = 2;
char fileName[] = "C:\\Users\\sridhar\\test\\test.wav";
unsigned int pos[2] = { 4 , 40 };
unsigned int val[2] = { 123456, 123456 };
ChangeHeaderByte(fileName,pos,val,size);
return 0;
}
I have to write a program where I take user input for a PPM image and then mirror the image from left to right (basically flipping it over the y-axis). So if the image was <, the new image would now be >. This should not be a 180 degree rotation, as that would make the image upside down. It should still be the same, just reflected.
I have the code here that I used to input and output the PPM, but I don't know how to mirror it. I made a function that would theoretically be used for the mirror code, but I'm not sure if that's the best way to do it either. If you know a better place to put the code, be my guest.
I have researched this topic quite a bit, but was only able to find issues where people needed to rotate the image.
Here is what I have so far:
#include<stdio.h>
#include<stdlib.h> //for fopen()
typedef struct {
unsigned char red,green,blue;
} pixel_t; //struct for pixels
typedef struct {
int x, y;
pixel_t *data;
} PPMImage; //struct for creating the image
#define RGB_COMPONENT_COLOR 255
static PPMImage *readPPM(const char *filename)
{
char buff[16];
PPMImage *img;
FILE *fp;
int c, rgb_comp_color;
fp = fopen(filename, "rb");
if (!fp) {
fprintf(stderr, "Unable to open file '%s'\n", filename);
exit(1);} //opens the ppm and checks to make sure it can be opened
if (!fgets(buff, sizeof(buff), fp)) {
perror(filename);
exit(1);} //read the format of the image
if (buff[0] != 'P' || buff[1] != '6') {
fprintf(stderr, "Invalid image format (must be 'P6')\n");
exit(1);} //checks to see if the format is ppm
img = (PPMImage *)malloc(sizeof(PPMImage));
if (!img) {
fprintf(stderr, "Unable to allocate memory\n");
exit(1);} //allocates the memory needed to form the input image
c = getc(fp);
while (c == '#') {
while (getc(fp) != '\n') ;
c = getc(fp);
}//checks for comments
ungetc(c, fp);
if (fscanf(fp, "%d %d", &img->x, &img->y) != 2) {
fprintf(stderr, "Invalid image size (error loading '%s')\n", filename);
exit(1);} //reads the size of the image, height becomes img->y, and width becomes img->x
if (fscanf(fp, "%d", &rgb_comp_color) != 1) {
fprintf(stderr, "Invalid rgb component (error loading '%s')\n", filename);
exit(1);} //reads how much of each color there is
if (rgb_comp_color!= RGB_COMPONENT_COLOR) {
fprintf(stderr, "'%s' does not have 8-bits components\n", filename);
exit(1);} //makes sure the the component is 8 bits
while (fgetc(fp) != '\n') ;
img->data = (pixel_t*)malloc(img->x * img->y * sizeof(pixel_t));
if (!img) {
fprintf(stderr, "Unable to allocate memory\n");
exit(1);} //allocates the memory need for the pixel data
if (fread(img->data, 3 * img->x, img->y, fp) != img->y) {
fprintf(stderr, "Error loading image '%s'\n", filename);
exit(1);} //reads the pixel data
fclose(fp);
return img;
}
void writePPM(const char *filename, PPMImage *img)
{
FILE *fp;
fp = fopen(filename, "wb");
if (!fp) {
fprintf(stderr, "Unable to open file '%s'\n", filename);
exit(1);} //opens the file for output
//write the header file
//image format
fprintf(fp, "P6\n");
//image size
fprintf(fp, "%d %d\n",img->x,img->y);
// rgb component depth
fprintf(fp, "%d\n",RGB_COMPONENT_COLOR);
// pixel data
fwrite(img->data, 3 * img->x, img->y, fp);
fclose(fp);
}
void mirror(PPMImage *img)
{
//this is where I want to insert the code for mirroring the image
}
int main(int argc, char* argv[]){ //takes command line parameters
PPMImage *image;
char* filename = argv[1];
image = readPPM(filename);
mirror(image);
writePPM("OutputFile.ppm",image); //creates the output file
printf("Press Enter");
getchar();
}
Your mirror() function can work on the image one row at a time. For each row, take the left-most pixel in the row and swap its value with the value of the right-most pixel in the row. Then take the second-left-most pixel and swap its value with the second-right-most pixel, and so on, until the column-positions of the pixels you are swapping "meet in the middle". (Then move on to the next row and do the same thing to it, until you've done all the rows).
Note that if the image contains an odd number of columns, there will be one column in the center of the image that stays unmodified (since it forms the axis around which the mirroring occurs). With an even number of columns, all columns will be swapped.
To mirror image vertically you can use this function:
void mirrorVert(PPMImage *img)
{
int y;
int x;
const int middleX = img->x / 2;
pixel_t tmp;
pixel_t* p;
for (y = 0; y < img->y; ++y)
{
p = img->data + y * img->x;
for (x = 0; x < middleX; ++x)
{
// swap pixels
tmp = p[x];
p[x] = p[img->x - 1 - x];
p[img->x - 1 - x] = tmp;
}
}
}
And to mirror it horizontally:
void mirrorHoriz(PPMImage *img)
{
const int line_size = img->x * sizeof(pixel_t);
const int middle = img->y / 2;
int y;
// allocate swap buffer
pixel_t* buff = (pixel_t*)malloc(line_size);
pixel_t* top;
pixel_t* bottom;
for (y = 0; y < middle; ++y)
{
// swap lines from top and bottom
top = img->data + (y * img->x);
bottom = img->data + ((img->y - y - 1) * img->x);
memcpy(buff, top, line_size);
memcpy(top, bottom, line_size);
memcpy(bottom, buff, line_size);
}
}
I am working on a project where I need to read data from a binary file. I am trying to store the data into a char buffer. Suppose the binary file consisted of a character, an int and a double what size would the char buffer need to be ? And how would I convert back into int's and doubles ?
I am reading the data into a char buffer because it would improve the speed of my program.
Thanks!
The following example program fread()s the first DATASIZE sets of a char, an int and a float from a file specified on the command line:
typedef struct Data_s {
char c;
int i;
float f;
} Data_t;
#define DATASIZE 3
int main(int argc, char ** argv) {
if (1 >= argc) {
fprintf(stderr, "usage: %s <file name>\n", argv[0]);
return EXIT_SUCCESS;
}
{
FILE * f = fopen(argv[1], "r");
if (!f) {
perror("fopen() failed.");
return EXIT_FAILURE;
}
{
Data_t data[DATASIZE];
size_t sizeData = sizeof(*data);
size_t sizeToRead = sizeof(data)/sizeData;
memset(data, 0, sizeToRead * sizeData);
size_t sizeRead = fread(&data, sizeData, sizeToRead, f);
if (0 != fclose(f))
perror("fclose() failed,");
if (sizeToRead != sizeRead) {
perror("fread() failed.");
return EXIT_FAILURE;
}
for (size_t i = 0; i < sizeToRead; ++ i)
printf("read c=0x%02hhx, i=%d, f=%f from '%s'\n", data[i].c, data[i].i, data[i].f, argv[1]);
}
}
return EXIT_SUCCESS;
}
You can use the fscanf function to read the data from the file straight into eagerly awaiting variables:
char c;
int i;
double d;
FILE *fp = fopen("C:\\example.txt", "rb");
if (fp)
{
fscanf(fp, "%c%d%lf", &c, &i, &d);
fclose(fp);
printf("Character: %c\nInteger: %d\nDouble: %lf\n", c, i, d);
}
EDIT: If you're looking for more info on fscanf, see here
EDIT2: Binary Solution
FILE *fp = fopen("C:\\example.txt", "rb");
if (fp)
{
char buffer[sizeof(int) + sizeof(double) + sizeof(char)];
if (fread(buffer, 1, sizeof(buffer), fp) == sizeof(buffer))
{
char c = *(char*)buffer;
int i = *(int*)(buffer + sizeof(char));
double d = *(double*)(buffer + sizeof(char) + sizeof(int));
}
fclose(fp);
}
I'm trying to read a binary file that is in the following format:
number of images [4-byte int]
width [4-byte int]
height [4-byte int]
grayscale data [width * height bytes]
(more elements of the same type)
That's the first function being called:
int process_file(const char *filename) {
FILE *input_file = fopen(filename, "r");
//Get number of images
unsigned int number_of_images = read_int_from_file(input_file);
//Allocate memory for all images
struct image *images = malloc(sizeof(struct image) * number_of_images);
read_images(images, number_of_images, input_file)
}
Here's the image structure for anyone wondering:
struct image {
unsigned int width;
unsigned int height;
unsigned char *data;
};
And that's what read_int_from_file does:
static unsigned int read_int_from_file(FILE *file) {
unsigned char chars[4];
if (fread(&chars, sizeof(char), 4, file) != 4) {
fprintf(stderr, "Couldn't read enough bytes!\n");
return 0;
}
//Calculations follow that return right numbers
return out;
}
That's the rest:
static int read_images(struct image *images, unsigned int number_of_images, FILE * file) {
struct image *current_image = images;
int i;
for (i = 0; i < number_of_images; i++) {
read_image(current_image++, file)
}
return EXIT_SUCCESS;
}
static int read_image(struct image *image, FILE *file) {
static long int expected_position = 4;
if (ftell(file) != expected_position) {
fprintf(stderr, "Reading # %lu when should be # %lu!",
ftell(file), expected_position);
exit(EXIT_FAILURE);
}
unsigned int width = read_int_from_file(file);
unsigned int height = read_int_from_file(file);
unsigned int size = width * height;
unsigned char *data = malloc(sizeof(char) * size);
if (data) {
if (fread(data, sizeof(char), size, file) != size) {
exit(EXIT_FAILURE);
}
image->width = width;
image->height = height;
image->data = data;
expected_position += 2 * 4 + width * height;
return EXIT_SUCCESS;
} else {
exit(EXIT_FAILURE);
}
}
The problem is that the file pointer is sometimes going ahead when it shouldn't do so, i.e. I'm hitting ftell(file) != expected_position. I'm getting it after a good amount of successful reads, but some good time before the end, too.
Does anyone have any idea why that may be? I mean, even if the numbers were wrong, that shouldn't happen, should it? Thanks!
MS-DOS end-of-line sequences are Carriage Return, New Line (CR NL, 0x0D, 0x0A), and Unix uses simply New Line (NL or 0x0A).
Change the line
FILE *input_file = fopen(filename, "r");
to
FILE *input_file = fopen(filename, "rb");
Otherwise, the fread() function used to translate CR NL as NL, on Unix systems prior to POSIX standard "IEEE Std 1003.1-1988".
On MS-DOS, Windows and derivatives, it translates NL as CR NL.
These translations cause your opinion of the file position to differ from ftell()'s calculations.
You need to open the binary file as such:
// v
FILE *input_file = fopen(filename, "rb");