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