13 IDATSIZE = 8*1024*1024,
15 /* filtering algorithms */
16 FilterNone = 0, /* new[x][y] = buf[x][y] */
17 FilterSub = 1, /* new[x][y] = buf[x][y] + new[x-1][y] */
18 FilterUp = 2, /* new[x][y] = buf[x][y] + new[x][y-1] */
19 FilterAvg = 3, /* new[x][y] = buf[x][y] + (new[x-1][y]+new[x][y-1])/2 */
20 FilterPaeth = 4, /* new[x][y] = buf[x][y] + paeth(new[x-1][y],new[x][y-1],new[x-1][y-1]) */
26 typedef struct ZlibR ZlibR;
27 typedef struct ZlibW ZlibW;
31 uchar *data; /* Rawimage data */
37 uchar *scan; /* new scanline */
38 uchar *lastscan; /* previous scan line */
39 int scanlen; /* scan line length */
40 int scanpos; /* scan position */
42 int dx; /* width of image */
43 int dy; /* height of image */
44 int bpc; /* bits per channel (per pixel) */
45 int y; /* current scan line */
46 int pass; /* adam7 pass#; 0 means no adam7 */
47 uchar palette[3*256]; /* color palette */
48 int palsize; /* number of palette entries */
53 Biobuf *io; /* input buffer */
54 uchar *buf; /* malloc'ed staging buffer */
55 uchar *p; /* next byte to decompress */
56 uchar *e; /* end of buffer */
61 static uchar PNGmagic[] = { 137, 'P', 'N', 'G', '\r', '\n', 26, '\n'};
66 return (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3];
78 crctab = mkcrctab(0xedb88320);
80 sysfatal("mkcrctab error");
86 pngmalloc(ulong n, int clear)
90 p = mallocz(n, clear);
92 sysfatal("malloc: %r");
97 getchunk(Biobuf *b, char *type, uchar *d, int m)
103 if(Breadn(b, buf, 8) != 8)
106 memmove(type, buf+4, 4);
109 sysfatal("getchunk needed %d, had %d", n, m);
110 nr = Breadn(b, d, n);
112 sysfatal("getchunk read %d, expected %d", nr, n);
113 crc = blockcrc(crctab, crc, type, 4);
114 crc = blockcrc(crctab, crc, d, n);
115 if(Breadn(b, buf, 4) != 4)
116 sysfatal("getchunk tlr failed");
119 sysfatal("getchunk crc failed");
134 n = getchunk(z->io, type, z->p, IDATSIZE);
135 if(n < 0 || strcmp(type, "IEND") == 0)
138 if(!strcmp(type,"PLTE")){
139 if(n < 3 || n > 3*256 || n%3)
140 sysfatal("invalid PLTE chunk len %d", n);
141 memcpy(z->w->palette, z->p, n);
145 if(type[0] & PropertyBit)
146 goto Again; /* skip auxiliary chunks fornow */
147 if(strcmp(type,"IDAT")){
148 sysfatal("unrecognized mandatory chunk %s", type);
156 paeth(uchar a, uchar b, uchar c)
165 if(pa <= pb && pa <= pc)
173 unfilter(int alg, uchar *buf, uchar *up, int len, int bypp)
179 fprint(2, "unknown filtering scheme %d\n", alg);
184 for(i = bypp; i < len; ++i)
185 buf[i] += buf[i-bypp];
189 for(i = 0; i < len; ++i)
194 for(i = 0; i < bypp; ++i)
195 buf[i] += (0+up[i])/2;
197 buf[i] += (buf[i-bypp]+up[i])/2;
201 for(i = 0; i < bypp; ++i)
202 buf[i] += paeth(0, up[i], 0);
204 buf[i] += paeth(buf[i-bypp], up[i], up[i-bypp]);
215 {0,0,1,1}, /* eve alone */
216 {0,0,8,8}, /* pass 1 */
217 {4,0,8,8}, /* pass 2 */
218 {0,4,4,8}, /* pass 3 */
219 {2,0,4,4}, /* pass 4 */
220 {0,2,2,4}, /* pass 5 */
221 {1,0,2,2}, /* pass 6 */
222 {0,1,1,2}, /* pass 7 */
226 scan(int len, ZlibW *z)
228 int chan, i, j, nbit, off, val;
229 uchar pixel[4], *p, *w;
231 unfilter(z->scan[0], z->scan+1, z->lastscan+1, len-1, (z->nchan*z->bpc+7)/8);
234 * loop over raw bits extracting pixel values and converting to 8-bit
239 off = z->y*z->dx + adam7[z->pass].x;
240 w = z->data + z->noutchan*off;
241 p = z->scan+1; /* skip alg byte */
243 for(i=0; i<len*8; i++){
245 if(p[i>>3] & (1<<(7-(i&7))))
247 if(++nbit == z->bpc){
248 /* finished the value */
249 pixel[chan++] = (val*255)/((1<<z->bpc)-1);
252 if(chan == z->nchan){
253 /* finished the pixel */
254 if(off < z->dx*z->dy){
255 if(z->nchan < 3 && z->palsize){
260 sysfatal("index %d >= palette size %d", j, z->palsize);
261 pixel[3] = pixel[1]; /* alpha */
262 pixel[0] = z->palette[3*j];
263 pixel[1] = z->palette[3*j+1];
264 pixel[2] = z->palette[3*j+2];
268 // print("%.2x%.2x ", pixel[0], pixel[1]);
270 *w++ += (pixel[0]*pixel[1])/255;
273 // print("%.2x%.2x%.2x%.2x ", pixel[0], pixel[1], pixel[2], pixel[3]);
275 *w++ += (pixel[2]*pixel[3])/255;
276 *w++ += (pixel[1]*pixel[3])/255;
277 *w++ += (pixel[0]*pixel[3])/255;
286 w += (adam7[z->pass].dx-1)*z->noutchan;
288 off += adam7[z->pass].dx;
289 if(off >= (z->y+1)*z->dx){
290 /* finished the line */
297 sysfatal("scan line too short");
303 int bits, n, adx, dx;
305 if(adam7[z->pass].y >= z->dy || adam7[z->pass].x >= z->dx)
307 adx = adam7[z->pass].dx;
308 dx = z->dx - adam7[z->pass].x;
313 if(n != 1 + (z->dx - (adam7[z->pass].x+1)) / adam7[z->pass].dx){
314 fprint(2, "%d/%d != 1+(%d-1)/%d = %d\n",
315 z->dx - adam7[z->pass].x - 1 + adx, adx,
316 z->dx - (adam7[z->pass].x+1), adam7[z->pass].dx,
317 1 + (z->dx - (adam7[z->pass].x+1)) / adam7[z->pass].dx);
319 bits = n*z->bpc*z->nchan;
320 return 1 + (bits+7)/8;
328 memset(z->lastscan, 0, z->scanlen);
330 z->pass = (z->pass+1)%8;
331 z->y = adam7[z->pass].y;
338 zwrite(void *vz, void *vbuf, int n)
353 m = len - z->scanpos;
355 /* save final partial line */
356 memmove(z->scan+z->scanpos, buf, n);
362 memmove(z->scan+z->scanpos, buf, m);
369 z->scan = z->lastscan;
373 z->y += adam7[z->pass].dy;
384 int bpc, colorfmt, dx, dy, err, n, nchan, nout, useadam7;
390 buf = pngmalloc(IDATSIZE, 0);
391 Breadn(b, buf, sizeof PNGmagic);
392 if(memcmp(PNGmagic, buf, sizeof PNGmagic) != 0)
393 sysfatal("bad PNGmagic");
395 n = getchunk(b, type, buf, IDATSIZE);
396 if(n < 13 || strcmp(type,"IHDR") != 0)
397 sysfatal("missing IHDR chunk");
403 if(dx <= 0 || dy <= 0)
404 sysfatal("impossible image size %dx%d", dx, dy);
406 fprint(2, "readpng %dx%d\n", dx, dy);
412 sysfatal("only deflate supported for now [%d]", h[-1]);
413 if(*h++ != FilterNone)
414 sysfatal("only FilterNone supported for now [%d]", h[-1]);
418 image = pngmalloc(sizeof(Rawimage), 1);
419 image->r = Rect(0, 0, dx, dy);
424 image->chandesc = CY;
430 image->chandesc = CRGB24;
434 case 3: /* indexed rgb with PLTE */
436 image->chandesc = CRGB24;
440 case 4: /* grey+alpha */
442 image->chandesc = CYA16;
446 case 6: /* rgb+alpha */
448 image->chandesc = CRGBA32;
453 sysfatal("unsupported color scheme %d", h[-1]);
455 image->chanlen = dx*dy*nout;
456 image->chans[0] = pngmalloc(image->chanlen, 0);
457 memset(image->chans[0], 0, image->chanlen);
459 memset(&zr, 0, sizeof zr);
464 memset(&zw, 0, sizeof zw);
467 zw.data = image->chans[0];
468 zw.ndata = image->chanlen;
469 zw.chandesc = image->chandesc;
474 zw.scanlen = (nchan*dx*bpc+7)/8+1;
475 zw.scan = pngmalloc(zw.scanlen, 1);
476 zw.lastscan = pngmalloc(zw.scanlen, 1);
480 err = inflatezlib(&zw, zwrite, &zr, zread);
483 sysfatal("inflatezlib %s\n", flateerr(err));
492 Breadpng(Biobuf *b, int colorspace)
494 Rawimage **array, *r;
496 if(colorspace != CRGB){
497 werrstr("ReadPNG: unknown color space %d", colorspace);
501 array = malloc(2*sizeof(*array));
511 readpng(int fd, int colorspace)
516 if(Binit(&b, fd, OREAD) < 0)
518 a = Breadpng(&b, colorspace);