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" 8 9 int debug; 10 11 enum 12 { 13 IDATSIZE = 1000000, 14 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]) */ 21 FilterLast = 5, 22 23 PropertyBit = 1<<5, 24 }; 25 26 typedef struct ZlibR ZlibR; 27 typedef struct ZlibW ZlibW; 28 29 struct ZlibW 30 { 31 uchar *data; /* Rawimage data */ 32 int ndata; 33 int noutchan; 34 int chandesc; 35 int nchan; 36 37 uchar *scan; /* new scanline */ 38 uchar *lastscan; /* previous scan line */ 39 int scanlen; /* scan line length */ 40 int scanpos; /* scan position */ 41 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 */ 49 }; 50 51 struct ZlibR 52 { 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 */ 57 ZlibW *w; 58 }; 59 60 static ulong *crctab; 61 static uchar PNGmagic[] = { 137, 'P', 'N', 'G', '\r', '\n', 26, '\n'}; 62 63 static ulong 64 get4(uchar *a) 65 { 66 return (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3]; 67 } 68 69 static 70 void 71 pnginit(void) 72 { 73 static int inited; 74 75 if(inited) 76 return; 77 inited = 1; 78 crctab = mkcrctab(0xedb88320); 79 if(crctab == nil) 80 sysfatal("mkcrctab error"); 81 inflateinit(); 82 } 83 84 static 85 void* 86 pngmalloc(ulong n, int clear) 87 { 88 void *p; 89 90 p = mallocz(n, clear); 91 if(p == nil) 92 sysfatal("malloc: %r"); 93 return p; 94 } 95 96 static int 97 getchunk(Biobuf *b, char *type, uchar *d, int m) 98 { 99 uchar buf[8]; 100 ulong crc = 0, crc2; 101 int n, nr; 102 103 if(Bread(b, buf, 8) != 8) 104 return -1; 105 n = get4(buf); 106 memmove(type, buf+4, 4); 107 type[4] = 0; 108 if(n > m) 109 sysfatal("getchunk needed %d, had %d", n, m); 110 nr = Bread(b, d, n); 111 if(nr != 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(Bread(b, buf, 4) != 4) 116 sysfatal("getchunk tlr failed"); 117 crc2 = get4(buf); 118 if(crc != crc2) 119 sysfatal("getchunk crc failed"); 120 return n; 121 } 122 123 static int 124 zread(void *va) 125 { 126 ZlibR *z = va; 127 char type[5]; 128 int n; 129 130 if(z->p >= z->e){ 131 Again: 132 z->p = z->buf; 133 z->e = z->p; 134 n = getchunk(z->io, type, z->p, IDATSIZE); 135 if(n < 0 || strcmp(type, "IEND") == 0) 136 return -1; 137 z->e = z->p + n; 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); 142 z->w->palsize = 256; 143 goto Again; 144 } 145 if(type[0] & PropertyBit) 146 goto Again; /* skip auxiliary chunks fornow */ 147 if(strcmp(type,"IDAT")){ 148 sysfatal("unrecognized mandatory chunk %s", type); 149 goto Again; 150 } 151 } 152 return *z->p++; 153 } 154 155 static uchar 156 paeth(uchar a, uchar b, uchar c) 157 { 158 int p, pa, pb, pc; 159 160 p = a + b - c; 161 pa = abs(p - a); 162 pb = abs(p - b); 163 pc = abs(p - c); 164 165 if(pa <= pb && pa <= pc) 166 return a; 167 else if(pb <= pc) 168 return b; 169 return c; 170 } 171 172 static void 173 unfilter(int alg, uchar *buf, uchar *up, int len, int bypp) 174 { 175 int i; 176 177 switch(alg){ 178 case FilterNone: 179 break; 180 181 case FilterSub: 182 for(i = bypp; i < len; ++i) 183 buf[i] += buf[i-bypp]; 184 break; 185 186 case FilterUp: 187 for(i = 0; i < len; ++i) 188 buf[i] += up[i]; 189 break; 190 191 case FilterAvg: 192 for(i = 0; i < bypp; ++i) 193 buf[i] += (0+up[i])/2; 194 for(; i < len; ++i) 195 buf[i] += (buf[i-bypp]+up[i])/2; 196 break; 197 198 case FilterPaeth: 199 for(i = 0; i < bypp; ++i) 200 buf[i] += paeth(0, up[i], 0); 201 for(; i < len; ++i) 202 buf[i] += paeth(buf[i-bypp], up[i], up[i-bypp]); 203 break; 204 205 default: 206 sysfatal("unknown filtering scheme %d\n", alg); 207 } 208 } 209 210 struct { 211 int x; 212 int y; 213 int dx; 214 int dy; 215 } adam7[] = { 216 {0,0,1,1}, /* eve alone */ 217 {0,0,8,8}, /* pass 1 */ 218 {4,0,8,8}, /* pass 2 */ 219 {0,4,4,8}, /* pass 3 */ 220 {2,0,4,4}, /* pass 4 */ 221 {0,2,2,4}, /* pass 5 */ 222 {1,0,2,2}, /* pass 6 */ 223 {0,1,1,2}, /* pass 7 */ 224 }; 225 226 static void 227 scan(int len, ZlibW *z) 228 { 229 int chan, i, j, nbit, off, val; 230 uchar pixel[4], *p, *w; 231 232 unfilter(z->scan[0], z->scan+1, z->lastscan+1, len-1, (z->nchan*z->bpc+7)/8); 233 234 /* 235 * loop over raw bits extracting pixel values and converting to 8-bit 236 */ 237 nbit = 0; 238 chan = 0; 239 val = 0; 240 off = z->y*z->dx + adam7[z->pass].x; 241 w = z->data + z->noutchan*off; 242 p = z->scan+1; /* skip alg byte */ 243 len--; 244 for(i=0; i<len*8; i++){ 245 val <<= 1; 246 if(p[i>>3] & (1<<(7-(i&7)))) 247 val++; 248 if(++nbit == z->bpc){ 249 /* finished the value */ 250 pixel[chan++] = (val*255)/((1<<z->bpc)-1); 251 val = 0; 252 nbit = 0; 253 if(chan == z->nchan){ 254 /* finished the pixel */ 255 if(off < z->dx*z->dy){ 256 if(z->nchan < 3 && z->palsize){ 257 j = pixel[0]; 258 if(z->bpc < 8) 259 j >>= 8-z->bpc; 260 if(j >= z->palsize) 261 sysfatal("index %d >= palette size %d", j, z->palsize); 262 pixel[3] = pixel[1]; /* alpha */ 263 pixel[0] = z->palette[3*j]; 264 pixel[1] = z->palette[3*j+1]; 265 pixel[2] = z->palette[3*j+2]; 266 } 267 switch(z->chandesc){ 268 case CYA16: 269 // print("%.2x%.2x ", pixel[0], pixel[1]); 270 *w++ = pixel[1]; 271 *w++ += (pixel[0]*pixel[1])/255; 272 break; 273 case CRGBA32: 274 // print("%.2x%.2x%.2x%.2x ", pixel[0], pixel[1], pixel[2], pixel[3]); 275 *w++ += pixel[3]; 276 *w++ += (pixel[2]*pixel[3])/255; 277 *w++ += (pixel[1]*pixel[3])/255; 278 *w++ += (pixel[0]*pixel[3])/255; 279 break; 280 case CRGB24: 281 *w++ = pixel[2]; 282 *w++ = pixel[1]; 283 case CY: 284 *w++ = pixel[0]; 285 break; 286 } 287 w += (adam7[z->pass].dx-1)*z->noutchan; 288 } 289 off += adam7[z->pass].dx; 290 if(off >= (z->y+1)*z->dx){ 291 /* finished the line */ 292 return; 293 } 294 chan = 0; 295 } 296 } 297 } 298 sysfatal("scan line too short"); 299 } 300 301 static int 302 scanbytes(ZlibW *z) 303 { 304 int bits, n, adx, dx; 305 306 if(adam7[z->pass].y >= z->dy || adam7[z->pass].x >= z->dx) 307 return 0; 308 adx = adam7[z->pass].dx; 309 dx = z->dx - adam7[z->pass].x; 310 if(dx <= 0) 311 n = 1; 312 else 313 n = (dx+adx-1)/adx; 314 if(n != 1 + (z->dx - (adam7[z->pass].x+1)) / adam7[z->pass].dx){ 315 print("%d/%d != 1+(%d-1)/%d = %d\n", 316 z->dx - adam7[z->pass].x - 1 + adx, adx, 317 z->dx - (adam7[z->pass].x+1), adam7[z->pass].dx, 318 1 + (z->dx - (adam7[z->pass].x+1)) / adam7[z->pass].dx); 319 } 320 bits = n*z->bpc*z->nchan; 321 return 1 + (bits+7)/8; 322 } 323 324 static int 325 nextpass(ZlibW *z) 326 { 327 int len; 328 329 memset(z->lastscan, 0, z->scanlen); 330 do{ 331 z->pass = (z->pass+1)%8; 332 z->y = adam7[z->pass].y; 333 len = scanbytes(z); 334 }while(len < 2); 335 return len; 336 } 337 338 static int 339 zwrite(void *vz, void *vbuf, int n) 340 { 341 int oldn, m, len; 342 uchar *buf, *t; 343 ZlibW *z; 344 345 z = vz; 346 buf = vbuf; 347 oldn = n; 348 349 len = scanbytes(z); 350 if(len < 2) 351 len = nextpass(z); 352 353 while(n > 0){ 354 m = len - z->scanpos; 355 if(m > n){ 356 /* save final partial line */ 357 memmove(z->scan+z->scanpos, buf, n); 358 z->scanpos += n; 359 break; 360 } 361 362 /* fill line */ 363 memmove(z->scan+z->scanpos, buf, m); 364 buf += m; 365 n -= m; 366 367 /* process line */ 368 scan(len, z); 369 t = z->scan; 370 z->scan = z->lastscan; 371 z->lastscan = t; 372 373 z->scanpos = 0; 374 z->y += adam7[z->pass].dy; 375 if(z->y >= z->dy) 376 len = nextpass(z); 377 } 378 return oldn; 379 } 380 381 static Rawimage* 382 readslave(Biobuf *b) 383 { 384 char type[5]; 385 int bpc, colorfmt, dx, dy, err, n, nchan, nout, useadam7; 386 uchar *buf, *h; 387 Rawimage *image; 388 ZlibR zr; 389 ZlibW zw; 390 391 buf = pngmalloc(IDATSIZE, 0); 392 if(Bread(b, buf, sizeof PNGmagic) != sizeof PNGmagic || 393 memcmp(PNGmagic, buf, sizeof PNGmagic) != 0) 394 sysfatal("bad PNGmagic"); 395 396 n = getchunk(b, type, buf, IDATSIZE); 397 if(n < 13 || strcmp(type,"IHDR") != 0) 398 sysfatal("missing IHDR chunk"); 399 h = buf; 400 dx = get4(h); 401 h += 4; 402 dy = get4(h); 403 h += 4; 404 if(dx <= 0 || dy <= 0) 405 sysfatal("impossible image size %dx%d", dx, dy); 406 if(debug) 407 fprint(2, "readpng %dx%d\n", dx, dy); 408 409 bpc = *h++; 410 colorfmt = *h++; 411 nchan = 0; 412 if(*h++ != 0) 413 sysfatal("only deflate supported for now [%d]", h[-1]); 414 if(*h++ != FilterNone) 415 sysfatal("only FilterNone supported for now [%d]", h[-1]); 416 useadam7 = *h++; 417 USED(h); 418 419 image = pngmalloc(sizeof(Rawimage), 1); 420 image->r = Rect(0, 0, dx, dy); 421 nout = 0; 422 switch(colorfmt){ 423 case 0: /* grey */ 424 image->nchans = 1; 425 image->chandesc = CY; 426 nout = 1; 427 nchan = 1; 428 break; 429 case 2: /* rgb */ 430 image->nchans = 1; 431 image->chandesc = CRGB24; 432 nout = 3; 433 nchan = 3; 434 break; 435 case 3: /* indexed rgb with PLTE */ 436 image->nchans = 1; 437 image->chandesc = CRGB24; 438 nout = 3; 439 nchan = 1; 440 break; 441 case 4: /* grey+alpha */ 442 image->nchans = 1; 443 image->chandesc = CYA16; 444 nout = 2; 445 nchan = 2; 446 break; 447 case 6: /* rgb+alpha */ 448 image->nchans = 1; 449 image->chandesc = CRGBA32; 450 nout = 4; 451 nchan = 4; 452 break; 453 default: 454 sysfatal("unsupported color scheme %d", h[-1]); 455 } 456 image->chanlen = dx*dy*nout; 457 image->chans[0] = pngmalloc(image->chanlen, 0); 458 memset(image->chans[0], 0, image->chanlen); 459 460 memset(&zr, 0, sizeof zr); 461 zr.w = &zw; 462 zr.io = b; 463 zr.buf = buf; 464 465 memset(&zw, 0, sizeof zw); 466 if(useadam7) 467 zw.pass = 1; 468 zw.data = image->chans[0]; 469 zw.ndata = image->chanlen; 470 zw.chandesc = image->chandesc; 471 zw.noutchan = nout; 472 473 zw.dx = dx; 474 zw.dy = dy; 475 zw.scanlen = (nchan*dx*bpc+7)/8+1; 476 zw.scan = pngmalloc(zw.scanlen, 1); 477 zw.lastscan = pngmalloc(zw.scanlen, 1); 478 zw.nchan = nchan; 479 zw.bpc = bpc; 480 481 err = inflatezlib(&zw, zwrite, &zr, zread); 482 483 if(err) 484 sysfatal("inflatezlib %s\n", flateerr(err)); 485 486 free(buf); 487 free(zw.scan); 488 free(zw.lastscan); 489 return image; 490 } 491 492 Rawimage** 493 Breadpng(Biobuf *b, int colorspace) 494 { 495 Rawimage **array, *r; 496 497 if(colorspace != CRGB){ 498 werrstr("ReadPNG: unknown color space %d", colorspace); 499 return nil; 500 } 501 pnginit(); 502 array = malloc(2*sizeof(*array)); 503 if(array==nil) 504 return nil; 505 r = readslave(b); 506 array[0] = r; 507 array[1] = nil; 508 return array; 509 } 510 511 Rawimage** 512 readpng(int fd, int colorspace) 513 { 514 Biobuf b; 515 Rawimage **a; 516 517 if(Binit(&b, fd, OREAD) < 0) 518 return nil; 519 a = Breadpng(&b, colorspace); 520 Bterm(&b); 521 return a; 522 } 523