blob: d9b542939fdf937cd50636f37e1f0c1ba5f6f967 [file] [log] [blame]
rsc28994502004-04-21 22:19:33 +00001#include <u.h>
2#include <libc.h>
3#include <bio.h>
4#include <draw.h>
5#include <ctype.h>
6#include "imagefile.h"
7
8Rawimage *readppm(Biobuf*, Rawimage*);
9
10/*
11 * fetch a non-comment character.
12 */
13static
14int
15Bgetch(Biobuf *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 */
32static
33int
34Bgetint(Biobuf *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
52static
53int
54Bgetdecimalbit(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}
63
64static int bitc, nbit;
65
66static
67int
68Bgetbit(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}
79
80static
81void
82Bflushbit(Biobuf *b)
83{
84 USED(b);
85 nbit = 0;
86}
87
88
89Rawimage**
90readpixmap(int fd, int colorspace)
91{
92 Rawimage **array, *a;
93 Biobuf b;
94 char buf[ERRMAX];
95 int i;
96 char *e;
97
98 USED(colorspace);
99 if(Binit(&b, fd, OREAD) < 0)
100 return nil;
101
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]);
109
110 for(i=0; i<3; i++)
111 array[0]->chans[i] = nil;
112
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;
122 }
123 if(a == nil)
124 goto Error;
125 array[0] = a;
126
127 return array;
128
129Error:
130 if(array)
131 free(array[0]);
132 free(array);
133
134 errstr(buf, sizeof buf);
135 if(buf[0] == 0)
136 strcpy(buf, e);
137 errstr(buf, sizeof buf);
138
139 return nil;
140}
141
142typedef struct Pix Pix;
143struct 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};
152
153static Pix pix[] = {
rsc840bb962004-04-25 21:36:03 +0000154 { '1', 1, Bgetdecimalbit, 1, CY, 1, 0 }, /* portable bitmap */
rsc28994502004-04-21 22:19:33 +0000155 { '4', 1, Bgetbit, 1, CY, 1, Bflushbit }, /* raw portable bitmap */
rsc840bb962004-04-25 21:36:03 +0000156 { '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 */
rsc28994502004-04-21 22:19:33 +0000160 { 0 },
161};
162
163Rawimage*
164readppm(Biobuf *b, Rawimage *a)
165{
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;
173
174 e = "bad file format";
175 if(Bgetc(b) != 'P')
176 goto Error;
177
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;
184
185
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);
191
192 maxcol = p->maxcol;
193 if(maxcol == 0) {
194 maxcol = Bgetint(b);
195 if(maxcol <= 0)
196 goto Error;
197 }
198
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;
206
207 e = "error reading file";
208
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;
220 }
221 }
222 if(p->flush)
223 (*p->flush)(b);
224 }
225
226 return a;
227
228Error:
229 errstr(buf, sizeof buf);
230 if(buf[0] == 0)
231 strcpy(buf, e);
232 errstr(buf, sizeof buf);
233
234 for(i=0; i<3; i++)
235 free(a->chans[i]);
236 free(a->cmap);
237 return nil;
238}