1 /* 2 * pnglite.c - pnglite library 3 * For conditions of distribution and use, see copyright notice in pnglite.h 4 */ 5 6 #ifdef _STANDALONE 7 #include <sys/cdefs.h> 8 #include <stand.h> 9 #else 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <sys/types.h> 13 #include <sys/stat.h> 14 #include <fcntl.h> 15 #endif 16 #include <zlib.h> 17 #include "pnglite.h" 18 19 #ifndef abs 20 #define abs(x) ((x) < 0? -(x):(x)) 21 #endif 22 23 #define PNG_32b(b, s) ((uint32_t)(b) << (s)) 24 #define PNG_U32(b1, b2, b3, b4) \ 25 (PNG_32b(b1, 24) | PNG_32b(b2, 16) | PNG_32b(b3, 8) | PNG_32b(b4, 0)) 26 27 #define png_IDAT PNG_U32(73, 68, 65, 84) 28 #define png_IEND PNG_U32(73, 69, 78, 68) 29 30 static ssize_t 31 file_read(png_t *png, void *out, size_t size, size_t numel) 32 { 33 ssize_t result; 34 off_t offset = (off_t)(size * numel); 35 36 if (offset < 0) 37 return (PNG_FILE_ERROR); 38 39 if (!out) { 40 result = lseek(png->fd, offset, SEEK_CUR); 41 } else { 42 result = read(png->fd, out, size * numel); 43 } 44 45 return (result); 46 } 47 48 static int 49 file_read_ul(png_t *png, unsigned *out) 50 { 51 uint8_t buf[4]; 52 53 if (file_read(png, buf, 1, 4) != 4) 54 return (PNG_FILE_ERROR); 55 56 *out = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3]; 57 58 return (PNG_NO_ERROR); 59 } 60 61 static unsigned 62 get_ul(uint8_t *buf) 63 { 64 unsigned result; 65 uint8_t foo[4]; 66 67 memcpy(foo, buf, 4); 68 69 result = (foo[0]<<24) | (foo[1]<<16) | (foo[2]<<8) | foo[3]; 70 71 return (result); 72 } 73 74 static int 75 png_get_bpp(png_t *png) 76 { 77 int bpp; 78 79 switch (png->color_type) { 80 case PNG_GREYSCALE: 81 bpp = 1; break; 82 case PNG_TRUECOLOR: 83 bpp = 3; break; 84 case PNG_INDEXED: 85 bpp = 1; break; 86 case PNG_GREYSCALE_ALPHA: 87 bpp = 2; break; 88 case PNG_TRUECOLOR_ALPHA: 89 bpp = 4; break; 90 default: 91 return (PNG_FILE_ERROR); 92 } 93 94 bpp *= png->depth / 8; 95 96 return (bpp); 97 } 98 99 static int 100 png_read_ihdr(png_t *png) 101 { 102 unsigned length = 0; 103 unsigned orig_crc; 104 unsigned calc_crc; 105 uint8_t ihdr[13+4]; /* length should be 13, make room for type (IHDR) */ 106 107 if (file_read_ul(png, &length) != PNG_NO_ERROR) 108 return (PNG_FILE_ERROR); 109 110 if (length != 13) 111 return (PNG_CRC_ERROR); 112 113 if (file_read(png, ihdr, 1, 13+4) != 13+4) 114 return (PNG_EOF_ERROR); 115 116 if (file_read_ul(png, &orig_crc) != PNG_NO_ERROR) 117 return (PNG_FILE_ERROR); 118 119 calc_crc = crc32(0L, Z_NULL, 0); 120 calc_crc = crc32(calc_crc, ihdr, 13+4); 121 122 if (orig_crc != calc_crc) { 123 return (PNG_CRC_ERROR); 124 } 125 126 png->width = get_ul(ihdr+4); 127 png->height = get_ul(ihdr+8); 128 png->depth = ihdr[12]; 129 png->color_type = ihdr[13]; 130 png->compression_method = ihdr[14]; 131 png->filter_method = ihdr[15]; 132 png->interlace_method = ihdr[16]; 133 134 if (png->color_type == PNG_INDEXED) 135 return (PNG_NOT_SUPPORTED); 136 137 if (png->depth != 8 && png->depth != 16) 138 return (PNG_NOT_SUPPORTED); 139 140 if (png->interlace_method) 141 return (PNG_NOT_SUPPORTED); 142 143 return (PNG_NO_ERROR); 144 } 145 146 void 147 png_print_info(png_t *png) 148 { 149 printf("PNG INFO:\n"); 150 printf("\twidth:\t\t%d\n", png->width); 151 printf("\theight:\t\t%d\n", png->height); 152 printf("\tdepth:\t\t%d\n", png->depth); 153 printf("\tcolor:\t\t"); 154 155 switch (png->color_type) { 156 case PNG_GREYSCALE: 157 printf("greyscale\n"); break; 158 case PNG_TRUECOLOR: 159 printf("truecolor\n"); break; 160 case PNG_INDEXED: 161 printf("palette\n"); break; 162 case PNG_GREYSCALE_ALPHA: 163 printf("greyscale with alpha\n"); break; 164 case PNG_TRUECOLOR_ALPHA: 165 printf("truecolor with alpha\n"); break; 166 default: 167 printf("unknown, this is not good\n"); break; 168 } 169 170 printf("\tcompression:\t%s\n", 171 png->compression_method? 172 "unknown, this is not good":"inflate/deflate"); 173 printf("\tfilter:\t\t%s\n", 174 png->filter_method? "unknown, this is not good":"adaptive"); 175 printf("\tinterlace:\t%s\n", 176 png->interlace_method? "interlace":"no interlace"); 177 } 178 179 int 180 png_open(png_t *png, const char *filename) 181 { 182 char header[8]; 183 int result; 184 185 png->image = NULL; 186 png->fd = open(filename, O_RDONLY); 187 if (png->fd == -1) 188 return (PNG_FILE_ERROR); 189 190 if (file_read(png, header, 1, 8) != 8) { 191 result = PNG_EOF_ERROR; 192 goto done; 193 } 194 195 if (memcmp(header, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8) != 0) { 196 result = PNG_HEADER_ERROR; 197 goto done; 198 } 199 200 result = png_read_ihdr(png); 201 if (result == PNG_NO_ERROR) { 202 result = png_get_bpp(png); 203 if (result > 0) { 204 png->bpp = (uint8_t)result; 205 result = PNG_NO_ERROR; 206 } 207 } 208 209 done: 210 if (result == PNG_NO_ERROR) { 211 uint64_t size = png->width * png->height * png->bpp; 212 213 if (size < UINT_MAX) 214 png->image = malloc(size); 215 if (png->image == NULL) 216 result = PNG_MEMORY_ERROR; 217 } 218 219 if (result == PNG_NO_ERROR) 220 result = png_get_data(png, png->image); 221 222 if (result != PNG_NO_ERROR) { 223 free(png->image); 224 (void) close(png->fd); 225 png->fd = -1; 226 return (result); 227 } 228 229 return (result); 230 } 231 232 int 233 png_close(png_t *png) 234 { 235 (void) close(png->fd); 236 png->fd = -1; 237 free(png->image); 238 png->image = NULL; 239 240 return (PNG_NO_ERROR); 241 } 242 243 static int 244 png_init_inflate(png_t *png) 245 { 246 z_stream *stream; 247 png->zs = calloc(1, sizeof (z_stream)); 248 249 stream = png->zs; 250 251 if (!stream) 252 return (PNG_MEMORY_ERROR); 253 254 if (inflateInit(stream) != Z_OK) { 255 free(png->zs); 256 png->zs = NULL; 257 return (PNG_ZLIB_ERROR); 258 } 259 260 stream->next_out = png->png_data; 261 stream->avail_out = png->png_datalen; 262 263 return (PNG_NO_ERROR); 264 } 265 266 static int 267 png_end_inflate(png_t *png) 268 { 269 z_stream *stream = png->zs; 270 int rc = PNG_NO_ERROR; 271 272 if (!stream) 273 return (PNG_MEMORY_ERROR); 274 275 if (inflateEnd(stream) != Z_OK) { 276 printf("ZLIB says: %s\n", stream->msg); 277 rc = PNG_ZLIB_ERROR; 278 } 279 280 free(png->zs); 281 png->zs = NULL; 282 283 return (rc); 284 } 285 286 static int 287 png_inflate(png_t *png, uint8_t *data, int len) 288 { 289 int result; 290 z_stream *stream = png->zs; 291 292 if (!stream) 293 return (PNG_MEMORY_ERROR); 294 295 stream->next_in = data; 296 stream->avail_in = len; 297 298 result = inflate(stream, Z_SYNC_FLUSH); 299 300 if (result != Z_STREAM_END && result != Z_OK) { 301 printf("%s\n", stream->msg); 302 return (PNG_ZLIB_ERROR); 303 } 304 305 if (stream->avail_in != 0) 306 return (PNG_ZLIB_ERROR); 307 308 return (PNG_NO_ERROR); 309 } 310 311 static int 312 png_read_idat(png_t *png, unsigned length) 313 { 314 unsigned orig_crc; 315 unsigned calc_crc; 316 ssize_t len = length; 317 318 if (!png->readbuf || png->readbuflen < length) { 319 png->readbuf = realloc(png->readbuf, length); 320 png->readbuflen = length; 321 } 322 323 if (!png->readbuf) 324 return (PNG_MEMORY_ERROR); 325 326 if (file_read(png, png->readbuf, 1, length) != len) 327 return (PNG_FILE_ERROR); 328 329 calc_crc = crc32(0L, Z_NULL, 0); 330 calc_crc = crc32(calc_crc, (uint8_t *)"IDAT", 4); 331 calc_crc = crc32(calc_crc, (uint8_t *)png->readbuf, length); 332 333 if (file_read_ul(png, &orig_crc) != PNG_NO_ERROR) 334 return (PNG_FILE_ERROR); 335 336 if (orig_crc != calc_crc) 337 return (PNG_CRC_ERROR); 338 339 return (png_inflate(png, png->readbuf, length)); 340 } 341 342 static int 343 png_process_chunk(png_t *png) 344 { 345 int result = PNG_NO_ERROR; 346 unsigned type; 347 unsigned length; 348 349 if (file_read_ul(png, &length) != PNG_NO_ERROR) 350 return (PNG_FILE_ERROR); 351 352 if (file_read_ul(png, &type) != PNG_NO_ERROR) 353 return (PNG_FILE_ERROR); 354 355 /* 356 * if we found an idat, all other idats should be followed with no 357 * other chunks in between 358 */ 359 if (type == png_IDAT) { 360 if (!png->png_data) { /* first IDAT */ 361 png->png_datalen = png->width * png->height * 362 png->bpp + png->height; 363 png->png_data = malloc(png->png_datalen); 364 } 365 366 if (!png->png_data) 367 return (PNG_MEMORY_ERROR); 368 369 if (!png->zs) { 370 result = png_init_inflate(png); 371 if (result != PNG_NO_ERROR) 372 return (result); 373 } 374 375 return (png_read_idat(png, length)); 376 } else if (type == png_IEND) 377 return (PNG_DONE); 378 else 379 (void) file_read(png, 0, 1, length + 4); /* unknown chunk */ 380 381 return (result); 382 } 383 384 static void 385 png_filter_sub(unsigned stride, uint8_t *in, uint8_t *out, unsigned len) 386 { 387 unsigned i; 388 uint8_t a = 0; 389 390 for (i = 0; i < len; i++) { 391 if (i >= stride) 392 a = out[i - stride]; 393 394 out[i] = in[i] + a; 395 } 396 } 397 398 static void 399 png_filter_up(unsigned stride __unused, uint8_t *in, uint8_t *out, 400 uint8_t *prev_line, unsigned len) 401 { 402 unsigned i; 403 404 if (prev_line) { 405 for (i = 0; i < len; i++) 406 out[i] = in[i] + prev_line[i]; 407 } else 408 memcpy(out, in, len); 409 } 410 411 static void 412 png_filter_average(unsigned stride, uint8_t *in, uint8_t *out, 413 uint8_t *prev_line, unsigned len) 414 { 415 unsigned int i; 416 uint8_t a = 0; 417 uint8_t b = 0; 418 unsigned int sum = 0; 419 420 for (i = 0; i < len; i++) { 421 if (prev_line) 422 b = prev_line[i]; 423 424 if (i >= stride) 425 a = out[i - stride]; 426 427 sum = a; 428 sum += b; 429 430 out[i] = in[i] + sum/2; 431 } 432 } 433 434 static uint8_t 435 png_paeth(uint8_t a, uint8_t b, uint8_t c) 436 { 437 int p = (int)a + b - c; 438 int pa = abs(p - a); 439 int pb = abs(p - b); 440 int pc = abs(p - c); 441 442 int pr; 443 444 if (pa <= pb && pa <= pc) 445 pr = a; 446 else if (pb <= pc) 447 pr = b; 448 else 449 pr = c; 450 451 return (pr); 452 } 453 454 static void 455 png_filter_paeth(unsigned stride, uint8_t *in, uint8_t *out, uint8_t *prev_line, 456 unsigned len) 457 { 458 unsigned i; 459 uint8_t a; 460 uint8_t b; 461 uint8_t c; 462 463 for (i = 0; i < len; i++) { 464 if (prev_line && i >= stride) { 465 a = out[i - stride]; 466 b = prev_line[i]; 467 c = prev_line[i - stride]; 468 } else { 469 if (prev_line) 470 b = prev_line[i]; 471 else 472 b = 0; 473 474 if (i >= stride) 475 a = out[i - stride]; 476 else 477 a = 0; 478 479 c = 0; 480 } 481 482 out[i] = in[i] + png_paeth(a, b, c); 483 } 484 } 485 486 static int 487 png_unfilter(png_t *png, uint8_t *data) 488 { 489 unsigned i; 490 unsigned pos = 0; 491 unsigned outpos = 0; 492 uint8_t *filtered = png->png_data; 493 unsigned stride = png->bpp; 494 495 while (pos < png->png_datalen) { 496 uint8_t filter = filtered[pos]; 497 498 pos++; 499 500 if (png->depth == 16) { 501 for (i = 0; i < png->width * stride; i += 2) { 502 *(short *)(filtered+pos+i) = 503 (filtered[pos+i] << 8) | filtered[pos+i+1]; 504 } 505 } 506 507 switch (filter) { 508 case 0: /* none */ 509 memcpy(data+outpos, filtered+pos, png->width * stride); 510 break; 511 case 1: /* sub */ 512 png_filter_sub(stride, filtered+pos, data+outpos, 513 png->width * stride); 514 break; 515 case 2: /* up */ 516 if (outpos) { 517 png_filter_up(stride, filtered+pos, data+outpos, 518 data + outpos - (png->width*stride), 519 png->width*stride); 520 } else { 521 png_filter_up(stride, filtered+pos, data+outpos, 522 0, png->width*stride); 523 } 524 break; 525 case 3: /* average */ 526 if (outpos) { 527 png_filter_average(stride, filtered+pos, 528 data+outpos, 529 data + outpos - (png->width*stride), 530 png->width*stride); 531 } else { 532 png_filter_average(stride, filtered+pos, 533 data+outpos, 0, png->width*stride); 534 } 535 break; 536 case 4: /* paeth */ 537 if (outpos) { 538 png_filter_paeth(stride, filtered+pos, 539 data+outpos, 540 data + outpos - (png->width*stride), 541 png->width*stride); 542 } else { 543 png_filter_paeth(stride, filtered+pos, 544 data+outpos, 0, png->width*stride); 545 } 546 break; 547 default: 548 return (PNG_UNKNOWN_FILTER); 549 } 550 551 outpos += png->width * stride; 552 pos += png->width * stride; 553 } 554 555 return (PNG_NO_ERROR); 556 } 557 558 int 559 png_get_data(png_t *png, uint8_t *data) 560 { 561 int result = PNG_NO_ERROR; 562 563 png->zs = NULL; 564 png->png_datalen = 0; 565 png->png_data = NULL; 566 png->readbuf = NULL; 567 png->readbuflen = 0; 568 569 while (result == PNG_NO_ERROR) 570 result = png_process_chunk(png); 571 572 if (png->readbuf) { 573 free(png->readbuf); 574 png->readbuflen = 0; 575 } 576 if (png->zs) 577 (void) png_end_inflate(png); 578 579 if (result != PNG_DONE) { 580 free(png->png_data); 581 return (result); 582 } 583 584 result = png_unfilter(png, data); 585 586 free(png->png_data); 587 588 return (result); 589 } 590 591 char * 592 png_error_string(int error) 593 { 594 switch (error) { 595 case PNG_NO_ERROR: 596 return ("No error"); 597 case PNG_FILE_ERROR: 598 return ("Unknown file error."); 599 case PNG_HEADER_ERROR: 600 return ("No PNG header found. Are you sure this is a PNG?"); 601 case PNG_IO_ERROR: 602 return ("Failure while reading file."); 603 case PNG_EOF_ERROR: 604 return ("Reached end of file."); 605 case PNG_CRC_ERROR: 606 return ("CRC or chunk length error."); 607 case PNG_MEMORY_ERROR: 608 return ("Could not allocate memory."); 609 case PNG_ZLIB_ERROR: 610 return ("zlib reported an error."); 611 case PNG_UNKNOWN_FILTER: 612 return ("Unknown filter method used in scanline."); 613 case PNG_DONE: 614 return ("PNG done"); 615 case PNG_NOT_SUPPORTED: 616 return ("The PNG is unsupported by pnglite, too bad for you!"); 617 case PNG_WRONG_ARGUMENTS: 618 return ("Wrong combination of arguments passed to png_open. " 619 "You must use either a read_function or supply a file " 620 "pointer to use."); 621 default: 622 return ("Unknown error."); 623 }; 624 } 625