Load cups into easysw/current.
[thirdparty/cups.git] / filter / image-png.c
1 /*
2  * "$Id: image-png.c 4741 2005-10-02 04:25:52Z mike $"
3  *
4  *   PNG image routines for the Common UNIX Printing System (CUPS).
5  *
6  *   Copyright 1993-2005 by Easy Software Products.
7  *
8  *   These coded instructions, statements, and computer programs are the
9  *   property of Easy Software Products and are protected by Federal
10  *   copyright law.  Distribution and use rights are outlined in the file
11  *   "LICENSE.txt" which should have been included with this file.  If this
12  *   file is missing or damaged please contact Easy Software Products
13  *   at:
14  *
15  *       Attn: CUPS Licensing Information
16  *       Easy Software Products
17  *       44141 Airport View Drive, Suite 204
18  *       Hollywood, Maryland 20636 USA
19  *
20  *       Voice: (301) 373-9600
21  *       EMail: cups-info@cups.org
22  *         WWW: http://www.cups.org
23  *
24  *   This file is subject to the Apple OS-Developed Software exception.
25  *
26  * Contents:
27  *
28  *   _cupsImageReadPNG() - Read a PNG image file.
29  */
30
31 /*
32  * Include necessary headers...
33  */
34
35 #include "image-private.h"
36
37 #if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ)
38 #  include <png.h>      /* Portable Network Graphics (PNG) definitions */
39
40
41 /*
42  * '_cupsImageReadPNG()' - Read a PNG image file.
43  */
44
45 int                                     /* O - Read status */
46 _cupsImageReadPNG(
47     cups_image_t    *img,               /* IO - cupsImage */
48     FILE            *fp,                /* I - cupsImage file */
49     cups_icspace_t  primary,            /* I - Primary choice for colorspace */
50     cups_icspace_t  secondary,          /* I - Secondary choice for colorspace */
51     int             saturation,         /* I - Color saturation (%) */
52     int             hue,                /* I - Color hue (degrees) */
53     const cups_ib_t *lut)               /* I - Lookup table for gamma/brightness */
54 {
55   int           y;                      /* Looping var */
56   png_structp   pp;                     /* PNG read pointer */
57   png_infop     info;                   /* PNG info pointers */
58   int           bpp;                    /* Bytes per pixel */
59   int           pass,                   /* Current pass */
60                 passes;                 /* Number of passes required */
61   cups_ib_t     *in,                    /* Input pixels */
62                 *inptr,                 /* Pointer into pixels */
63                 *out;                   /* Output pixels */
64   png_color_16  bg;                     /* Background color */
65
66
67  /*
68   * Setup the PNG data structures...
69   */
70
71   pp   = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
72   info = png_create_info_struct(pp);
73
74  /*
75   * Initialize the PNG read "engine"...
76   */
77
78   png_init_io(pp, fp);
79
80  /*
81   * Get the image dimensions and load the output image...
82   */
83
84   png_read_info(pp, info);
85
86   fprintf(stderr, "DEBUG: PNG image: %dx%dx%d, color_type=%x (%s%s%s)\n",
87           (int)info->width, (int)info->height, info->bit_depth, info->color_type,
88           (info->color_type & PNG_COLOR_MASK_COLOR) ? "RGB" : "GRAYSCALE",
89           (info->color_type & PNG_COLOR_MASK_ALPHA) ? "+ALPHA" : "",
90           (info->color_type & PNG_COLOR_MASK_PALETTE) ? "+PALETTE" : "");
91
92   if (info->color_type & PNG_COLOR_MASK_PALETTE)
93     png_set_expand(pp);
94   else if (info->bit_depth < 8)
95   {
96     png_set_packing(pp);
97     png_set_expand(pp);
98   }
99   else if (info->bit_depth == 16)
100     png_set_strip_16(pp);
101
102   if (info->color_type & PNG_COLOR_MASK_COLOR)
103     img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary;
104   else
105     img->colorspace = secondary;
106
107   if (info->width == 0 || info->width > CUPS_IMAGE_MAX_WIDTH ||
108       info->height == 0 || info->height > CUPS_IMAGE_MAX_HEIGHT)
109   {
110     fprintf(stderr, "ERROR: PNG image has invalid dimensions %ux%u!\n",
111             (unsigned)info->width, (unsigned)info->height);
112     fclose(fp);
113     return (1);
114   }
115
116   img->xsize = info->width;
117   img->ysize = info->height;
118
119   if (info->valid & PNG_INFO_pHYs &&
120       info->phys_unit_type == PNG_RESOLUTION_METER)
121   {
122     img->xppi = (int)((float)info->x_pixels_per_unit * 0.0254);
123     img->yppi = (int)((float)info->y_pixels_per_unit * 0.0254);
124
125     if (img->xppi == 0 || img->yppi == 0)
126     {
127       fprintf(stderr, "ERROR: PNG image has invalid resolution %dx%d PPI\n",
128               img->xppi, img->yppi);
129
130       img->xppi = img->yppi = 128;
131     }
132   }
133
134   cupsImageSetMaxTiles(img, 0);
135
136   passes = png_set_interlace_handling(pp);
137
138  /*
139   * Handle transparency...
140   */
141
142   if (png_get_valid(pp, info, PNG_INFO_tRNS))
143     png_set_tRNS_to_alpha(pp);
144
145   bg.red   = 65535;
146   bg.green = 65535;
147   bg.blue  = 65535;
148
149   png_set_background(pp, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
150
151   if (passes == 1)
152   {
153    /*
154     * Load one row at a time...
155     */
156
157     if (info->color_type == PNG_COLOR_TYPE_GRAY ||
158         info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
159       in = malloc(img->xsize);
160     else
161       in = malloc(img->xsize * 3);
162   }
163   else
164   {
165    /*
166     * Interlaced images must be loaded all at once...
167     */
168
169     if (info->color_type == PNG_COLOR_TYPE_GRAY ||
170         info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
171       in = malloc(img->xsize * img->ysize);
172     else
173       in = malloc(img->xsize * img->ysize * 3);
174   }
175
176   bpp = cupsImageGetDepth(img);
177   out = malloc(img->xsize * bpp);
178
179  /*
180   * Read the image, interlacing as needed...
181   */
182
183   for (pass = 1; pass <= passes; pass ++)
184     for (inptr = in, y = 0; y < img->ysize; y ++)
185     {
186       png_read_row(pp, (png_bytep)inptr, NULL);
187
188       if (pass == passes)
189       {
190        /*
191         * Output this row...
192         */
193
194         if (info->color_type & PNG_COLOR_MASK_COLOR)
195         {
196           if ((saturation != 100 || hue != 0) && bpp > 1)
197             cupsImageRGBAdjust(inptr, img->xsize, saturation, hue);
198
199           switch (img->colorspace)
200           {
201             case CUPS_IMAGE_WHITE :
202                 cupsImageRGBToWhite(inptr, out, img->xsize);
203                 break;
204             case CUPS_IMAGE_RGB :
205             case CUPS_IMAGE_RGB_CMYK :
206                 memcpy(out, inptr, img->xsize * 3);
207                 break;
208             case CUPS_IMAGE_BLACK :
209                 cupsImageRGBToBlack(inptr, out, img->xsize);
210                 break;
211             case CUPS_IMAGE_CMY :
212                 cupsImageRGBToCMY(inptr, out, img->xsize);
213                 break;
214             case CUPS_IMAGE_CMYK :
215                 cupsImageRGBToCMYK(inptr, out, img->xsize);
216                 break;
217           }
218         }
219         else
220         {
221           switch (img->colorspace)
222           {
223             case CUPS_IMAGE_WHITE :
224                 memcpy(out, inptr, img->xsize);
225                 break;
226             case CUPS_IMAGE_RGB :
227             case CUPS_IMAGE_RGB_CMYK :
228                 cupsImageWhiteToRGB(inptr, out, img->xsize);
229                 break;
230             case CUPS_IMAGE_BLACK :
231                 cupsImageWhiteToBlack(inptr, out, img->xsize);
232                 break;
233             case CUPS_IMAGE_CMY :
234                 cupsImageWhiteToCMY(inptr, out, img->xsize);
235                 break;
236             case CUPS_IMAGE_CMYK :
237                 cupsImageWhiteToCMYK(inptr, out, img->xsize);
238                 break;
239           }
240         }
241
242         if (lut)
243           cupsImageLut(out, img->xsize * bpp, lut);
244
245         _cupsImagePutRow(img, 0, y, img->xsize, out);
246       }
247
248       if (passes > 1)
249       {
250         if (info->color_type & PNG_COLOR_MASK_COLOR)
251           inptr += img->xsize * 3;
252         else
253           inptr += img->xsize;
254       }
255     }
256
257   png_read_end(pp, info);
258   png_read_destroy(pp, info, NULL);
259
260   fclose(fp);
261   free(in);
262   free(out);
263
264   return (0);
265 }
266 #endif /* HAVE_LIBPNG && HAVE_LIBZ */
267
268
269 /*
270  * End of "$Id: image-png.c 4741 2005-10-02 04:25:52Z mike $".
271  */