ppm.c
raw
1#include "all.h"
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <ctype.h>
6#include <string.h>
7
8Image read_ppm_image(const char *filename) {
9 Image img = {0};
10
11 FILE *f = fopen(filename, "rb");
12 if (!f) {
13 perror("fopen");
14 return (Image){};
15 }
16
17 int j = 0;
18 int in_token = 0;
19 int header_done = 0;
20
21 size_t pixel_count = 0;
22 size_t pixel_capacity = 0;
23
24 unsigned char buf[4096];
25 size_t nread;
26
27 while ((nread = fread(buf, 1, sizeof buf, f)) > 0) {
28 for (size_t i = 0; i < nread; ++i) {
29 unsigned char c = buf[i];
30
31 if (!header_done) {
32 if (isspace(c)) {
33 if (in_token) {
34 j++;
35 in_token = 0;
36
37 if (j == 4) {
38 header_done = 1;
39
40 pixel_capacity = img.width * img.height * 3;
41 img.pixels = malloc(pixel_capacity);
42
43 if (!img.pixels) {
44 perror("malloc");
45 fclose(f);
46 return (Image){};
47 }
48 }
49 }
50
51 continue;
52 }
53
54 in_token = 1;
55
56 switch (j) {
57 case 0:
58 {
59 size_t len = strlen(img.format);
60 if (len + 1 < sizeof img.format) {
61 img.format[len] = (char)c;
62 img.format[len + 1] = '\0';
63 }
64 } break;
65
66 case 1:
67 {
68 if (isdigit(c)) {
69 img.width = img.width * 10 + (c - '0');
70 }
71 } break;
72
73 case 2:
74 {
75 if (isdigit(c)) {
76 img.height = img.height * 10 + (c - '0');
77 }
78 } break;
79
80 case 3:
81 {
82 if (isdigit(c)) {
83 img.color_space = img.color_space * 10 + (c - '0');
84 }
85 } break;
86 }
87 } else {
88 if (pixel_count < pixel_capacity) {
89 img.pixels[pixel_count++] = c;
90 }
91 }
92 }
93 }
94
95 fclose(f);
96
97 printf("Loading image: [%s] %s (%dx%d) %d (%zu/%zu)\n", filename, img.format, img.width, img.height, img.color_space, pixel_count, pixel_capacity);
98
99 return img;
100}