-
Notifications
You must be signed in to change notification settings - Fork 0
/
ppm_io.c
138 lines (116 loc) · 3.9 KB
/
ppm_io.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include "ppm_io.h" // PPM I/O header
#include <stdlib.h> // c functions: malloc, free
#include <assert.h> // c functions: assert
#include <string.h> // c functions: strncmp, memcpy
#include <ctype.h> // c functions: isspace
/* ReadNum
* helper function for ReadPPM, takes a filehandle
* and reads a number, but detects and skips comment lines
*/
int ReadNum(FILE *fp) {
/* confirm that we received a good file handle */
assert(fp);
int ch; // use int, which is in fact return type of fgetc to avoid casting of 255 to -1
while((ch = fgetc(fp)) == '#') { // # marks a comment line
while( ((ch = fgetc(fp)) != '\n') && ch != EOF ) {
/* discard characters til end of line */
}
}
ungetc(ch, fp); // put back the last thing we found
int val;
if (fscanf(fp, "%d", &val) == 1) { // try to get an int
while(isspace(ch = fgetc(fp))) {
// drop trailing whitespace
}
ungetc(ch, fp);
return val; // we got a value, so return it
} else {
fprintf(stderr, "Error:ppm_io - failed to read number from file\n");
return -1;
}
}
/* ReadPPM
* Read a PPM-formatted image from a file (assumes fp != NULL).
* Returns the address of the heap-allocated Image struct it
* creates and populates with the Image data.
*/
Image* ReadPPM(FILE *fp) {
// check that fp is not NULL
assert(fp);
// allocate image (but not space to hold pixels -- yet)
Image *im = malloc(sizeof(Image));
if (!im) {
fprintf(stderr, "Error:ppm_io - failed to allocate memory for image!\n");
return NULL;
}
// initialize fields to error codes, in case we have to bail out early
im->rows = im->cols = -1;
// read in tag; fail if not P6
char tag[20];
tag[19]='\0';
fscanf(fp, "%19s\n", tag);
if (strncmp(tag, "P6", 20)) {
fprintf(stderr, "Error:ppm_io - not a PPM (bad tag)\n");
free(im);
return NULL;
}
/* read image dimensions */
//read in columns
im->cols = ReadNum(fp); // NOTE: cols, then rows (i.e. X size followed by Y size)
//read in rows
im->rows = ReadNum(fp);
//read in colors; fail if not 255
int colors = ReadNum(fp);
if (colors != 255) {
fprintf(stderr, "Error:ppm_io - PPM file with colors different from 255\n");
free(im);
return NULL;
}
//confirm that dimensions are positive
if (im->cols <= 0 || im->rows <= 0) {
fprintf(stderr, "Error:ppm_io - PPM file with non-positive dimensions\n");
free(im);
return NULL;
}
// allocate the right amount of space for the Pixels
im->data = malloc(sizeof(Pixel) * (im->rows) * (im->cols));
if (!im->data) {
fprintf(stderr, "Error:ppm_io - failed to allocate memory for image pixels!\n");
free(im);
return NULL;
}
// read in the binary Pixel data
int num_pixels_read = (int) fread(im->data, sizeof(Pixel), (im->rows) * (im->cols), fp);
if (num_pixels_read != (im->rows) * (im->cols)) {
fprintf(stderr, "Error:ppm_io - failed to read data from file with size %d (read %d)!\n", (im->rows) * (im->cols), num_pixels_read);
free(im);
return NULL;
}
//return the image struct pointer
return im;
}
/* WritePPM
* Write a PPM-formatted image to a file (assumes fp != NULL),
* and return the number of pixels successfully written.
*/
int WritePPM(FILE *fp, const Image *im) {
// check that fp and im are not NULL
assert(fp);
assert(im);
// write PPM file header, in the following format
// P6
// cols rows
// 255
fprintf(fp, "P6\n%d %d\n%d\n", im->cols, im->rows, 255);
// now write the pixel array
int num_pixels_written = (int) fwrite(im->data, sizeof(Pixel), (im->rows) * (im->cols), fp);
// check if write was successful or not; indicate failure with -1
if (num_pixels_written != (im->rows) * (im->cols)) {
fprintf(stderr, "Error:Uh oh. Pixel data failed to write properly!\n");
return -1;
}
// add a newline character before ending the file
fprintf(fp, "\n");
// return number of pixels written
return num_pixels_written;
}