Blob


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