]>
Commit | Line | Data |
---|---|---|
ef416fc2 | 1 | /* |
f7faf1f5 | 2 | * "$Id: image-png.c 5509 2006-05-11 11:41:36Z mike $" |
ef416fc2 | 3 | * |
4 | * PNG image routines for the Common UNIX Printing System (CUPS). | |
5 | * | |
89d46774 | 6 | * Copyright 1993-2006 by Easy Software Products. |
ef416fc2 | 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 */ | |
89d46774 | 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 */ | |
ef416fc2 | 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 | ||
89d46774 | 95 | png_get_IHDR(pp, info, &width, &height, &bit_depth, &color_type, |
96 | &interlace_type, &compression_type, &filter_type); | |
97 | ||
ef416fc2 | 98 | fprintf(stderr, "DEBUG: PNG image: %dx%dx%d, color_type=%x (%s%s%s)\n", |
89d46774 | 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" : ""); | |
ef416fc2 | 103 | |
89d46774 | 104 | if (color_type & PNG_COLOR_MASK_PALETTE) |
ef416fc2 | 105 | png_set_expand(pp); |
89d46774 | 106 | else if (bit_depth < 8) |
ef416fc2 | 107 | { |
108 | png_set_packing(pp); | |
109 | png_set_expand(pp); | |
110 | } | |
89d46774 | 111 | else if (bit_depth == 16) |
ef416fc2 | 112 | png_set_strip_16(pp); |
113 | ||
89d46774 | 114 | if (color_type & PNG_COLOR_MASK_COLOR) |
115 | img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : | |
116 | primary; | |
ef416fc2 | 117 | else |
118 | img->colorspace = secondary; | |
119 | ||
89d46774 | 120 | if (width == 0 || width > CUPS_IMAGE_MAX_WIDTH || |
121 | height == 0 || height > CUPS_IMAGE_MAX_HEIGHT) | |
ef416fc2 | 122 | { |
123 | fprintf(stderr, "ERROR: PNG image has invalid dimensions %ux%u!\n", | |
89d46774 | 124 | (unsigned)width, (unsigned)height); |
ef416fc2 | 125 | fclose(fp); |
126 | return (1); | |
127 | } | |
128 | ||
89d46774 | 129 | img->xsize = width; |
130 | img->ysize = height; | |
ef416fc2 | 131 | |
89d46774 | 132 | if ((xppm = png_get_x_pixels_per_meter(pp, info)) != 0 && |
133 | (yppm = png_get_y_pixels_per_meter(pp, info)) != 0) | |
ef416fc2 | 134 | { |
89d46774 | 135 | img->xppi = (int)((float)xppm * 0.0254); |
136 | img->yppi = (int)((float)yppm * 0.0254); | |
ef416fc2 | 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 | ||
89d46774 | 170 | if (color_type == PNG_COLOR_TYPE_GRAY || |
171 | color_type == PNG_COLOR_TYPE_GRAY_ALPHA) | |
ef416fc2 | 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 | ||
89d46774 | 182 | if (color_type == PNG_COLOR_TYPE_GRAY || |
183 | color_type == PNG_COLOR_TYPE_GRAY_ALPHA) | |
ef416fc2 | 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 | ||
89d46774 | 207 | if (color_type & PNG_COLOR_MASK_COLOR) |
ef416fc2 | 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 : | |
f301802f | 219 | cupsImageRGBToRGB(inptr, out, img->xsize); |
ef416fc2 | 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 | { | |
89d46774 | 263 | if (color_type & PNG_COLOR_MASK_COLOR) |
ef416fc2 | 264 | inptr += img->xsize * 3; |
265 | else | |
266 | inptr += img->xsize; | |
267 | } | |
268 | } | |
269 | ||
270 | png_read_end(pp, info); | |
89d46774 | 271 | png_destroy_read_struct(&pp, &info, NULL); |
ef416fc2 | 272 | |
273 | fclose(fp); | |
274 | free(in); | |
275 | free(out); | |
276 | ||
277 | return (0); | |
278 | } | |
279 | #endif /* HAVE_LIBPNG && HAVE_LIBZ */ | |
280 | ||
281 | ||
282 | /* | |
f7faf1f5 | 283 | * End of "$Id: image-png.c 5509 2006-05-11 11:41:36Z mike $". |
ef416fc2 | 284 | */ |