include alloca header
[libjh.git] / ppm.c
1 // Copyright (2013) Jann Horn <jann@thejh.net>
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <errno.h>
7
8 HEADER typedef struct {
9 HEADER   int width, height;
10 HEADER   unsigned char *data;
11 HEADER   int data_size;
12 HEADER } pnm_image;
13
14 PUBLIC_FN pnm_image *read_image(char *path) {
15   int saved_errno = 0;
16   
17   // prepare stuff
18   FILE *f = fopen(path, "r");
19   if (!f) return NULL;
20   pnm_image *result = malloc(sizeof(pnm_image));
21   if (!result) { saved_errno = errno; goto out_close; }
22   
23   // read header
24   int line = 0;
25   int bufsize = 1024;
26   char *buf = malloc(bufsize);
27   while (line < 3) {
28     assert(fgets(buf, bufsize, f) == buf);
29     if (buf[0] == '#') continue;
30     switch (line) {
31       case 0: {
32         if (strcmp(buf, "P6\n")) {
33           saved_errno = ENOEXEC;
34           free(result);
35           goto out_freebuf;
36         }
37         break;
38       }
39       case 1: {
40         sscanf(buf, "%i %i", &result->width, &result->height);
41         result->data_size = 3 * result->width * result->height;
42         result->data = malloc(result->data_size);
43         // FIXME NULL check?
44         break;
45       }
46       case 2: {
47         if (strcmp(buf, "255\n")) {
48           saved_errno = EINVAL;
49           free(result->data);
50           free(result);
51           goto out_freebuf;
52         }
53         break;
54       }
55       default: assert(0);
56     }
57     line++;
58   }
59   
60   // read pixel data
61   assert(fread(result->data, result->data_size, 1, f) == 1);
62
63   // clean up
64 out_freebuf:
65   free(buf);
66 out_close:
67   fclose(f);
68   if (saved_errno) errno = saved_errno;
69   return result;
70 }
71
72 PUBLIC_FN int write_image(pnm_image *img, char *outfile) {
73   char outbuf[100+img->data_size];
74   int ob_used = snprintf(outbuf, sizeof(outbuf), "P6\n%d %d\n255\n", img->width, img->height);
75   if (ob_used >= 100) xperror("header size is bigger than anticipated", 0);
76   memcpy(outbuf+ob_used, img->data, img->data_size);
77   return write_file(outfile, outbuf, ob_used+img->data_size, 0);
78 }
79
80 PUBLIC_FN pnm_image *dup_image(pnm_image *img) {
81   pnm_image *r = malloc(sizeof(pnm_image));
82   if (!r) return NULL;
83   *r = *img;
84   r->data = malloc(r->data_size);
85   if (!r->data) { free(r); return NULL; }
86   memcpy(r->data, img->data, r->data_size);
87   return r;
88 }