]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/jpg/readppm.c
cwfs: back to previous version
[plan9front.git] / sys / src / cmd / jpg / readppm.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <draw.h>
5 #include <ctype.h>
6 #include "imagefile.h"
7
8 Rawimage *readppm(Biobuf*, Rawimage*);
9
10 /*
11  * fetch a non-comment character.
12  */
13 static
14 int
15 Bgetch(Biobufhdr *b)
16 {
17         int c;
18
19         for(;;) {
20                 c = Bgetc(b);
21                 if(c == '#') {
22                         while((c = Bgetc(b)) != Beof && c != '\n')
23                                 ;
24                 }
25                 return c;
26         }               
27 }
28
29 /*
30  * fetch a nonnegative decimal integer.
31  */
32 static
33 int
34 Bgetint(Biobufhdr *b)
35 {
36         int c;
37         int i;
38
39         while((c = Bgetch(b)) != Beof && !isdigit(c))
40                 ;
41         if(c == Beof)
42                 return -1;
43
44         i = 0;
45         do { 
46                 i = i*10 + (c-'0');
47         } while((c = Bgetch(b)) != Beof && isdigit(c));
48
49         return i;
50 }
51
52 static
53 int
54 Bgetdecimalbit(Biobufhdr *b)
55 {
56         int c;
57         while((c = Bgetch(b)) != Beof && c != '0' && c != '1')
58                 ;
59         if(c == Beof)
60                 return -1;
61         return c == '1';
62 }
63
64 static int bitc, nbit;
65
66 static
67 int
68 Bgetbit(Biobufhdr *b)
69 {
70         if(nbit == 0) {
71                 nbit = 8;
72                 bitc = Bgetc(b);
73                 if(bitc == -1)
74                         return -1;
75         }
76         nbit--;
77         return (bitc >> nbit) & 0x1;
78 }
79
80 static
81 void
82 Bflushbit(Biobufhdr*)
83 {
84         nbit = 0;
85 }
86
87
88 Rawimage**
89 readpixmap(int fd, int colorspace)
90 {
91         Rawimage **array, *a;
92         Biobuf b;
93         char buf[ERRMAX];
94         int i;
95         char *e;
96
97         USED(colorspace);
98         if(Binit(&b, fd, OREAD) < 0)
99                 return nil;
100
101         werrstr("");
102         e = "out of memory";
103         if((array = malloc(sizeof *array)) == nil)
104                 goto Error;
105         if((array[0] = malloc(sizeof *array[0])) == nil)
106                 goto Error;
107         memset(array[0], 0, sizeof *array[0]);
108
109         for(i=0; i<3; i++)
110                 array[0]->chans[i] = nil;
111
112         e = "bad file format";
113         switch(Bgetc(&b)) {
114         case 'P':
115                 Bungetc(&b);
116                 a = readppm(&b, array[0]);
117                 break;
118         default:
119                 a = nil;
120                 break;
121         }
122         if(a == nil)
123                 goto Error;
124         array[0] = a;
125
126         return array;
127
128 Error:
129         if(array)
130                 free(array[0]);
131         free(array);
132
133         errstr(buf, sizeof buf);
134         if(buf[0] == 0)
135                 strcpy(buf, e);
136         errstr(buf, sizeof buf);
137
138         return nil;
139 }
140
141 typedef struct Pix      Pix;
142 struct Pix {
143         char magic;
144         int     maxcol;
145         int     (*fetch)(Biobufhdr*);
146         int     nchan;
147         int     chandesc;
148         int     invert;
149         void    (*flush)(Biobufhdr*);
150 };
151
152 static Pix pix[] = {
153         { '1', 1, Bgetdecimalbit, 1, CY, 1, nil },      /* portable bitmap */
154         { '4', 1, Bgetbit, 1, CY, 1, Bflushbit },       /* raw portable bitmap */
155         { '2', 0, Bgetint, 1, CY, 0, nil },     /* portable greymap */
156         { '5', 0, Bgetc, 1, CY, 0, nil },       /* raw portable greymap */
157         { '3', 0, Bgetint, 3, CRGB, 0, nil },   /* portable pixmap */
158         { '6', 0, Bgetc, 3, CRGB, 0, nil },     /* raw portable pixmap */
159         { 0 },
160 };
161
162 Rawimage*
163 readppm(Biobuf *b, Rawimage *a)
164 {
165         int i, ch, wid, ht, r, c;
166         int maxcol, nchan, invert;
167         int (*fetch)(Biobufhdr*);
168         uchar *rgb[3];
169         char buf[ERRMAX];
170         char *e;
171         Pix *p;
172
173         e = "bad file format";
174         if(Bgetc(b) != 'P')
175                 goto Error;
176
177         c = Bgetc(b);
178         for(p=pix; p->magic; p++)
179                 if(p->magic == c)
180                         break;
181         if(p->magic == 0)
182                 goto Error;
183
184
185         wid = Bgetint(b);
186         ht = Bgetint(b);
187         if(wid <= 0 || ht <= 0)
188                 goto Error;
189         a->r = Rect(0,0,wid,ht);
190
191         maxcol = p->maxcol;
192         if(maxcol == 0) {
193                 maxcol = Bgetint(b);
194                 if(maxcol <= 0)
195                         goto Error;
196         }
197
198         e = "out of memory";
199         for(i=0; i<p->nchan; i++)
200                 if((rgb[i] = a->chans[i] = malloc(wid*ht)) == nil)
201                         goto Error;
202         a->nchans = p->nchan;
203         a->chanlen = wid*ht;
204         a->chandesc = p->chandesc;
205
206         e = "error reading file";
207
208         fetch = p->fetch;
209         nchan = p->nchan;
210         invert = p->invert;
211         for(r=0; r<ht; r++) {
212                 for(c=0; c<wid; c++) {
213                         for(i=0; i<nchan; i++) {
214                                 if((ch = (*fetch)(b)) < 0)
215                                         goto Error;
216                                 if(invert)
217                                         ch = maxcol - ch;
218                                 *rgb[i]++ = (ch * 255)/maxcol;
219                         }
220                 }
221                 if(p->flush)
222                         (*p->flush)(b);
223         }
224
225         return a;
226
227 Error:
228         errstr(buf, sizeof buf);
229         if(buf[0] == 0)
230                 strcpy(buf, e);
231         errstr(buf, sizeof buf);
232
233         for(i=0; i<3; i++)
234                 free(a->chans[i]);
235         free(a->cmap);
236         return nil;
237 }