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",