#include "image.h"
#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
#include <png.h>
int
ImageReadPNG(image_t *img,
FILE *fp,
int primary,
int secondary,
int saturation,
int hue,
const ib_t *lut)
{
int y;
png_structp pp;
png_infop info;
int bpp;
int pass,
passes;
ib_t *in,
*inptr,
*out;
png_color_16 bg;
pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
info = png_create_info_struct(pp);
png_init_io(pp, fp);
png_read_info(pp, info);
fprintf(stderr, "DEBUG: PNG image: %dx%dx%d, color_type=%x (%s%s%s)\n",
info->width, info->height, info->bit_depth, info->color_type,
(info->color_type & PNG_COLOR_MASK_COLOR) ? "RGB" : "GRAYSCALE",
(info->color_type & PNG_COLOR_MASK_ALPHA) ? "+ALPHA" : "",
(info->color_type & PNG_COLOR_MASK_PALETTE) ? "+PALETTE" : "");
if (info->color_type & PNG_COLOR_MASK_PALETTE)
png_set_expand(pp);
else if (info->bit_depth < 8)
{
png_set_packing(pp);
png_set_expand(pp);
}
else if (info->bit_depth == 16)
png_set_strip_16(pp);
if (info->color_type & PNG_COLOR_MASK_COLOR)
img->colorspace = (primary == IMAGE_RGB_CMYK) ? IMAGE_RGB : primary;
else
img->colorspace = secondary;
if (info->width == 0 || info->width > IMAGE_MAX_WIDTH ||
info->height == 0 || info->height > IMAGE_MAX_HEIGHT)
{
fprintf(stderr, "ERROR: PNG image has invalid dimensions %ux%u!\n",
(unsigned)info->width, (unsigned)info->height);
fclose(fp);
return (1);
}
img->xsize = info->width;
img->ysize = info->height;
if (info->valid & PNG_INFO_pHYs &&
info->phys_unit_type == PNG_RESOLUTION_METER)
{
img->xppi = (int)((float)info->x_pixels_per_unit * 0.0254);
img->yppi = (int)((float)info->y_pixels_per_unit * 0.0254);
if (img->xppi == 0 || img->yppi == 0)
{
fprintf(stderr, "ERROR: PNG image has invalid resolution %dx%d PPI\n",
img->xppi, img->yppi);
img->xppi = img->yppi = 128;
}
}
ImageSetMaxTiles(img, 0);
passes = png_set_interlace_handling(pp);
if (png_get_valid(pp, info, PNG_INFO_tRNS))
png_set_tRNS_to_alpha(pp);
bg.red = 65535;
bg.green = 65535;
bg.blue = 65535;
png_set_background(pp, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
if (passes == 1)
{
if (info->color_type == PNG_COLOR_TYPE_GRAY ||
info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
in = malloc(img->xsize);
else
in = malloc(img->xsize * 3);
}
else
{
if (info->color_type == PNG_COLOR_TYPE_GRAY ||
info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
in = malloc(img->xsize * img->ysize);
else
in = malloc(img->xsize * img->ysize * 3);
}
bpp = ImageGetDepth(img);
out = malloc(img->xsize * bpp);
for (pass = 1; pass <= passes; pass ++)
for (inptr = in, y = 0; y < img->ysize; y ++)
{
png_read_row(pp, (png_bytep)inptr, NULL);
if (pass == passes)
{
if (info->color_type & PNG_COLOR_MASK_COLOR)
{
if ((saturation != 100 || hue != 0) && bpp > 1)
ImageRGBAdjust(inptr, img->xsize, saturation, hue);
switch (img->colorspace)
{
case IMAGE_WHITE :
ImageRGBToWhite(inptr, out, img->xsize);
break;
case IMAGE_RGB :
memcpy(out, inptr, img->xsize * 3);
break;
case IMAGE_BLACK :
ImageRGBToBlack(inptr, out, img->xsize);
break;
case IMAGE_CMY :
ImageRGBToCMY(inptr, out, img->xsize);
break;
case IMAGE_CMYK :
ImageRGBToCMYK(inptr, out, img->xsize);
break;
}
}
else
{
switch (img->colorspace)
{
case IMAGE_WHITE :
memcpy(out, inptr, img->xsize);
break;
case IMAGE_RGB :
ImageWhiteToRGB(inptr, out, img->xsize);
break;
case IMAGE_BLACK :
ImageWhiteToBlack(inptr, out, img->xsize);
break;
case IMAGE_CMY :
ImageWhiteToCMY(inptr, out, img->xsize);
break;
case IMAGE_CMYK :
ImageWhiteToCMYK(inptr, out, img->xsize);
break;
}
}
if (lut)
ImageLut(out, img->xsize * bpp, lut);
ImagePutRow(img, 0, y, img->xsize, out);
}
if (passes > 1)
{
if (info->color_type & PNG_COLOR_MASK_COLOR)
inptr += img->xsize * 3;
else
inptr += img->xsize;
}
}
png_read_end(pp, info);
png_read_destroy(pp, info, NULL);
fclose(fp);
free(in);
free(out);
return (0);
}
#endif