]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
75bd9771 | 2 | * "$Id: image-png.c 7437 2008-04-09 03:16:10Z mike $" |
ef416fc2 | 3 | * |
4 | * PNG image routines for the Common UNIX Printing System (CUPS). | |
5 | * | |
839a51c8 | 6 | * Copyright 2007-2008 by Apple Inc. |
c0e1af83 | 7 | * Copyright 1993-2007 by Easy Software Products. |
ef416fc2 | 8 | * |
9 | * These coded instructions, statements, and computer programs are the | |
bc44d920 | 10 | * property of Apple Inc. and are protected by Federal copyright |
11 | * law. Distribution and use rights are outlined in the file "LICENSE.txt" | |
12 | * which should have been included with this file. If this file is | |
13 | * file is missing or damaged, see the license at "http://www.cups.org/". | |
ef416fc2 | 14 | * |
15 | * This file is subject to the Apple OS-Developed Software exception. | |
16 | * | |
17 | * Contents: | |
18 | * | |
19 | * _cupsImageReadPNG() - Read a PNG image file. | |
20 | */ | |
21 | ||
22 | /* | |
23 | * Include necessary headers... | |
24 | */ | |
25 | ||
26 | #include "image-private.h" | |
27 | ||
28 | #if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ) | |
29 | # include <png.h> /* Portable Network Graphics (PNG) definitions */ | |
30 | ||
31 | ||
32 | /* | |
33 | * '_cupsImageReadPNG()' - Read a PNG image file. | |
34 | */ | |
35 | ||
36 | int /* O - Read status */ | |
37 | _cupsImageReadPNG( | |
38 | cups_image_t *img, /* IO - cupsImage */ | |
39 | FILE *fp, /* I - cupsImage file */ | |
40 | cups_icspace_t primary, /* I - Primary choice for colorspace */ | |
41 | cups_icspace_t secondary, /* I - Secondary choice for colorspace */ | |
42 | int saturation, /* I - Color saturation (%) */ | |
43 | int hue, /* I - Color hue (degrees) */ | |
44 | const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */ | |
45 | { | |
46 | int y; /* Looping var */ | |
47 | png_structp pp; /* PNG read pointer */ | |
48 | png_infop info; /* PNG info pointers */ | |
89d46774 | 49 | png_uint_32 width, /* Width of image */ |
50 | height; /* Height of image */ | |
51 | int bit_depth, /* Bit depth */ | |
52 | color_type, /* Color type */ | |
53 | interlace_type, /* Interlace type */ | |
54 | compression_type, /* Compression type */ | |
55 | filter_type; /* Filter type */ | |
56 | png_uint_32 xppm, /* X pixels per meter */ | |
57 | yppm; /* Y pixels per meter */ | |
ef416fc2 | 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 | ||
89d46774 | 86 | png_get_IHDR(pp, info, &width, &height, &bit_depth, &color_type, |
87 | &interlace_type, &compression_type, &filter_type); | |
88 | ||
ef416fc2 | 89 | fprintf(stderr, "DEBUG: PNG image: %dx%dx%d, color_type=%x (%s%s%s)\n", |
89d46774 | 90 | (int)width, (int)height, bit_depth, color_type, |
91 | (color_type & PNG_COLOR_MASK_COLOR) ? "RGB" : "GRAYSCALE", | |
92 | (color_type & PNG_COLOR_MASK_ALPHA) ? "+ALPHA" : "", | |
93 | (color_type & PNG_COLOR_MASK_PALETTE) ? "+PALETTE" : ""); | |
ef416fc2 | 94 | |
89d46774 | 95 | if (color_type & PNG_COLOR_MASK_PALETTE) |
ef416fc2 | 96 | png_set_expand(pp); |
89d46774 | 97 | else if (bit_depth < 8) |
ef416fc2 | 98 | { |
99 | png_set_packing(pp); | |
100 | png_set_expand(pp); | |
101 | } | |
89d46774 | 102 | else if (bit_depth == 16) |
ef416fc2 | 103 | png_set_strip_16(pp); |
104 | ||
89d46774 | 105 | if (color_type & PNG_COLOR_MASK_COLOR) |
106 | img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : | |
107 | primary; | |
ef416fc2 | 108 | else |
109 | img->colorspace = secondary; | |
110 | ||
89d46774 | 111 | if (width == 0 || width > CUPS_IMAGE_MAX_WIDTH || |
112 | height == 0 || height > CUPS_IMAGE_MAX_HEIGHT) | |
ef416fc2 | 113 | { |
c0e1af83 | 114 | fprintf(stderr, "DEBUG: PNG image has invalid dimensions %ux%u!\n", |
89d46774 | 115 | (unsigned)width, (unsigned)height); |
ef416fc2 | 116 | fclose(fp); |
117 | return (1); | |
118 | } | |
119 | ||
89d46774 | 120 | img->xsize = width; |
121 | img->ysize = height; | |
ef416fc2 | 122 | |
89d46774 | 123 | if ((xppm = png_get_x_pixels_per_meter(pp, info)) != 0 && |
124 | (yppm = png_get_y_pixels_per_meter(pp, info)) != 0) | |
ef416fc2 | 125 | { |
89d46774 | 126 | img->xppi = (int)((float)xppm * 0.0254); |
127 | img->yppi = (int)((float)yppm * 0.0254); | |
ef416fc2 | 128 | |
129 | if (img->xppi == 0 || img->yppi == 0) | |
130 | { | |
c0e1af83 | 131 | fprintf(stderr, "DEBUG: PNG image has invalid resolution %dx%d PPI\n", |
ef416fc2 | 132 | img->xppi, img->yppi); |
133 | ||
134 | img->xppi = img->yppi = 128; | |
135 | } | |
136 | } | |
137 | ||
138 | cupsImageSetMaxTiles(img, 0); | |
139 | ||
140 | passes = png_set_interlace_handling(pp); | |
141 | ||
142 | /* | |
143 | * Handle transparency... | |
144 | */ | |
145 | ||
146 | if (png_get_valid(pp, info, PNG_INFO_tRNS)) | |
147 | png_set_tRNS_to_alpha(pp); | |
148 | ||
149 | bg.red = 65535; | |
150 | bg.green = 65535; | |
151 | bg.blue = 65535; | |
152 | ||
153 | png_set_background(pp, &bg, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); | |
154 | ||
155 | if (passes == 1) | |
156 | { | |
157 | /* | |
158 | * Load one row at a time... | |
159 | */ | |
160 | ||
89d46774 | 161 | if (color_type == PNG_COLOR_TYPE_GRAY || |
162 | color_type == PNG_COLOR_TYPE_GRAY_ALPHA) | |
ef416fc2 | 163 | in = malloc(img->xsize); |
164 | else | |
165 | in = malloc(img->xsize * 3); | |
166 | } | |
167 | else | |
168 | { | |
169 | /* | |
170 | * Interlaced images must be loaded all at once... | |
171 | */ | |
172 | ||
839a51c8 MS |
173 | size_t bufsize; /* Size of buffer */ |
174 | ||
175 | ||
89d46774 | 176 | if (color_type == PNG_COLOR_TYPE_GRAY || |
177 | color_type == PNG_COLOR_TYPE_GRAY_ALPHA) | |
839a51c8 MS |
178 | { |
179 | bufsize = img->xsize * img->ysize; | |
180 | ||
28b9d139 | 181 | if ((bufsize / img->xsize) != img->ysize) |
839a51c8 MS |
182 | { |
183 | fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n", | |
184 | (unsigned)width, (unsigned)height); | |
185 | fclose(fp); | |
186 | return (1); | |
187 | } | |
188 | } | |
ef416fc2 | 189 | else |
839a51c8 MS |
190 | { |
191 | bufsize = img->xsize * img->ysize * 3; | |
192 | ||
28b9d139 | 193 | if ((bufsize / (img->xsize * 3)) != img->ysize) |
839a51c8 MS |
194 | { |
195 | fprintf(stderr, "DEBUG: PNG image dimensions (%ux%u) too large!\n", | |
196 | (unsigned)width, (unsigned)height); | |
197 | fclose(fp); | |
198 | return (1); | |
199 | } | |
200 | } | |
201 | ||
202 | in = malloc(bufsize); | |
ef416fc2 | 203 | } |
204 | ||
205 | bpp = cupsImageGetDepth(img); | |
206 | out = malloc(img->xsize * bpp); | |
207 | ||
839a51c8 MS |
208 | if (!in || !out) |
209 | { | |
210 | fputs("DEBUG: Unable to allocate memory for PNG image!\n", stderr); | |
211 | ||
212 | if (in) | |
213 | free(in); | |
214 | ||
215 | if (out) | |
216 | free(out); | |
217 | ||
218 | fclose(fp); | |
219 | ||
220 | return (1); | |
221 | } | |
222 | ||
ef416fc2 | 223 | /* |
224 | * Read the image, interlacing as needed... | |
225 | */ | |
226 | ||
227 | for (pass = 1; pass <= passes; pass ++) | |
228 | for (inptr = in, y = 0; y < img->ysize; y ++) | |
229 | { | |
230 | png_read_row(pp, (png_bytep)inptr, NULL); | |
231 | ||
232 | if (pass == passes) | |
233 | { | |
234 | /* | |
235 | * Output this row... | |
236 | */ | |
237 | ||
89d46774 | 238 | if (color_type & PNG_COLOR_MASK_COLOR) |
ef416fc2 | 239 | { |
240 | if ((saturation != 100 || hue != 0) && bpp > 1) | |
241 | cupsImageRGBAdjust(inptr, img->xsize, saturation, hue); | |
242 | ||
243 | switch (img->colorspace) | |
244 | { | |
245 | case CUPS_IMAGE_WHITE : | |
246 | cupsImageRGBToWhite(inptr, out, img->xsize); | |
247 | break; | |
248 | case CUPS_IMAGE_RGB : | |
249 | case CUPS_IMAGE_RGB_CMYK : | |
f301802f | 250 | cupsImageRGBToRGB(inptr, out, img->xsize); |
ef416fc2 | 251 | break; |
252 | case CUPS_IMAGE_BLACK : | |
253 | cupsImageRGBToBlack(inptr, out, img->xsize); | |
254 | break; | |
255 | case CUPS_IMAGE_CMY : | |
256 | cupsImageRGBToCMY(inptr, out, img->xsize); | |
257 | break; | |
258 | case CUPS_IMAGE_CMYK : | |
259 | cupsImageRGBToCMYK(inptr, out, img->xsize); | |
260 | break; | |
261 | } | |
262 | } | |
263 | else | |
264 | { | |
265 | switch (img->colorspace) | |
266 | { | |
267 | case CUPS_IMAGE_WHITE : | |
268 | memcpy(out, inptr, img->xsize); | |
269 | break; | |
270 | case CUPS_IMAGE_RGB : | |
271 | case CUPS_IMAGE_RGB_CMYK : | |
272 | cupsImageWhiteToRGB(inptr, out, img->xsize); | |
273 | break; | |
274 | case CUPS_IMAGE_BLACK : | |
275 | cupsImageWhiteToBlack(inptr, out, img->xsize); | |
276 | break; | |
277 | case CUPS_IMAGE_CMY : | |
278 | cupsImageWhiteToCMY(inptr, out, img->xsize); | |
279 | break; | |
280 | case CUPS_IMAGE_CMYK : | |
281 | cupsImageWhiteToCMYK(inptr, out, img->xsize); | |
282 | break; | |
283 | } | |
284 | } | |
285 | ||
286 | if (lut) | |
287 | cupsImageLut(out, img->xsize * bpp, lut); | |
288 | ||
289 | _cupsImagePutRow(img, 0, y, img->xsize, out); | |
290 | } | |
291 | ||
292 | if (passes > 1) | |
293 | { | |
89d46774 | 294 | if (color_type & PNG_COLOR_MASK_COLOR) |
ef416fc2 | 295 | inptr += img->xsize * 3; |
296 | else | |
297 | inptr += img->xsize; | |
298 | } | |
299 | } | |
300 | ||
301 | png_read_end(pp, info); | |
89d46774 | 302 | png_destroy_read_struct(&pp, &info, NULL); |
ef416fc2 | 303 | |
304 | fclose(fp); | |
305 | free(in); | |
306 | free(out); | |
307 | ||
308 | return (0); | |
309 | } | |
310 | #endif /* HAVE_LIBPNG && HAVE_LIBZ */ | |
311 | ||
312 | ||
313 | /* | |
75bd9771 | 314 | * End of "$Id: image-png.c 7437 2008-04-09 03:16:10Z mike $". |
ef416fc2 | 315 | */ |