]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
bc44d920 | 2 | * "$Id: image-png.c 6649 2007-07-11 21:46:42Z mike $" |
ef416fc2 | 3 | * |
4 | * PNG image routines for the Common UNIX Printing System (CUPS). | |
5 | * | |
bc44d920 | 6 | * Copyright 2007 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 | ||
89d46774 | 173 | if (color_type == PNG_COLOR_TYPE_GRAY || |
174 | color_type == PNG_COLOR_TYPE_GRAY_ALPHA) | |
ef416fc2 | 175 | in = malloc(img->xsize * img->ysize); |
176 | else | |
177 | in = malloc(img->xsize * img->ysize * 3); | |
178 | } | |
179 | ||
180 | bpp = cupsImageGetDepth(img); | |
181 | out = malloc(img->xsize * bpp); | |
182 | ||
183 | /* | |
184 | * Read the image, interlacing as needed... | |
185 | */ | |
186 | ||
187 | for (pass = 1; pass <= passes; pass ++) | |
188 | for (inptr = in, y = 0; y < img->ysize; y ++) | |
189 | { | |
190 | png_read_row(pp, (png_bytep)inptr, NULL); | |
191 | ||
192 | if (pass == passes) | |
193 | { | |
194 | /* | |
195 | * Output this row... | |
196 | */ | |
197 | ||
89d46774 | 198 | if (color_type & PNG_COLOR_MASK_COLOR) |
ef416fc2 | 199 | { |
200 | if ((saturation != 100 || hue != 0) && bpp > 1) | |
201 | cupsImageRGBAdjust(inptr, img->xsize, saturation, hue); | |
202 | ||
203 | switch (img->colorspace) | |
204 | { | |
205 | case CUPS_IMAGE_WHITE : | |
206 | cupsImageRGBToWhite(inptr, out, img->xsize); | |
207 | break; | |
208 | case CUPS_IMAGE_RGB : | |
209 | case CUPS_IMAGE_RGB_CMYK : | |
f301802f | 210 | cupsImageRGBToRGB(inptr, out, img->xsize); |
ef416fc2 | 211 | break; |
212 | case CUPS_IMAGE_BLACK : | |
213 | cupsImageRGBToBlack(inptr, out, img->xsize); | |
214 | break; | |
215 | case CUPS_IMAGE_CMY : | |
216 | cupsImageRGBToCMY(inptr, out, img->xsize); | |
217 | break; | |
218 | case CUPS_IMAGE_CMYK : | |
219 | cupsImageRGBToCMYK(inptr, out, img->xsize); | |
220 | break; | |
221 | } | |
222 | } | |
223 | else | |
224 | { | |
225 | switch (img->colorspace) | |
226 | { | |
227 | case CUPS_IMAGE_WHITE : | |
228 | memcpy(out, inptr, img->xsize); | |
229 | break; | |
230 | case CUPS_IMAGE_RGB : | |
231 | case CUPS_IMAGE_RGB_CMYK : | |
232 | cupsImageWhiteToRGB(inptr, out, img->xsize); | |
233 | break; | |
234 | case CUPS_IMAGE_BLACK : | |
235 | cupsImageWhiteToBlack(inptr, out, img->xsize); | |
236 | break; | |
237 | case CUPS_IMAGE_CMY : | |
238 | cupsImageWhiteToCMY(inptr, out, img->xsize); | |
239 | break; | |
240 | case CUPS_IMAGE_CMYK : | |
241 | cupsImageWhiteToCMYK(inptr, out, img->xsize); | |
242 | break; | |
243 | } | |
244 | } | |
245 | ||
246 | if (lut) | |
247 | cupsImageLut(out, img->xsize * bpp, lut); | |
248 | ||
249 | _cupsImagePutRow(img, 0, y, img->xsize, out); | |
250 | } | |
251 | ||
252 | if (passes > 1) | |
253 | { | |
89d46774 | 254 | if (color_type & PNG_COLOR_MASK_COLOR) |
ef416fc2 | 255 | inptr += img->xsize * 3; |
256 | else | |
257 | inptr += img->xsize; | |
258 | } | |
259 | } | |
260 | ||
261 | png_read_end(pp, info); | |
89d46774 | 262 | png_destroy_read_struct(&pp, &info, NULL); |
ef416fc2 | 263 | |
264 | fclose(fp); | |
265 | free(in); | |
266 | free(out); | |
267 | ||
268 | return (0); | |
269 | } | |
270 | #endif /* HAVE_LIBPNG && HAVE_LIBZ */ | |
271 | ||
272 | ||
273 | /* | |
bc44d920 | 274 | * End of "$Id: image-png.c 6649 2007-07-11 21:46:42Z mike $". |
ef416fc2 | 275 | */ |