]> git.ipfire.org Git - thirdparty/cups.git/blob - filter/image-png.c
Remove svn:keywords since they cause svn_load_dirs.pl to complain about every file.
[thirdparty/cups.git] / filter / image-png.c
1 /*
2 * "$Id: image-png.c 177 2006-06-21 00:20:03Z jlovell $"
3 *
4 * PNG image routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1993-2006 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 png_uint_32 width, /* Width of image */
59 height; /* Height of image */
60 int bit_depth, /* Bit depth */
61 color_type, /* Color type */
62 interlace_type, /* Interlace type */
63 compression_type, /* Compression type */
64 filter_type; /* Filter type */
65 png_uint_32 xppm, /* X pixels per meter */
66 yppm; /* Y pixels per meter */
67 int bpp; /* Bytes per pixel */
68 int pass, /* Current pass */
69 passes; /* Number of passes required */
70 cups_ib_t *in, /* Input pixels */
71 *inptr, /* Pointer into pixels */
72 *out; /* Output pixels */
73 png_color_16 bg; /* Background color */
74
75
76 /*
77 * Setup the PNG data structures...
78 */
79
80 pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
81 info = png_create_info_struct(pp);
82
83 /*
84 * Initialize the PNG read "engine"...
85 */
86
87 png_init_io(pp, fp);
88
89 /*
90 * Get the image dimensions and load the output image...
91 */
92
93 png_read_info(pp, info);
94
95 png_get_IHDR(pp, info, &width, &height, &bit_depth, &color_type,
96 &interlace_type, &compression_type, &filter_type);
97
98 fprintf(stderr, "DEBUG: PNG image: %dx%dx%d, color_type=%x (%s%s%s)\n",
99 (int)width, (int)height, bit_depth, color_type,
100 (color_type & PNG_COLOR_MASK_COLOR) ? "RGB" : "GRAYSCALE",
101 (color_type & PNG_COLOR_MASK_ALPHA) ? "+ALPHA" : "",
102 (color_type & PNG_COLOR_MASK_PALETTE) ? "+PALETTE" : "");
103
104 if (color_type & PNG_COLOR_MASK_PALETTE)
105 png_set_expand(pp);
106 else if (bit_depth < 8)
107 {
108 png_set_packing(pp);
109 png_set_expand(pp);
110 }
111 else if (bit_depth == 16)
112 png_set_strip_16(pp);
113
114 if (color_type & PNG_COLOR_MASK_COLOR)
115 img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB :
116 primary;
117 else
118 img->colorspace = secondary;
119
120 if (width == 0 || width > CUPS_IMAGE_MAX_WIDTH ||
121 height == 0 || height > CUPS_IMAGE_MAX_HEIGHT)
122 {
123 fprintf(stderr, "ERROR: PNG image has invalid dimensions %ux%u!\n",
124 (unsigned)width, (unsigned)height);
125 fclose(fp);
126 return (1);
127 }
128
129 img->xsize = width;
130 img->ysize = height;
131
132 if ((xppm = png_get_x_pixels_per_meter(pp, info)) != 0 &&
133 (yppm = png_get_y_pixels_per_meter(pp, info)) != 0)
134 {
135 img->xppi = (int)((float)xppm * 0.0254);
136 img->yppi = (int)((float)yppm * 0.0254);
137
138 if (img->xppi == 0 || img->yppi == 0)
139 {
140 fprintf(stderr, "ERROR: PNG image has invalid resolution %dx%d PPI\n",
141 img->xppi, img->yppi);
142
143 img->xppi = img->yppi = 128;
144 }
145 }
146
147 cupsImageSetMaxTiles(img, 0);
148
149 passes = png_set_interlace_handling(pp);
150
151 /*
152 * Handle transparency...
153 */
154
155 if (png_get_valid(pp, info, PNG_INFO_tRNS))
156 png_set_tRNS_to_alpha(pp);
157
158 bg.red = 65535;
159 bg.green = 65535;
160 bg.blue = 65535;
161
162 png_set_background(pp, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
163
164 if (passes == 1)
165 {
166 /*
167 * Load one row at a time...
168 */
169
170 if (color_type == PNG_COLOR_TYPE_GRAY ||
171 color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
172 in = malloc(img->xsize);
173 else
174 in = malloc(img->xsize * 3);
175 }
176 else
177 {
178 /*
179 * Interlaced images must be loaded all at once...
180 */
181
182 if (color_type == PNG_COLOR_TYPE_GRAY ||
183 color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
184 in = malloc(img->xsize * img->ysize);
185 else
186 in = malloc(img->xsize * img->ysize * 3);
187 }
188
189 bpp = cupsImageGetDepth(img);
190 out = malloc(img->xsize * bpp);
191
192 /*
193 * Read the image, interlacing as needed...
194 */
195
196 for (pass = 1; pass <= passes; pass ++)
197 for (inptr = in, y = 0; y < img->ysize; y ++)
198 {
199 png_read_row(pp, (png_bytep)inptr, NULL);
200
201 if (pass == passes)
202 {
203 /*
204 * Output this row...
205 */
206
207 if (color_type & PNG_COLOR_MASK_COLOR)
208 {
209 if ((saturation != 100 || hue != 0) && bpp > 1)
210 cupsImageRGBAdjust(inptr, img->xsize, saturation, hue);
211
212 switch (img->colorspace)
213 {
214 case CUPS_IMAGE_WHITE :
215 cupsImageRGBToWhite(inptr, out, img->xsize);
216 break;
217 case CUPS_IMAGE_RGB :
218 case CUPS_IMAGE_RGB_CMYK :
219 cupsImageRGBToRGB(inptr, out, img->xsize);
220 break;
221 case CUPS_IMAGE_BLACK :
222 cupsImageRGBToBlack(inptr, out, img->xsize);
223 break;
224 case CUPS_IMAGE_CMY :
225 cupsImageRGBToCMY(inptr, out, img->xsize);
226 break;
227 case CUPS_IMAGE_CMYK :
228 cupsImageRGBToCMYK(inptr, out, img->xsize);
229 break;
230 }
231 }
232 else
233 {
234 switch (img->colorspace)
235 {
236 case CUPS_IMAGE_WHITE :
237 memcpy(out, inptr, img->xsize);
238 break;
239 case CUPS_IMAGE_RGB :
240 case CUPS_IMAGE_RGB_CMYK :
241 cupsImageWhiteToRGB(inptr, out, img->xsize);
242 break;
243 case CUPS_IMAGE_BLACK :
244 cupsImageWhiteToBlack(inptr, out, img->xsize);
245 break;
246 case CUPS_IMAGE_CMY :
247 cupsImageWhiteToCMY(inptr, out, img->xsize);
248 break;
249 case CUPS_IMAGE_CMYK :
250 cupsImageWhiteToCMYK(inptr, out, img->xsize);
251 break;
252 }
253 }
254
255 if (lut)
256 cupsImageLut(out, img->xsize * bpp, lut);
257
258 _cupsImagePutRow(img, 0, y, img->xsize, out);
259 }
260
261 if (passes > 1)
262 {
263 if (color_type & PNG_COLOR_MASK_COLOR)
264 inptr += img->xsize * 3;
265 else
266 inptr += img->xsize;
267 }
268 }
269
270 png_read_end(pp, info);
271 png_destroy_read_struct(&pp, &info, NULL);
272
273 fclose(fp);
274 free(in);
275 free(out);
276
277 return (0);
278 }
279 #endif /* HAVE_LIBPNG && HAVE_LIBZ */
280
281
282 /*
283 * End of "$Id: image-png.c 177 2006-06-21 00:20:03Z jlovell $".
284 */