Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <ctype.h>
4 #include <bio.h>
5 #include <flate.h>
6 #include <draw.h>
7 #include "imagefile.h"
9 int debug;
11 enum{ IDATSIZE=1000000,
12 /* filtering algorithms, supposedly increase compression */
13 FilterNone = 0, /* new[x][y] = buf[x][y] */
14 FilterSub = 1, /* new[x][y] = buf[x][y] + new[x-1][y] */
15 FilterUp = 2, /* new[x][y] = buf[x][y] + new[x][y-1] */
16 FilterAvg = 3, /* new[x][y] = buf[x][y] + (new[x-1][y]+new[x][y-1])/2 */
17 FilterPaeth= 4, /* new[x][y] = buf[x][y] + paeth(new[x-1][y],new[x][y-1],new[x-1][y-1]) */
18 FilterLast = 5,
19 PropertyBit = 1<<5
20 };
23 typedef struct ZlibW{
24 uchar *chan[4]; /* Rawimage channels */
25 uchar *scan; /* new scanline */
26 uchar *pscan; /* previous scanline */
27 int scanl; /* scan len */
28 int scanp; /* scan pos */
29 int nchan; /* number of input chans */
30 int npix; /* pixels read so far */
31 int chanl; /* number of bytes allocated to chan[x] */
32 int scanpix;
33 int bpp; /* bits per sample */
34 int palsize;
35 int row; /* current scanline number */
36 uchar palette[3*256];
37 } ZlibW;
39 typedef struct ZlibR{
40 Biobuf *bi;
41 uchar *buf;
42 uchar *b; /* next byte to decompress */
43 uchar *e; /* past end of buf */
44 ZlibW *w;
45 } ZlibR;
47 static uint32 *crctab;
48 static uchar PNGmagic[] = {137,80,78,71,13,10,26,10};
49 static char memerr[] = "ReadPNG: malloc failed: %r";
51 static uint32
52 get4(uchar *a)
53 {
54 return (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3];
55 }
57 static
58 void
59 pnginit(void)
60 {
61 static int inited;
63 if(inited)
64 return;
65 inited = 1;
66 crctab = mkcrctab(0xedb88320);
67 if(crctab == nil)
68 sysfatal("mkcrctab error");
69 inflateinit();
70 }
72 static
73 void*
74 pngmalloc(ulong n, int clear)
75 {
76 void *p;
78 p = malloc(n);
79 if(p == nil)
80 sysfatal(memerr);
81 if(clear)
82 memset(p, 0, n);
83 return p;
84 }
86 static int
87 getchunk(Biobuf *b, char *type, uchar *d, int m)
88 {
89 uchar buf[8];
90 uint32 crc = 0, crc2;
91 int n, nr;
93 if(Bread(b, buf, 8) != 8)
94 return -1;
95 n = get4(buf);
96 memmove(type, buf+4, 4);
97 type[4] = 0;
98 if(n > m)
99 sysfatal("getchunk needed %d, had %d", n, m);
100 nr = Bread(b, d, n);
101 if(nr != n)
102 sysfatal("getchunk read %d, expected %d", nr, n);
103 crc = blockcrc(crctab, crc, type, 4);
104 crc = blockcrc(crctab, crc, d, n);
105 if(Bread(b, buf, 4) != 4)
106 sysfatal("getchunk tlr failed");
107 crc2 = get4(buf);
108 if(crc != crc2)
109 sysfatal("getchunk crc failed");
110 return n;
113 static int
114 zread(void *va)
116 ZlibR *z = va;
117 char type[5];
118 int n;
120 if(z->b >= z->e){
121 refill_buffer:
122 z->b = z->buf;
123 n = getchunk(z->bi, type, z->b, IDATSIZE);
124 if(n < 0 || strcmp(type, "IEND") == 0)
125 return -1;
126 z->e = z->b + n;
127 if(!strcmp(type,"PLTE")) {
128 if (n < 3 || n > 3*256 || n%3)
129 sysfatal("invalid PLTE chunk len %d", n);
130 memcpy(z->w->palette, z->b, n);
131 z->w->palsize = n/3;
132 goto refill_buffer;
134 if(type[0] & PropertyBit)
135 goto refill_buffer; /* skip auxiliary chunks for now */
136 if(strcmp(type,"IDAT")) {
137 sysfatal("unrecognized mandatory chunk %s", type);
138 goto refill_buffer;
141 return *z->b++;
144 static uchar
145 paeth(uchar a, uchar b, uchar c)
147 int p, pa, pb, pc;
149 p = (int)a + (int)b - (int)c;
150 pa = abs(p - (int)a);
151 pb = abs(p - (int)b);
152 pc = abs(p - (int)c);
154 if(pa <= pb && pa <= pc)
155 return a;
156 else if(pb <= pc)
157 return b;
158 return c;
161 static void
162 unfilter(int alg, uchar *buf, uchar *up, int len, int bypp)
164 int i;
165 switch(alg){
166 case FilterNone:
167 break;
169 case FilterSub:
170 for (i = bypp; i < len; ++i)
171 buf[i] += buf[i-bypp];
172 break;
174 case FilterUp:
175 for (i = 0; i < len; ++i)
176 buf[i] += up[i];
177 break;
179 case FilterAvg:
180 for (i = 0; i < bypp; ++i)
181 buf[i] += (0+up[i])/2;
182 for (; i < len; ++i)
183 buf[i] += (buf[i-bypp]+up[i])/2;
184 break;
186 case FilterPaeth:
187 for (i = 0; i < bypp; ++i)
188 buf[i] += paeth(0, up[i], 0);
189 for (; i < len; ++i)
190 buf[i] += paeth(buf[i-bypp], up[i], up[i-bypp]);
191 break;
192 default:
193 sysfatal("unknown filtering scheme %d\n", alg);
197 static void
198 convertpix(ZlibW *z, uchar *pixel, uchar *r, uchar *g, uchar *b)
200 int off;
201 switch (z->nchan) {
202 case 1: /* gray or indexed */
203 case 2: /* gray+alpha */
204 if (z->bpp < 8)
205 pixel[0] >>= 8-z->bpp;
206 if (pixel[0] > z->palsize)
207 sysfatal("index %d out of bounds %d", pixel[0], z->palsize);
208 off = 3*pixel[0];
209 *r = z->palette[off];
210 *g = z->palette[off+1];
211 *b = z->palette[off+2];
212 break;
213 case 3: /* rgb */
214 case 4: /* rgb+alpha */
215 *r = pixel[0];
216 *g = pixel[1];
217 *b = pixel[2];
218 break;
219 default:
220 sysfatal("bad number of channels: %d", z->nchan);
224 static void
225 scan(ZlibW *z)
227 uchar *p;
228 int i, bit, n, ch, nch, pd;
229 uchar cb;
230 uchar pixel[4];
232 p = z->scan;
233 nch = z->nchan;
235 unfilter(p[0], p+1, z->pscan+1, z->scanl-1, (nch*z->bpp+7)/8);
236 /*
237 * Adam7 interlace order.
238 * 1 6 4 6 2 6 4 6
239 * 7 7 7 7 7 7 7 7
240 * 5 6 5 6 5 6 5 6
241 * 7 7 7 7 7 7 7 7
242 * 3 6 4 6 3 6 4 6
243 * 7 7 7 7 7 7 7 7
244 * 5 6 5 6 5 6 5 6
245 * 7 7 7 7 7 7 7 7
246 */
247 ch = 0;
248 n = 0;
249 cb = 128;
250 pd = z->row * z->scanpix;
251 for (i = 1; i < z->scanl; ++i)
252 for (bit = 128; bit > 0; bit /= 2) {
254 pixel[ch] &= ~cb;
255 if (p[i] & bit)
256 pixel[ch] |= cb;
258 cb >>= 1;
260 if (++n == z->bpp) {
261 cb = 128;
262 n = 0;
263 ch++;
265 if (ch == nch) {
266 if (z->npix++ < z->chanl)
267 convertpix(z,pixel,z->chan[0]+pd,z->chan[1]+pd,z->chan[2]+pd);
268 pd++;
269 if (pd % z->scanpix == 0)
270 goto out;
271 ch = 0;
274 out: ;
277 static int
278 zwrite(void *va, void *vb, int n)
280 ZlibW *z = va;
281 uchar *buf = vb;
282 int i, j;
284 j = z->scanp;
285 for (i = 0; i < n; ++i) {
286 z->scan[j++] = buf[i];
287 if (j == z->scanl) {
288 uchar *tp;
289 scan(z);
291 tp = z->scan;
292 z->scan = z->pscan;
293 z->pscan = tp;
294 z->row++;
295 j = 0;
298 z->scanp = j;
300 return n;
303 static Rawimage*
304 readslave(Biobuf *b)
306 ZlibR zr;
307 ZlibW zw;
308 Rawimage *image;
309 char type[5];
310 uchar *buf, *h;
311 int k, n, nrow, ncol, err, bpp, nch;
313 zr.w = &zw;
315 buf = pngmalloc(IDATSIZE, 0);
316 Bread(b, buf, sizeof PNGmagic);
317 if(memcmp(PNGmagic, buf, sizeof PNGmagic) != 0)
318 sysfatal("bad PNGmagic");
320 n = getchunk(b, type, buf, IDATSIZE);
321 if(n < 13 || strcmp(type,"IHDR") != 0)
322 sysfatal("missing IHDR chunk");
323 h = buf;
324 ncol = get4(h); h += 4;
325 nrow = get4(h); h += 4;
326 if(ncol <= 0 || nrow <= 0)
327 sysfatal("impossible image size nrow=%d ncol=%d", nrow, ncol);
328 if(debug)
329 fprint(2, "readpng nrow=%d ncol=%d\n", nrow, ncol);
331 bpp = *h++;
332 nch = 0;
333 switch (*h++) {
334 case 0: /* grey */
335 nch = 1;
336 break;
337 case 2: /* rgb */
338 nch = 3;
339 break;
340 case 3: /* indexed rgb with PLTE */
341 nch = 1;
342 break;
343 case 4: /* grey+alpha */
344 nch = 2;
345 break;
346 case 6: /* rgb+alpha */
347 nch = 4;
348 break;
349 default:
350 sysfatal("unsupported color scheme %d", h[-1]);
353 /* generate default palette for grayscale */
354 zw.palsize = 256;
355 if (nch < 3 && bpp < 9)
356 zw.palsize = 1<<bpp;
357 for (k = 0; k < zw.palsize; ++k) {
358 zw.palette[3*k] = (k*255)/(zw.palsize-1);
359 zw.palette[3*k+1] = (k*255)/(zw.palsize-1);
360 zw.palette[3*k+2] = (k*255)/(zw.palsize-1);
363 if(*h++ != 0)
364 sysfatal("only deflate supported for now [%d]", h[-1]);
365 if(*h++ != FilterNone)
366 sysfatal("only FilterNone supported for now [%d]", h[-1]);
367 if(*h != 0)
368 sysfatal("only non-interlaced supported for now [%d]", h[-1]);
370 image = pngmalloc(sizeof(Rawimage), 1);
371 image->r = Rect(0, 0, ncol, nrow);
372 image->cmap = nil;
373 image->cmaplen = 0;
374 image->chanlen = ncol*nrow;
375 image->fields = 0;
376 image->gifflags = 0;
377 image->gifdelay = 0;
378 image->giftrindex = 0;
379 image->chandesc = CRGB;
380 image->nchans = 3;
382 zw.chanl = ncol*nrow;
383 zw.npix = 0;
384 for(k=0; k<4; k++)
385 image->chans[k] = zw.chan[k] = pngmalloc(ncol*nrow, 1);
387 zr.bi = b;
388 zr.buf = buf;
389 zr.b = zr.e = buf + IDATSIZE;
391 zw.scanp = 0;
392 zw.row = 0;
393 zw.scanpix = ncol;
394 zw.scanl = (nch*ncol*bpp+7)/8+1;
395 zw.scan = pngmalloc(zw.scanl, 1);
396 zw.pscan = pngmalloc(zw.scanl, 1);
397 zw.nchan = nch;
398 zw.bpp = bpp;
400 err = inflatezlib(&zw, zwrite, &zr, zread);
402 if (zw.npix > zw.chanl)
403 fprint(2, "tried to overflow by %d pix\n", zw.npix - zw.chanl);
406 if(err)
407 sysfatal("inflatezlib %s\n", flateerr(err));
409 free(image->chans[3]);
410 image->chans[3] = nil;
411 free(buf);
412 free(zw.scan);
413 free(zw.pscan);
414 return image;
417 Rawimage**
418 Breadpng(Biobuf *b, int colorspace)
420 Rawimage *r, **array;
421 char buf[ERRMAX];
423 buf[0] = '\0';
424 if(colorspace != CRGB){
425 errstr(buf, sizeof buf); /* throw it away */
426 werrstr("ReadPNG: unknown color space %d", colorspace);
427 return nil;
429 pnginit();
430 array = malloc(2*sizeof(*array));
431 if(array==nil)
432 return nil;
433 errstr(buf, sizeof buf); /* throw it away */
434 r = readslave(b);
435 array[0] = r;
436 array[1] = nil;
437 return array;
440 Rawimage**
441 readpng(int fd, int colorspace)
443 Rawimage** a;
444 Biobuf b;
446 if(Binit(&b, fd, OREAD) < 0)
447 return nil;
448 a = Breadpng(&b, colorspace);
449 Bterm(&b);
450 return a;