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
Bgetch(Biobufhdr * b)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
Bgetint(Biobufhdr * b)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
Bgetdecimalbit(Biobufhdr * b)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
Bgetbit(Biobufhdr * b)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
Bflushbit(Biobufhdr *)82 Bflushbit(Biobufhdr*)
83 {
84 nbit = 0;
85 }
86
87
88 Rawimage**
readpixmap(int fd,int colorspace)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*
readppm(Biobuf * b,Rawimage * a)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 }
238