1*a67afe4dSAndroid Build Coastguard Worker /*---------------------------------------------------------------------------
2*a67afe4dSAndroid Build Coastguard Worker
3*a67afe4dSAndroid Build Coastguard Worker rpng2 - progressive-model PNG display program readpng2.c
4*a67afe4dSAndroid Build Coastguard Worker
5*a67afe4dSAndroid Build Coastguard Worker ---------------------------------------------------------------------------
6*a67afe4dSAndroid Build Coastguard Worker
7*a67afe4dSAndroid Build Coastguard Worker Copyright (c) 1998-2015 Greg Roelofs. All rights reserved.
8*a67afe4dSAndroid Build Coastguard Worker
9*a67afe4dSAndroid Build Coastguard Worker This software is provided "as is," without warranty of any kind,
10*a67afe4dSAndroid Build Coastguard Worker express or implied. In no event shall the author or contributors
11*a67afe4dSAndroid Build Coastguard Worker be held liable for any damages arising in any way from the use of
12*a67afe4dSAndroid Build Coastguard Worker this software.
13*a67afe4dSAndroid Build Coastguard Worker
14*a67afe4dSAndroid Build Coastguard Worker The contents of this file are DUAL-LICENSED. You may modify and/or
15*a67afe4dSAndroid Build Coastguard Worker redistribute this software according to the terms of one of the
16*a67afe4dSAndroid Build Coastguard Worker following two licenses (at your option):
17*a67afe4dSAndroid Build Coastguard Worker
18*a67afe4dSAndroid Build Coastguard Worker
19*a67afe4dSAndroid Build Coastguard Worker LICENSE 1 ("BSD-like with advertising clause"):
20*a67afe4dSAndroid Build Coastguard Worker
21*a67afe4dSAndroid Build Coastguard Worker Permission is granted to anyone to use this software for any purpose,
22*a67afe4dSAndroid Build Coastguard Worker including commercial applications, and to alter it and redistribute
23*a67afe4dSAndroid Build Coastguard Worker it freely, subject to the following restrictions:
24*a67afe4dSAndroid Build Coastguard Worker
25*a67afe4dSAndroid Build Coastguard Worker 1. Redistributions of source code must retain the above copyright
26*a67afe4dSAndroid Build Coastguard Worker notice, disclaimer, and this list of conditions.
27*a67afe4dSAndroid Build Coastguard Worker 2. Redistributions in binary form must reproduce the above copyright
28*a67afe4dSAndroid Build Coastguard Worker notice, disclaimer, and this list of conditions in the documenta-
29*a67afe4dSAndroid Build Coastguard Worker tion and/or other materials provided with the distribution.
30*a67afe4dSAndroid Build Coastguard Worker 3. All advertising materials mentioning features or use of this
31*a67afe4dSAndroid Build Coastguard Worker software must display the following acknowledgment:
32*a67afe4dSAndroid Build Coastguard Worker
33*a67afe4dSAndroid Build Coastguard Worker This product includes software developed by Greg Roelofs
34*a67afe4dSAndroid Build Coastguard Worker and contributors for the book, "PNG: The Definitive Guide,"
35*a67afe4dSAndroid Build Coastguard Worker published by O'Reilly and Associates.
36*a67afe4dSAndroid Build Coastguard Worker
37*a67afe4dSAndroid Build Coastguard Worker
38*a67afe4dSAndroid Build Coastguard Worker LICENSE 2 (GNU GPL v2 or later):
39*a67afe4dSAndroid Build Coastguard Worker
40*a67afe4dSAndroid Build Coastguard Worker This program is free software; you can redistribute it and/or modify
41*a67afe4dSAndroid Build Coastguard Worker it under the terms of the GNU General Public License as published by
42*a67afe4dSAndroid Build Coastguard Worker the Free Software Foundation; either version 2 of the License, or
43*a67afe4dSAndroid Build Coastguard Worker (at your option) any later version.
44*a67afe4dSAndroid Build Coastguard Worker
45*a67afe4dSAndroid Build Coastguard Worker This program is distributed in the hope that it will be useful,
46*a67afe4dSAndroid Build Coastguard Worker but WITHOUT ANY WARRANTY; without even the implied warranty of
47*a67afe4dSAndroid Build Coastguard Worker MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48*a67afe4dSAndroid Build Coastguard Worker GNU General Public License for more details.
49*a67afe4dSAndroid Build Coastguard Worker
50*a67afe4dSAndroid Build Coastguard Worker You should have received a copy of the GNU General Public License
51*a67afe4dSAndroid Build Coastguard Worker along with this program; if not, write to the Free Software Foundation,
52*a67afe4dSAndroid Build Coastguard Worker Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
53*a67afe4dSAndroid Build Coastguard Worker
54*a67afe4dSAndroid Build Coastguard Worker ---------------------------------------------------------------------------
55*a67afe4dSAndroid Build Coastguard Worker
56*a67afe4dSAndroid Build Coastguard Worker Changelog:
57*a67afe4dSAndroid Build Coastguard Worker 2015-11-12 - Check return value of png_get_bKGD() (Glenn R-P)
58*a67afe4dSAndroid Build Coastguard Worker 2017-04-22 - Guard against integer overflow (Glenn R-P)
59*a67afe4dSAndroid Build Coastguard Worker
60*a67afe4dSAndroid Build Coastguard Worker ---------------------------------------------------------------------------*/
61*a67afe4dSAndroid Build Coastguard Worker
62*a67afe4dSAndroid Build Coastguard Worker
63*a67afe4dSAndroid Build Coastguard Worker #include <stdlib.h> /* for exit() prototype */
64*a67afe4dSAndroid Build Coastguard Worker #include <setjmp.h>
65*a67afe4dSAndroid Build Coastguard Worker
66*a67afe4dSAndroid Build Coastguard Worker #include <zlib.h>
67*a67afe4dSAndroid Build Coastguard Worker #include "png.h" /* libpng header from the local directory */
68*a67afe4dSAndroid Build Coastguard Worker #include "readpng2.h" /* typedefs, common macros, public prototypes */
69*a67afe4dSAndroid Build Coastguard Worker
70*a67afe4dSAndroid Build Coastguard Worker
71*a67afe4dSAndroid Build Coastguard Worker /* local prototypes */
72*a67afe4dSAndroid Build Coastguard Worker
73*a67afe4dSAndroid Build Coastguard Worker static void readpng2_info_callback(png_structp png_ptr, png_infop info_ptr);
74*a67afe4dSAndroid Build Coastguard Worker static void readpng2_row_callback(png_structp png_ptr, png_bytep new_row,
75*a67afe4dSAndroid Build Coastguard Worker png_uint_32 row_num, int pass);
76*a67afe4dSAndroid Build Coastguard Worker static void readpng2_end_callback(png_structp png_ptr, png_infop info_ptr);
77*a67afe4dSAndroid Build Coastguard Worker static void readpng2_error_handler(png_structp png_ptr, png_const_charp msg);
78*a67afe4dSAndroid Build Coastguard Worker static void readpng2_warning_handler(png_structp png_ptr, png_const_charp msg);
79*a67afe4dSAndroid Build Coastguard Worker
80*a67afe4dSAndroid Build Coastguard Worker
81*a67afe4dSAndroid Build Coastguard Worker
82*a67afe4dSAndroid Build Coastguard Worker
readpng2_version_info(void)83*a67afe4dSAndroid Build Coastguard Worker void readpng2_version_info(void)
84*a67afe4dSAndroid Build Coastguard Worker {
85*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, " Compiled with libpng %s; using libpng %s\n",
86*a67afe4dSAndroid Build Coastguard Worker PNG_LIBPNG_VER_STRING, png_libpng_ver);
87*a67afe4dSAndroid Build Coastguard Worker
88*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, " and with zlib %s; using zlib %s.\n",
89*a67afe4dSAndroid Build Coastguard Worker ZLIB_VERSION, zlib_version);
90*a67afe4dSAndroid Build Coastguard Worker }
91*a67afe4dSAndroid Build Coastguard Worker
92*a67afe4dSAndroid Build Coastguard Worker
93*a67afe4dSAndroid Build Coastguard Worker
94*a67afe4dSAndroid Build Coastguard Worker
readpng2_check_sig(uch * sig,int num)95*a67afe4dSAndroid Build Coastguard Worker int readpng2_check_sig(uch *sig, int num)
96*a67afe4dSAndroid Build Coastguard Worker {
97*a67afe4dSAndroid Build Coastguard Worker return !png_sig_cmp(sig, 0, num);
98*a67afe4dSAndroid Build Coastguard Worker }
99*a67afe4dSAndroid Build Coastguard Worker
100*a67afe4dSAndroid Build Coastguard Worker
101*a67afe4dSAndroid Build Coastguard Worker
102*a67afe4dSAndroid Build Coastguard Worker
103*a67afe4dSAndroid Build Coastguard Worker /* returns 0 for success, 2 for libpng problem, 4 for out of memory */
104*a67afe4dSAndroid Build Coastguard Worker
readpng2_init(mainprog_info * mainprog_ptr)105*a67afe4dSAndroid Build Coastguard Worker int readpng2_init(mainprog_info *mainprog_ptr)
106*a67afe4dSAndroid Build Coastguard Worker {
107*a67afe4dSAndroid Build Coastguard Worker png_structp png_ptr; /* note: temporary variables! */
108*a67afe4dSAndroid Build Coastguard Worker png_infop info_ptr;
109*a67afe4dSAndroid Build Coastguard Worker
110*a67afe4dSAndroid Build Coastguard Worker
111*a67afe4dSAndroid Build Coastguard Worker /* could also replace libpng warning-handler (final NULL), but no need: */
112*a67afe4dSAndroid Build Coastguard Worker
113*a67afe4dSAndroid Build Coastguard Worker png_ptr = png_create_read_struct(png_get_libpng_ver(NULL), mainprog_ptr,
114*a67afe4dSAndroid Build Coastguard Worker readpng2_error_handler, readpng2_warning_handler);
115*a67afe4dSAndroid Build Coastguard Worker if (!png_ptr)
116*a67afe4dSAndroid Build Coastguard Worker return 4; /* out of memory */
117*a67afe4dSAndroid Build Coastguard Worker
118*a67afe4dSAndroid Build Coastguard Worker info_ptr = png_create_info_struct(png_ptr);
119*a67afe4dSAndroid Build Coastguard Worker if (!info_ptr) {
120*a67afe4dSAndroid Build Coastguard Worker png_destroy_read_struct(&png_ptr, NULL, NULL);
121*a67afe4dSAndroid Build Coastguard Worker return 4; /* out of memory */
122*a67afe4dSAndroid Build Coastguard Worker }
123*a67afe4dSAndroid Build Coastguard Worker
124*a67afe4dSAndroid Build Coastguard Worker
125*a67afe4dSAndroid Build Coastguard Worker /* we could create a second info struct here (end_info), but it's only
126*a67afe4dSAndroid Build Coastguard Worker * useful if we want to keep pre- and post-IDAT chunk info separated
127*a67afe4dSAndroid Build Coastguard Worker * (mainly for PNG-aware image editors and converters) */
128*a67afe4dSAndroid Build Coastguard Worker
129*a67afe4dSAndroid Build Coastguard Worker
130*a67afe4dSAndroid Build Coastguard Worker /* setjmp() must be called in every function that calls a PNG-reading
131*a67afe4dSAndroid Build Coastguard Worker * libpng function, unless an alternate error handler was installed--
132*a67afe4dSAndroid Build Coastguard Worker * but compatible error handlers must either use longjmp() themselves
133*a67afe4dSAndroid Build Coastguard Worker * (as in this program) or exit immediately, so here we are: */
134*a67afe4dSAndroid Build Coastguard Worker
135*a67afe4dSAndroid Build Coastguard Worker if (setjmp(mainprog_ptr->jmpbuf)) {
136*a67afe4dSAndroid Build Coastguard Worker png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
137*a67afe4dSAndroid Build Coastguard Worker return 2;
138*a67afe4dSAndroid Build Coastguard Worker }
139*a67afe4dSAndroid Build Coastguard Worker
140*a67afe4dSAndroid Build Coastguard Worker
141*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
142*a67afe4dSAndroid Build Coastguard Worker /* prepare the reader to ignore all recognized chunks whose data won't be
143*a67afe4dSAndroid Build Coastguard Worker * used, i.e., all chunks recognized by libpng except for IHDR, PLTE, IDAT,
144*a67afe4dSAndroid Build Coastguard Worker * IEND, tRNS, bKGD, gAMA, and sRGB (small performance improvement) */
145*a67afe4dSAndroid Build Coastguard Worker {
146*a67afe4dSAndroid Build Coastguard Worker /* These byte strings were copied from png.h. If a future version
147*a67afe4dSAndroid Build Coastguard Worker * of readpng2.c recognizes more chunks, add them to this list.
148*a67afe4dSAndroid Build Coastguard Worker */
149*a67afe4dSAndroid Build Coastguard Worker static const png_byte chunks_to_process[] = {
150*a67afe4dSAndroid Build Coastguard Worker 98, 75, 71, 68, '\0', /* bKGD */
151*a67afe4dSAndroid Build Coastguard Worker 103, 65, 77, 65, '\0', /* gAMA */
152*a67afe4dSAndroid Build Coastguard Worker 115, 82, 71, 66, '\0', /* sRGB */
153*a67afe4dSAndroid Build Coastguard Worker };
154*a67afe4dSAndroid Build Coastguard Worker
155*a67afe4dSAndroid Build Coastguard Worker /* Ignore all chunks except for IHDR, PLTE, tRNS, IDAT, and IEND */
156*a67afe4dSAndroid Build Coastguard Worker png_set_keep_unknown_chunks(png_ptr, -1 /* PNG_HANDLE_CHUNK_NEVER */,
157*a67afe4dSAndroid Build Coastguard Worker NULL, -1);
158*a67afe4dSAndroid Build Coastguard Worker
159*a67afe4dSAndroid Build Coastguard Worker /* But do not ignore chunks in the "chunks_to_process" list */
160*a67afe4dSAndroid Build Coastguard Worker png_set_keep_unknown_chunks(png_ptr,
161*a67afe4dSAndroid Build Coastguard Worker 0 /* PNG_HANDLE_CHUNK_AS_DEFAULT */, chunks_to_process,
162*a67afe4dSAndroid Build Coastguard Worker sizeof(chunks_to_process)/5);
163*a67afe4dSAndroid Build Coastguard Worker }
164*a67afe4dSAndroid Build Coastguard Worker #endif /* PNG_HANDLE_AS_UNKNOWN_SUPPORTED */
165*a67afe4dSAndroid Build Coastguard Worker
166*a67afe4dSAndroid Build Coastguard Worker
167*a67afe4dSAndroid Build Coastguard Worker /* instead of doing png_init_io() here, now we set up our callback
168*a67afe4dSAndroid Build Coastguard Worker * functions for progressive decoding */
169*a67afe4dSAndroid Build Coastguard Worker
170*a67afe4dSAndroid Build Coastguard Worker png_set_progressive_read_fn(png_ptr, mainprog_ptr,
171*a67afe4dSAndroid Build Coastguard Worker readpng2_info_callback, readpng2_row_callback, readpng2_end_callback);
172*a67afe4dSAndroid Build Coastguard Worker
173*a67afe4dSAndroid Build Coastguard Worker
174*a67afe4dSAndroid Build Coastguard Worker /* make sure we save our pointers for use in readpng2_decode_data() */
175*a67afe4dSAndroid Build Coastguard Worker
176*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->png_ptr = png_ptr;
177*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->info_ptr = info_ptr;
178*a67afe4dSAndroid Build Coastguard Worker
179*a67afe4dSAndroid Build Coastguard Worker
180*a67afe4dSAndroid Build Coastguard Worker /* and that's all there is to initialization */
181*a67afe4dSAndroid Build Coastguard Worker
182*a67afe4dSAndroid Build Coastguard Worker return 0;
183*a67afe4dSAndroid Build Coastguard Worker }
184*a67afe4dSAndroid Build Coastguard Worker
185*a67afe4dSAndroid Build Coastguard Worker
186*a67afe4dSAndroid Build Coastguard Worker
187*a67afe4dSAndroid Build Coastguard Worker
188*a67afe4dSAndroid Build Coastguard Worker /* returns 0 for success, 2 for libpng (longjmp) problem */
189*a67afe4dSAndroid Build Coastguard Worker
readpng2_decode_data(mainprog_info * mainprog_ptr,uch * rawbuf,ulg length)190*a67afe4dSAndroid Build Coastguard Worker int readpng2_decode_data(mainprog_info *mainprog_ptr, uch *rawbuf, ulg length)
191*a67afe4dSAndroid Build Coastguard Worker {
192*a67afe4dSAndroid Build Coastguard Worker png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
193*a67afe4dSAndroid Build Coastguard Worker png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
194*a67afe4dSAndroid Build Coastguard Worker
195*a67afe4dSAndroid Build Coastguard Worker
196*a67afe4dSAndroid Build Coastguard Worker /* setjmp() must be called in every function that calls a PNG-reading
197*a67afe4dSAndroid Build Coastguard Worker * libpng function */
198*a67afe4dSAndroid Build Coastguard Worker
199*a67afe4dSAndroid Build Coastguard Worker if (setjmp(mainprog_ptr->jmpbuf)) {
200*a67afe4dSAndroid Build Coastguard Worker png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
201*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->png_ptr = NULL;
202*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->info_ptr = NULL;
203*a67afe4dSAndroid Build Coastguard Worker return 2;
204*a67afe4dSAndroid Build Coastguard Worker }
205*a67afe4dSAndroid Build Coastguard Worker
206*a67afe4dSAndroid Build Coastguard Worker
207*a67afe4dSAndroid Build Coastguard Worker /* hand off the next chunk of input data to libpng for decoding */
208*a67afe4dSAndroid Build Coastguard Worker
209*a67afe4dSAndroid Build Coastguard Worker png_process_data(png_ptr, info_ptr, rawbuf, length);
210*a67afe4dSAndroid Build Coastguard Worker
211*a67afe4dSAndroid Build Coastguard Worker return 0;
212*a67afe4dSAndroid Build Coastguard Worker }
213*a67afe4dSAndroid Build Coastguard Worker
214*a67afe4dSAndroid Build Coastguard Worker
215*a67afe4dSAndroid Build Coastguard Worker
216*a67afe4dSAndroid Build Coastguard Worker
readpng2_info_callback(png_structp png_ptr,png_infop info_ptr)217*a67afe4dSAndroid Build Coastguard Worker static void readpng2_info_callback(png_structp png_ptr, png_infop info_ptr)
218*a67afe4dSAndroid Build Coastguard Worker {
219*a67afe4dSAndroid Build Coastguard Worker mainprog_info *mainprog_ptr;
220*a67afe4dSAndroid Build Coastguard Worker int color_type, bit_depth;
221*a67afe4dSAndroid Build Coastguard Worker png_uint_32 width, height;
222*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_FLOATING_POINT_SUPPORTED
223*a67afe4dSAndroid Build Coastguard Worker double gamma;
224*a67afe4dSAndroid Build Coastguard Worker #else
225*a67afe4dSAndroid Build Coastguard Worker png_fixed_point gamma;
226*a67afe4dSAndroid Build Coastguard Worker #endif
227*a67afe4dSAndroid Build Coastguard Worker
228*a67afe4dSAndroid Build Coastguard Worker
229*a67afe4dSAndroid Build Coastguard Worker /* setjmp() doesn't make sense here, because we'd either have to exit(),
230*a67afe4dSAndroid Build Coastguard Worker * longjmp() ourselves, or return control to libpng, which doesn't want
231*a67afe4dSAndroid Build Coastguard Worker * to see us again. By not doing anything here, libpng will instead jump
232*a67afe4dSAndroid Build Coastguard Worker * to readpng2_decode_data(), which can return an error value to the main
233*a67afe4dSAndroid Build Coastguard Worker * program. */
234*a67afe4dSAndroid Build Coastguard Worker
235*a67afe4dSAndroid Build Coastguard Worker
236*a67afe4dSAndroid Build Coastguard Worker /* retrieve the pointer to our special-purpose struct, using the png_ptr
237*a67afe4dSAndroid Build Coastguard Worker * that libpng passed back to us (i.e., not a global this time--there's
238*a67afe4dSAndroid Build Coastguard Worker * no real difference for a single image, but for a multithreaded browser
239*a67afe4dSAndroid Build Coastguard Worker * decoding several PNG images at the same time, one needs to avoid mixing
240*a67afe4dSAndroid Build Coastguard Worker * up different images' structs) */
241*a67afe4dSAndroid Build Coastguard Worker
242*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr = png_get_progressive_ptr(png_ptr);
243*a67afe4dSAndroid Build Coastguard Worker
244*a67afe4dSAndroid Build Coastguard Worker if (mainprog_ptr == NULL) { /* we be hosed */
245*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr,
246*a67afe4dSAndroid Build Coastguard Worker "readpng2 error: main struct not recoverable in info_callback.\n");
247*a67afe4dSAndroid Build Coastguard Worker fflush(stderr);
248*a67afe4dSAndroid Build Coastguard Worker return;
249*a67afe4dSAndroid Build Coastguard Worker /*
250*a67afe4dSAndroid Build Coastguard Worker * Alternatively, we could call our error-handler just like libpng
251*a67afe4dSAndroid Build Coastguard Worker * does, which would effectively terminate the program. Since this
252*a67afe4dSAndroid Build Coastguard Worker * can only happen if png_ptr gets redirected somewhere odd or the
253*a67afe4dSAndroid Build Coastguard Worker * main PNG struct gets wiped, we're probably toast anyway. (If
254*a67afe4dSAndroid Build Coastguard Worker * png_ptr itself is NULL, we would not have been called.)
255*a67afe4dSAndroid Build Coastguard Worker */
256*a67afe4dSAndroid Build Coastguard Worker }
257*a67afe4dSAndroid Build Coastguard Worker
258*a67afe4dSAndroid Build Coastguard Worker
259*a67afe4dSAndroid Build Coastguard Worker /* this is just like in the non-progressive case */
260*a67afe4dSAndroid Build Coastguard Worker
261*a67afe4dSAndroid Build Coastguard Worker png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
262*a67afe4dSAndroid Build Coastguard Worker NULL, NULL, NULL);
263*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->width = (ulg)width;
264*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->height = (ulg)height;
265*a67afe4dSAndroid Build Coastguard Worker
266*a67afe4dSAndroid Build Coastguard Worker
267*a67afe4dSAndroid Build Coastguard Worker /* since we know we've read all of the PNG file's "header" (i.e., up
268*a67afe4dSAndroid Build Coastguard Worker * to IDAT), we can check for a background color here */
269*a67afe4dSAndroid Build Coastguard Worker
270*a67afe4dSAndroid Build Coastguard Worker if (mainprog_ptr->need_bgcolor)
271*a67afe4dSAndroid Build Coastguard Worker {
272*a67afe4dSAndroid Build Coastguard Worker png_color_16p pBackground;
273*a67afe4dSAndroid Build Coastguard Worker
274*a67afe4dSAndroid Build Coastguard Worker /* it is not obvious from the libpng documentation, but this function
275*a67afe4dSAndroid Build Coastguard Worker * takes a pointer to a pointer, and it always returns valid red,
276*a67afe4dSAndroid Build Coastguard Worker * green and blue values, regardless of color_type: */
277*a67afe4dSAndroid Build Coastguard Worker if (png_get_bKGD(png_ptr, info_ptr, &pBackground))
278*a67afe4dSAndroid Build Coastguard Worker {
279*a67afe4dSAndroid Build Coastguard Worker
280*a67afe4dSAndroid Build Coastguard Worker /* however, it always returns the raw bKGD data, regardless of any
281*a67afe4dSAndroid Build Coastguard Worker * bit-depth transformations, so check depth and adjust if necessary
282*a67afe4dSAndroid Build Coastguard Worker */
283*a67afe4dSAndroid Build Coastguard Worker if (bit_depth == 16) {
284*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->bg_red = pBackground->red >> 8;
285*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->bg_green = pBackground->green >> 8;
286*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->bg_blue = pBackground->blue >> 8;
287*a67afe4dSAndroid Build Coastguard Worker } else if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
288*a67afe4dSAndroid Build Coastguard Worker if (bit_depth == 1)
289*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->bg_red = mainprog_ptr->bg_green =
290*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->bg_blue = pBackground->gray? 255 : 0;
291*a67afe4dSAndroid Build Coastguard Worker else if (bit_depth == 2)
292*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->bg_red = mainprog_ptr->bg_green =
293*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->bg_blue = (255/3) * pBackground->gray;
294*a67afe4dSAndroid Build Coastguard Worker else /* bit_depth == 4 */
295*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->bg_red = mainprog_ptr->bg_green =
296*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->bg_blue = (255/15) * pBackground->gray;
297*a67afe4dSAndroid Build Coastguard Worker } else {
298*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->bg_red = (uch)pBackground->red;
299*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->bg_green = (uch)pBackground->green;
300*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->bg_blue = (uch)pBackground->blue;
301*a67afe4dSAndroid Build Coastguard Worker }
302*a67afe4dSAndroid Build Coastguard Worker }
303*a67afe4dSAndroid Build Coastguard Worker }
304*a67afe4dSAndroid Build Coastguard Worker
305*a67afe4dSAndroid Build Coastguard Worker
306*a67afe4dSAndroid Build Coastguard Worker /* as before, let libpng expand palette images to RGB, low-bit-depth
307*a67afe4dSAndroid Build Coastguard Worker * grayscale images to 8 bits, transparency chunks to full alpha channel;
308*a67afe4dSAndroid Build Coastguard Worker * strip 16-bit-per-sample images to 8 bits per sample; and convert
309*a67afe4dSAndroid Build Coastguard Worker * grayscale to RGB[A] */
310*a67afe4dSAndroid Build Coastguard Worker
311*a67afe4dSAndroid Build Coastguard Worker if (color_type == PNG_COLOR_TYPE_PALETTE)
312*a67afe4dSAndroid Build Coastguard Worker png_set_expand(png_ptr);
313*a67afe4dSAndroid Build Coastguard Worker if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
314*a67afe4dSAndroid Build Coastguard Worker png_set_expand(png_ptr);
315*a67afe4dSAndroid Build Coastguard Worker if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
316*a67afe4dSAndroid Build Coastguard Worker png_set_expand(png_ptr);
317*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_16_TO_8_SUPPORTED
318*a67afe4dSAndroid Build Coastguard Worker if (bit_depth == 16)
319*a67afe4dSAndroid Build Coastguard Worker # ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
320*a67afe4dSAndroid Build Coastguard Worker png_set_scale_16(png_ptr);
321*a67afe4dSAndroid Build Coastguard Worker # else
322*a67afe4dSAndroid Build Coastguard Worker png_set_strip_16(png_ptr);
323*a67afe4dSAndroid Build Coastguard Worker # endif
324*a67afe4dSAndroid Build Coastguard Worker #endif
325*a67afe4dSAndroid Build Coastguard Worker if (color_type == PNG_COLOR_TYPE_GRAY ||
326*a67afe4dSAndroid Build Coastguard Worker color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
327*a67afe4dSAndroid Build Coastguard Worker png_set_gray_to_rgb(png_ptr);
328*a67afe4dSAndroid Build Coastguard Worker
329*a67afe4dSAndroid Build Coastguard Worker
330*a67afe4dSAndroid Build Coastguard Worker /* Unlike the basic viewer, which was designed to operate on local files,
331*a67afe4dSAndroid Build Coastguard Worker * this program is intended to simulate a web browser--even though we
332*a67afe4dSAndroid Build Coastguard Worker * actually read from a local file, too. But because we are pretending
333*a67afe4dSAndroid Build Coastguard Worker * that most of the images originate on the Internet, we follow the recom-
334*a67afe4dSAndroid Build Coastguard Worker * mendation of the sRGB proposal and treat unlabelled images (no gAMA
335*a67afe4dSAndroid Build Coastguard Worker * chunk) as existing in the sRGB color space. That is, we assume that
336*a67afe4dSAndroid Build Coastguard Worker * such images have a file gamma of 0.45455, which corresponds to a PC-like
337*a67afe4dSAndroid Build Coastguard Worker * display system. This change in assumptions will have no effect on a
338*a67afe4dSAndroid Build Coastguard Worker * PC-like system, but on a Mac, SGI, NeXT or other system with a non-
339*a67afe4dSAndroid Build Coastguard Worker * identity lookup table, it will darken unlabelled images, which effec-
340*a67afe4dSAndroid Build Coastguard Worker * tively favors images from PC-like systems over those originating on
341*a67afe4dSAndroid Build Coastguard Worker * the local platform. Note that mainprog_ptr->display_exponent is the
342*a67afe4dSAndroid Build Coastguard Worker * "gamma" value for the entire display system, i.e., the product of
343*a67afe4dSAndroid Build Coastguard Worker * LUT_exponent and CRT_exponent. */
344*a67afe4dSAndroid Build Coastguard Worker
345*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_FLOATING_POINT_SUPPORTED
346*a67afe4dSAndroid Build Coastguard Worker if (png_get_gAMA(png_ptr, info_ptr, &gamma))
347*a67afe4dSAndroid Build Coastguard Worker png_set_gamma(png_ptr, mainprog_ptr->display_exponent, gamma);
348*a67afe4dSAndroid Build Coastguard Worker else
349*a67afe4dSAndroid Build Coastguard Worker png_set_gamma(png_ptr, mainprog_ptr->display_exponent, 0.45455);
350*a67afe4dSAndroid Build Coastguard Worker #else
351*a67afe4dSAndroid Build Coastguard Worker if (png_get_gAMA_fixed(png_ptr, info_ptr, &gamma))
352*a67afe4dSAndroid Build Coastguard Worker png_set_gamma_fixed(png_ptr,
353*a67afe4dSAndroid Build Coastguard Worker (png_fixed_point)(100000*mainprog_ptr->display_exponent+.5), gamma);
354*a67afe4dSAndroid Build Coastguard Worker else
355*a67afe4dSAndroid Build Coastguard Worker png_set_gamma_fixed(png_ptr,
356*a67afe4dSAndroid Build Coastguard Worker (png_fixed_point)(100000*mainprog_ptr->display_exponent+.5), 45455);
357*a67afe4dSAndroid Build Coastguard Worker #endif
358*a67afe4dSAndroid Build Coastguard Worker
359*a67afe4dSAndroid Build Coastguard Worker /* we'll let libpng expand interlaced images, too */
360*a67afe4dSAndroid Build Coastguard Worker
361*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->passes = png_set_interlace_handling(png_ptr);
362*a67afe4dSAndroid Build Coastguard Worker
363*a67afe4dSAndroid Build Coastguard Worker
364*a67afe4dSAndroid Build Coastguard Worker /* all transformations have been registered; now update info_ptr data and
365*a67afe4dSAndroid Build Coastguard Worker * then get rowbytes and channels */
366*a67afe4dSAndroid Build Coastguard Worker
367*a67afe4dSAndroid Build Coastguard Worker png_read_update_info(png_ptr, info_ptr);
368*a67afe4dSAndroid Build Coastguard Worker
369*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->rowbytes = (int)png_get_rowbytes(png_ptr, info_ptr);
370*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->channels = png_get_channels(png_ptr, info_ptr);
371*a67afe4dSAndroid Build Coastguard Worker
372*a67afe4dSAndroid Build Coastguard Worker
373*a67afe4dSAndroid Build Coastguard Worker /* Call the main program to allocate memory for the image buffer and
374*a67afe4dSAndroid Build Coastguard Worker * initialize windows and whatnot. (The old-style function-pointer
375*a67afe4dSAndroid Build Coastguard Worker * invocation is used for compatibility with a few supposedly ANSI
376*a67afe4dSAndroid Build Coastguard Worker * compilers that nevertheless barf on "fn_ptr()"-style syntax.) */
377*a67afe4dSAndroid Build Coastguard Worker
378*a67afe4dSAndroid Build Coastguard Worker (*mainprog_ptr->mainprog_init)();
379*a67afe4dSAndroid Build Coastguard Worker
380*a67afe4dSAndroid Build Coastguard Worker
381*a67afe4dSAndroid Build Coastguard Worker /* and that takes care of initialization */
382*a67afe4dSAndroid Build Coastguard Worker
383*a67afe4dSAndroid Build Coastguard Worker return;
384*a67afe4dSAndroid Build Coastguard Worker }
385*a67afe4dSAndroid Build Coastguard Worker
386*a67afe4dSAndroid Build Coastguard Worker
387*a67afe4dSAndroid Build Coastguard Worker
388*a67afe4dSAndroid Build Coastguard Worker
389*a67afe4dSAndroid Build Coastguard Worker
readpng2_row_callback(png_structp png_ptr,png_bytep new_row,png_uint_32 row_num,int pass)390*a67afe4dSAndroid Build Coastguard Worker static void readpng2_row_callback(png_structp png_ptr, png_bytep new_row,
391*a67afe4dSAndroid Build Coastguard Worker png_uint_32 row_num, int pass)
392*a67afe4dSAndroid Build Coastguard Worker {
393*a67afe4dSAndroid Build Coastguard Worker mainprog_info *mainprog_ptr;
394*a67afe4dSAndroid Build Coastguard Worker
395*a67afe4dSAndroid Build Coastguard Worker
396*a67afe4dSAndroid Build Coastguard Worker /* first check whether the row differs from the previous pass; if not,
397*a67afe4dSAndroid Build Coastguard Worker * nothing to combine or display */
398*a67afe4dSAndroid Build Coastguard Worker
399*a67afe4dSAndroid Build Coastguard Worker if (!new_row)
400*a67afe4dSAndroid Build Coastguard Worker return;
401*a67afe4dSAndroid Build Coastguard Worker
402*a67afe4dSAndroid Build Coastguard Worker
403*a67afe4dSAndroid Build Coastguard Worker /* retrieve the pointer to our special-purpose struct so we can access
404*a67afe4dSAndroid Build Coastguard Worker * the old rows and image-display callback function */
405*a67afe4dSAndroid Build Coastguard Worker
406*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr = png_get_progressive_ptr(png_ptr);
407*a67afe4dSAndroid Build Coastguard Worker
408*a67afe4dSAndroid Build Coastguard Worker
409*a67afe4dSAndroid Build Coastguard Worker /* save the pass number for optional use by the front end */
410*a67afe4dSAndroid Build Coastguard Worker
411*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->pass = pass;
412*a67afe4dSAndroid Build Coastguard Worker
413*a67afe4dSAndroid Build Coastguard Worker
414*a67afe4dSAndroid Build Coastguard Worker /* have libpng either combine the new row data with the existing row data
415*a67afe4dSAndroid Build Coastguard Worker * from previous passes (if interlaced) or else just copy the new row
416*a67afe4dSAndroid Build Coastguard Worker * into the main program's image buffer */
417*a67afe4dSAndroid Build Coastguard Worker
418*a67afe4dSAndroid Build Coastguard Worker png_progressive_combine_row(png_ptr, mainprog_ptr->row_pointers[row_num],
419*a67afe4dSAndroid Build Coastguard Worker new_row);
420*a67afe4dSAndroid Build Coastguard Worker
421*a67afe4dSAndroid Build Coastguard Worker
422*a67afe4dSAndroid Build Coastguard Worker /* finally, call the display routine in the main program with the number
423*a67afe4dSAndroid Build Coastguard Worker * of the row we just updated */
424*a67afe4dSAndroid Build Coastguard Worker
425*a67afe4dSAndroid Build Coastguard Worker (*mainprog_ptr->mainprog_display_row)(row_num);
426*a67afe4dSAndroid Build Coastguard Worker
427*a67afe4dSAndroid Build Coastguard Worker
428*a67afe4dSAndroid Build Coastguard Worker /* and we're ready for more */
429*a67afe4dSAndroid Build Coastguard Worker
430*a67afe4dSAndroid Build Coastguard Worker return;
431*a67afe4dSAndroid Build Coastguard Worker }
432*a67afe4dSAndroid Build Coastguard Worker
433*a67afe4dSAndroid Build Coastguard Worker
434*a67afe4dSAndroid Build Coastguard Worker
435*a67afe4dSAndroid Build Coastguard Worker
436*a67afe4dSAndroid Build Coastguard Worker
readpng2_end_callback(png_structp png_ptr,png_infop info_ptr)437*a67afe4dSAndroid Build Coastguard Worker static void readpng2_end_callback(png_structp png_ptr, png_infop info_ptr)
438*a67afe4dSAndroid Build Coastguard Worker {
439*a67afe4dSAndroid Build Coastguard Worker mainprog_info *mainprog_ptr;
440*a67afe4dSAndroid Build Coastguard Worker
441*a67afe4dSAndroid Build Coastguard Worker
442*a67afe4dSAndroid Build Coastguard Worker /* retrieve the pointer to our special-purpose struct */
443*a67afe4dSAndroid Build Coastguard Worker
444*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr = png_get_progressive_ptr(png_ptr);
445*a67afe4dSAndroid Build Coastguard Worker
446*a67afe4dSAndroid Build Coastguard Worker
447*a67afe4dSAndroid Build Coastguard Worker /* let the main program know that it should flush any buffered image
448*a67afe4dSAndroid Build Coastguard Worker * data to the display now and set a "done" flag or whatever, but note
449*a67afe4dSAndroid Build Coastguard Worker * that it SHOULD NOT DESTROY THE PNG STRUCTS YET--in other words, do
450*a67afe4dSAndroid Build Coastguard Worker * NOT call readpng2_cleanup() either here or in the finish_display()
451*a67afe4dSAndroid Build Coastguard Worker * routine; wait until control returns to the main program via
452*a67afe4dSAndroid Build Coastguard Worker * readpng2_decode_data() */
453*a67afe4dSAndroid Build Coastguard Worker
454*a67afe4dSAndroid Build Coastguard Worker (*mainprog_ptr->mainprog_finish_display)();
455*a67afe4dSAndroid Build Coastguard Worker
456*a67afe4dSAndroid Build Coastguard Worker
457*a67afe4dSAndroid Build Coastguard Worker /* all done */
458*a67afe4dSAndroid Build Coastguard Worker
459*a67afe4dSAndroid Build Coastguard Worker (void)info_ptr; /* Unused */
460*a67afe4dSAndroid Build Coastguard Worker
461*a67afe4dSAndroid Build Coastguard Worker return;
462*a67afe4dSAndroid Build Coastguard Worker }
463*a67afe4dSAndroid Build Coastguard Worker
464*a67afe4dSAndroid Build Coastguard Worker
465*a67afe4dSAndroid Build Coastguard Worker
466*a67afe4dSAndroid Build Coastguard Worker
467*a67afe4dSAndroid Build Coastguard Worker
readpng2_cleanup(mainprog_info * mainprog_ptr)468*a67afe4dSAndroid Build Coastguard Worker void readpng2_cleanup(mainprog_info *mainprog_ptr)
469*a67afe4dSAndroid Build Coastguard Worker {
470*a67afe4dSAndroid Build Coastguard Worker png_structp png_ptr = (png_structp)mainprog_ptr->png_ptr;
471*a67afe4dSAndroid Build Coastguard Worker png_infop info_ptr = (png_infop)mainprog_ptr->info_ptr;
472*a67afe4dSAndroid Build Coastguard Worker
473*a67afe4dSAndroid Build Coastguard Worker if (png_ptr && info_ptr)
474*a67afe4dSAndroid Build Coastguard Worker png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
475*a67afe4dSAndroid Build Coastguard Worker
476*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->png_ptr = NULL;
477*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr->info_ptr = NULL;
478*a67afe4dSAndroid Build Coastguard Worker }
479*a67afe4dSAndroid Build Coastguard Worker
480*a67afe4dSAndroid Build Coastguard Worker
readpng2_warning_handler(png_structp png_ptr,png_const_charp msg)481*a67afe4dSAndroid Build Coastguard Worker static void readpng2_warning_handler(png_structp png_ptr, png_const_charp msg)
482*a67afe4dSAndroid Build Coastguard Worker {
483*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "readpng2 libpng warning: %s\n", msg);
484*a67afe4dSAndroid Build Coastguard Worker fflush(stderr);
485*a67afe4dSAndroid Build Coastguard Worker (void)png_ptr; /* Unused */
486*a67afe4dSAndroid Build Coastguard Worker }
487*a67afe4dSAndroid Build Coastguard Worker
488*a67afe4dSAndroid Build Coastguard Worker
readpng2_error_handler(png_structp png_ptr,png_const_charp msg)489*a67afe4dSAndroid Build Coastguard Worker static void readpng2_error_handler(png_structp png_ptr, png_const_charp msg)
490*a67afe4dSAndroid Build Coastguard Worker {
491*a67afe4dSAndroid Build Coastguard Worker mainprog_info *mainprog_ptr;
492*a67afe4dSAndroid Build Coastguard Worker
493*a67afe4dSAndroid Build Coastguard Worker /* This function, aside from the extra step of retrieving the "error
494*a67afe4dSAndroid Build Coastguard Worker * pointer" (below) and the fact that it exists within the application
495*a67afe4dSAndroid Build Coastguard Worker * rather than within libpng, is essentially identical to libpng's
496*a67afe4dSAndroid Build Coastguard Worker * default error handler. The second point is critical: since both
497*a67afe4dSAndroid Build Coastguard Worker * setjmp() and longjmp() are called from the same code, they are
498*a67afe4dSAndroid Build Coastguard Worker * guaranteed to have compatible notions of how big a jmp_buf is,
499*a67afe4dSAndroid Build Coastguard Worker * regardless of whether _BSD_SOURCE or anything else has (or has not)
500*a67afe4dSAndroid Build Coastguard Worker * been defined. */
501*a67afe4dSAndroid Build Coastguard Worker
502*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr, "readpng2 libpng error: %s\n", msg);
503*a67afe4dSAndroid Build Coastguard Worker fflush(stderr);
504*a67afe4dSAndroid Build Coastguard Worker
505*a67afe4dSAndroid Build Coastguard Worker mainprog_ptr = png_get_error_ptr(png_ptr);
506*a67afe4dSAndroid Build Coastguard Worker if (mainprog_ptr == NULL) { /* we are completely hosed now */
507*a67afe4dSAndroid Build Coastguard Worker fprintf(stderr,
508*a67afe4dSAndroid Build Coastguard Worker "readpng2 severe error: jmpbuf not recoverable; terminating.\n");
509*a67afe4dSAndroid Build Coastguard Worker fflush(stderr);
510*a67afe4dSAndroid Build Coastguard Worker exit(99);
511*a67afe4dSAndroid Build Coastguard Worker }
512*a67afe4dSAndroid Build Coastguard Worker
513*a67afe4dSAndroid Build Coastguard Worker /* Now we have our data structure we can use the information in it
514*a67afe4dSAndroid Build Coastguard Worker * to return control to our own higher level code (all the points
515*a67afe4dSAndroid Build Coastguard Worker * where 'setjmp' is called in this file.) This will work with other
516*a67afe4dSAndroid Build Coastguard Worker * error handling mechanisms as well - libpng always calls png_error
517*a67afe4dSAndroid Build Coastguard Worker * when it can proceed no further, thus, so long as the error handler
518*a67afe4dSAndroid Build Coastguard Worker * is intercepted, application code can do its own error recovery.
519*a67afe4dSAndroid Build Coastguard Worker */
520*a67afe4dSAndroid Build Coastguard Worker longjmp(mainprog_ptr->jmpbuf, 1);
521*a67afe4dSAndroid Build Coastguard Worker }
522