/* * "$Id: image-png.c 9771 2011-05-12 05:21:56Z mike $" * * PNG image routines for CUPS. * * Copyright 2007-2011 by Apple Inc. * Copyright 1993-2007 by Easy Software Products. * * These coded instructions, statements, and computer programs are the * property of Apple Inc. and are protected by Federal copyright * law. Distribution and use rights are outlined in the file "LICENSE.txt" * which should have been included with this file. If this file is * file is missing or damaged, see the license at "http://www.cups.org/". * * This file is subject to the Apple OS-Developed Software exception. * * Contents: * * _cupsImageReadPNG() - Read a PNG image file. */ /* * Include necessary headers... */ #include "image-private.h" #if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ) # include /* Portable Network Graphics (PNG) definitions */ /* * '_cupsImageReadPNG()' - Read a PNG image file. */ int /* O - Read status */ _cupsImageReadPNG( cups_image_t *img, /* IO - cupsImage */ FILE *fp, /* I - cupsImage file */ cups_icspace_t primary, /* I - Primary choice for colorspace */ cups_icspace_t secondary, /* I - Secondary choice for colorspace */ int saturation, /* I - Color saturation (%) */ int hue, /* I - Color hue (degrees) */ const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */ { int y; /* Looping var */ png_structp pp; /* PNG read pointer */ png_infop info; /* PNG info pointers */ png_uint_32 width, /* Width of image */ height; /* Height of image */ int bit_depth, /* Bit depth */ color_type, /* Color type */ interlace_type, /* Interlace type */ compression_type, /* Compression type */ filter_type; /* Filter type */ png_uint_32 xppm, /* X pixels per meter */ yppm; /* Y pixels per meter */ int bpp; /* Bytes per pixel */ int pass, /* Current pass */ passes; /* Number of passes required */ cups_ib_t *in, /* Input pixels */ *inptr, /* Pointer into pixels */ *out; /* Output pixels */ png_color_16 bg; /* Background color */ /* * Setup the PNG data structures... */ pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); info = png_create_info_struct(pp); /* * Initialize the PNG read "engine"... */ png_init_io(pp, fp); /* * Get the image dimensions and load the output image... */ png_read_info(pp, info); png_get_IHDR(pp, info, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); fprintf(stderr, "DEBUG: PNG image: %dx%dx%d, color_type=%x (%s%s%s)\n", (int)width, (int)height, bit_depth, color_type, (color_type & PNG_COLOR_MASK_COLOR) ? "RGB" : "GRAYSCALE", (color_type & PNG_COLOR_MASK_ALPHA) ? "+ALPHA" : "", (color_type & PNG_COLOR_MASK_PALETTE) ? "+PALETTE" : ""); if (color_type & PNG_COLOR_MASK_PALETTE) png_set_expand(pp); else if (bit_depth < 8) { png_set_packing(pp); png_set_expand(pp); } else if (bit_depth == 16) png_set_strip_16(pp); if (color_type & PNG_COLOR_MASK_COLOR) img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary; else img->colorspace = secondary; if (width == 0 || width > CUPS_IMAGE_MAX_WIDTH || height == 0 || height > CUPS_IMAGE_MAX_HEIGHT) { fprintf(stderr, "DEBUG: PNG image has invalid dimensions %ux%u!\n", (unsigned)width, (unsigned)height); fclose(fp); return (1); } img->xsize = width; img->ysize = height; if ((xppm = png_get_x_pixels_per_meter(pp, info)) != 0 && (yppm = png_get_y_pixels_per_meter(pp, info)) != 0) { img->xppi = (int)((float)xppm * 0.0254); img->yppi = (int)((float)yppm * 0.0254); if (img->xppi == 0 || img->yppi == 0) { fprintf(stderr, "DEBUG: PNG image has invalid resolution %dx%d PPI\n", img->xppi, img->yppi); img->xppi = img->yppi = 128; } } cupsImageSetMaxTiles(img, 0); passes = png_set_interlace_handling(pp); /* * Handle transparency... */ 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) { /* * Load one row at a time... */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) in = malloc(img->xsize); else in = malloc(img->xsize * 3); } else { /* * Interlaced images must be loaded all at once... */ size_t bufsize; /* Size of buffer */ if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { bufsize = img->xsize * img->ysize; if ((bufsize / img->xsize) != img->ysize) { fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n", (unsigned)width, (unsigned)height); fclose(fp); return (1); } } else { bufsize = img->xsize * img->ysize * 3; if ((bufsize / (img->xsize * 3)) != img->ysize) { fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n", (unsigned)width, (unsigned)height); fclose(fp); return (1); } } in = malloc(bufsize); } bpp = cupsImageGetDepth(img); out = malloc(img->xsize * bpp); if (!in || !out) { fputs("DEBUG: Unable to allocate memory for PNG image!\n", stderr); if (in) free(in); if (out) free(out); fclose(fp); return (1); } /* * Read the image, interlacing as needed... */ 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) { /* * Output this row... */ if (color_type & PNG_COLOR_MASK_COLOR) { if ((saturation != 100 || hue != 0) && bpp > 1) cupsImageRGBAdjust(inptr, img->xsize, saturation, hue); switch (img->colorspace) { case CUPS_IMAGE_WHITE : cupsImageRGBToWhite(inptr, out, img->xsize); break; case CUPS_IMAGE_RGB : case CUPS_IMAGE_RGB_CMYK : cupsImageRGBToRGB(inptr, out, img->xsize); break; case CUPS_IMAGE_BLACK : cupsImageRGBToBlack(inptr, out, img->xsize); break; case CUPS_IMAGE_CMY : cupsImageRGBToCMY(inptr, out, img->xsize); break; case CUPS_IMAGE_CMYK : cupsImageRGBToCMYK(inptr, out, img->xsize); break; } } else { switch (img->colorspace) { case CUPS_IMAGE_WHITE : memcpy(out, inptr, img->xsize); break; case CUPS_IMAGE_RGB : case CUPS_IMAGE_RGB_CMYK : cupsImageWhiteToRGB(inptr, out, img->xsize); break; case CUPS_IMAGE_BLACK : cupsImageWhiteToBlack(inptr, out, img->xsize); break; case CUPS_IMAGE_CMY : cupsImageWhiteToCMY(inptr, out, img->xsize); break; case CUPS_IMAGE_CMYK : cupsImageWhiteToCMYK(inptr, out, img->xsize); break; } } if (lut) cupsImageLut(out, img->xsize * bpp, lut); _cupsImagePutRow(img, 0, y, img->xsize, out); } if (passes > 1) { if (color_type & PNG_COLOR_MASK_COLOR) inptr += img->xsize * 3; else inptr += img->xsize; } } png_read_end(pp, info); png_destroy_read_struct(&pp, &info, NULL); fclose(fp); free(in); free(out); return (0); } #endif /* HAVE_LIBPNG && HAVE_LIBZ */ /* * End of "$Id: image-png.c 9771 2011-05-12 05:21:56Z mike $". */