# HG changeset patch # User Matti Hamalainen # Date 1352023679 -7200 # Node ID 349a2ff11531ac7c462b6fbce668214036136b62 # Parent d1f7ddc84c7c2f3e7db82741b70e7e766e676b3c Implement PNG (1-8bpp indexed) reading support via libPNG. diff -r d1f7ddc84c7c -r 349a2ff11531 libgfx.c --- a/libgfx.c Sun Nov 04 12:07:03 2012 +0200 +++ b/libgfx.c Sun Nov 04 12:07:59 2012 +0200 @@ -464,6 +464,181 @@ fclose(fp); return res; } + + +int dmReadPNGImageFILE(FILE *fp, DMImage **pimg) +{ + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + png_colorp palette = NULL; + png_bytep *row_pointers = NULL; + png_uint_32 width, height; + int i, bit_depth, color_type, ncolors; + int res = DMERR_OK; + DMImage *img; + + // Create PNG structures + png_ptr = png_create_read_struct( + PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + + if (png_ptr == NULL) + { + dmError("PNG: png_create_write_struct() failed.\n"); + res = DMERR_MALLOC; + goto error; + } + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + dmError("PNG: png_create_info_struct(%p) failed.\n", png_ptr); + res = DMERR_INIT_FAIL; + goto error; + } + + if (setjmp(png_jmpbuf(png_ptr))) + { + dmError("PNG: Error during image reading..\n"); + res = DMERR_INIT_FAIL; + goto error; + } + + png_init_io(png_ptr, fp); + + // Read image information + png_read_info(png_ptr, info_ptr); + + png_get_IHDR(png_ptr, info_ptr, &width, &height, + &bit_depth, &color_type, NULL, NULL, NULL); + + if (width < 1 || height < 1) + { + dmError("PNG: Invalid width or height (%d x %d)\n", + width, height); + res = DMERR_INVALID_DATA; + goto error; + } + + switch (color_type) + { + case PNG_COLOR_TYPE_GRAY: + if (bit_depth < 8) + png_set_expand_gray_1_2_4_to_8(png_ptr); + + if (bit_depth > 8) + { + dmError("PNG: Unsupported bit depth for grayscale image: %d\n", + bit_depth); + res = DMERR_NOT_SUPPORTED; + goto error; + } + break; + + case PNG_COLOR_TYPE_PALETTE: + png_set_packing(png_ptr); + break; + + default: + dmError("PNG: RGB/RGBA images not supported for loading.\n"); + res = DMERR_NOT_SUPPORTED; + goto error; + } + + // Allocate image + dmMsg(2, "PNG: %d x %d, depth=%d, type=%d\n", + width, height, bit_depth, color_type); + + if ((*pimg = img = dmImageAlloc(width, height)) == NULL) + { + dmError("PNG: Could not allocate image data.\n"); + res = DMERR_MALLOC; + goto error; + } + + // ... + row_pointers = png_malloc(png_ptr, height * sizeof(png_bytep)); + for (i = 0; i < img->height; i++) + row_pointers[i] = img->data + (i * img->pitch); + + png_read_image(png_ptr, row_pointers); + + png_read_end(png_ptr, NULL); + + // Create palette + palette = png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof(png_color)); + if (palette == NULL) + { + dmError("PNG: Could not allocate palette structure."); + res = DMERR_MALLOC; + goto error; + } + + switch (color_type) + { + case PNG_COLOR_TYPE_GRAY: + ncolors = 256; + dmMsg(2, "PNG: Generating %d color grayscale palette.\n", ncolors); + + if (!dmImageAllocPalette(img, ncolors)) + { + res = DMERR_MALLOC; + goto error; + } + + for (i = 0; i < img->ncolors; i++) + { + img->pal[i].r = img->pal[i].g = img->pal[i].b = i; + } + break; + + case PNG_COLOR_TYPE_PALETTE: + png_get_PLTE(png_ptr, info_ptr, &palette, &ncolors); + dmMsg(2, "PNG: Palette of %d colors found.\n", ncolors); + if (ncolors <= 0) + goto error; + + if (!dmImageAllocPalette(img, ncolors)) + { + res = DMERR_MALLOC; + goto error; + } + + for (i = 0; i < img->ncolors; i++) + { + img->pal[i].r = palette[i].red; + img->pal[i].g = palette[i].green; + img->pal[i].b = palette[i].blue; + } + break; + } + +error: + png_free(png_ptr, palette); + + if (png_ptr && info_ptr) + png_destroy_read_struct(&png_ptr, &info_ptr, NULL); + + return res; +} + + +int dmReadPNGImage(const char *filename, DMImage **img) +{ + int res; + FILE *fp; + + if ((fp = fopen(filename, "rb")) == NULL) + { + dmError("PNG: Could not open file '%s' for reading.\n", filename); + return DMERR_FOPEN; + } + + res = dmReadPNGImageFILE(fp, img); + + fclose(fp); + return res; +} #endif @@ -1488,11 +1663,12 @@ { "PNG", "Portable Network Graphics", fmtProbePNG, - NULL, NULL, #ifdef DM_USE_LIBPNG + dmReadPNGImage, dmReadPNGImageFILE, dmWritePNGImage, dmWritePNGImageFILE, #else NULL, NULL, + NULL, NULL, #endif }, {