Blame


1 28994509 2004-04-21 devnull // work in progress... this version only good enough to read
2 28994509 2004-04-21 devnull // non-interleaved, 24bit RGB images
3 28994509 2004-04-21 devnull
4 28994509 2004-04-21 devnull #include <u.h>
5 28994509 2004-04-21 devnull #include <libc.h>
6 28994509 2004-04-21 devnull #include <ctype.h>
7 28994509 2004-04-21 devnull #include <bio.h>
8 28994509 2004-04-21 devnull #include <flate.h>
9 28994509 2004-04-21 devnull #include <draw.h>
10 28994509 2004-04-21 devnull #include "imagefile.h"
11 28994509 2004-04-21 devnull
12 28994509 2004-04-21 devnull int debug;
13 28994509 2004-04-21 devnull
14 28994509 2004-04-21 devnull enum{ IDATSIZE=1000000,
15 28994509 2004-04-21 devnull /* filtering algorithms, supposedly increase compression */
16 28994509 2004-04-21 devnull FilterNone = 0, /* new[x][y] = buf[x][y] */
17 28994509 2004-04-21 devnull FilterSub = 1, /* new[x][y] = buf[x][y] + new[x-1][y] */
18 28994509 2004-04-21 devnull FilterUp = 2, /* new[x][y] = buf[x][y] + new[x][y-1] */
19 28994509 2004-04-21 devnull FilterAvg = 3, /* new[x][y] = buf[x][y] + (new[x-1][y]+new[x][y-1])/2 */
20 28994509 2004-04-21 devnull FilterPaeth= 4, /* new[x][y] = buf[x][y] + paeth(new[x-1][y],new[x][y-1],new[x-1][y-1]) */
21 28994509 2004-04-21 devnull FilterLast = 5,
22 28994509 2004-04-21 devnull PropertyBit = 1<<5,
23 28994509 2004-04-21 devnull };
24 28994509 2004-04-21 devnull
25 28994509 2004-04-21 devnull typedef struct ZlibR{
26 28994509 2004-04-21 devnull Biobuf *bi;
27 28994509 2004-04-21 devnull uchar *buf;
28 28994509 2004-04-21 devnull uchar *b; // next byte to decompress
29 28994509 2004-04-21 devnull uchar *e; // past end of buf
30 28994509 2004-04-21 devnull } ZlibR;
31 28994509 2004-04-21 devnull
32 28994509 2004-04-21 devnull typedef struct ZlibW{
33 28994509 2004-04-21 devnull uchar *r, *g, *b; // Rawimage channels
34 28994509 2004-04-21 devnull int chan; // next channel to write
35 28994509 2004-04-21 devnull int col; // column index of current pixel
36 28994509 2004-04-21 devnull // -1 = one-byte pseudo-column for filter spec
37 28994509 2004-04-21 devnull int row; // row index of current pixel
38 28994509 2004-04-21 devnull int ncol, nrow; // image width, height
39 28994509 2004-04-21 devnull int filter; // algorithm for current scanline
40 28994509 2004-04-21 devnull } ZlibW;
41 28994509 2004-04-21 devnull
42 28994509 2004-04-21 devnull static ulong *crctab;
43 28994509 2004-04-21 devnull static uchar PNGmagic[] = {137,80,78,71,13,10,26,10};
44 28994509 2004-04-21 devnull static char memerr[] = "ReadPNG: malloc failed: %r";
45 28994509 2004-04-21 devnull
46 28994509 2004-04-21 devnull static ulong
47 28994509 2004-04-21 devnull get4(uchar *a)
48 28994509 2004-04-21 devnull {
49 28994509 2004-04-21 devnull return (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3];
50 28994509 2004-04-21 devnull }
51 28994509 2004-04-21 devnull
52 28994509 2004-04-21 devnull static
53 28994509 2004-04-21 devnull void
54 28994509 2004-04-21 devnull pnginit(void)
55 28994509 2004-04-21 devnull {
56 28994509 2004-04-21 devnull static int inited;
57 28994509 2004-04-21 devnull
58 28994509 2004-04-21 devnull if(inited)
59 28994509 2004-04-21 devnull return;
60 28994509 2004-04-21 devnull inited = 1;
61 28994509 2004-04-21 devnull crctab = mkcrctab(0xedb88320);
62 28994509 2004-04-21 devnull if(crctab == nil)
63 28994509 2004-04-21 devnull sysfatal("mkcrctab error");
64 28994509 2004-04-21 devnull inflateinit();
65 28994509 2004-04-21 devnull }
66 28994509 2004-04-21 devnull
67 28994509 2004-04-21 devnull static
68 28994509 2004-04-21 devnull void*
69 28994509 2004-04-21 devnull pngmalloc(ulong n, int clear)
70 28994509 2004-04-21 devnull {
71 28994509 2004-04-21 devnull void *p;
72 28994509 2004-04-21 devnull
73 28994509 2004-04-21 devnull p = malloc(n);
74 28994509 2004-04-21 devnull if(p == nil)
75 28994509 2004-04-21 devnull sysfatal(memerr);
76 28994509 2004-04-21 devnull if(clear)
77 28994509 2004-04-21 devnull memset(p, 0, n);
78 28994509 2004-04-21 devnull return p;
79 28994509 2004-04-21 devnull }
80 28994509 2004-04-21 devnull
81 28994509 2004-04-21 devnull static int
82 28994509 2004-04-21 devnull getchunk(Biobuf *b, char *type, uchar *d, int m)
83 28994509 2004-04-21 devnull {
84 28994509 2004-04-21 devnull uchar buf[8];
85 28994509 2004-04-21 devnull ulong crc = 0, crc2;
86 28994509 2004-04-21 devnull int n, nr;
87 28994509 2004-04-21 devnull
88 28994509 2004-04-21 devnull if(Bread(b, buf, 8) != 8)
89 28994509 2004-04-21 devnull return -1;
90 28994509 2004-04-21 devnull n = get4(buf);
91 28994509 2004-04-21 devnull memmove(type, buf+4, 4);
92 28994509 2004-04-21 devnull type[4] = 0;
93 28994509 2004-04-21 devnull if(n > m)
94 28994509 2004-04-21 devnull sysfatal("getchunk needed %d, had %d", n, m);
95 28994509 2004-04-21 devnull nr = Bread(b, d, n);
96 28994509 2004-04-21 devnull if(nr != n)
97 28994509 2004-04-21 devnull sysfatal("getchunk read %d, expected %d", nr, n);
98 28994509 2004-04-21 devnull crc = blockcrc(crctab, crc, type, 4);
99 28994509 2004-04-21 devnull crc = blockcrc(crctab, crc, d, n);
100 28994509 2004-04-21 devnull if(Bread(b, buf, 4) != 4)
101 28994509 2004-04-21 devnull sysfatal("getchunk tlr failed");
102 28994509 2004-04-21 devnull crc2 = get4(buf);
103 28994509 2004-04-21 devnull if(crc != crc2)
104 28994509 2004-04-21 devnull sysfatal("getchunk crc failed");
105 28994509 2004-04-21 devnull return n;
106 28994509 2004-04-21 devnull }
107 28994509 2004-04-21 devnull
108 28994509 2004-04-21 devnull static int
109 28994509 2004-04-21 devnull zread(void *va)
110 28994509 2004-04-21 devnull {
111 28994509 2004-04-21 devnull ZlibR *z = va;
112 28994509 2004-04-21 devnull char type[5];
113 28994509 2004-04-21 devnull int n;
114 28994509 2004-04-21 devnull
115 28994509 2004-04-21 devnull if(z->b >= z->e){
116 28994509 2004-04-21 devnull refill_buffer:
117 28994509 2004-04-21 devnull z->b = z->buf;
118 28994509 2004-04-21 devnull n = getchunk(z->bi, type, z->b, IDATSIZE);
119 28994509 2004-04-21 devnull if(n < 0 || strcmp(type, "IEND") == 0)
120 28994509 2004-04-21 devnull return -1;
121 28994509 2004-04-21 devnull z->e = z->b + n;
122 28994509 2004-04-21 devnull if(type[0] & PropertyBit)
123 28994509 2004-04-21 devnull goto refill_buffer; /* skip auxiliary chunks for now */
124 28994509 2004-04-21 devnull if(strcmp(type,"IDAT") != 0)
125 28994509 2004-04-21 devnull sysfatal("unrecognized mandatory chunk %s", type);
126 28994509 2004-04-21 devnull }
127 28994509 2004-04-21 devnull return *z->b++;
128 28994509 2004-04-21 devnull }
129 28994509 2004-04-21 devnull
130 28994509 2004-04-21 devnull static uchar
131 28994509 2004-04-21 devnull paeth(uchar a, uchar b, uchar c)
132 28994509 2004-04-21 devnull {
133 28994509 2004-04-21 devnull int p, pa, pb, pc;
134 28994509 2004-04-21 devnull
135 28994509 2004-04-21 devnull p = (int)a + (int)b - (int)c;
136 28994509 2004-04-21 devnull pa = abs(p - (int)a);
137 28994509 2004-04-21 devnull pb = abs(p - (int)b);
138 28994509 2004-04-21 devnull pc = abs(p - (int)c);
139 28994509 2004-04-21 devnull
140 28994509 2004-04-21 devnull if(pa <= pb && pa <= pc)
141 28994509 2004-04-21 devnull return a;
142 28994509 2004-04-21 devnull else if(pb <= pc)
143 28994509 2004-04-21 devnull return b;
144 28994509 2004-04-21 devnull return c;
145 28994509 2004-04-21 devnull }
146 28994509 2004-04-21 devnull
147 28994509 2004-04-21 devnull static void
148 28994509 2004-04-21 devnull unfilter(int alg, uchar *buf, uchar *ebuf, int up)
149 28994509 2004-04-21 devnull {
150 28994509 2004-04-21 devnull switch(alg){
151 28994509 2004-04-21 devnull case FilterSub:
152 28994509 2004-04-21 devnull while (++buf < ebuf)
153 28994509 2004-04-21 devnull *buf += buf[-1];
154 28994509 2004-04-21 devnull break;
155 28994509 2004-04-21 devnull case FilterUp:
156 28994509 2004-04-21 devnull if (up != 0)
157 28994509 2004-04-21 devnull do
158 28994509 2004-04-21 devnull *buf += buf[up];
159 28994509 2004-04-21 devnull while (++buf < ebuf);
160 28994509 2004-04-21 devnull break;
161 28994509 2004-04-21 devnull case FilterAvg:
162 28994509 2004-04-21 devnull if (up == 0)
163 28994509 2004-04-21 devnull while (++buf < ebuf)
164 28994509 2004-04-21 devnull *buf += buf[-1]/2;
165 28994509 2004-04-21 devnull else{
166 28994509 2004-04-21 devnull *buf += buf[up]/2;
167 28994509 2004-04-21 devnull while (++buf < ebuf)
168 28994509 2004-04-21 devnull *buf += (buf[-1]+buf[up])/2;
169 28994509 2004-04-21 devnull }
170 28994509 2004-04-21 devnull break;
171 28994509 2004-04-21 devnull case FilterPaeth:
172 28994509 2004-04-21 devnull if (up == 0)
173 28994509 2004-04-21 devnull while (++buf < ebuf)
174 28994509 2004-04-21 devnull *buf += buf[-1];
175 28994509 2004-04-21 devnull else{
176 28994509 2004-04-21 devnull *buf += paeth(0, buf[up], 0);
177 28994509 2004-04-21 devnull while (++buf < ebuf)
178 28994509 2004-04-21 devnull *buf += paeth(buf[-1], buf[up], buf[up-1]);
179 28994509 2004-04-21 devnull }
180 28994509 2004-04-21 devnull break;
181 28994509 2004-04-21 devnull }
182 28994509 2004-04-21 devnull }
183 28994509 2004-04-21 devnull
184 28994509 2004-04-21 devnull static int
185 28994509 2004-04-21 devnull zwrite(void *va, void *vb, int n)
186 28994509 2004-04-21 devnull {
187 28994509 2004-04-21 devnull ZlibW *z = va;
188 28994509 2004-04-21 devnull uchar *buf = vb;
189 28994509 2004-04-21 devnull int i, up;
190 28994509 2004-04-21 devnull for(i=0; i<n; i++){
191 28994509 2004-04-21 devnull if(z->col == -1){
192 28994509 2004-04-21 devnull // set filter byte
193 28994509 2004-04-21 devnull z->filter = *buf++;
194 28994509 2004-04-21 devnull if (z->filter >= FilterLast)
195 28994509 2004-04-21 devnull sysfatal("unknown filter algorithm %d for row %d", z->row, z->filter);
196 28994509 2004-04-21 devnull z->col++;
197 28994509 2004-04-21 devnull continue;
198 28994509 2004-04-21 devnull }
199 28994509 2004-04-21 devnull switch(z->chan){
200 28994509 2004-04-21 devnull case 0:
201 28994509 2004-04-21 devnull *z->r++ = *buf++;
202 28994509 2004-04-21 devnull z->chan = 1;
203 28994509 2004-04-21 devnull break;
204 28994509 2004-04-21 devnull case 1:
205 28994509 2004-04-21 devnull *z->g++ = *buf++;
206 28994509 2004-04-21 devnull z->chan = 2;
207 28994509 2004-04-21 devnull break;
208 28994509 2004-04-21 devnull case 2:
209 28994509 2004-04-21 devnull *z->b++ = *buf++;
210 28994509 2004-04-21 devnull z->chan = 0;
211 28994509 2004-04-21 devnull z->col++;
212 28994509 2004-04-21 devnull if(z->col == z->ncol){
213 28994509 2004-04-21 devnull if (z->filter){
214 28994509 2004-04-21 devnull if(z->row == 0)
215 28994509 2004-04-21 devnull up = 0;
216 28994509 2004-04-21 devnull else
217 28994509 2004-04-21 devnull up = -z->ncol;
218 28994509 2004-04-21 devnull unfilter(z->filter, z->r - z->col, z->r, up);
219 28994509 2004-04-21 devnull unfilter(z->filter, z->g - z->col, z->g, up);
220 28994509 2004-04-21 devnull unfilter(z->filter, z->b - z->col, z->b, up);
221 28994509 2004-04-21 devnull }
222 28994509 2004-04-21 devnull z->col = -1;
223 28994509 2004-04-21 devnull z->row++;
224 28994509 2004-04-21 devnull if((z->row >= z->nrow) && (i < n-1) )
225 28994509 2004-04-21 devnull sysfatal("header said %d rows; data goes further", z->nrow);
226 28994509 2004-04-21 devnull }
227 28994509 2004-04-21 devnull break;
228 28994509 2004-04-21 devnull }
229 28994509 2004-04-21 devnull }
230 28994509 2004-04-21 devnull return n;
231 28994509 2004-04-21 devnull }
232 28994509 2004-04-21 devnull
233 28994509 2004-04-21 devnull static Rawimage*
234 28994509 2004-04-21 devnull readslave(Biobuf *b)
235 28994509 2004-04-21 devnull {
236 28994509 2004-04-21 devnull ZlibR zr;
237 28994509 2004-04-21 devnull ZlibW zw;
238 28994509 2004-04-21 devnull Rawimage *image;
239 28994509 2004-04-21 devnull char type[5];
240 28994509 2004-04-21 devnull uchar *buf, *h;
241 28994509 2004-04-21 devnull int k, n, nrow, ncol, err;
242 28994509 2004-04-21 devnull
243 28994509 2004-04-21 devnull buf = pngmalloc(IDATSIZE, 0);
244 28994509 2004-04-21 devnull Bread(b, buf, sizeof PNGmagic);
245 28994509 2004-04-21 devnull if(memcmp(PNGmagic, buf, sizeof PNGmagic) != 0)
246 28994509 2004-04-21 devnull sysfatal("bad PNGmagic");
247 28994509 2004-04-21 devnull
248 28994509 2004-04-21 devnull n = getchunk(b, type, buf, IDATSIZE);
249 28994509 2004-04-21 devnull if(n < 13 || strcmp(type,"IHDR") != 0)
250 28994509 2004-04-21 devnull sysfatal("missing IHDR chunk");
251 28994509 2004-04-21 devnull h = buf;
252 28994509 2004-04-21 devnull ncol = get4(h); h += 4;
253 28994509 2004-04-21 devnull nrow = get4(h); h += 4;
254 28994509 2004-04-21 devnull if(ncol <= 0 || nrow <= 0)
255 28994509 2004-04-21 devnull sysfatal("impossible image size nrow=%d ncol=%d", nrow, ncol);
256 28994509 2004-04-21 devnull if(debug)
257 28994509 2004-04-21 devnull fprint(2, "readpng nrow=%d ncol=%d\n", nrow, ncol);
258 28994509 2004-04-21 devnull if(*h++ != 8)
259 28994509 2004-04-21 devnull sysfatal("only 24 bit per pixel supported for now [%d]", h[-1]);
260 28994509 2004-04-21 devnull if(*h++ != 2)
261 28994509 2004-04-21 devnull sysfatal("only rgb supported for now [%d]", h[-1]);
262 28994509 2004-04-21 devnull if(*h++ != 0)
263 28994509 2004-04-21 devnull sysfatal("only deflate supported for now [%d]", h[-1]);
264 28994509 2004-04-21 devnull if(*h++ != FilterNone)
265 28994509 2004-04-21 devnull sysfatal("only FilterNone supported for now [%d]", h[-1]);
266 28994509 2004-04-21 devnull if(*h != 0)
267 28994509 2004-04-21 devnull sysfatal("only non-interlaced supported for now [%d]", h[-1]);
268 28994509 2004-04-21 devnull
269 28994509 2004-04-21 devnull image = pngmalloc(sizeof(Rawimage), 1);
270 28994509 2004-04-21 devnull image->r = Rect(0, 0, ncol, nrow);
271 28994509 2004-04-21 devnull image->cmap = nil;
272 28994509 2004-04-21 devnull image->cmaplen = 0;
273 28994509 2004-04-21 devnull image->chanlen = ncol*nrow;
274 28994509 2004-04-21 devnull image->fields = 0;
275 28994509 2004-04-21 devnull image->gifflags = 0;
276 28994509 2004-04-21 devnull image->gifdelay = 0;
277 28994509 2004-04-21 devnull image->giftrindex = 0;
278 28994509 2004-04-21 devnull image->chandesc = CRGB;
279 28994509 2004-04-21 devnull image->nchans = 3;
280 28994509 2004-04-21 devnull for(k=0; k<3; k++)
281 28994509 2004-04-21 devnull image->chans[k] = pngmalloc(ncol*nrow, 0);
282 28994509 2004-04-21 devnull zr.bi = b;
283 28994509 2004-04-21 devnull zr.buf = buf;
284 28994509 2004-04-21 devnull zr.b = zr.e = buf + IDATSIZE;
285 28994509 2004-04-21 devnull zw.r = image->chans[0];
286 28994509 2004-04-21 devnull zw.g = image->chans[1];
287 28994509 2004-04-21 devnull zw.b = image->chans[2];
288 28994509 2004-04-21 devnull zw.chan = 0;
289 28994509 2004-04-21 devnull zw.col = -1;
290 28994509 2004-04-21 devnull zw.row = 0;
291 28994509 2004-04-21 devnull zw.ncol = ncol;
292 28994509 2004-04-21 devnull zw.nrow = nrow;
293 28994509 2004-04-21 devnull err = inflatezlib(&zw, zwrite, &zr, zread);
294 28994509 2004-04-21 devnull if(err)
295 28994509 2004-04-21 devnull sysfatal("inflatezlib %s\n", flateerr(err));
296 28994509 2004-04-21 devnull free(buf);
297 28994509 2004-04-21 devnull return image;
298 28994509 2004-04-21 devnull }
299 28994509 2004-04-21 devnull
300 28994509 2004-04-21 devnull Rawimage**
301 28994509 2004-04-21 devnull Breadpng(Biobuf *b, int colorspace)
302 28994509 2004-04-21 devnull {
303 28994509 2004-04-21 devnull Rawimage *r, **array;
304 28994509 2004-04-21 devnull char buf[ERRMAX];
305 28994509 2004-04-21 devnull
306 28994509 2004-04-21 devnull buf[0] = '\0';
307 28994509 2004-04-21 devnull if(colorspace != CRGB){
308 28994509 2004-04-21 devnull errstr(buf, sizeof buf); /* throw it away */
309 28994509 2004-04-21 devnull werrstr("ReadPNG: unknown color space %d", colorspace);
310 28994509 2004-04-21 devnull return nil;
311 28994509 2004-04-21 devnull }
312 28994509 2004-04-21 devnull pnginit();
313 28994509 2004-04-21 devnull array = malloc(2*sizeof(*array));
314 28994509 2004-04-21 devnull if(array==nil)
315 28994509 2004-04-21 devnull return nil;
316 28994509 2004-04-21 devnull errstr(buf, sizeof buf); /* throw it away */
317 28994509 2004-04-21 devnull r = readslave(b);
318 28994509 2004-04-21 devnull array[0] = r;
319 28994509 2004-04-21 devnull array[1] = nil;
320 28994509 2004-04-21 devnull return array;
321 28994509 2004-04-21 devnull }
322 28994509 2004-04-21 devnull
323 28994509 2004-04-21 devnull Rawimage**
324 28994509 2004-04-21 devnull readpng(int fd, int colorspace)
325 28994509 2004-04-21 devnull {
326 28994509 2004-04-21 devnull Rawimage** a;
327 28994509 2004-04-21 devnull Biobuf b;
328 28994509 2004-04-21 devnull
329 28994509 2004-04-21 devnull if(Binit(&b, fd, OREAD) < 0)
330 28994509 2004-04-21 devnull return nil;
331 28994509 2004-04-21 devnull a = Breadpng(&b, colorspace);
332 28994509 2004-04-21 devnull Bterm(&b);
333 28994509 2004-04-21 devnull return a;
334 28994509 2004-04-21 devnull }