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 c = Bgetc(b);
20 if(c == '#') {
21 while((c = Bgetc(b)) != Beof && c != '\n')
22 ;
23 }
24 return c;
25 }
27 /*
28 * fetch a nonnegative decimal integer.
29 */
30 static
31 int
32 Bgetint(Biobuf *b)
33 {
34 int c;
35 int i;
37 while((c = Bgetch(b)) != Beof && !isdigit(c))
38 ;
39 if(c == Beof)
40 return -1;
42 i = 0;
43 do {
44 i = i*10 + (c-'0');
45 } while((c = Bgetch(b)) != Beof && isdigit(c));
47 return i;
48 }
50 static
51 int
52 Bgetdecimalbit(Biobuf *b)
53 {
54 int c;
55 while((c = Bgetch(b)) != Beof && c != '0' && c != '1')
56 ;
57 if(c == Beof)
58 return -1;
59 return c == '1';
60 }
62 static int bitc, nbit;
64 static
65 int
66 Bgetbit(Biobuf *b)
67 {
68 if(nbit == 0) {
69 nbit = 8;
70 bitc = Bgetc(b);
71 if(bitc == -1)
72 return -1;
73 }
74 nbit--;
75 return (bitc >> (nbit-1)) & 0x1;
76 }
78 static
79 void
80 Bflushbit(Biobuf *b)
81 {
82 USED(b);
83 nbit = 0;
84 }
87 Rawimage**
88 readpixmap(int fd, int colorspace)
89 {
90 Rawimage **array, *a;
91 Biobuf b;
92 char buf[ERRMAX];
93 int i;
94 char *e;
96 USED(colorspace);
97 if(Binit(&b, fd, OREAD) < 0)
98 return nil;
100 werrstr("");
101 e = "out of memory";
102 if((array = malloc(sizeof *array)) == nil)
103 goto Error;
104 if((array[0] = malloc(sizeof *array[0])) == nil)
105 goto Error;
106 memset(array[0], 0, sizeof *array[0]);
108 for(i=0; i<3; i++)
109 array[0]->chans[i] = nil;
111 e = "bad file format";
112 switch(Bgetc(&b)) {
113 case 'P':
114 Bungetc(&b);
115 a = readppm(&b, array[0]);
116 break;
117 default:
118 a = nil;
119 break;
121 if(a == nil)
122 goto Error;
123 array[0] = a;
125 return array;
127 Error:
128 if(array)
129 free(array[0]);
130 free(array);
132 errstr(buf, sizeof buf);
133 if(buf[0] == 0)
134 strcpy(buf, e);
135 errstr(buf, sizeof buf);
137 return nil;
140 typedef struct Pix Pix;
141 struct Pix {
142 char magic;
143 int maxcol;
144 int (*fetch)(Biobuf*);
145 int nchan;
146 int chandesc;
147 int invert;
148 void (*flush)(Biobuf*);
149 };
151 static Pix pix[] = {
152 { '1', 1, Bgetdecimalbit, 1, CY, 1, 0 }, /* portable bitmap */
153 { '4', 1, Bgetbit, 1, CY, 1, Bflushbit }, /* raw portable bitmap */
154 { '2', 0, Bgetint, 1, CY, 0, 0 }, /* portable greymap */
155 { '5', 0, Bgetc, 1, CY, 0, 0 }, /* raw portable greymap */
156 { '3', 0, Bgetint, 3, CRGB, 0, 0 }, /* portable pixmap */
157 { '6', 0, Bgetc, 3, CRGB, 0, 0 }, /* raw portable pixmap */
158 { 0 }
159 };
161 Rawimage*
162 readppm(Biobuf *b, Rawimage *a)
164 int i, ch, wid, ht, r, c;
165 int maxcol, nchan, invert;
166 int (*fetch)(Biobuf*);
167 uchar *rgb[3];
168 char buf[ERRMAX];
169 char *e;
170 Pix *p;
172 e = "bad file format";
173 if(Bgetc(b) != 'P')
174 goto Error;
176 c = Bgetc(b);
177 for(p=pix; p->magic; p++)
178 if(p->magic == c)
179 break;
180 if(p->magic == 0)
181 goto Error;
184 wid = Bgetint(b);
185 ht = Bgetint(b);
186 if(wid <= 0 || ht <= 0)
187 goto Error;
188 a->r = Rect(0,0,wid,ht);
190 maxcol = p->maxcol;
191 if(maxcol == 0) {
192 maxcol = Bgetint(b);
193 if(maxcol <= 0)
194 goto Error;
197 e = "out of memory";
198 for(i=0; i<p->nchan; i++)
199 if((rgb[i] = a->chans[i] = malloc(wid*ht)) == nil)
200 goto Error;
201 a->nchans = p->nchan;
202 a->chanlen = wid*ht;
203 a->chandesc = p->chandesc;
205 e = "error reading file";
207 fetch = p->fetch;
208 nchan = p->nchan;
209 invert = p->invert;
210 for(r=0; r<ht; r++) {
211 for(c=0; c<wid; c++) {
212 for(i=0; i<nchan; i++) {
213 if((ch = (*fetch)(b)) < 0)
214 goto Error;
215 if(invert)
216 ch = maxcol - ch;
217 *rgb[i]++ = (ch * 255)/maxcol;
220 if(p->flush)
221 (*p->flush)(b);
224 return a;
226 Error:
227 errstr(buf, sizeof buf);
228 if(buf[0] == 0)
229 strcpy(buf, e);
230 errstr(buf, sizeof buf);
232 for(i=0; i<3; i++)
233 free(a->chans[i]);
234 free(a->cmap);
235 return nil;