1 | /*--------------------------------------------------------------------------- |
---|
2 | |
---|
3 | rpng - simple PNG display program readpng.c |
---|
4 | |
---|
5 | --------------------------------------------------------------------------- |
---|
6 | |
---|
7 | Copyright (c) 1998-2007 Greg Roelofs. All rights reserved. |
---|
8 | |
---|
9 | This software is provided "as is," without warranty of any kind, |
---|
10 | express or implied. In no event shall the author or contributors |
---|
11 | be held liable for any damages arising in any way from the use of |
---|
12 | this software. |
---|
13 | |
---|
14 | The contents of this file are DUAL-LICENSED. You may modify and/or |
---|
15 | redistribute this software according to the terms of one of the |
---|
16 | following two licenses (at your option): |
---|
17 | |
---|
18 | |
---|
19 | LICENSE 1 ("BSD-like with advertising clause"): |
---|
20 | |
---|
21 | Permission is granted to anyone to use this software for any purpose, |
---|
22 | including commercial applications, and to alter it and redistribute |
---|
23 | it freely, subject to the following restrictions: |
---|
24 | |
---|
25 | 1. Redistributions of source code must retain the above copyright |
---|
26 | notice, disclaimer, and this list of conditions. |
---|
27 | 2. Redistributions in binary form must reproduce the above copyright |
---|
28 | notice, disclaimer, and this list of conditions in the documenta- |
---|
29 | tion and/or other materials provided with the distribution. |
---|
30 | 3. All advertising materials mentioning features or use of this |
---|
31 | software must display the following acknowledgment: |
---|
32 | |
---|
33 | This product includes software developed by Greg Roelofs |
---|
34 | and contributors for the book, "PNG: The Definitive Guide," |
---|
35 | published by O'Reilly and Associates. |
---|
36 | |
---|
37 | |
---|
38 | LICENSE 2 (GNU GPL v2 or later): |
---|
39 | |
---|
40 | This program is free software; you can redistribute it and/or modify |
---|
41 | it under the terms of the GNU General Public License as published by |
---|
42 | the Free Software Foundation; either version 2 of the License, or |
---|
43 | (at your option) any later version. |
---|
44 | |
---|
45 | This program is distributed in the hope that it will be useful, |
---|
46 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
47 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
48 | GNU General Public License for more details. |
---|
49 | |
---|
50 | You should have received a copy of the GNU General Public License |
---|
51 | along with this program; if not, write to the Free Software Foundation, |
---|
52 | Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
53 | |
---|
54 | ---------------------------------------------------------------------------*/ |
---|
55 | |
---|
56 | #include <stdio.h> |
---|
57 | #include <stdlib.h> |
---|
58 | #include <zlib.h> |
---|
59 | |
---|
60 | #include "png.h" /* libpng header; includes zlib.h */ |
---|
61 | #include "readpng.h" /* typedefs, common macros, public prototypes */ |
---|
62 | |
---|
63 | /* future versions of libpng will provide this macro: */ |
---|
64 | #ifndef png_jmpbuf |
---|
65 | #if (PNG_LIBPNG_VER < 10500) |
---|
66 | # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) |
---|
67 | #else |
---|
68 | # define png_jmpbuf(png_jmpbuf) ((png_jmpbuf)->png_ptr) |
---|
69 | #endif |
---|
70 | #endif |
---|
71 | |
---|
72 | static png_structp png_ptr = NULL; |
---|
73 | static png_infop info_ptr = NULL; |
---|
74 | |
---|
75 | png_uint_32 width, height; |
---|
76 | int bit_depth, color_type; |
---|
77 | uch *image_data = NULL; |
---|
78 | |
---|
79 | void readpng_version_info(void) |
---|
80 | { |
---|
81 | fprintf(stderr, " Compiled with libpng %s; using libpng %s.\n", |
---|
82 | PNG_LIBPNG_VER_STRING, png_libpng_ver); |
---|
83 | fprintf(stderr, " Compiled with zlib %s; using zlib %s.\n", |
---|
84 | ZLIB_VERSION, zlib_version); |
---|
85 | } |
---|
86 | |
---|
87 | |
---|
88 | /* return value = 0 for success, 1 for bad sig, 2 for bad IHDR, 4 for no mem */ |
---|
89 | |
---|
90 | int readpng_init(FILE *infile, ulg *pWidth, ulg *pHeight) |
---|
91 | { |
---|
92 | uch sig[8]; |
---|
93 | |
---|
94 | |
---|
95 | /* first do a quick check that the file really is a PNG image; could |
---|
96 | * have used slightly more general png_sig_cmp() function instead */ |
---|
97 | |
---|
98 | fread(sig, 1, 8, infile); |
---|
99 | if (!png_check_sig(sig, 8)) |
---|
100 | return 1; /* bad signature */ |
---|
101 | |
---|
102 | |
---|
103 | /* could pass pointers to user-defined error handlers instead of NULLs: */ |
---|
104 | |
---|
105 | png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); |
---|
106 | if (!png_ptr) |
---|
107 | return 4; /* out of memory */ |
---|
108 | |
---|
109 | info_ptr = png_create_info_struct(png_ptr); |
---|
110 | if (!info_ptr) { |
---|
111 | png_destroy_read_struct(&png_ptr, NULL, NULL); |
---|
112 | return 4; /* out of memory */ |
---|
113 | } |
---|
114 | |
---|
115 | |
---|
116 | /* we could create a second info struct here (end_info), but it's only |
---|
117 | * useful if we want to keep pre- and post-IDAT chunk info separated |
---|
118 | * (mainly for PNG-aware image editors and converters) */ |
---|
119 | |
---|
120 | |
---|
121 | /* setjmp() must be called in every function that calls a PNG-reading |
---|
122 | * libpng function */ |
---|
123 | |
---|
124 | if (setjmp(png_jmpbuf(png_ptr))) { |
---|
125 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); |
---|
126 | return 2; |
---|
127 | } |
---|
128 | |
---|
129 | |
---|
130 | png_init_io(png_ptr, infile); |
---|
131 | png_set_sig_bytes(png_ptr, 8); /* we already read the 8 signature bytes */ |
---|
132 | |
---|
133 | png_read_info(png_ptr, info_ptr); /* read all PNG info up to image data */ |
---|
134 | |
---|
135 | |
---|
136 | /* alternatively, could make separate calls to png_get_image_width(), |
---|
137 | * etc., but want bit_depth and color_type for later [don't care about |
---|
138 | * compression_type and filter_type => NULLs] */ |
---|
139 | |
---|
140 | png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, |
---|
141 | NULL, NULL, NULL); |
---|
142 | *pWidth = width; |
---|
143 | *pHeight = height; |
---|
144 | |
---|
145 | |
---|
146 | /* OK, that's all we need for now; return happy */ |
---|
147 | |
---|
148 | return 0; |
---|
149 | } |
---|
150 | |
---|
151 | |
---|
152 | |
---|
153 | |
---|
154 | /* returns 0 if succeeds, 1 if fails due to no bKGD chunk, 2 if libpng error; |
---|
155 | * scales values to 8-bit if necessary */ |
---|
156 | |
---|
157 | int readpng_get_bgcolor(uch *red, uch *green, uch *blue) |
---|
158 | { |
---|
159 | png_color_16p pBackground; |
---|
160 | |
---|
161 | |
---|
162 | /* setjmp() must be called in every function that calls a PNG-reading |
---|
163 | * libpng function */ |
---|
164 | |
---|
165 | if (setjmp(png_jmpbuf(png_ptr))) { |
---|
166 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); |
---|
167 | return 2; |
---|
168 | } |
---|
169 | |
---|
170 | |
---|
171 | if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) |
---|
172 | return 1; |
---|
173 | |
---|
174 | /* it is not obvious from the libpng documentation, but this function |
---|
175 | * takes a pointer to a pointer, and it always returns valid red, green |
---|
176 | * and blue values, regardless of color_type: */ |
---|
177 | |
---|
178 | png_get_bKGD(png_ptr, info_ptr, &pBackground); |
---|
179 | |
---|
180 | |
---|
181 | /* however, it always returns the raw bKGD data, regardless of any |
---|
182 | * bit-depth transformations, so check depth and adjust if necessary */ |
---|
183 | |
---|
184 | if (bit_depth == 16) { |
---|
185 | *red = pBackground->red >> 8; |
---|
186 | *green = pBackground->green >> 8; |
---|
187 | *blue = pBackground->blue >> 8; |
---|
188 | } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { |
---|
189 | if (bit_depth == 1) |
---|
190 | *red = *green = *blue = pBackground->gray? 255 : 0; |
---|
191 | else if (bit_depth == 2) |
---|
192 | *red = *green = *blue = (255/3) * pBackground->gray; |
---|
193 | else /* bit_depth == 4 */ |
---|
194 | *red = *green = *blue = (255/15) * pBackground->gray; |
---|
195 | } else { |
---|
196 | *red = (uch)pBackground->red; |
---|
197 | *green = (uch)pBackground->green; |
---|
198 | *blue = (uch)pBackground->blue; |
---|
199 | } |
---|
200 | |
---|
201 | return 0; |
---|
202 | } |
---|
203 | |
---|
204 | |
---|
205 | |
---|
206 | |
---|
207 | /* display_exponent == LUT_exponent * CRT_exponent */ |
---|
208 | |
---|
209 | uch *readpng_get_image(double display_exponent, int *pChannels, ulg *pRowbytes) |
---|
210 | { |
---|
211 | double gamma; |
---|
212 | png_uint_32 i, rowbytes; |
---|
213 | png_bytepp row_pointers = NULL; |
---|
214 | |
---|
215 | |
---|
216 | /* setjmp() must be called in every function that calls a PNG-reading |
---|
217 | * libpng function */ |
---|
218 | |
---|
219 | if (setjmp(png_jmpbuf(png_ptr))) { |
---|
220 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); |
---|
221 | return NULL; |
---|
222 | } |
---|
223 | |
---|
224 | |
---|
225 | /* expand palette images to RGB, low-bit-depth grayscale images to 8 bits, |
---|
226 | * transparency chunks to full alpha channel; strip 16-bit-per-sample |
---|
227 | * images to 8 bits per sample; and convert grayscale to RGB[A] */ |
---|
228 | |
---|
229 | if (color_type == PNG_COLOR_TYPE_PALETTE) |
---|
230 | png_set_expand(png_ptr); |
---|
231 | if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) |
---|
232 | png_set_expand(png_ptr); |
---|
233 | if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) |
---|
234 | png_set_expand(png_ptr); |
---|
235 | if (bit_depth == 16) |
---|
236 | png_set_strip_16(png_ptr); |
---|
237 | if (color_type == PNG_COLOR_TYPE_GRAY || |
---|
238 | color_type == PNG_COLOR_TYPE_GRAY_ALPHA) |
---|
239 | png_set_gray_to_rgb(png_ptr); |
---|
240 | |
---|
241 | |
---|
242 | /* unlike the example in the libpng documentation, we have *no* idea where |
---|
243 | * this file may have come from--so if it doesn't have a file gamma, don't |
---|
244 | * do any correction ("do no harm") */ |
---|
245 | |
---|
246 | if (png_get_gAMA(png_ptr, info_ptr, &gamma)) |
---|
247 | png_set_gamma(png_ptr, display_exponent, gamma); |
---|
248 | |
---|
249 | |
---|
250 | /* all transformations have been registered; now update info_ptr data, |
---|
251 | * get rowbytes and channels, and allocate image memory */ |
---|
252 | |
---|
253 | png_read_update_info(png_ptr, info_ptr); |
---|
254 | |
---|
255 | *pRowbytes = rowbytes = png_get_rowbytes(png_ptr, info_ptr); |
---|
256 | *pChannels = (int)png_get_channels(png_ptr, info_ptr); |
---|
257 | |
---|
258 | if ((image_data = (uch *)malloc(rowbytes*height)) == NULL) { |
---|
259 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); |
---|
260 | return NULL; |
---|
261 | } |
---|
262 | if ((row_pointers = (png_bytepp)malloc(height*sizeof(png_bytep))) == NULL) { |
---|
263 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); |
---|
264 | free(image_data); |
---|
265 | image_data = NULL; |
---|
266 | return NULL; |
---|
267 | } |
---|
268 | |
---|
269 | Trace((stderr, "readpng_get_image: channels = %d, rowbytes = %ld, height = %ld\n", *pChannels, rowbytes, height)); |
---|
270 | |
---|
271 | |
---|
272 | /* set the individual row_pointers to point at the correct offsets */ |
---|
273 | |
---|
274 | for (i = 0; i < height; ++i) |
---|
275 | row_pointers[i] = image_data + i*rowbytes; |
---|
276 | |
---|
277 | |
---|
278 | /* now we can go ahead and just read the whole image */ |
---|
279 | |
---|
280 | png_read_image(png_ptr, row_pointers); |
---|
281 | |
---|
282 | |
---|
283 | /* and we're done! (png_read_end() can be omitted if no processing of |
---|
284 | * post-IDAT text/time/etc. is desired) */ |
---|
285 | |
---|
286 | free(row_pointers); |
---|
287 | row_pointers = NULL; |
---|
288 | |
---|
289 | png_read_end(png_ptr, NULL); |
---|
290 | |
---|
291 | return image_data; |
---|
292 | } |
---|
293 | |
---|
294 | |
---|
295 | void readpng_cleanup(int free_image_data) |
---|
296 | { |
---|
297 | if (free_image_data && image_data) { |
---|
298 | free(image_data); |
---|
299 | image_data = NULL; |
---|
300 | } |
---|
301 | |
---|
302 | if (png_ptr && info_ptr) { |
---|
303 | png_destroy_read_struct(&png_ptr, &info_ptr, NULL); |
---|
304 | png_ptr = NULL; |
---|
305 | info_ptr = NULL; |
---|
306 | } |
---|
307 | } |
---|