add code for reading ppm files (P6 magic)
[libjh.git] / ppm.c
diff --git a/ppm.c b/ppm.c
new file mode 100644 (file)
index 0000000..cdaebf5
--- /dev/null
+++ b/ppm.c
@@ -0,0 +1,71 @@
+// Copyright (2013) Jann Horn <jann@thejh.net>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+
+HEADER typedef struct {
+HEADER   int width, height;
+HEADER   unsigned char *data;
+HEADER   int data_size;
+HEADER } pnm_image;
+
+pnm_image *read_image(char *path) {
+  int saved_errno = 0;
+  
+  // prepare stuff
+  FILE *f = fopen(path, "r");
+  if (!f) return NULL;
+  pnm_image *result = malloc(sizeof(pnm_image));
+  if (!result) { saved_errno = errno; goto out_close; }
+  
+  // read header
+  int line = 0;
+  int bufsize = 1024;
+  char *buf = malloc(bufsize);
+  while (line < 3) {
+    assert(fgets(buf, bufsize, f) == buf);
+    if (buf[0] == '#') continue;
+    switch (line) {
+      case 0: {
+        if (strcmp(buf, "P6\n")) {
+          saved_errno = ENOEXEC;
+          free(result);
+          goto out_freebuf;
+        }
+        break;
+      }
+      case 1: {
+        sscanf(buf, "%i %i", &result->width, &result->height);
+        result->data_size = 3 * result->width * result->height;
+        result->data = malloc(result->data_size);
+        // FIXME NULL check?
+        break;
+      }
+      case 2: {
+        if (strcmp(buf, "255\n")) {
+          saved_errno = EINVAL;
+          free(result->data);
+          free(result);
+          goto out_freebuf;
+        }
+        break;
+      }
+      default: assert(0);
+    }
+    line++;
+  }
+  
+  // read pixel data
+  assert(fread(result->data, result->data_size, 1, f) == 1);
+
+  // clean up
+out_freebuf:
+  free(buf);
+out_close:
+  fclose(f);
+  if (saved_errno) errno = saved_errno;
+  return result;
+}
\ No newline at end of file