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}