Mercurial > fife-parpg
comparison ext/libpng-1.2.29/contrib/gregbook/readpng2.c @ 0:4a0efb7baf70
* Datasets becomes the new trunk and retires after that :-)
author | mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Sun, 29 Jun 2008 18:44:17 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4a0efb7baf70 |
---|---|
1 /*--------------------------------------------------------------------------- | |
2 | |
3 rpng2 - progressive-model PNG display program readpng2.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 | |
57 #include <stdlib.h> /* for exit() prototype */ | |
58 | |
59 #include "png.h" /* libpng header; includes zlib.h and setjmp.h */ | |
60 #include "readpng2.h" /* typedefs, common macros, public prototypes */ | |
61 | |
62 | |
63 /* local prototypes */ | |
64 | |
65 static void readpng2_info_callback(png_structp png_ptr, png_infop info_ptr); | |
66 static void readpng2_row_callback(png_structp png_ptr, png_bytep new_row, | |
67 png_uint_32 row_num, int pass); | |
68 static void readpng2_end_callback(png_structp png_ptr, png_infop info_ptr); | |
69 static void readpng2_error_handler(png_structp png_ptr, png_const_charp msg); | |
70 | |
71 | |
72 | |
73 | |
74 void readpng2_version_info(void) | |
75 { | |
76 #if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && \ | |
77 (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__)) && \ | |
78 defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) | |
79 /* | |
80 * WARNING: This preprocessor approach means that the following code | |
81 * cannot be used with a libpng DLL older than 1.2.0--the | |
82 * compiled-in symbols for the new functions will not exist. | |
83 * (Could use dlopen() and dlsym() on Unix and corresponding | |
84 * calls for Windows, but not portable...) | |
85 */ | |
86 { | |
87 int mmxsupport = png_mmx_support(); | |
88 if (mmxsupport < 0) | |
89 fprintf(stderr, " Compiled with libpng %s; using libpng %s " | |
90 "without MMX support.\n", PNG_LIBPNG_VER_STRING, png_libpng_ver); | |
91 else { | |
92 int compilerID; | |
93 png_uint_32 mmx_mask = png_get_mmx_flagmask( | |
94 PNG_SELECT_READ | PNG_SELECT_WRITE, &compilerID); | |
95 | |
96 fprintf(stderr, " Compiled with libpng %s; using libpng %s " | |
97 "with MMX support\n (%s version).", PNG_LIBPNG_VER_STRING, | |
98 png_libpng_ver, compilerID == 1? "MSVC++" : | |
99 (compilerID == 2? "GNU C" : "unknown")); | |
100 fprintf(stderr, " Processor (x86%s) %s MMX instructions.\n", | |
101 #if defined(__x86_64__) | |
102 "_64", | |
103 #else | |
104 "", | |
105 #endif | |
106 mmxsupport? "supports" : "does not support"); | |
107 if (mmxsupport > 0) { | |
108 int num_optims = 0; | |
109 | |
110 fprintf(stderr, | |
111 " Potential MMX optimizations supported by libpng:\n"); | |
112 if (mmx_mask & PNG_ASM_FLAG_MMX_READ_FILTER_SUB) | |
113 ++num_optims; | |
114 if (mmx_mask & PNG_ASM_FLAG_MMX_READ_FILTER_UP) | |
115 ++num_optims; | |
116 if (mmx_mask & PNG_ASM_FLAG_MMX_READ_FILTER_AVG) | |
117 ++num_optims; | |
118 if (mmx_mask & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH) | |
119 ++num_optims; | |
120 if (num_optims) | |
121 fprintf(stderr, | |
122 " decoding %s row filters (reading)\n", | |
123 (num_optims == 4)? "all non-trivial" : "some"); | |
124 if (mmx_mask & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW) { | |
125 fprintf(stderr, " combining rows (reading)\n"); | |
126 ++num_optims; | |
127 } | |
128 if (mmx_mask & PNG_ASM_FLAG_MMX_READ_INTERLACE) { | |
129 fprintf(stderr, | |
130 " expanding interlacing (reading)\n"); | |
131 ++num_optims; | |
132 } | |
133 mmx_mask &= ~( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \ | |
134 | PNG_ASM_FLAG_MMX_READ_INTERLACE \ | |
135 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ | |
136 | PNG_ASM_FLAG_MMX_READ_FILTER_UP \ | |
137 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ | |
138 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ); | |
139 if (mmx_mask) { | |
140 fprintf(stderr, " other (unknown)\n"); | |
141 ++num_optims; | |
142 } | |
143 if (num_optims == 0) | |
144 fprintf(stderr, " (none)\n"); | |
145 } | |
146 } | |
147 } | |
148 #else | |
149 fprintf(stderr, " Compiled with libpng %s; using libpng %s " | |
150 "without MMX support.\n", PNG_LIBPNG_VER_STRING, png_libpng_ver); | |
151 #endif | |
152 | |
153 fprintf(stderr, " Compiled with zlib %s; using zlib %s.\n", | |
154 ZLIB_VERSION, zlib_version); | |
155 } | |
156 | |
157 | |
158 | |
159 | |
160 int readpng2_check_sig(uch *sig, int num) | |
161 { | |
162 return png_check_sig(sig, num); | |
163 } | |
164 | |
165 | |
166 | |
167 | |
168 /* returns 0 for success, 2 for libpng problem, 4 for out of memory */ | |
169 | |
170 int readpng2_init(mainprog_info *mainprog_ptr) | |
171 { | |
172 png_structp png_ptr; /* note: temporary variables! */ | |
173 png_infop info_ptr; | |
174 | |
175 | |
176 /* could also replace libpng warning-handler (final NULL), but no need: */ | |
177 | |
178 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr, | |
179 readpng2_error_handler, NULL); | |
180 if (!png_ptr) | |
181 return 4; /* out of memory */ | |
182 | |
183 info_ptr = png_create_info_struct(png_ptr); | |
184 if (!info_ptr) { | |
185 png_destroy_read_struct(&png_ptr, NULL, NULL); | |
186 return 4; /* out of memory */ | |
187 } | |
188 | |
189 | |
190 /* we could create a second info struct here (end_info), but it's only | |
191 * useful if we want to keep pre- and post-IDAT chunk info separated | |
192 * (mainly for PNG-aware image editors and converters) */ | |
193 | |
194 | |
195 /* setjmp() must be called in every function that calls a PNG-reading | |
196 * libpng function, unless an alternate error handler was installed-- | |
197 * but compatible error handlers must either use longjmp() themselves | |
198 * (as in this program) or exit immediately, so here we are: */ | |
199 | |
200 if (setjmp(mainprog_ptr->jmpbuf)) { | |
201 png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | |
202 return 2; | |
203 } | |
204 | |
205 | |
206 #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED | |
207 /* prepare the reader to ignore all recognized chunks whose data won't be | |
208 * used, i.e., all chunks recognized by libpng except for IHDR, PLTE, IDAT, | |
209 * IEND, tRNS, bKGD, gAMA, and sRGB (small performance improvement) */ | |
210 { | |
211 /* These byte strings were copied from png.h. If a future libpng | |
212 * version recognizes more chunks, add them to this list. If a | |
213 * future version of readpng2.c recognizes more chunks, delete them | |
214 * from this list. */ | |
215 static const png_byte chunks_to_ignore[] = { | |
216 99, 72, 82, 77, '\0', /* cHRM */ | |
217 104, 73, 83, 84, '\0', /* hIST */ | |
218 105, 67, 67, 80, '\0', /* iCCP */ | |
219 105, 84, 88, 116, '\0', /* iTXt */ | |
220 111, 70, 70, 115, '\0', /* oFFs */ | |
221 112, 67, 65, 76, '\0', /* pCAL */ | |
222 112, 72, 89, 115, '\0', /* pHYs */ | |
223 115, 66, 73, 84, '\0', /* sBIT */ | |
224 115, 67, 65, 76, '\0', /* sCAL */ | |
225 115, 80, 76, 84, '\0', /* sPLT */ | |
226 115, 84, 69, 82, '\0', /* sTER */ | |
227 116, 69, 88, 116, '\0', /* tEXt */ | |
228 116, 73, 77, 69, '\0', /* tIME */ | |
229 122, 84, 88, 116, '\0' /* zTXt */ | |
230 }; | |
231 | |
232 png_set_keep_unknown_chunks(png_ptr, 1 /* PNG_HANDLE_CHUNK_NEVER */, | |
233 chunks_to_ignore, sizeof(chunks_to_ignore)/5); | |
234 } | |
235 #endif /* PNG_UNKNOWN_CHUNKS_SUPPORTED */ | |
236 | |
237 | |
238 /* instead of doing png_init_io() here, now we set up our callback | |
239 * functions for progressive decoding */ | |
240 | |
241 png_set_progressive_read_fn(png_ptr, mainprog_ptr, | |
242 readpng2_info_callback, readpng2_row_callback, readpng2_end_callback); | |
243 | |
244 | |
245 /* | |
246 * may as well enable or disable MMX routines here, if supported; | |
247 * | |
248 * to enable all: mask = png_get_mmx_flagmask ( | |
249 * PNG_SELECT_READ | PNG_SELECT_WRITE, &compilerID); | |
250 * flags = png_get_asm_flags (png_ptr); | |
251 * flags |= mask; | |
252 * png_set_asm_flags (png_ptr, flags); | |
253 * | |
254 * to disable all: mask = png_get_mmx_flagmask ( | |
255 * PNG_SELECT_READ | PNG_SELECT_WRITE, &compilerID); | |
256 * flags = png_get_asm_flags (png_ptr); | |
257 * flags &= ~mask; | |
258 * png_set_asm_flags (png_ptr, flags); | |
259 */ | |
260 | |
261 #if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__)) && \ | |
262 defined(PNG_LIBPNG_VER) && (PNG_LIBPNG_VER >= 10200) | |
263 /* | |
264 * WARNING: This preprocessor approach means that the following code | |
265 * cannot be used with a libpng DLL older than 1.2.0--the | |
266 * compiled-in symbols for the new functions will not exist. | |
267 * (Could use dlopen() and dlsym() on Unix and corresponding | |
268 * calls for Windows, but not portable...) | |
269 */ | |
270 { | |
271 #ifdef PNG_ASSEMBLER_CODE_SUPPORTED | |
272 png_uint_32 mmx_disable_mask = 0; | |
273 png_uint_32 asm_flags, mmx_mask; | |
274 int compilerID; | |
275 | |
276 if (mainprog_ptr->nommxfilters) | |
277 mmx_disable_mask |= ( PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ | |
278 | PNG_ASM_FLAG_MMX_READ_FILTER_UP \ | |
279 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ | |
280 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ); | |
281 if (mainprog_ptr->nommxcombine) | |
282 mmx_disable_mask |= PNG_ASM_FLAG_MMX_READ_COMBINE_ROW; | |
283 if (mainprog_ptr->nommxinterlace) | |
284 mmx_disable_mask |= PNG_ASM_FLAG_MMX_READ_INTERLACE; | |
285 asm_flags = png_get_asm_flags(png_ptr); | |
286 png_set_asm_flags(png_ptr, asm_flags & ~mmx_disable_mask); | |
287 | |
288 | |
289 /* Now query libpng's asm settings, just for yuks. Note that this | |
290 * differs from the querying of its *potential* MMX capabilities | |
291 * in readpng2_version_info(); this is true runtime verification. */ | |
292 | |
293 asm_flags = png_get_asm_flags(png_ptr); | |
294 mmx_mask = png_get_mmx_flagmask(PNG_SELECT_READ | PNG_SELECT_WRITE, | |
295 &compilerID); | |
296 if (asm_flags & PNG_ASM_FLAG_MMX_SUPPORT_COMPILED) | |
297 fprintf(stderr, | |
298 " MMX support (%s version) is compiled into libpng\n", | |
299 compilerID == 1? "MSVC++" : | |
300 (compilerID == 2? "GNU C" : "unknown")); | |
301 else | |
302 fprintf(stderr, " MMX support is not compiled into libpng\n"); | |
303 fprintf(stderr, " MMX instructions are %ssupported by CPU\n", | |
304 (asm_flags & PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU)? "" : "not "); | |
305 fprintf(stderr, " MMX read support for combining rows is %sabled\n", | |
306 (asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)? "en" : "dis"); | |
307 fprintf(stderr, | |
308 " MMX read support for expanding interlacing is %sabled\n", | |
309 (asm_flags & PNG_ASM_FLAG_MMX_READ_INTERLACE)? "en" : "dis"); | |
310 fprintf(stderr, " MMX read support for \"sub\" filter is %sabled\n", | |
311 (asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB)? "en" : "dis"); | |
312 fprintf(stderr, " MMX read support for \"up\" filter is %sabled\n", | |
313 (asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP)? "en" : "dis"); | |
314 fprintf(stderr, " MMX read support for \"avg\" filter is %sabled\n", | |
315 (asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG)? "en" : "dis"); | |
316 fprintf(stderr, " MMX read support for \"Paeth\" filter is %sabled\n", | |
317 (asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH)? "en" : "dis"); | |
318 asm_flags &= (mmx_mask & ~( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \ | |
319 | PNG_ASM_FLAG_MMX_READ_INTERLACE \ | |
320 | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \ | |
321 | PNG_ASM_FLAG_MMX_READ_FILTER_UP \ | |
322 | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \ | |
323 | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH )); | |
324 if (asm_flags) | |
325 fprintf(stderr, | |
326 " additional MMX support is also enabled (0x%02lx)\n", | |
327 asm_flags); | |
328 #else /* !PNG_ASSEMBLER_CODE_SUPPORTED */ | |
329 fprintf(stderr, " MMX querying is disabled in libpng.\n"); | |
330 #endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */ | |
331 } | |
332 #endif | |
333 | |
334 | |
335 /* make sure we save our pointers for use in readpng2_decode_data() */ | |
336 | |
337 mainprog_ptr->png_ptr = png_ptr; | |
338 mainprog_ptr->info_ptr = info_ptr; | |
339 | |
340 | |
341 /* and that's all there is to initialization */ | |
342 | |
343 return 0; | |
344 } | |
345 | |
346 | |
347 | |
348 | |
349 /* returns 0 for success, 2 for libpng (longjmp) problem */ | |
350 | |
351 int readpng2_decode_data(mainprog_info *mainprog_ptr, uch *rawbuf, ulg length) | |
352 { | |
353 png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr; | |
354 png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr; | |
355 | |
356 | |
357 /* setjmp() must be called in every function that calls a PNG-reading | |
358 * libpng function */ | |
359 | |
360 if (setjmp(mainprog_ptr->jmpbuf)) { | |
361 png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | |
362 mainprog_ptr->png_ptr = NULL; | |
363 mainprog_ptr->info_ptr = NULL; | |
364 return 2; | |
365 } | |
366 | |
367 | |
368 /* hand off the next chunk of input data to libpng for decoding */ | |
369 | |
370 png_process_data(png_ptr, info_ptr, rawbuf, length); | |
371 | |
372 return 0; | |
373 } | |
374 | |
375 | |
376 | |
377 | |
378 static void readpng2_info_callback(png_structp png_ptr, png_infop info_ptr) | |
379 { | |
380 mainprog_info *mainprog_ptr; | |
381 int color_type, bit_depth; | |
382 double gamma; | |
383 | |
384 | |
385 /* setjmp() doesn't make sense here, because we'd either have to exit(), | |
386 * longjmp() ourselves, or return control to libpng, which doesn't want | |
387 * to see us again. By not doing anything here, libpng will instead jump | |
388 * to readpng2_decode_data(), which can return an error value to the main | |
389 * program. */ | |
390 | |
391 | |
392 /* retrieve the pointer to our special-purpose struct, using the png_ptr | |
393 * that libpng passed back to us (i.e., not a global this time--there's | |
394 * no real difference for a single image, but for a multithreaded browser | |
395 * decoding several PNG images at the same time, one needs to avoid mixing | |
396 * up different images' structs) */ | |
397 | |
398 mainprog_ptr = png_get_progressive_ptr(png_ptr); | |
399 | |
400 if (mainprog_ptr == NULL) { /* we be hosed */ | |
401 fprintf(stderr, | |
402 "readpng2 error: main struct not recoverable in info_callback.\n"); | |
403 fflush(stderr); | |
404 return; | |
405 /* | |
406 * Alternatively, we could call our error-handler just like libpng | |
407 * does, which would effectively terminate the program. Since this | |
408 * can only happen if png_ptr gets redirected somewhere odd or the | |
409 * main PNG struct gets wiped, we're probably toast anyway. (If | |
410 * png_ptr itself is NULL, we would not have been called.) | |
411 */ | |
412 } | |
413 | |
414 | |
415 /* this is just like in the non-progressive case */ | |
416 | |
417 png_get_IHDR(png_ptr, info_ptr, &mainprog_ptr->width, | |
418 &mainprog_ptr->height, &bit_depth, &color_type, NULL, NULL, NULL); | |
419 | |
420 | |
421 /* since we know we've read all of the PNG file's "header" (i.e., up | |
422 * to IDAT), we can check for a background color here */ | |
423 | |
424 if (mainprog_ptr->need_bgcolor && | |
425 png_get_valid(png_ptr, info_ptr, PNG_INFO_bKGD)) | |
426 { | |
427 png_color_16p pBackground; | |
428 | |
429 /* it is not obvious from the libpng documentation, but this function | |
430 * takes a pointer to a pointer, and it always returns valid red, | |
431 * green and blue values, regardless of color_type: */ | |
432 png_get_bKGD(png_ptr, info_ptr, &pBackground); | |
433 | |
434 /* however, it always returns the raw bKGD data, regardless of any | |
435 * bit-depth transformations, so check depth and adjust if necessary */ | |
436 if (bit_depth == 16) { | |
437 mainprog_ptr->bg_red = pBackground->red >> 8; | |
438 mainprog_ptr->bg_green = pBackground->green >> 8; | |
439 mainprog_ptr->bg_blue = pBackground->blue >> 8; | |
440 } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { | |
441 if (bit_depth == 1) | |
442 mainprog_ptr->bg_red = mainprog_ptr->bg_green = | |
443 mainprog_ptr->bg_blue = pBackground->gray? 255 : 0; | |
444 else if (bit_depth == 2) | |
445 mainprog_ptr->bg_red = mainprog_ptr->bg_green = | |
446 mainprog_ptr->bg_blue = (255/3) * pBackground->gray; | |
447 else /* bit_depth == 4 */ | |
448 mainprog_ptr->bg_red = mainprog_ptr->bg_green = | |
449 mainprog_ptr->bg_blue = (255/15) * pBackground->gray; | |
450 } else { | |
451 mainprog_ptr->bg_red = (uch)pBackground->red; | |
452 mainprog_ptr->bg_green = (uch)pBackground->green; | |
453 mainprog_ptr->bg_blue = (uch)pBackground->blue; | |
454 } | |
455 } | |
456 | |
457 | |
458 /* as before, let libpng expand palette images to RGB, low-bit-depth | |
459 * grayscale images to 8 bits, transparency chunks to full alpha channel; | |
460 * strip 16-bit-per-sample images to 8 bits per sample; and convert | |
461 * grayscale to RGB[A] */ | |
462 | |
463 if (color_type == PNG_COLOR_TYPE_PALETTE) | |
464 png_set_expand(png_ptr); | |
465 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) | |
466 png_set_expand(png_ptr); | |
467 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) | |
468 png_set_expand(png_ptr); | |
469 if (bit_depth == 16) | |
470 png_set_strip_16(png_ptr); | |
471 if (color_type == PNG_COLOR_TYPE_GRAY || | |
472 color_type == PNG_COLOR_TYPE_GRAY_ALPHA) | |
473 png_set_gray_to_rgb(png_ptr); | |
474 | |
475 | |
476 /* Unlike the basic viewer, which was designed to operate on local files, | |
477 * this program is intended to simulate a web browser--even though we | |
478 * actually read from a local file, too. But because we are pretending | |
479 * that most of the images originate on the Internet, we follow the recom- | |
480 * mendation of the sRGB proposal and treat unlabelled images (no gAMA | |
481 * chunk) as existing in the sRGB color space. That is, we assume that | |
482 * such images have a file gamma of 0.45455, which corresponds to a PC-like | |
483 * display system. This change in assumptions will have no effect on a | |
484 * PC-like system, but on a Mac, SGI, NeXT or other system with a non- | |
485 * identity lookup table, it will darken unlabelled images, which effec- | |
486 * tively favors images from PC-like systems over those originating on | |
487 * the local platform. Note that mainprog_ptr->display_exponent is the | |
488 * "gamma" value for the entire display system, i.e., the product of | |
489 * LUT_exponent and CRT_exponent. */ | |
490 | |
491 if (png_get_gAMA(png_ptr, info_ptr, &gamma)) | |
492 png_set_gamma(png_ptr, mainprog_ptr->display_exponent, gamma); | |
493 else | |
494 png_set_gamma(png_ptr, mainprog_ptr->display_exponent, 0.45455); | |
495 | |
496 | |
497 /* we'll let libpng expand interlaced images, too */ | |
498 | |
499 mainprog_ptr->passes = png_set_interlace_handling(png_ptr); | |
500 | |
501 | |
502 /* all transformations have been registered; now update info_ptr data and | |
503 * then get rowbytes and channels */ | |
504 | |
505 png_read_update_info(png_ptr, info_ptr); | |
506 | |
507 mainprog_ptr->rowbytes = (int)png_get_rowbytes(png_ptr, info_ptr); | |
508 mainprog_ptr->channels = png_get_channels(png_ptr, info_ptr); | |
509 | |
510 | |
511 /* Call the main program to allocate memory for the image buffer and | |
512 * initialize windows and whatnot. (The old-style function-pointer | |
513 * invocation is used for compatibility with a few supposedly ANSI | |
514 * compilers that nevertheless barf on "fn_ptr()"-style syntax.) */ | |
515 | |
516 (*mainprog_ptr->mainprog_init)(); | |
517 | |
518 | |
519 /* and that takes care of initialization */ | |
520 | |
521 return; | |
522 } | |
523 | |
524 | |
525 | |
526 | |
527 | |
528 static void readpng2_row_callback(png_structp png_ptr, png_bytep new_row, | |
529 png_uint_32 row_num, int pass) | |
530 { | |
531 mainprog_info *mainprog_ptr; | |
532 | |
533 | |
534 /* first check whether the row differs from the previous pass; if not, | |
535 * nothing to combine or display */ | |
536 | |
537 if (!new_row) | |
538 return; | |
539 | |
540 | |
541 /* retrieve the pointer to our special-purpose struct so we can access | |
542 * the old rows and image-display callback function */ | |
543 | |
544 mainprog_ptr = png_get_progressive_ptr(png_ptr); | |
545 | |
546 | |
547 /* save the pass number for optional use by the front end */ | |
548 | |
549 mainprog_ptr->pass = pass; | |
550 | |
551 | |
552 /* have libpng either combine the new row data with the existing row data | |
553 * from previous passes (if interlaced) or else just copy the new row | |
554 * into the main program's image buffer */ | |
555 | |
556 png_progressive_combine_row(png_ptr, mainprog_ptr->row_pointers[row_num], | |
557 new_row); | |
558 | |
559 | |
560 /* finally, call the display routine in the main program with the number | |
561 * of the row we just updated */ | |
562 | |
563 (*mainprog_ptr->mainprog_display_row)(row_num); | |
564 | |
565 | |
566 /* and we're ready for more */ | |
567 | |
568 return; | |
569 } | |
570 | |
571 | |
572 | |
573 | |
574 | |
575 static void readpng2_end_callback(png_structp png_ptr, png_infop info_ptr) | |
576 { | |
577 mainprog_info *mainprog_ptr; | |
578 | |
579 | |
580 /* retrieve the pointer to our special-purpose struct */ | |
581 | |
582 mainprog_ptr = png_get_progressive_ptr(png_ptr); | |
583 | |
584 | |
585 /* let the main program know that it should flush any buffered image | |
586 * data to the display now and set a "done" flag or whatever, but note | |
587 * that it SHOULD NOT DESTROY THE PNG STRUCTS YET--in other words, do | |
588 * NOT call readpng2_cleanup() either here or in the finish_display() | |
589 * routine; wait until control returns to the main program via | |
590 * readpng2_decode_data() */ | |
591 | |
592 (*mainprog_ptr->mainprog_finish_display)(); | |
593 | |
594 | |
595 /* all done */ | |
596 | |
597 return; | |
598 } | |
599 | |
600 | |
601 | |
602 | |
603 | |
604 void readpng2_cleanup(mainprog_info *mainprog_ptr) | |
605 { | |
606 png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr; | |
607 png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr; | |
608 | |
609 if (png_ptr && info_ptr) | |
610 png_destroy_read_struct(&png_ptr, &info_ptr, NULL); | |
611 | |
612 mainprog_ptr->png_ptr = NULL; | |
613 mainprog_ptr->info_ptr = NULL; | |
614 } | |
615 | |
616 | |
617 | |
618 | |
619 | |
620 static void readpng2_error_handler(png_structp png_ptr, png_const_charp msg) | |
621 { | |
622 mainprog_info *mainprog_ptr; | |
623 | |
624 /* This function, aside from the extra step of retrieving the "error | |
625 * pointer" (below) and the fact that it exists within the application | |
626 * rather than within libpng, is essentially identical to libpng's | |
627 * default error handler. The second point is critical: since both | |
628 * setjmp() and longjmp() are called from the same code, they are | |
629 * guaranteed to have compatible notions of how big a jmp_buf is, | |
630 * regardless of whether _BSD_SOURCE or anything else has (or has not) | |
631 * been defined. */ | |
632 | |
633 fprintf(stderr, "readpng2 libpng error: %s\n", msg); | |
634 fflush(stderr); | |
635 | |
636 mainprog_ptr = png_get_error_ptr(png_ptr); | |
637 if (mainprog_ptr == NULL) { /* we are completely hosed now */ | |
638 fprintf(stderr, | |
639 "readpng2 severe error: jmpbuf not recoverable; terminating.\n"); | |
640 fflush(stderr); | |
641 exit(99); | |
642 } | |
643 | |
644 longjmp(mainprog_ptr->jmpbuf, 1); | |
645 } |