xref: /aosp_15_r20/external/libpng/contrib/gregbook/readpng2.c (revision a67afe4df73cf47866eedc69947994b8ff839aba)
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