Mercurial > hg > dmlib
comparison libgfx.c @ 453:349a2ff11531
Implement PNG (1-8bpp indexed) reading support via libPNG.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sun, 04 Nov 2012 12:07:59 +0200 |
parents | d1f7ddc84c7c |
children | 0af039b6c0ae |
comparison
equal
deleted
inserted
replaced
452:d1f7ddc84c7c | 453:349a2ff11531 |
---|---|
458 dmError("PNG: could not open file '%s' for writing.\n", filename); | 458 dmError("PNG: could not open file '%s' for writing.\n", filename); |
459 return DMERR_FOPEN; | 459 return DMERR_FOPEN; |
460 } | 460 } |
461 | 461 |
462 res = dmWritePNGImageFILE(fp, img, spec); | 462 res = dmWritePNGImageFILE(fp, img, spec); |
463 | |
464 fclose(fp); | |
465 return res; | |
466 } | |
467 | |
468 | |
469 int dmReadPNGImageFILE(FILE *fp, DMImage **pimg) | |
470 { | |
471 png_structp png_ptr = NULL; | |
472 png_infop info_ptr = NULL; | |
473 png_colorp palette = NULL; | |
474 png_bytep *row_pointers = NULL; | |
475 png_uint_32 width, height; | |
476 int i, bit_depth, color_type, ncolors; | |
477 int res = DMERR_OK; | |
478 DMImage *img; | |
479 | |
480 // Create PNG structures | |
481 png_ptr = png_create_read_struct( | |
482 PNG_LIBPNG_VER_STRING, | |
483 NULL, NULL, NULL); | |
484 | |
485 if (png_ptr == NULL) | |
486 { | |
487 dmError("PNG: png_create_write_struct() failed.\n"); | |
488 res = DMERR_MALLOC; | |
489 goto error; | |
490 } | |
491 | |
492 info_ptr = png_create_info_struct(png_ptr); | |
493 if (info_ptr == NULL) | |
494 { | |
495 dmError("PNG: png_create_info_struct(%p) failed.\n", png_ptr); | |
496 res = DMERR_INIT_FAIL; | |
497 goto error; | |
498 } | |
499 | |
500 if (setjmp(png_jmpbuf(png_ptr))) | |
501 { | |
502 dmError("PNG: Error during image reading..\n"); | |
503 res = DMERR_INIT_FAIL; | |
504 goto error; | |
505 } | |
506 | |
507 png_init_io(png_ptr, fp); | |
508 | |
509 // Read image information | |
510 png_read_info(png_ptr, info_ptr); | |
511 | |
512 png_get_IHDR(png_ptr, info_ptr, &width, &height, | |
513 &bit_depth, &color_type, NULL, NULL, NULL); | |
514 | |
515 if (width < 1 || height < 1) | |
516 { | |
517 dmError("PNG: Invalid width or height (%d x %d)\n", | |
518 width, height); | |
519 res = DMERR_INVALID_DATA; | |
520 goto error; | |
521 } | |
522 | |
523 switch (color_type) | |
524 { | |
525 case PNG_COLOR_TYPE_GRAY: | |
526 if (bit_depth < 8) | |
527 png_set_expand_gray_1_2_4_to_8(png_ptr); | |
528 | |
529 if (bit_depth > 8) | |
530 { | |
531 dmError("PNG: Unsupported bit depth for grayscale image: %d\n", | |
532 bit_depth); | |
533 res = DMERR_NOT_SUPPORTED; | |
534 goto error; | |
535 } | |
536 break; | |
537 | |
538 case PNG_COLOR_TYPE_PALETTE: | |
539 png_set_packing(png_ptr); | |
540 break; | |
541 | |
542 default: | |
543 dmError("PNG: RGB/RGBA images not supported for loading.\n"); | |
544 res = DMERR_NOT_SUPPORTED; | |
545 goto error; | |
546 } | |
547 | |
548 // Allocate image | |
549 dmMsg(2, "PNG: %d x %d, depth=%d, type=%d\n", | |
550 width, height, bit_depth, color_type); | |
551 | |
552 if ((*pimg = img = dmImageAlloc(width, height)) == NULL) | |
553 { | |
554 dmError("PNG: Could not allocate image data.\n"); | |
555 res = DMERR_MALLOC; | |
556 goto error; | |
557 } | |
558 | |
559 // ... | |
560 row_pointers = png_malloc(png_ptr, height * sizeof(png_bytep)); | |
561 for (i = 0; i < img->height; i++) | |
562 row_pointers[i] = img->data + (i * img->pitch); | |
563 | |
564 png_read_image(png_ptr, row_pointers); | |
565 | |
566 png_read_end(png_ptr, NULL); | |
567 | |
568 // Create palette | |
569 palette = png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof(png_color)); | |
570 if (palette == NULL) | |
571 { | |
572 dmError("PNG: Could not allocate palette structure."); | |
573 res = DMERR_MALLOC; | |
574 goto error; | |
575 } | |
576 | |
577 switch (color_type) | |
578 { | |
579 case PNG_COLOR_TYPE_GRAY: | |
580 ncolors = 256; | |
581 dmMsg(2, "PNG: Generating %d color grayscale palette.\n", ncolors); | |
582 | |
583 if (!dmImageAllocPalette(img, ncolors)) | |
584 { | |
585 res = DMERR_MALLOC; | |
586 goto error; | |
587 } | |
588 | |
589 for (i = 0; i < img->ncolors; i++) | |
590 { | |
591 img->pal[i].r = img->pal[i].g = img->pal[i].b = i; | |
592 } | |
593 break; | |
594 | |
595 case PNG_COLOR_TYPE_PALETTE: | |
596 png_get_PLTE(png_ptr, info_ptr, &palette, &ncolors); | |
597 dmMsg(2, "PNG: Palette of %d colors found.\n", ncolors); | |
598 if (ncolors <= 0) | |
599 goto error; | |
600 | |
601 if (!dmImageAllocPalette(img, ncolors)) | |
602 { | |
603 res = DMERR_MALLOC; | |
604 goto error; | |
605 } | |
606 | |
607 for (i = 0; i < img->ncolors; i++) | |
608 { | |
609 img->pal[i].r = palette[i].red; | |
610 img->pal[i].g = palette[i].green; | |
611 img->pal[i].b = palette[i].blue; | |
612 } | |
613 break; | |
614 } | |
615 | |
616 error: | |
617 png_free(png_ptr, palette); | |
618 | |
619 if (png_ptr && info_ptr) | |
620 png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | |
621 | |
622 return res; | |
623 } | |
624 | |
625 | |
626 int dmReadPNGImage(const char *filename, DMImage **img) | |
627 { | |
628 int res; | |
629 FILE *fp; | |
630 | |
631 if ((fp = fopen(filename, "rb")) == NULL) | |
632 { | |
633 dmError("PNG: Could not open file '%s' for reading.\n", filename); | |
634 return DMERR_FOPEN; | |
635 } | |
636 | |
637 res = dmReadPNGImageFILE(fp, img); | |
463 | 638 |
464 fclose(fp); | 639 fclose(fp); |
465 return res; | 640 return res; |
466 } | 641 } |
467 #endif | 642 #endif |
1486 DMImageFormat dmImageFormatList[IMGFMT_LAST] = | 1661 DMImageFormat dmImageFormatList[IMGFMT_LAST] = |
1487 { | 1662 { |
1488 { | 1663 { |
1489 "PNG", "Portable Network Graphics", | 1664 "PNG", "Portable Network Graphics", |
1490 fmtProbePNG, | 1665 fmtProbePNG, |
1491 NULL, NULL, | |
1492 #ifdef DM_USE_LIBPNG | 1666 #ifdef DM_USE_LIBPNG |
1667 dmReadPNGImage, dmReadPNGImageFILE, | |
1493 dmWritePNGImage, dmWritePNGImageFILE, | 1668 dmWritePNGImage, dmWritePNGImageFILE, |
1494 #else | 1669 #else |
1670 NULL, NULL, | |
1495 NULL, NULL, | 1671 NULL, NULL, |
1496 #endif | 1672 #endif |
1497 }, | 1673 }, |
1498 { | 1674 { |
1499 "PPM", "Portable PixMap", | 1675 "PPM", "Portable PixMap", |