xref: /aosp_15_r20/external/libpng/pngread.c (revision a67afe4df73cf47866eedc69947994b8ff839aba)
1*a67afe4dSAndroid Build Coastguard Worker 
2*a67afe4dSAndroid Build Coastguard Worker /* pngread.c - read a PNG file
3*a67afe4dSAndroid Build Coastguard Worker  *
4*a67afe4dSAndroid Build Coastguard Worker  * Copyright (c) 2018-2024 Cosmin Truta
5*a67afe4dSAndroid Build Coastguard Worker  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
6*a67afe4dSAndroid Build Coastguard Worker  * Copyright (c) 1996-1997 Andreas Dilger
7*a67afe4dSAndroid Build Coastguard Worker  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
8*a67afe4dSAndroid Build Coastguard Worker  *
9*a67afe4dSAndroid Build Coastguard Worker  * This code is released under the libpng license.
10*a67afe4dSAndroid Build Coastguard Worker  * For conditions of distribution and use, see the disclaimer
11*a67afe4dSAndroid Build Coastguard Worker  * and license in png.h
12*a67afe4dSAndroid Build Coastguard Worker  *
13*a67afe4dSAndroid Build Coastguard Worker  * This file contains routines that an application calls directly to
14*a67afe4dSAndroid Build Coastguard Worker  * read a PNG file or stream.
15*a67afe4dSAndroid Build Coastguard Worker  */
16*a67afe4dSAndroid Build Coastguard Worker 
17*a67afe4dSAndroid Build Coastguard Worker #include "pngpriv.h"
18*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_SIMPLIFIED_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED)
19*a67afe4dSAndroid Build Coastguard Worker #  include <errno.h>
20*a67afe4dSAndroid Build Coastguard Worker #endif
21*a67afe4dSAndroid Build Coastguard Worker 
22*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_SUPPORTED
23*a67afe4dSAndroid Build Coastguard Worker 
24*a67afe4dSAndroid Build Coastguard Worker /* Create a PNG structure for reading, and allocate any memory needed. */
25*a67afe4dSAndroid Build Coastguard Worker PNG_FUNCTION(png_structp,PNGAPI
26*a67afe4dSAndroid Build Coastguard Worker png_create_read_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
27*a67afe4dSAndroid Build Coastguard Worker     png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED)
28*a67afe4dSAndroid Build Coastguard Worker {
29*a67afe4dSAndroid Build Coastguard Worker #ifndef PNG_USER_MEM_SUPPORTED
30*a67afe4dSAndroid Build Coastguard Worker    png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr,
31*a67afe4dSAndroid Build Coastguard Worker         error_fn, warn_fn, NULL, NULL, NULL);
32*a67afe4dSAndroid Build Coastguard Worker #else
33*a67afe4dSAndroid Build Coastguard Worker    return png_create_read_struct_2(user_png_ver, error_ptr, error_fn,
34*a67afe4dSAndroid Build Coastguard Worker         warn_fn, NULL, NULL, NULL);
35*a67afe4dSAndroid Build Coastguard Worker }
36*a67afe4dSAndroid Build Coastguard Worker 
37*a67afe4dSAndroid Build Coastguard Worker /* Alternate create PNG structure for reading, and allocate any memory
38*a67afe4dSAndroid Build Coastguard Worker  * needed.
39*a67afe4dSAndroid Build Coastguard Worker  */
40*a67afe4dSAndroid Build Coastguard Worker PNG_FUNCTION(png_structp,PNGAPI
41*a67afe4dSAndroid Build Coastguard Worker png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
42*a67afe4dSAndroid Build Coastguard Worker     png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
43*a67afe4dSAndroid Build Coastguard Worker     png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED)
44*a67afe4dSAndroid Build Coastguard Worker {
45*a67afe4dSAndroid Build Coastguard Worker    png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr,
46*a67afe4dSAndroid Build Coastguard Worker        error_fn, warn_fn, mem_ptr, malloc_fn, free_fn);
47*a67afe4dSAndroid Build Coastguard Worker #endif /* USER_MEM */
48*a67afe4dSAndroid Build Coastguard Worker 
49*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr != NULL)
50*a67afe4dSAndroid Build Coastguard Worker    {
51*a67afe4dSAndroid Build Coastguard Worker       png_ptr->mode = PNG_IS_READ_STRUCT;
52*a67afe4dSAndroid Build Coastguard Worker 
53*a67afe4dSAndroid Build Coastguard Worker       /* Added in libpng-1.6.0; this can be used to detect a read structure if
54*a67afe4dSAndroid Build Coastguard Worker        * required (it will be zero in a write structure.)
55*a67afe4dSAndroid Build Coastguard Worker        */
56*a67afe4dSAndroid Build Coastguard Worker #     ifdef PNG_SEQUENTIAL_READ_SUPPORTED
57*a67afe4dSAndroid Build Coastguard Worker          png_ptr->IDAT_read_size = PNG_IDAT_READ_SIZE;
58*a67afe4dSAndroid Build Coastguard Worker #     endif
59*a67afe4dSAndroid Build Coastguard Worker 
60*a67afe4dSAndroid Build Coastguard Worker #     ifdef PNG_BENIGN_READ_ERRORS_SUPPORTED
61*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN;
62*a67afe4dSAndroid Build Coastguard Worker 
63*a67afe4dSAndroid Build Coastguard Worker          /* In stable builds only warn if an application error can be completely
64*a67afe4dSAndroid Build Coastguard Worker           * handled.
65*a67afe4dSAndroid Build Coastguard Worker           */
66*a67afe4dSAndroid Build Coastguard Worker #        if PNG_RELEASE_BUILD
67*a67afe4dSAndroid Build Coastguard Worker             png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN;
68*a67afe4dSAndroid Build Coastguard Worker #        endif
69*a67afe4dSAndroid Build Coastguard Worker #     endif
70*a67afe4dSAndroid Build Coastguard Worker 
71*a67afe4dSAndroid Build Coastguard Worker       /* TODO: delay this, it can be done in png_init_io (if the app doesn't
72*a67afe4dSAndroid Build Coastguard Worker        * do it itself) avoiding setting the default function if it is not
73*a67afe4dSAndroid Build Coastguard Worker        * required.
74*a67afe4dSAndroid Build Coastguard Worker        */
75*a67afe4dSAndroid Build Coastguard Worker       png_set_read_fn(png_ptr, NULL, NULL);
76*a67afe4dSAndroid Build Coastguard Worker    }
77*a67afe4dSAndroid Build Coastguard Worker 
78*a67afe4dSAndroid Build Coastguard Worker    return png_ptr;
79*a67afe4dSAndroid Build Coastguard Worker }
80*a67afe4dSAndroid Build Coastguard Worker 
81*a67afe4dSAndroid Build Coastguard Worker 
82*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
83*a67afe4dSAndroid Build Coastguard Worker /* Read the information before the actual image data.  This has been
84*a67afe4dSAndroid Build Coastguard Worker  * changed in v0.90 to allow reading a file that already has the magic
85*a67afe4dSAndroid Build Coastguard Worker  * bytes read from the stream.  You can tell libpng how many bytes have
86*a67afe4dSAndroid Build Coastguard Worker  * been read from the beginning of the stream (up to the maximum of 8)
87*a67afe4dSAndroid Build Coastguard Worker  * via png_set_sig_bytes(), and we will only check the remaining bytes
88*a67afe4dSAndroid Build Coastguard Worker  * here.  The application can then have access to the signature bytes we
89*a67afe4dSAndroid Build Coastguard Worker  * read if it is determined that this isn't a valid PNG file.
90*a67afe4dSAndroid Build Coastguard Worker  */
91*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_read_info(png_structrp png_ptr,png_inforp info_ptr)92*a67afe4dSAndroid Build Coastguard Worker png_read_info(png_structrp png_ptr, png_inforp info_ptr)
93*a67afe4dSAndroid Build Coastguard Worker {
94*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
95*a67afe4dSAndroid Build Coastguard Worker    int keep;
96*a67afe4dSAndroid Build Coastguard Worker #endif
97*a67afe4dSAndroid Build Coastguard Worker 
98*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_read_info");
99*a67afe4dSAndroid Build Coastguard Worker 
100*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr == NULL || info_ptr == NULL)
101*a67afe4dSAndroid Build Coastguard Worker       return;
102*a67afe4dSAndroid Build Coastguard Worker 
103*a67afe4dSAndroid Build Coastguard Worker    /* Read and check the PNG file signature. */
104*a67afe4dSAndroid Build Coastguard Worker    png_read_sig(png_ptr, info_ptr);
105*a67afe4dSAndroid Build Coastguard Worker 
106*a67afe4dSAndroid Build Coastguard Worker    for (;;)
107*a67afe4dSAndroid Build Coastguard Worker    {
108*a67afe4dSAndroid Build Coastguard Worker       png_uint_32 length = png_read_chunk_header(png_ptr);
109*a67afe4dSAndroid Build Coastguard Worker       png_uint_32 chunk_name = png_ptr->chunk_name;
110*a67afe4dSAndroid Build Coastguard Worker 
111*a67afe4dSAndroid Build Coastguard Worker       /* IDAT logic needs to happen here to simplify getting the two flags
112*a67afe4dSAndroid Build Coastguard Worker        * right.
113*a67afe4dSAndroid Build Coastguard Worker        */
114*a67afe4dSAndroid Build Coastguard Worker       if (chunk_name == png_IDAT)
115*a67afe4dSAndroid Build Coastguard Worker       {
116*a67afe4dSAndroid Build Coastguard Worker          if ((png_ptr->mode & PNG_HAVE_IHDR) == 0)
117*a67afe4dSAndroid Build Coastguard Worker             png_chunk_error(png_ptr, "Missing IHDR before IDAT");
118*a67afe4dSAndroid Build Coastguard Worker 
119*a67afe4dSAndroid Build Coastguard Worker          else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
120*a67afe4dSAndroid Build Coastguard Worker              (png_ptr->mode & PNG_HAVE_PLTE) == 0)
121*a67afe4dSAndroid Build Coastguard Worker             png_chunk_error(png_ptr, "Missing PLTE before IDAT");
122*a67afe4dSAndroid Build Coastguard Worker 
123*a67afe4dSAndroid Build Coastguard Worker          else if ((png_ptr->mode & PNG_AFTER_IDAT) != 0)
124*a67afe4dSAndroid Build Coastguard Worker             png_chunk_benign_error(png_ptr, "Too many IDATs found");
125*a67afe4dSAndroid Build Coastguard Worker 
126*a67afe4dSAndroid Build Coastguard Worker          png_ptr->mode |= PNG_HAVE_IDAT;
127*a67afe4dSAndroid Build Coastguard Worker       }
128*a67afe4dSAndroid Build Coastguard Worker 
129*a67afe4dSAndroid Build Coastguard Worker       else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0)
130*a67afe4dSAndroid Build Coastguard Worker       {
131*a67afe4dSAndroid Build Coastguard Worker          png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
132*a67afe4dSAndroid Build Coastguard Worker          png_ptr->mode |= PNG_AFTER_IDAT;
133*a67afe4dSAndroid Build Coastguard Worker       }
134*a67afe4dSAndroid Build Coastguard Worker 
135*a67afe4dSAndroid Build Coastguard Worker       /* This should be a binary subdivision search or a hash for
136*a67afe4dSAndroid Build Coastguard Worker        * matching the chunk name rather than a linear search.
137*a67afe4dSAndroid Build Coastguard Worker        */
138*a67afe4dSAndroid Build Coastguard Worker       if (chunk_name == png_IHDR)
139*a67afe4dSAndroid Build Coastguard Worker          png_handle_IHDR(png_ptr, info_ptr, length);
140*a67afe4dSAndroid Build Coastguard Worker 
141*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_IEND)
142*a67afe4dSAndroid Build Coastguard Worker          png_handle_IEND(png_ptr, info_ptr, length);
143*a67afe4dSAndroid Build Coastguard Worker 
144*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
145*a67afe4dSAndroid Build Coastguard Worker       else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0)
146*a67afe4dSAndroid Build Coastguard Worker       {
147*a67afe4dSAndroid Build Coastguard Worker          png_handle_unknown(png_ptr, info_ptr, length, keep);
148*a67afe4dSAndroid Build Coastguard Worker 
149*a67afe4dSAndroid Build Coastguard Worker          if (chunk_name == png_PLTE)
150*a67afe4dSAndroid Build Coastguard Worker             png_ptr->mode |= PNG_HAVE_PLTE;
151*a67afe4dSAndroid Build Coastguard Worker 
152*a67afe4dSAndroid Build Coastguard Worker          else if (chunk_name == png_IDAT)
153*a67afe4dSAndroid Build Coastguard Worker          {
154*a67afe4dSAndroid Build Coastguard Worker             png_ptr->idat_size = 0; /* It has been consumed */
155*a67afe4dSAndroid Build Coastguard Worker             break;
156*a67afe4dSAndroid Build Coastguard Worker          }
157*a67afe4dSAndroid Build Coastguard Worker       }
158*a67afe4dSAndroid Build Coastguard Worker #endif
159*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_PLTE)
160*a67afe4dSAndroid Build Coastguard Worker          png_handle_PLTE(png_ptr, info_ptr, length);
161*a67afe4dSAndroid Build Coastguard Worker 
162*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_IDAT)
163*a67afe4dSAndroid Build Coastguard Worker       {
164*a67afe4dSAndroid Build Coastguard Worker          png_ptr->idat_size = length;
165*a67afe4dSAndroid Build Coastguard Worker          break;
166*a67afe4dSAndroid Build Coastguard Worker       }
167*a67afe4dSAndroid Build Coastguard Worker 
168*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_bKGD_SUPPORTED
169*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_bKGD)
170*a67afe4dSAndroid Build Coastguard Worker          png_handle_bKGD(png_ptr, info_ptr, length);
171*a67afe4dSAndroid Build Coastguard Worker #endif
172*a67afe4dSAndroid Build Coastguard Worker 
173*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_cHRM_SUPPORTED
174*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_cHRM)
175*a67afe4dSAndroid Build Coastguard Worker          png_handle_cHRM(png_ptr, info_ptr, length);
176*a67afe4dSAndroid Build Coastguard Worker #endif
177*a67afe4dSAndroid Build Coastguard Worker 
178*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_eXIf_SUPPORTED
179*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_eXIf)
180*a67afe4dSAndroid Build Coastguard Worker          png_handle_eXIf(png_ptr, info_ptr, length);
181*a67afe4dSAndroid Build Coastguard Worker #endif
182*a67afe4dSAndroid Build Coastguard Worker 
183*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_gAMA_SUPPORTED
184*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_gAMA)
185*a67afe4dSAndroid Build Coastguard Worker          png_handle_gAMA(png_ptr, info_ptr, length);
186*a67afe4dSAndroid Build Coastguard Worker #endif
187*a67afe4dSAndroid Build Coastguard Worker 
188*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_hIST_SUPPORTED
189*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_hIST)
190*a67afe4dSAndroid Build Coastguard Worker          png_handle_hIST(png_ptr, info_ptr, length);
191*a67afe4dSAndroid Build Coastguard Worker #endif
192*a67afe4dSAndroid Build Coastguard Worker 
193*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_oFFs_SUPPORTED
194*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_oFFs)
195*a67afe4dSAndroid Build Coastguard Worker          png_handle_oFFs(png_ptr, info_ptr, length);
196*a67afe4dSAndroid Build Coastguard Worker #endif
197*a67afe4dSAndroid Build Coastguard Worker 
198*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_pCAL_SUPPORTED
199*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_pCAL)
200*a67afe4dSAndroid Build Coastguard Worker          png_handle_pCAL(png_ptr, info_ptr, length);
201*a67afe4dSAndroid Build Coastguard Worker #endif
202*a67afe4dSAndroid Build Coastguard Worker 
203*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_sCAL_SUPPORTED
204*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_sCAL)
205*a67afe4dSAndroid Build Coastguard Worker          png_handle_sCAL(png_ptr, info_ptr, length);
206*a67afe4dSAndroid Build Coastguard Worker #endif
207*a67afe4dSAndroid Build Coastguard Worker 
208*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_pHYs_SUPPORTED
209*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_pHYs)
210*a67afe4dSAndroid Build Coastguard Worker          png_handle_pHYs(png_ptr, info_ptr, length);
211*a67afe4dSAndroid Build Coastguard Worker #endif
212*a67afe4dSAndroid Build Coastguard Worker 
213*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_sBIT_SUPPORTED
214*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_sBIT)
215*a67afe4dSAndroid Build Coastguard Worker          png_handle_sBIT(png_ptr, info_ptr, length);
216*a67afe4dSAndroid Build Coastguard Worker #endif
217*a67afe4dSAndroid Build Coastguard Worker 
218*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_sRGB_SUPPORTED
219*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_sRGB)
220*a67afe4dSAndroid Build Coastguard Worker          png_handle_sRGB(png_ptr, info_ptr, length);
221*a67afe4dSAndroid Build Coastguard Worker #endif
222*a67afe4dSAndroid Build Coastguard Worker 
223*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_iCCP_SUPPORTED
224*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_iCCP)
225*a67afe4dSAndroid Build Coastguard Worker          png_handle_iCCP(png_ptr, info_ptr, length);
226*a67afe4dSAndroid Build Coastguard Worker #endif
227*a67afe4dSAndroid Build Coastguard Worker 
228*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_sPLT_SUPPORTED
229*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_sPLT)
230*a67afe4dSAndroid Build Coastguard Worker          png_handle_sPLT(png_ptr, info_ptr, length);
231*a67afe4dSAndroid Build Coastguard Worker #endif
232*a67afe4dSAndroid Build Coastguard Worker 
233*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_tEXt_SUPPORTED
234*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_tEXt)
235*a67afe4dSAndroid Build Coastguard Worker          png_handle_tEXt(png_ptr, info_ptr, length);
236*a67afe4dSAndroid Build Coastguard Worker #endif
237*a67afe4dSAndroid Build Coastguard Worker 
238*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_tIME_SUPPORTED
239*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_tIME)
240*a67afe4dSAndroid Build Coastguard Worker          png_handle_tIME(png_ptr, info_ptr, length);
241*a67afe4dSAndroid Build Coastguard Worker #endif
242*a67afe4dSAndroid Build Coastguard Worker 
243*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_tRNS_SUPPORTED
244*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_tRNS)
245*a67afe4dSAndroid Build Coastguard Worker          png_handle_tRNS(png_ptr, info_ptr, length);
246*a67afe4dSAndroid Build Coastguard Worker #endif
247*a67afe4dSAndroid Build Coastguard Worker 
248*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_zTXt_SUPPORTED
249*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_zTXt)
250*a67afe4dSAndroid Build Coastguard Worker          png_handle_zTXt(png_ptr, info_ptr, length);
251*a67afe4dSAndroid Build Coastguard Worker #endif
252*a67afe4dSAndroid Build Coastguard Worker 
253*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_iTXt_SUPPORTED
254*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_iTXt)
255*a67afe4dSAndroid Build Coastguard Worker          png_handle_iTXt(png_ptr, info_ptr, length);
256*a67afe4dSAndroid Build Coastguard Worker #endif
257*a67afe4dSAndroid Build Coastguard Worker 
258*a67afe4dSAndroid Build Coastguard Worker       else
259*a67afe4dSAndroid Build Coastguard Worker          png_handle_unknown(png_ptr, info_ptr, length,
260*a67afe4dSAndroid Build Coastguard Worker              PNG_HANDLE_CHUNK_AS_DEFAULT);
261*a67afe4dSAndroid Build Coastguard Worker    }
262*a67afe4dSAndroid Build Coastguard Worker }
263*a67afe4dSAndroid Build Coastguard Worker #endif /* SEQUENTIAL_READ */
264*a67afe4dSAndroid Build Coastguard Worker 
265*a67afe4dSAndroid Build Coastguard Worker /* Optional call to update the users info_ptr structure */
266*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_read_update_info(png_structrp png_ptr,png_inforp info_ptr)267*a67afe4dSAndroid Build Coastguard Worker png_read_update_info(png_structrp png_ptr, png_inforp info_ptr)
268*a67afe4dSAndroid Build Coastguard Worker {
269*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_read_update_info");
270*a67afe4dSAndroid Build Coastguard Worker 
271*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr != NULL)
272*a67afe4dSAndroid Build Coastguard Worker    {
273*a67afe4dSAndroid Build Coastguard Worker       if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)
274*a67afe4dSAndroid Build Coastguard Worker       {
275*a67afe4dSAndroid Build Coastguard Worker          png_read_start_row(png_ptr);
276*a67afe4dSAndroid Build Coastguard Worker 
277*a67afe4dSAndroid Build Coastguard Worker #        ifdef PNG_READ_TRANSFORMS_SUPPORTED
278*a67afe4dSAndroid Build Coastguard Worker             png_read_transform_info(png_ptr, info_ptr);
279*a67afe4dSAndroid Build Coastguard Worker #        else
280*a67afe4dSAndroid Build Coastguard Worker             PNG_UNUSED(info_ptr)
281*a67afe4dSAndroid Build Coastguard Worker #        endif
282*a67afe4dSAndroid Build Coastguard Worker       }
283*a67afe4dSAndroid Build Coastguard Worker 
284*a67afe4dSAndroid Build Coastguard Worker       /* New in 1.6.0 this avoids the bug of doing the initializations twice */
285*a67afe4dSAndroid Build Coastguard Worker       else
286*a67afe4dSAndroid Build Coastguard Worker          png_app_error(png_ptr,
287*a67afe4dSAndroid Build Coastguard Worker              "png_read_update_info/png_start_read_image: duplicate call");
288*a67afe4dSAndroid Build Coastguard Worker    }
289*a67afe4dSAndroid Build Coastguard Worker }
290*a67afe4dSAndroid Build Coastguard Worker 
291*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
292*a67afe4dSAndroid Build Coastguard Worker /* Initialize palette, background, etc, after transformations
293*a67afe4dSAndroid Build Coastguard Worker  * are set, but before any reading takes place.  This allows
294*a67afe4dSAndroid Build Coastguard Worker  * the user to obtain a gamma-corrected palette, for example.
295*a67afe4dSAndroid Build Coastguard Worker  * If the user doesn't call this, we will do it ourselves.
296*a67afe4dSAndroid Build Coastguard Worker  */
297*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_start_read_image(png_structrp png_ptr)298*a67afe4dSAndroid Build Coastguard Worker png_start_read_image(png_structrp png_ptr)
299*a67afe4dSAndroid Build Coastguard Worker {
300*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_start_read_image");
301*a67afe4dSAndroid Build Coastguard Worker 
302*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr != NULL)
303*a67afe4dSAndroid Build Coastguard Worker    {
304*a67afe4dSAndroid Build Coastguard Worker       if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)
305*a67afe4dSAndroid Build Coastguard Worker          png_read_start_row(png_ptr);
306*a67afe4dSAndroid Build Coastguard Worker 
307*a67afe4dSAndroid Build Coastguard Worker       /* New in 1.6.0 this avoids the bug of doing the initializations twice */
308*a67afe4dSAndroid Build Coastguard Worker       else
309*a67afe4dSAndroid Build Coastguard Worker          png_app_error(png_ptr,
310*a67afe4dSAndroid Build Coastguard Worker              "png_start_read_image/png_read_update_info: duplicate call");
311*a67afe4dSAndroid Build Coastguard Worker    }
312*a67afe4dSAndroid Build Coastguard Worker }
313*a67afe4dSAndroid Build Coastguard Worker #endif /* SEQUENTIAL_READ */
314*a67afe4dSAndroid Build Coastguard Worker 
315*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
316*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_MNG_FEATURES_SUPPORTED
317*a67afe4dSAndroid Build Coastguard Worker /* Undoes intrapixel differencing,
318*a67afe4dSAndroid Build Coastguard Worker  * NOTE: this is apparently only supported in the 'sequential' reader.
319*a67afe4dSAndroid Build Coastguard Worker  */
320*a67afe4dSAndroid Build Coastguard Worker static void
png_do_read_intrapixel(png_row_infop row_info,png_bytep row)321*a67afe4dSAndroid Build Coastguard Worker png_do_read_intrapixel(png_row_infop row_info, png_bytep row)
322*a67afe4dSAndroid Build Coastguard Worker {
323*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_do_read_intrapixel");
324*a67afe4dSAndroid Build Coastguard Worker 
325*a67afe4dSAndroid Build Coastguard Worker    if (
326*a67afe4dSAndroid Build Coastguard Worker        (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)
327*a67afe4dSAndroid Build Coastguard Worker    {
328*a67afe4dSAndroid Build Coastguard Worker       int bytes_per_pixel;
329*a67afe4dSAndroid Build Coastguard Worker       png_uint_32 row_width = row_info->width;
330*a67afe4dSAndroid Build Coastguard Worker 
331*a67afe4dSAndroid Build Coastguard Worker       if (row_info->bit_depth == 8)
332*a67afe4dSAndroid Build Coastguard Worker       {
333*a67afe4dSAndroid Build Coastguard Worker          png_bytep rp;
334*a67afe4dSAndroid Build Coastguard Worker          png_uint_32 i;
335*a67afe4dSAndroid Build Coastguard Worker 
336*a67afe4dSAndroid Build Coastguard Worker          if (row_info->color_type == PNG_COLOR_TYPE_RGB)
337*a67afe4dSAndroid Build Coastguard Worker             bytes_per_pixel = 3;
338*a67afe4dSAndroid Build Coastguard Worker 
339*a67afe4dSAndroid Build Coastguard Worker          else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
340*a67afe4dSAndroid Build Coastguard Worker             bytes_per_pixel = 4;
341*a67afe4dSAndroid Build Coastguard Worker 
342*a67afe4dSAndroid Build Coastguard Worker          else
343*a67afe4dSAndroid Build Coastguard Worker             return;
344*a67afe4dSAndroid Build Coastguard Worker 
345*a67afe4dSAndroid Build Coastguard Worker          for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
346*a67afe4dSAndroid Build Coastguard Worker          {
347*a67afe4dSAndroid Build Coastguard Worker             *(rp) = (png_byte)((256 + *rp + *(rp + 1)) & 0xff);
348*a67afe4dSAndroid Build Coastguard Worker             *(rp+2) = (png_byte)((256 + *(rp + 2) + *(rp + 1)) & 0xff);
349*a67afe4dSAndroid Build Coastguard Worker          }
350*a67afe4dSAndroid Build Coastguard Worker       }
351*a67afe4dSAndroid Build Coastguard Worker       else if (row_info->bit_depth == 16)
352*a67afe4dSAndroid Build Coastguard Worker       {
353*a67afe4dSAndroid Build Coastguard Worker          png_bytep rp;
354*a67afe4dSAndroid Build Coastguard Worker          png_uint_32 i;
355*a67afe4dSAndroid Build Coastguard Worker 
356*a67afe4dSAndroid Build Coastguard Worker          if (row_info->color_type == PNG_COLOR_TYPE_RGB)
357*a67afe4dSAndroid Build Coastguard Worker             bytes_per_pixel = 6;
358*a67afe4dSAndroid Build Coastguard Worker 
359*a67afe4dSAndroid Build Coastguard Worker          else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
360*a67afe4dSAndroid Build Coastguard Worker             bytes_per_pixel = 8;
361*a67afe4dSAndroid Build Coastguard Worker 
362*a67afe4dSAndroid Build Coastguard Worker          else
363*a67afe4dSAndroid Build Coastguard Worker             return;
364*a67afe4dSAndroid Build Coastguard Worker 
365*a67afe4dSAndroid Build Coastguard Worker          for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
366*a67afe4dSAndroid Build Coastguard Worker          {
367*a67afe4dSAndroid Build Coastguard Worker             png_uint_32 s0   = (png_uint_32)(*(rp    ) << 8) | *(rp + 1);
368*a67afe4dSAndroid Build Coastguard Worker             png_uint_32 s1   = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3);
369*a67afe4dSAndroid Build Coastguard Worker             png_uint_32 s2   = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5);
370*a67afe4dSAndroid Build Coastguard Worker             png_uint_32 red  = (s0 + s1 + 65536) & 0xffff;
371*a67afe4dSAndroid Build Coastguard Worker             png_uint_32 blue = (s2 + s1 + 65536) & 0xffff;
372*a67afe4dSAndroid Build Coastguard Worker             *(rp    ) = (png_byte)((red >> 8) & 0xff);
373*a67afe4dSAndroid Build Coastguard Worker             *(rp + 1) = (png_byte)(red & 0xff);
374*a67afe4dSAndroid Build Coastguard Worker             *(rp + 4) = (png_byte)((blue >> 8) & 0xff);
375*a67afe4dSAndroid Build Coastguard Worker             *(rp + 5) = (png_byte)(blue & 0xff);
376*a67afe4dSAndroid Build Coastguard Worker          }
377*a67afe4dSAndroid Build Coastguard Worker       }
378*a67afe4dSAndroid Build Coastguard Worker    }
379*a67afe4dSAndroid Build Coastguard Worker }
380*a67afe4dSAndroid Build Coastguard Worker #endif /* MNG_FEATURES */
381*a67afe4dSAndroid Build Coastguard Worker 
382*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_read_row(png_structrp png_ptr,png_bytep row,png_bytep dsp_row)383*a67afe4dSAndroid Build Coastguard Worker png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row)
384*a67afe4dSAndroid Build Coastguard Worker {
385*a67afe4dSAndroid Build Coastguard Worker    png_row_info row_info;
386*a67afe4dSAndroid Build Coastguard Worker 
387*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr == NULL)
388*a67afe4dSAndroid Build Coastguard Worker       return;
389*a67afe4dSAndroid Build Coastguard Worker 
390*a67afe4dSAndroid Build Coastguard Worker    png_debug2(1, "in png_read_row (row %lu, pass %d)",
391*a67afe4dSAndroid Build Coastguard Worker        (unsigned long)png_ptr->row_number, png_ptr->pass);
392*a67afe4dSAndroid Build Coastguard Worker 
393*a67afe4dSAndroid Build Coastguard Worker    /* png_read_start_row sets the information (in particular iwidth) for this
394*a67afe4dSAndroid Build Coastguard Worker     * interlace pass.
395*a67afe4dSAndroid Build Coastguard Worker     */
396*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)
397*a67afe4dSAndroid Build Coastguard Worker       png_read_start_row(png_ptr);
398*a67afe4dSAndroid Build Coastguard Worker 
399*a67afe4dSAndroid Build Coastguard Worker    /* 1.5.6: row_info moved out of png_struct to a local here. */
400*a67afe4dSAndroid Build Coastguard Worker    row_info.width = png_ptr->iwidth; /* NOTE: width of current interlaced row */
401*a67afe4dSAndroid Build Coastguard Worker    row_info.color_type = png_ptr->color_type;
402*a67afe4dSAndroid Build Coastguard Worker    row_info.bit_depth = png_ptr->bit_depth;
403*a67afe4dSAndroid Build Coastguard Worker    row_info.channels = png_ptr->channels;
404*a67afe4dSAndroid Build Coastguard Worker    row_info.pixel_depth = png_ptr->pixel_depth;
405*a67afe4dSAndroid Build Coastguard Worker    row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width);
406*a67afe4dSAndroid Build Coastguard Worker 
407*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_WARNINGS_SUPPORTED
408*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr->row_number == 0 && png_ptr->pass == 0)
409*a67afe4dSAndroid Build Coastguard Worker    {
410*a67afe4dSAndroid Build Coastguard Worker    /* Check for transforms that have been set but were defined out */
411*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED)
412*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)
413*a67afe4dSAndroid Build Coastguard Worker       png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined");
414*a67afe4dSAndroid Build Coastguard Worker #endif
415*a67afe4dSAndroid Build Coastguard Worker 
416*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED)
417*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_FILLER) != 0)
418*a67afe4dSAndroid Build Coastguard Worker       png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined");
419*a67afe4dSAndroid Build Coastguard Worker #endif
420*a67afe4dSAndroid Build Coastguard Worker 
421*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \
422*a67afe4dSAndroid Build Coastguard Worker     !defined(PNG_READ_PACKSWAP_SUPPORTED)
423*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
424*a67afe4dSAndroid Build Coastguard Worker       png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined");
425*a67afe4dSAndroid Build Coastguard Worker #endif
426*a67afe4dSAndroid Build Coastguard Worker 
427*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED)
428*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_PACK) != 0)
429*a67afe4dSAndroid Build Coastguard Worker       png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined");
430*a67afe4dSAndroid Build Coastguard Worker #endif
431*a67afe4dSAndroid Build Coastguard Worker 
432*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED)
433*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_SHIFT) != 0)
434*a67afe4dSAndroid Build Coastguard Worker       png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined");
435*a67afe4dSAndroid Build Coastguard Worker #endif
436*a67afe4dSAndroid Build Coastguard Worker 
437*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED)
438*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_BGR) != 0)
439*a67afe4dSAndroid Build Coastguard Worker       png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined");
440*a67afe4dSAndroid Build Coastguard Worker #endif
441*a67afe4dSAndroid Build Coastguard Worker 
442*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED)
443*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)
444*a67afe4dSAndroid Build Coastguard Worker       png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined");
445*a67afe4dSAndroid Build Coastguard Worker #endif
446*a67afe4dSAndroid Build Coastguard Worker    }
447*a67afe4dSAndroid Build Coastguard Worker #endif /* WARNINGS */
448*a67afe4dSAndroid Build Coastguard Worker 
449*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_INTERLACING_SUPPORTED
450*a67afe4dSAndroid Build Coastguard Worker    /* If interlaced and we do not need a new row, combine row and return.
451*a67afe4dSAndroid Build Coastguard Worker     * Notice that the pixels we have from previous rows have been transformed
452*a67afe4dSAndroid Build Coastguard Worker     * already; we can only combine like with like (transformed or
453*a67afe4dSAndroid Build Coastguard Worker     * untransformed) and, because of the libpng API for interlaced images, this
454*a67afe4dSAndroid Build Coastguard Worker     * means we must transform before de-interlacing.
455*a67afe4dSAndroid Build Coastguard Worker     */
456*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr->interlaced != 0 &&
457*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->transformations & PNG_INTERLACE) != 0)
458*a67afe4dSAndroid Build Coastguard Worker    {
459*a67afe4dSAndroid Build Coastguard Worker       switch (png_ptr->pass)
460*a67afe4dSAndroid Build Coastguard Worker       {
461*a67afe4dSAndroid Build Coastguard Worker          case 0:
462*a67afe4dSAndroid Build Coastguard Worker             if (png_ptr->row_number & 0x07)
463*a67afe4dSAndroid Build Coastguard Worker             {
464*a67afe4dSAndroid Build Coastguard Worker                if (dsp_row != NULL)
465*a67afe4dSAndroid Build Coastguard Worker                   png_combine_row(png_ptr, dsp_row, 1/*display*/);
466*a67afe4dSAndroid Build Coastguard Worker                png_read_finish_row(png_ptr);
467*a67afe4dSAndroid Build Coastguard Worker                return;
468*a67afe4dSAndroid Build Coastguard Worker             }
469*a67afe4dSAndroid Build Coastguard Worker             break;
470*a67afe4dSAndroid Build Coastguard Worker 
471*a67afe4dSAndroid Build Coastguard Worker          case 1:
472*a67afe4dSAndroid Build Coastguard Worker             if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
473*a67afe4dSAndroid Build Coastguard Worker             {
474*a67afe4dSAndroid Build Coastguard Worker                if (dsp_row != NULL)
475*a67afe4dSAndroid Build Coastguard Worker                   png_combine_row(png_ptr, dsp_row, 1/*display*/);
476*a67afe4dSAndroid Build Coastguard Worker 
477*a67afe4dSAndroid Build Coastguard Worker                png_read_finish_row(png_ptr);
478*a67afe4dSAndroid Build Coastguard Worker                return;
479*a67afe4dSAndroid Build Coastguard Worker             }
480*a67afe4dSAndroid Build Coastguard Worker             break;
481*a67afe4dSAndroid Build Coastguard Worker 
482*a67afe4dSAndroid Build Coastguard Worker          case 2:
483*a67afe4dSAndroid Build Coastguard Worker             if ((png_ptr->row_number & 0x07) != 4)
484*a67afe4dSAndroid Build Coastguard Worker             {
485*a67afe4dSAndroid Build Coastguard Worker                if (dsp_row != NULL && (png_ptr->row_number & 4))
486*a67afe4dSAndroid Build Coastguard Worker                   png_combine_row(png_ptr, dsp_row, 1/*display*/);
487*a67afe4dSAndroid Build Coastguard Worker 
488*a67afe4dSAndroid Build Coastguard Worker                png_read_finish_row(png_ptr);
489*a67afe4dSAndroid Build Coastguard Worker                return;
490*a67afe4dSAndroid Build Coastguard Worker             }
491*a67afe4dSAndroid Build Coastguard Worker             break;
492*a67afe4dSAndroid Build Coastguard Worker 
493*a67afe4dSAndroid Build Coastguard Worker          case 3:
494*a67afe4dSAndroid Build Coastguard Worker             if ((png_ptr->row_number & 3) || png_ptr->width < 3)
495*a67afe4dSAndroid Build Coastguard Worker             {
496*a67afe4dSAndroid Build Coastguard Worker                if (dsp_row != NULL)
497*a67afe4dSAndroid Build Coastguard Worker                   png_combine_row(png_ptr, dsp_row, 1/*display*/);
498*a67afe4dSAndroid Build Coastguard Worker 
499*a67afe4dSAndroid Build Coastguard Worker                png_read_finish_row(png_ptr);
500*a67afe4dSAndroid Build Coastguard Worker                return;
501*a67afe4dSAndroid Build Coastguard Worker             }
502*a67afe4dSAndroid Build Coastguard Worker             break;
503*a67afe4dSAndroid Build Coastguard Worker 
504*a67afe4dSAndroid Build Coastguard Worker          case 4:
505*a67afe4dSAndroid Build Coastguard Worker             if ((png_ptr->row_number & 3) != 2)
506*a67afe4dSAndroid Build Coastguard Worker             {
507*a67afe4dSAndroid Build Coastguard Worker                if (dsp_row != NULL && (png_ptr->row_number & 2))
508*a67afe4dSAndroid Build Coastguard Worker                   png_combine_row(png_ptr, dsp_row, 1/*display*/);
509*a67afe4dSAndroid Build Coastguard Worker 
510*a67afe4dSAndroid Build Coastguard Worker                png_read_finish_row(png_ptr);
511*a67afe4dSAndroid Build Coastguard Worker                return;
512*a67afe4dSAndroid Build Coastguard Worker             }
513*a67afe4dSAndroid Build Coastguard Worker             break;
514*a67afe4dSAndroid Build Coastguard Worker 
515*a67afe4dSAndroid Build Coastguard Worker          case 5:
516*a67afe4dSAndroid Build Coastguard Worker             if ((png_ptr->row_number & 1) || png_ptr->width < 2)
517*a67afe4dSAndroid Build Coastguard Worker             {
518*a67afe4dSAndroid Build Coastguard Worker                if (dsp_row != NULL)
519*a67afe4dSAndroid Build Coastguard Worker                   png_combine_row(png_ptr, dsp_row, 1/*display*/);
520*a67afe4dSAndroid Build Coastguard Worker 
521*a67afe4dSAndroid Build Coastguard Worker                png_read_finish_row(png_ptr);
522*a67afe4dSAndroid Build Coastguard Worker                return;
523*a67afe4dSAndroid Build Coastguard Worker             }
524*a67afe4dSAndroid Build Coastguard Worker             break;
525*a67afe4dSAndroid Build Coastguard Worker 
526*a67afe4dSAndroid Build Coastguard Worker          default:
527*a67afe4dSAndroid Build Coastguard Worker          case 6:
528*a67afe4dSAndroid Build Coastguard Worker             if ((png_ptr->row_number & 1) == 0)
529*a67afe4dSAndroid Build Coastguard Worker             {
530*a67afe4dSAndroid Build Coastguard Worker                png_read_finish_row(png_ptr);
531*a67afe4dSAndroid Build Coastguard Worker                return;
532*a67afe4dSAndroid Build Coastguard Worker             }
533*a67afe4dSAndroid Build Coastguard Worker             break;
534*a67afe4dSAndroid Build Coastguard Worker       }
535*a67afe4dSAndroid Build Coastguard Worker    }
536*a67afe4dSAndroid Build Coastguard Worker #endif
537*a67afe4dSAndroid Build Coastguard Worker 
538*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->mode & PNG_HAVE_IDAT) == 0)
539*a67afe4dSAndroid Build Coastguard Worker       png_error(png_ptr, "Invalid attempt to read row data");
540*a67afe4dSAndroid Build Coastguard Worker 
541*a67afe4dSAndroid Build Coastguard Worker    /* Fill the row with IDAT data: */
542*a67afe4dSAndroid Build Coastguard Worker    png_ptr->row_buf[0]=255; /* to force error if no data was found */
543*a67afe4dSAndroid Build Coastguard Worker    png_read_IDAT_data(png_ptr, png_ptr->row_buf, row_info.rowbytes + 1);
544*a67afe4dSAndroid Build Coastguard Worker 
545*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE)
546*a67afe4dSAndroid Build Coastguard Worker    {
547*a67afe4dSAndroid Build Coastguard Worker       if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST)
548*a67afe4dSAndroid Build Coastguard Worker          png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1,
549*a67afe4dSAndroid Build Coastguard Worker              png_ptr->prev_row + 1, png_ptr->row_buf[0]);
550*a67afe4dSAndroid Build Coastguard Worker       else
551*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr, "bad adaptive filter value");
552*a67afe4dSAndroid Build Coastguard Worker    }
553*a67afe4dSAndroid Build Coastguard Worker 
554*a67afe4dSAndroid Build Coastguard Worker    /* libpng 1.5.6: the following line was copying png_ptr->rowbytes before
555*a67afe4dSAndroid Build Coastguard Worker     * 1.5.6, while the buffer really is this big in current versions of libpng
556*a67afe4dSAndroid Build Coastguard Worker     * it may not be in the future, so this was changed just to copy the
557*a67afe4dSAndroid Build Coastguard Worker     * interlaced count:
558*a67afe4dSAndroid Build Coastguard Worker     */
559*a67afe4dSAndroid Build Coastguard Worker    memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1);
560*a67afe4dSAndroid Build Coastguard Worker 
561*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_MNG_FEATURES_SUPPORTED
562*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 &&
563*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
564*a67afe4dSAndroid Build Coastguard Worker    {
565*a67afe4dSAndroid Build Coastguard Worker       /* Intrapixel differencing */
566*a67afe4dSAndroid Build Coastguard Worker       png_do_read_intrapixel(&row_info, png_ptr->row_buf + 1);
567*a67afe4dSAndroid Build Coastguard Worker    }
568*a67afe4dSAndroid Build Coastguard Worker #endif
569*a67afe4dSAndroid Build Coastguard Worker 
570*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_TRANSFORMS_SUPPORTED
571*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr->transformations
572*a67afe4dSAndroid Build Coastguard Worker #     ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
573*a67afe4dSAndroid Build Coastguard Worker          || png_ptr->num_palette_max >= 0
574*a67afe4dSAndroid Build Coastguard Worker #     endif
575*a67afe4dSAndroid Build Coastguard Worker       )
576*a67afe4dSAndroid Build Coastguard Worker       png_do_read_transformations(png_ptr, &row_info);
577*a67afe4dSAndroid Build Coastguard Worker #endif
578*a67afe4dSAndroid Build Coastguard Worker 
579*a67afe4dSAndroid Build Coastguard Worker    /* The transformed pixel depth should match the depth now in row_info. */
580*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr->transformed_pixel_depth == 0)
581*a67afe4dSAndroid Build Coastguard Worker    {
582*a67afe4dSAndroid Build Coastguard Worker       png_ptr->transformed_pixel_depth = row_info.pixel_depth;
583*a67afe4dSAndroid Build Coastguard Worker       if (row_info.pixel_depth > png_ptr->maximum_pixel_depth)
584*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr, "sequential row overflow");
585*a67afe4dSAndroid Build Coastguard Worker    }
586*a67afe4dSAndroid Build Coastguard Worker 
587*a67afe4dSAndroid Build Coastguard Worker    else if (png_ptr->transformed_pixel_depth != row_info.pixel_depth)
588*a67afe4dSAndroid Build Coastguard Worker       png_error(png_ptr, "internal sequential row size calculation error");
589*a67afe4dSAndroid Build Coastguard Worker 
590*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_INTERLACING_SUPPORTED
591*a67afe4dSAndroid Build Coastguard Worker    /* Expand interlaced rows to full size */
592*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr->interlaced != 0 &&
593*a67afe4dSAndroid Build Coastguard Worker       (png_ptr->transformations & PNG_INTERLACE) != 0)
594*a67afe4dSAndroid Build Coastguard Worker    {
595*a67afe4dSAndroid Build Coastguard Worker       if (png_ptr->pass < 6)
596*a67afe4dSAndroid Build Coastguard Worker          png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass,
597*a67afe4dSAndroid Build Coastguard Worker              png_ptr->transformations);
598*a67afe4dSAndroid Build Coastguard Worker 
599*a67afe4dSAndroid Build Coastguard Worker       if (dsp_row != NULL)
600*a67afe4dSAndroid Build Coastguard Worker          png_combine_row(png_ptr, dsp_row, 1/*display*/);
601*a67afe4dSAndroid Build Coastguard Worker 
602*a67afe4dSAndroid Build Coastguard Worker       if (row != NULL)
603*a67afe4dSAndroid Build Coastguard Worker          png_combine_row(png_ptr, row, 0/*row*/);
604*a67afe4dSAndroid Build Coastguard Worker    }
605*a67afe4dSAndroid Build Coastguard Worker 
606*a67afe4dSAndroid Build Coastguard Worker    else
607*a67afe4dSAndroid Build Coastguard Worker #endif
608*a67afe4dSAndroid Build Coastguard Worker    {
609*a67afe4dSAndroid Build Coastguard Worker       if (row != NULL)
610*a67afe4dSAndroid Build Coastguard Worker          png_combine_row(png_ptr, row, -1/*ignored*/);
611*a67afe4dSAndroid Build Coastguard Worker 
612*a67afe4dSAndroid Build Coastguard Worker       if (dsp_row != NULL)
613*a67afe4dSAndroid Build Coastguard Worker          png_combine_row(png_ptr, dsp_row, -1/*ignored*/);
614*a67afe4dSAndroid Build Coastguard Worker    }
615*a67afe4dSAndroid Build Coastguard Worker    png_read_finish_row(png_ptr);
616*a67afe4dSAndroid Build Coastguard Worker 
617*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr->read_row_fn != NULL)
618*a67afe4dSAndroid Build Coastguard Worker       (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
619*a67afe4dSAndroid Build Coastguard Worker 
620*a67afe4dSAndroid Build Coastguard Worker }
621*a67afe4dSAndroid Build Coastguard Worker #endif /* SEQUENTIAL_READ */
622*a67afe4dSAndroid Build Coastguard Worker 
623*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
624*a67afe4dSAndroid Build Coastguard Worker /* Read one or more rows of image data.  If the image is interlaced,
625*a67afe4dSAndroid Build Coastguard Worker  * and png_set_interlace_handling() has been called, the rows need to
626*a67afe4dSAndroid Build Coastguard Worker  * contain the contents of the rows from the previous pass.  If the
627*a67afe4dSAndroid Build Coastguard Worker  * image has alpha or transparency, and png_handle_alpha()[*] has been
628*a67afe4dSAndroid Build Coastguard Worker  * called, the rows contents must be initialized to the contents of the
629*a67afe4dSAndroid Build Coastguard Worker  * screen.
630*a67afe4dSAndroid Build Coastguard Worker  *
631*a67afe4dSAndroid Build Coastguard Worker  * "row" holds the actual image, and pixels are placed in it
632*a67afe4dSAndroid Build Coastguard Worker  * as they arrive.  If the image is displayed after each pass, it will
633*a67afe4dSAndroid Build Coastguard Worker  * appear to "sparkle" in.  "display_row" can be used to display a
634*a67afe4dSAndroid Build Coastguard Worker  * "chunky" progressive image, with finer detail added as it becomes
635*a67afe4dSAndroid Build Coastguard Worker  * available.  If you do not want this "chunky" display, you may pass
636*a67afe4dSAndroid Build Coastguard Worker  * NULL for display_row.  If you do not want the sparkle display, and
637*a67afe4dSAndroid Build Coastguard Worker  * you have not called png_handle_alpha(), you may pass NULL for rows.
638*a67afe4dSAndroid Build Coastguard Worker  * If you have called png_handle_alpha(), and the image has either an
639*a67afe4dSAndroid Build Coastguard Worker  * alpha channel or a transparency chunk, you must provide a buffer for
640*a67afe4dSAndroid Build Coastguard Worker  * rows.  In this case, you do not have to provide a display_row buffer
641*a67afe4dSAndroid Build Coastguard Worker  * also, but you may.  If the image is not interlaced, or if you have
642*a67afe4dSAndroid Build Coastguard Worker  * not called png_set_interlace_handling(), the display_row buffer will
643*a67afe4dSAndroid Build Coastguard Worker  * be ignored, so pass NULL to it.
644*a67afe4dSAndroid Build Coastguard Worker  *
645*a67afe4dSAndroid Build Coastguard Worker  * [*] png_handle_alpha() does not exist yet, as of this version of libpng
646*a67afe4dSAndroid Build Coastguard Worker  */
647*a67afe4dSAndroid Build Coastguard Worker 
648*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_read_rows(png_structrp png_ptr,png_bytepp row,png_bytepp display_row,png_uint_32 num_rows)649*a67afe4dSAndroid Build Coastguard Worker png_read_rows(png_structrp png_ptr, png_bytepp row,
650*a67afe4dSAndroid Build Coastguard Worker     png_bytepp display_row, png_uint_32 num_rows)
651*a67afe4dSAndroid Build Coastguard Worker {
652*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 i;
653*a67afe4dSAndroid Build Coastguard Worker    png_bytepp rp;
654*a67afe4dSAndroid Build Coastguard Worker    png_bytepp dp;
655*a67afe4dSAndroid Build Coastguard Worker 
656*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_read_rows");
657*a67afe4dSAndroid Build Coastguard Worker 
658*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr == NULL)
659*a67afe4dSAndroid Build Coastguard Worker       return;
660*a67afe4dSAndroid Build Coastguard Worker 
661*a67afe4dSAndroid Build Coastguard Worker    rp = row;
662*a67afe4dSAndroid Build Coastguard Worker    dp = display_row;
663*a67afe4dSAndroid Build Coastguard Worker    if (rp != NULL && dp != NULL)
664*a67afe4dSAndroid Build Coastguard Worker       for (i = 0; i < num_rows; i++)
665*a67afe4dSAndroid Build Coastguard Worker       {
666*a67afe4dSAndroid Build Coastguard Worker          png_bytep rptr = *rp++;
667*a67afe4dSAndroid Build Coastguard Worker          png_bytep dptr = *dp++;
668*a67afe4dSAndroid Build Coastguard Worker 
669*a67afe4dSAndroid Build Coastguard Worker          png_read_row(png_ptr, rptr, dptr);
670*a67afe4dSAndroid Build Coastguard Worker       }
671*a67afe4dSAndroid Build Coastguard Worker 
672*a67afe4dSAndroid Build Coastguard Worker    else if (rp != NULL)
673*a67afe4dSAndroid Build Coastguard Worker       for (i = 0; i < num_rows; i++)
674*a67afe4dSAndroid Build Coastguard Worker       {
675*a67afe4dSAndroid Build Coastguard Worker          png_bytep rptr = *rp;
676*a67afe4dSAndroid Build Coastguard Worker          png_read_row(png_ptr, rptr, NULL);
677*a67afe4dSAndroid Build Coastguard Worker          rp++;
678*a67afe4dSAndroid Build Coastguard Worker       }
679*a67afe4dSAndroid Build Coastguard Worker 
680*a67afe4dSAndroid Build Coastguard Worker    else if (dp != NULL)
681*a67afe4dSAndroid Build Coastguard Worker       for (i = 0; i < num_rows; i++)
682*a67afe4dSAndroid Build Coastguard Worker       {
683*a67afe4dSAndroid Build Coastguard Worker          png_bytep dptr = *dp;
684*a67afe4dSAndroid Build Coastguard Worker          png_read_row(png_ptr, NULL, dptr);
685*a67afe4dSAndroid Build Coastguard Worker          dp++;
686*a67afe4dSAndroid Build Coastguard Worker       }
687*a67afe4dSAndroid Build Coastguard Worker }
688*a67afe4dSAndroid Build Coastguard Worker #endif /* SEQUENTIAL_READ */
689*a67afe4dSAndroid Build Coastguard Worker 
690*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
691*a67afe4dSAndroid Build Coastguard Worker /* Read the entire image.  If the image has an alpha channel or a tRNS
692*a67afe4dSAndroid Build Coastguard Worker  * chunk, and you have called png_handle_alpha()[*], you will need to
693*a67afe4dSAndroid Build Coastguard Worker  * initialize the image to the current image that PNG will be overlaying.
694*a67afe4dSAndroid Build Coastguard Worker  * We set the num_rows again here, in case it was incorrectly set in
695*a67afe4dSAndroid Build Coastguard Worker  * png_read_start_row() by a call to png_read_update_info() or
696*a67afe4dSAndroid Build Coastguard Worker  * png_start_read_image() if png_set_interlace_handling() wasn't called
697*a67afe4dSAndroid Build Coastguard Worker  * prior to either of these functions like it should have been.  You can
698*a67afe4dSAndroid Build Coastguard Worker  * only call this function once.  If you desire to have an image for
699*a67afe4dSAndroid Build Coastguard Worker  * each pass of a interlaced image, use png_read_rows() instead.
700*a67afe4dSAndroid Build Coastguard Worker  *
701*a67afe4dSAndroid Build Coastguard Worker  * [*] png_handle_alpha() does not exist yet, as of this version of libpng
702*a67afe4dSAndroid Build Coastguard Worker  */
703*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_read_image(png_structrp png_ptr,png_bytepp image)704*a67afe4dSAndroid Build Coastguard Worker png_read_image(png_structrp png_ptr, png_bytepp image)
705*a67afe4dSAndroid Build Coastguard Worker {
706*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 i, image_height;
707*a67afe4dSAndroid Build Coastguard Worker    int pass, j;
708*a67afe4dSAndroid Build Coastguard Worker    png_bytepp rp;
709*a67afe4dSAndroid Build Coastguard Worker 
710*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_read_image");
711*a67afe4dSAndroid Build Coastguard Worker 
712*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr == NULL)
713*a67afe4dSAndroid Build Coastguard Worker       return;
714*a67afe4dSAndroid Build Coastguard Worker 
715*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_INTERLACING_SUPPORTED
716*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)
717*a67afe4dSAndroid Build Coastguard Worker    {
718*a67afe4dSAndroid Build Coastguard Worker       pass = png_set_interlace_handling(png_ptr);
719*a67afe4dSAndroid Build Coastguard Worker       /* And make sure transforms are initialized. */
720*a67afe4dSAndroid Build Coastguard Worker       png_start_read_image(png_ptr);
721*a67afe4dSAndroid Build Coastguard Worker    }
722*a67afe4dSAndroid Build Coastguard Worker    else
723*a67afe4dSAndroid Build Coastguard Worker    {
724*a67afe4dSAndroid Build Coastguard Worker       if (png_ptr->interlaced != 0 &&
725*a67afe4dSAndroid Build Coastguard Worker           (png_ptr->transformations & PNG_INTERLACE) == 0)
726*a67afe4dSAndroid Build Coastguard Worker       {
727*a67afe4dSAndroid Build Coastguard Worker          /* Caller called png_start_read_image or png_read_update_info without
728*a67afe4dSAndroid Build Coastguard Worker           * first turning on the PNG_INTERLACE transform.  We can fix this here,
729*a67afe4dSAndroid Build Coastguard Worker           * but the caller should do it!
730*a67afe4dSAndroid Build Coastguard Worker           */
731*a67afe4dSAndroid Build Coastguard Worker          png_warning(png_ptr, "Interlace handling should be turned on when "
732*a67afe4dSAndroid Build Coastguard Worker              "using png_read_image");
733*a67afe4dSAndroid Build Coastguard Worker          /* Make sure this is set correctly */
734*a67afe4dSAndroid Build Coastguard Worker          png_ptr->num_rows = png_ptr->height;
735*a67afe4dSAndroid Build Coastguard Worker       }
736*a67afe4dSAndroid Build Coastguard Worker 
737*a67afe4dSAndroid Build Coastguard Worker       /* Obtain the pass number, which also turns on the PNG_INTERLACE flag in
738*a67afe4dSAndroid Build Coastguard Worker        * the above error case.
739*a67afe4dSAndroid Build Coastguard Worker        */
740*a67afe4dSAndroid Build Coastguard Worker       pass = png_set_interlace_handling(png_ptr);
741*a67afe4dSAndroid Build Coastguard Worker    }
742*a67afe4dSAndroid Build Coastguard Worker #else
743*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr->interlaced)
744*a67afe4dSAndroid Build Coastguard Worker       png_error(png_ptr,
745*a67afe4dSAndroid Build Coastguard Worker           "Cannot read interlaced image -- interlace handler disabled");
746*a67afe4dSAndroid Build Coastguard Worker 
747*a67afe4dSAndroid Build Coastguard Worker    pass = 1;
748*a67afe4dSAndroid Build Coastguard Worker #endif
749*a67afe4dSAndroid Build Coastguard Worker 
750*a67afe4dSAndroid Build Coastguard Worker    image_height=png_ptr->height;
751*a67afe4dSAndroid Build Coastguard Worker 
752*a67afe4dSAndroid Build Coastguard Worker    for (j = 0; j < pass; j++)
753*a67afe4dSAndroid Build Coastguard Worker    {
754*a67afe4dSAndroid Build Coastguard Worker       rp = image;
755*a67afe4dSAndroid Build Coastguard Worker       for (i = 0; i < image_height; i++)
756*a67afe4dSAndroid Build Coastguard Worker       {
757*a67afe4dSAndroid Build Coastguard Worker          png_read_row(png_ptr, *rp, NULL);
758*a67afe4dSAndroid Build Coastguard Worker          rp++;
759*a67afe4dSAndroid Build Coastguard Worker       }
760*a67afe4dSAndroid Build Coastguard Worker    }
761*a67afe4dSAndroid Build Coastguard Worker }
762*a67afe4dSAndroid Build Coastguard Worker #endif /* SEQUENTIAL_READ */
763*a67afe4dSAndroid Build Coastguard Worker 
764*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
765*a67afe4dSAndroid Build Coastguard Worker /* Read the end of the PNG file.  Will not read past the end of the
766*a67afe4dSAndroid Build Coastguard Worker  * file, will verify the end is accurate, and will read any comments
767*a67afe4dSAndroid Build Coastguard Worker  * or time information at the end of the file, if info is not NULL.
768*a67afe4dSAndroid Build Coastguard Worker  */
769*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_read_end(png_structrp png_ptr,png_inforp info_ptr)770*a67afe4dSAndroid Build Coastguard Worker png_read_end(png_structrp png_ptr, png_inforp info_ptr)
771*a67afe4dSAndroid Build Coastguard Worker {
772*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
773*a67afe4dSAndroid Build Coastguard Worker    int keep;
774*a67afe4dSAndroid Build Coastguard Worker #endif
775*a67afe4dSAndroid Build Coastguard Worker 
776*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_read_end");
777*a67afe4dSAndroid Build Coastguard Worker 
778*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr == NULL)
779*a67afe4dSAndroid Build Coastguard Worker       return;
780*a67afe4dSAndroid Build Coastguard Worker 
781*a67afe4dSAndroid Build Coastguard Worker    /* If png_read_end is called in the middle of reading the rows there may
782*a67afe4dSAndroid Build Coastguard Worker     * still be pending IDAT data and an owned zstream.  Deal with this here.
783*a67afe4dSAndroid Build Coastguard Worker     */
784*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
785*a67afe4dSAndroid Build Coastguard Worker    if (png_chunk_unknown_handling(png_ptr, png_IDAT) == 0)
786*a67afe4dSAndroid Build Coastguard Worker #endif
787*a67afe4dSAndroid Build Coastguard Worker       png_read_finish_IDAT(png_ptr);
788*a67afe4dSAndroid Build Coastguard Worker 
789*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
790*a67afe4dSAndroid Build Coastguard Worker    /* Report invalid palette index; added at libng-1.5.10 */
791*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
792*a67afe4dSAndroid Build Coastguard Worker        png_ptr->num_palette_max >= png_ptr->num_palette)
793*a67afe4dSAndroid Build Coastguard Worker       png_benign_error(png_ptr, "Read palette index exceeding num_palette");
794*a67afe4dSAndroid Build Coastguard Worker #endif
795*a67afe4dSAndroid Build Coastguard Worker 
796*a67afe4dSAndroid Build Coastguard Worker    do
797*a67afe4dSAndroid Build Coastguard Worker    {
798*a67afe4dSAndroid Build Coastguard Worker       png_uint_32 length = png_read_chunk_header(png_ptr);
799*a67afe4dSAndroid Build Coastguard Worker       png_uint_32 chunk_name = png_ptr->chunk_name;
800*a67afe4dSAndroid Build Coastguard Worker 
801*a67afe4dSAndroid Build Coastguard Worker       if (chunk_name != png_IDAT)
802*a67afe4dSAndroid Build Coastguard Worker          png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
803*a67afe4dSAndroid Build Coastguard Worker 
804*a67afe4dSAndroid Build Coastguard Worker       if (chunk_name == png_IEND)
805*a67afe4dSAndroid Build Coastguard Worker          png_handle_IEND(png_ptr, info_ptr, length);
806*a67afe4dSAndroid Build Coastguard Worker 
807*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_IHDR)
808*a67afe4dSAndroid Build Coastguard Worker          png_handle_IHDR(png_ptr, info_ptr, length);
809*a67afe4dSAndroid Build Coastguard Worker 
810*a67afe4dSAndroid Build Coastguard Worker       else if (info_ptr == NULL)
811*a67afe4dSAndroid Build Coastguard Worker          png_crc_finish(png_ptr, length);
812*a67afe4dSAndroid Build Coastguard Worker 
813*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
814*a67afe4dSAndroid Build Coastguard Worker       else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0)
815*a67afe4dSAndroid Build Coastguard Worker       {
816*a67afe4dSAndroid Build Coastguard Worker          if (chunk_name == png_IDAT)
817*a67afe4dSAndroid Build Coastguard Worker          {
818*a67afe4dSAndroid Build Coastguard Worker             if ((length > 0 && !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED))
819*a67afe4dSAndroid Build Coastguard Worker                 || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0)
820*a67afe4dSAndroid Build Coastguard Worker                png_benign_error(png_ptr, ".Too many IDATs found");
821*a67afe4dSAndroid Build Coastguard Worker          }
822*a67afe4dSAndroid Build Coastguard Worker          png_handle_unknown(png_ptr, info_ptr, length, keep);
823*a67afe4dSAndroid Build Coastguard Worker          if (chunk_name == png_PLTE)
824*a67afe4dSAndroid Build Coastguard Worker             png_ptr->mode |= PNG_HAVE_PLTE;
825*a67afe4dSAndroid Build Coastguard Worker       }
826*a67afe4dSAndroid Build Coastguard Worker #endif
827*a67afe4dSAndroid Build Coastguard Worker 
828*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_IDAT)
829*a67afe4dSAndroid Build Coastguard Worker       {
830*a67afe4dSAndroid Build Coastguard Worker          /* Zero length IDATs are legal after the last IDAT has been
831*a67afe4dSAndroid Build Coastguard Worker           * read, but not after other chunks have been read.  1.6 does not
832*a67afe4dSAndroid Build Coastguard Worker           * always read all the deflate data; specifically it cannot be relied
833*a67afe4dSAndroid Build Coastguard Worker           * upon to read the Adler32 at the end.  If it doesn't ignore IDAT
834*a67afe4dSAndroid Build Coastguard Worker           * chunks which are longer than zero as well:
835*a67afe4dSAndroid Build Coastguard Worker           */
836*a67afe4dSAndroid Build Coastguard Worker          if ((length > 0 && !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED))
837*a67afe4dSAndroid Build Coastguard Worker              || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0)
838*a67afe4dSAndroid Build Coastguard Worker             png_benign_error(png_ptr, "..Too many IDATs found");
839*a67afe4dSAndroid Build Coastguard Worker 
840*a67afe4dSAndroid Build Coastguard Worker          png_crc_finish(png_ptr, length);
841*a67afe4dSAndroid Build Coastguard Worker       }
842*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_PLTE)
843*a67afe4dSAndroid Build Coastguard Worker          png_handle_PLTE(png_ptr, info_ptr, length);
844*a67afe4dSAndroid Build Coastguard Worker 
845*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_bKGD_SUPPORTED
846*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_bKGD)
847*a67afe4dSAndroid Build Coastguard Worker          png_handle_bKGD(png_ptr, info_ptr, length);
848*a67afe4dSAndroid Build Coastguard Worker #endif
849*a67afe4dSAndroid Build Coastguard Worker 
850*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_cHRM_SUPPORTED
851*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_cHRM)
852*a67afe4dSAndroid Build Coastguard Worker          png_handle_cHRM(png_ptr, info_ptr, length);
853*a67afe4dSAndroid Build Coastguard Worker #endif
854*a67afe4dSAndroid Build Coastguard Worker 
855*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_eXIf_SUPPORTED
856*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_eXIf)
857*a67afe4dSAndroid Build Coastguard Worker          png_handle_eXIf(png_ptr, info_ptr, length);
858*a67afe4dSAndroid Build Coastguard Worker #endif
859*a67afe4dSAndroid Build Coastguard Worker 
860*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_gAMA_SUPPORTED
861*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_gAMA)
862*a67afe4dSAndroid Build Coastguard Worker          png_handle_gAMA(png_ptr, info_ptr, length);
863*a67afe4dSAndroid Build Coastguard Worker #endif
864*a67afe4dSAndroid Build Coastguard Worker 
865*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_hIST_SUPPORTED
866*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_hIST)
867*a67afe4dSAndroid Build Coastguard Worker          png_handle_hIST(png_ptr, info_ptr, length);
868*a67afe4dSAndroid Build Coastguard Worker #endif
869*a67afe4dSAndroid Build Coastguard Worker 
870*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_oFFs_SUPPORTED
871*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_oFFs)
872*a67afe4dSAndroid Build Coastguard Worker          png_handle_oFFs(png_ptr, info_ptr, length);
873*a67afe4dSAndroid Build Coastguard Worker #endif
874*a67afe4dSAndroid Build Coastguard Worker 
875*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_pCAL_SUPPORTED
876*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_pCAL)
877*a67afe4dSAndroid Build Coastguard Worker          png_handle_pCAL(png_ptr, info_ptr, length);
878*a67afe4dSAndroid Build Coastguard Worker #endif
879*a67afe4dSAndroid Build Coastguard Worker 
880*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_sCAL_SUPPORTED
881*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_sCAL)
882*a67afe4dSAndroid Build Coastguard Worker          png_handle_sCAL(png_ptr, info_ptr, length);
883*a67afe4dSAndroid Build Coastguard Worker #endif
884*a67afe4dSAndroid Build Coastguard Worker 
885*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_pHYs_SUPPORTED
886*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_pHYs)
887*a67afe4dSAndroid Build Coastguard Worker          png_handle_pHYs(png_ptr, info_ptr, length);
888*a67afe4dSAndroid Build Coastguard Worker #endif
889*a67afe4dSAndroid Build Coastguard Worker 
890*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_sBIT_SUPPORTED
891*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_sBIT)
892*a67afe4dSAndroid Build Coastguard Worker          png_handle_sBIT(png_ptr, info_ptr, length);
893*a67afe4dSAndroid Build Coastguard Worker #endif
894*a67afe4dSAndroid Build Coastguard Worker 
895*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_sRGB_SUPPORTED
896*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_sRGB)
897*a67afe4dSAndroid Build Coastguard Worker          png_handle_sRGB(png_ptr, info_ptr, length);
898*a67afe4dSAndroid Build Coastguard Worker #endif
899*a67afe4dSAndroid Build Coastguard Worker 
900*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_iCCP_SUPPORTED
901*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_iCCP)
902*a67afe4dSAndroid Build Coastguard Worker          png_handle_iCCP(png_ptr, info_ptr, length);
903*a67afe4dSAndroid Build Coastguard Worker #endif
904*a67afe4dSAndroid Build Coastguard Worker 
905*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_sPLT_SUPPORTED
906*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_sPLT)
907*a67afe4dSAndroid Build Coastguard Worker          png_handle_sPLT(png_ptr, info_ptr, length);
908*a67afe4dSAndroid Build Coastguard Worker #endif
909*a67afe4dSAndroid Build Coastguard Worker 
910*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_tEXt_SUPPORTED
911*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_tEXt)
912*a67afe4dSAndroid Build Coastguard Worker          png_handle_tEXt(png_ptr, info_ptr, length);
913*a67afe4dSAndroid Build Coastguard Worker #endif
914*a67afe4dSAndroid Build Coastguard Worker 
915*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_tIME_SUPPORTED
916*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_tIME)
917*a67afe4dSAndroid Build Coastguard Worker          png_handle_tIME(png_ptr, info_ptr, length);
918*a67afe4dSAndroid Build Coastguard Worker #endif
919*a67afe4dSAndroid Build Coastguard Worker 
920*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_tRNS_SUPPORTED
921*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_tRNS)
922*a67afe4dSAndroid Build Coastguard Worker          png_handle_tRNS(png_ptr, info_ptr, length);
923*a67afe4dSAndroid Build Coastguard Worker #endif
924*a67afe4dSAndroid Build Coastguard Worker 
925*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_zTXt_SUPPORTED
926*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_zTXt)
927*a67afe4dSAndroid Build Coastguard Worker          png_handle_zTXt(png_ptr, info_ptr, length);
928*a67afe4dSAndroid Build Coastguard Worker #endif
929*a67afe4dSAndroid Build Coastguard Worker 
930*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_iTXt_SUPPORTED
931*a67afe4dSAndroid Build Coastguard Worker       else if (chunk_name == png_iTXt)
932*a67afe4dSAndroid Build Coastguard Worker          png_handle_iTXt(png_ptr, info_ptr, length);
933*a67afe4dSAndroid Build Coastguard Worker #endif
934*a67afe4dSAndroid Build Coastguard Worker 
935*a67afe4dSAndroid Build Coastguard Worker       else
936*a67afe4dSAndroid Build Coastguard Worker          png_handle_unknown(png_ptr, info_ptr, length,
937*a67afe4dSAndroid Build Coastguard Worker              PNG_HANDLE_CHUNK_AS_DEFAULT);
938*a67afe4dSAndroid Build Coastguard Worker    } while ((png_ptr->mode & PNG_HAVE_IEND) == 0);
939*a67afe4dSAndroid Build Coastguard Worker }
940*a67afe4dSAndroid Build Coastguard Worker #endif /* SEQUENTIAL_READ */
941*a67afe4dSAndroid Build Coastguard Worker 
942*a67afe4dSAndroid Build Coastguard Worker /* Free all memory used in the read struct */
943*a67afe4dSAndroid Build Coastguard Worker static void
png_read_destroy(png_structrp png_ptr)944*a67afe4dSAndroid Build Coastguard Worker png_read_destroy(png_structrp png_ptr)
945*a67afe4dSAndroid Build Coastguard Worker {
946*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_read_destroy");
947*a67afe4dSAndroid Build Coastguard Worker 
948*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
949*a67afe4dSAndroid Build Coastguard Worker    png_destroy_gamma_table(png_ptr);
950*a67afe4dSAndroid Build Coastguard Worker #endif
951*a67afe4dSAndroid Build Coastguard Worker 
952*a67afe4dSAndroid Build Coastguard Worker    png_free(png_ptr, png_ptr->big_row_buf);
953*a67afe4dSAndroid Build Coastguard Worker    png_ptr->big_row_buf = NULL;
954*a67afe4dSAndroid Build Coastguard Worker    png_free(png_ptr, png_ptr->big_prev_row);
955*a67afe4dSAndroid Build Coastguard Worker    png_ptr->big_prev_row = NULL;
956*a67afe4dSAndroid Build Coastguard Worker    png_free(png_ptr, png_ptr->read_buffer);
957*a67afe4dSAndroid Build Coastguard Worker    png_ptr->read_buffer = NULL;
958*a67afe4dSAndroid Build Coastguard Worker 
959*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_QUANTIZE_SUPPORTED
960*a67afe4dSAndroid Build Coastguard Worker    png_free(png_ptr, png_ptr->palette_lookup);
961*a67afe4dSAndroid Build Coastguard Worker    png_ptr->palette_lookup = NULL;
962*a67afe4dSAndroid Build Coastguard Worker    png_free(png_ptr, png_ptr->quantize_index);
963*a67afe4dSAndroid Build Coastguard Worker    png_ptr->quantize_index = NULL;
964*a67afe4dSAndroid Build Coastguard Worker #endif
965*a67afe4dSAndroid Build Coastguard Worker 
966*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->free_me & PNG_FREE_PLTE) != 0)
967*a67afe4dSAndroid Build Coastguard Worker    {
968*a67afe4dSAndroid Build Coastguard Worker       png_zfree(png_ptr, png_ptr->palette);
969*a67afe4dSAndroid Build Coastguard Worker       png_ptr->palette = NULL;
970*a67afe4dSAndroid Build Coastguard Worker    }
971*a67afe4dSAndroid Build Coastguard Worker    png_ptr->free_me &= ~PNG_FREE_PLTE;
972*a67afe4dSAndroid Build Coastguard Worker 
973*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_tRNS_SUPPORTED) || \
974*a67afe4dSAndroid Build Coastguard Worker     defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
975*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->free_me & PNG_FREE_TRNS) != 0)
976*a67afe4dSAndroid Build Coastguard Worker    {
977*a67afe4dSAndroid Build Coastguard Worker       png_free(png_ptr, png_ptr->trans_alpha);
978*a67afe4dSAndroid Build Coastguard Worker       png_ptr->trans_alpha = NULL;
979*a67afe4dSAndroid Build Coastguard Worker    }
980*a67afe4dSAndroid Build Coastguard Worker    png_ptr->free_me &= ~PNG_FREE_TRNS;
981*a67afe4dSAndroid Build Coastguard Worker #endif
982*a67afe4dSAndroid Build Coastguard Worker 
983*a67afe4dSAndroid Build Coastguard Worker    inflateEnd(&png_ptr->zstream);
984*a67afe4dSAndroid Build Coastguard Worker 
985*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_PROGRESSIVE_READ_SUPPORTED
986*a67afe4dSAndroid Build Coastguard Worker    png_free(png_ptr, png_ptr->save_buffer);
987*a67afe4dSAndroid Build Coastguard Worker    png_ptr->save_buffer = NULL;
988*a67afe4dSAndroid Build Coastguard Worker #endif
989*a67afe4dSAndroid Build Coastguard Worker 
990*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) && \
991*a67afe4dSAndroid Build Coastguard Worker    defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
992*a67afe4dSAndroid Build Coastguard Worker    png_free(png_ptr, png_ptr->unknown_chunk.data);
993*a67afe4dSAndroid Build Coastguard Worker    png_ptr->unknown_chunk.data = NULL;
994*a67afe4dSAndroid Build Coastguard Worker #endif
995*a67afe4dSAndroid Build Coastguard Worker 
996*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED
997*a67afe4dSAndroid Build Coastguard Worker    png_free(png_ptr, png_ptr->chunk_list);
998*a67afe4dSAndroid Build Coastguard Worker    png_ptr->chunk_list = NULL;
999*a67afe4dSAndroid Build Coastguard Worker #endif
1000*a67afe4dSAndroid Build Coastguard Worker 
1001*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_READ_EXPAND_SUPPORTED) && \
1002*a67afe4dSAndroid Build Coastguard Worker     defined(PNG_ARM_NEON_IMPLEMENTATION)
1003*a67afe4dSAndroid Build Coastguard Worker    png_free(png_ptr, png_ptr->riffled_palette);
1004*a67afe4dSAndroid Build Coastguard Worker    png_ptr->riffled_palette = NULL;
1005*a67afe4dSAndroid Build Coastguard Worker #endif
1006*a67afe4dSAndroid Build Coastguard Worker 
1007*a67afe4dSAndroid Build Coastguard Worker    /* NOTE: the 'setjmp' buffer may still be allocated and the memory and error
1008*a67afe4dSAndroid Build Coastguard Worker     * callbacks are still set at this point.  They are required to complete the
1009*a67afe4dSAndroid Build Coastguard Worker     * destruction of the png_struct itself.
1010*a67afe4dSAndroid Build Coastguard Worker     */
1011*a67afe4dSAndroid Build Coastguard Worker }
1012*a67afe4dSAndroid Build Coastguard Worker 
1013*a67afe4dSAndroid Build Coastguard Worker /* Free all memory used by the read */
1014*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_destroy_read_struct(png_structpp png_ptr_ptr,png_infopp info_ptr_ptr,png_infopp end_info_ptr_ptr)1015*a67afe4dSAndroid Build Coastguard Worker png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr,
1016*a67afe4dSAndroid Build Coastguard Worker     png_infopp end_info_ptr_ptr)
1017*a67afe4dSAndroid Build Coastguard Worker {
1018*a67afe4dSAndroid Build Coastguard Worker    png_structrp png_ptr = NULL;
1019*a67afe4dSAndroid Build Coastguard Worker 
1020*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_destroy_read_struct");
1021*a67afe4dSAndroid Build Coastguard Worker 
1022*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr_ptr != NULL)
1023*a67afe4dSAndroid Build Coastguard Worker       png_ptr = *png_ptr_ptr;
1024*a67afe4dSAndroid Build Coastguard Worker 
1025*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr == NULL)
1026*a67afe4dSAndroid Build Coastguard Worker       return;
1027*a67afe4dSAndroid Build Coastguard Worker 
1028*a67afe4dSAndroid Build Coastguard Worker    /* libpng 1.6.0: use the API to destroy info structs to ensure consistent
1029*a67afe4dSAndroid Build Coastguard Worker     * behavior.  Prior to 1.6.0 libpng did extra 'info' destruction in this API.
1030*a67afe4dSAndroid Build Coastguard Worker     * The extra was, apparently, unnecessary yet this hides memory leak bugs.
1031*a67afe4dSAndroid Build Coastguard Worker     */
1032*a67afe4dSAndroid Build Coastguard Worker    png_destroy_info_struct(png_ptr, end_info_ptr_ptr);
1033*a67afe4dSAndroid Build Coastguard Worker    png_destroy_info_struct(png_ptr, info_ptr_ptr);
1034*a67afe4dSAndroid Build Coastguard Worker 
1035*a67afe4dSAndroid Build Coastguard Worker    *png_ptr_ptr = NULL;
1036*a67afe4dSAndroid Build Coastguard Worker    png_read_destroy(png_ptr);
1037*a67afe4dSAndroid Build Coastguard Worker    png_destroy_png_struct(png_ptr);
1038*a67afe4dSAndroid Build Coastguard Worker }
1039*a67afe4dSAndroid Build Coastguard Worker 
1040*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_set_read_status_fn(png_structrp png_ptr,png_read_status_ptr read_row_fn)1041*a67afe4dSAndroid Build Coastguard Worker png_set_read_status_fn(png_structrp png_ptr, png_read_status_ptr read_row_fn)
1042*a67afe4dSAndroid Build Coastguard Worker {
1043*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr == NULL)
1044*a67afe4dSAndroid Build Coastguard Worker       return;
1045*a67afe4dSAndroid Build Coastguard Worker 
1046*a67afe4dSAndroid Build Coastguard Worker    png_ptr->read_row_fn = read_row_fn;
1047*a67afe4dSAndroid Build Coastguard Worker }
1048*a67afe4dSAndroid Build Coastguard Worker 
1049*a67afe4dSAndroid Build Coastguard Worker 
1050*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_SEQUENTIAL_READ_SUPPORTED
1051*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_INFO_IMAGE_SUPPORTED
1052*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_read_png(png_structrp png_ptr,png_inforp info_ptr,int transforms,voidp params)1053*a67afe4dSAndroid Build Coastguard Worker png_read_png(png_structrp png_ptr, png_inforp info_ptr,
1054*a67afe4dSAndroid Build Coastguard Worker     int transforms, voidp params)
1055*a67afe4dSAndroid Build Coastguard Worker {
1056*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_read_png");
1057*a67afe4dSAndroid Build Coastguard Worker 
1058*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr == NULL || info_ptr == NULL)
1059*a67afe4dSAndroid Build Coastguard Worker       return;
1060*a67afe4dSAndroid Build Coastguard Worker 
1061*a67afe4dSAndroid Build Coastguard Worker    /* png_read_info() gives us all of the information from the
1062*a67afe4dSAndroid Build Coastguard Worker     * PNG file before the first IDAT (image data chunk).
1063*a67afe4dSAndroid Build Coastguard Worker     */
1064*a67afe4dSAndroid Build Coastguard Worker    png_read_info(png_ptr, info_ptr);
1065*a67afe4dSAndroid Build Coastguard Worker    if (info_ptr->height > PNG_UINT_32_MAX/(sizeof (png_bytep)))
1066*a67afe4dSAndroid Build Coastguard Worker       png_error(png_ptr, "Image is too high to process with png_read_png()");
1067*a67afe4dSAndroid Build Coastguard Worker 
1068*a67afe4dSAndroid Build Coastguard Worker    /* -------------- image transformations start here ------------------- */
1069*a67afe4dSAndroid Build Coastguard Worker    /* libpng 1.6.10: add code to cause a png_app_error if a selected TRANSFORM
1070*a67afe4dSAndroid Build Coastguard Worker     * is not implemented.  This will only happen in de-configured (non-default)
1071*a67afe4dSAndroid Build Coastguard Worker     * libpng builds.  The results can be unexpected - png_read_png may return
1072*a67afe4dSAndroid Build Coastguard Worker     * short or mal-formed rows because the transform is skipped.
1073*a67afe4dSAndroid Build Coastguard Worker     */
1074*a67afe4dSAndroid Build Coastguard Worker 
1075*a67afe4dSAndroid Build Coastguard Worker    /* Tell libpng to strip 16-bit/color files down to 8 bits per color.
1076*a67afe4dSAndroid Build Coastguard Worker     */
1077*a67afe4dSAndroid Build Coastguard Worker    if ((transforms & PNG_TRANSFORM_SCALE_16) != 0)
1078*a67afe4dSAndroid Build Coastguard Worker       /* Added at libpng-1.5.4. "strip_16" produces the same result that it
1079*a67afe4dSAndroid Build Coastguard Worker        * did in earlier versions, while "scale_16" is now more accurate.
1080*a67afe4dSAndroid Build Coastguard Worker        */
1081*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
1082*a67afe4dSAndroid Build Coastguard Worker       png_set_scale_16(png_ptr);
1083*a67afe4dSAndroid Build Coastguard Worker #else
1084*a67afe4dSAndroid Build Coastguard Worker       png_app_error(png_ptr, "PNG_TRANSFORM_SCALE_16 not supported");
1085*a67afe4dSAndroid Build Coastguard Worker #endif
1086*a67afe4dSAndroid Build Coastguard Worker 
1087*a67afe4dSAndroid Build Coastguard Worker    /* If both SCALE and STRIP are required pngrtran will effectively cancel the
1088*a67afe4dSAndroid Build Coastguard Worker     * latter by doing SCALE first.  This is ok and allows apps not to check for
1089*a67afe4dSAndroid Build Coastguard Worker     * which is supported to get the right answer.
1090*a67afe4dSAndroid Build Coastguard Worker     */
1091*a67afe4dSAndroid Build Coastguard Worker    if ((transforms & PNG_TRANSFORM_STRIP_16) != 0)
1092*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
1093*a67afe4dSAndroid Build Coastguard Worker       png_set_strip_16(png_ptr);
1094*a67afe4dSAndroid Build Coastguard Worker #else
1095*a67afe4dSAndroid Build Coastguard Worker       png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_16 not supported");
1096*a67afe4dSAndroid Build Coastguard Worker #endif
1097*a67afe4dSAndroid Build Coastguard Worker 
1098*a67afe4dSAndroid Build Coastguard Worker    /* Strip alpha bytes from the input data without combining with
1099*a67afe4dSAndroid Build Coastguard Worker     * the background (not recommended).
1100*a67afe4dSAndroid Build Coastguard Worker     */
1101*a67afe4dSAndroid Build Coastguard Worker    if ((transforms & PNG_TRANSFORM_STRIP_ALPHA) != 0)
1102*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
1103*a67afe4dSAndroid Build Coastguard Worker       png_set_strip_alpha(png_ptr);
1104*a67afe4dSAndroid Build Coastguard Worker #else
1105*a67afe4dSAndroid Build Coastguard Worker       png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_ALPHA not supported");
1106*a67afe4dSAndroid Build Coastguard Worker #endif
1107*a67afe4dSAndroid Build Coastguard Worker 
1108*a67afe4dSAndroid Build Coastguard Worker    /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single
1109*a67afe4dSAndroid Build Coastguard Worker     * byte into separate bytes (useful for paletted and grayscale images).
1110*a67afe4dSAndroid Build Coastguard Worker     */
1111*a67afe4dSAndroid Build Coastguard Worker    if ((transforms & PNG_TRANSFORM_PACKING) != 0)
1112*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_PACK_SUPPORTED
1113*a67afe4dSAndroid Build Coastguard Worker       png_set_packing(png_ptr);
1114*a67afe4dSAndroid Build Coastguard Worker #else
1115*a67afe4dSAndroid Build Coastguard Worker       png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported");
1116*a67afe4dSAndroid Build Coastguard Worker #endif
1117*a67afe4dSAndroid Build Coastguard Worker 
1118*a67afe4dSAndroid Build Coastguard Worker    /* Change the order of packed pixels to least significant bit first
1119*a67afe4dSAndroid Build Coastguard Worker     * (not useful if you are using png_set_packing).
1120*a67afe4dSAndroid Build Coastguard Worker     */
1121*a67afe4dSAndroid Build Coastguard Worker    if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0)
1122*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_PACKSWAP_SUPPORTED
1123*a67afe4dSAndroid Build Coastguard Worker       png_set_packswap(png_ptr);
1124*a67afe4dSAndroid Build Coastguard Worker #else
1125*a67afe4dSAndroid Build Coastguard Worker       png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported");
1126*a67afe4dSAndroid Build Coastguard Worker #endif
1127*a67afe4dSAndroid Build Coastguard Worker 
1128*a67afe4dSAndroid Build Coastguard Worker    /* Expand paletted colors into true RGB triplets
1129*a67afe4dSAndroid Build Coastguard Worker     * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel
1130*a67afe4dSAndroid Build Coastguard Worker     * Expand paletted or RGB images with transparency to full alpha
1131*a67afe4dSAndroid Build Coastguard Worker     * channels so the data will be available as RGBA quartets.
1132*a67afe4dSAndroid Build Coastguard Worker     */
1133*a67afe4dSAndroid Build Coastguard Worker    if ((transforms & PNG_TRANSFORM_EXPAND) != 0)
1134*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_EXPAND_SUPPORTED
1135*a67afe4dSAndroid Build Coastguard Worker       png_set_expand(png_ptr);
1136*a67afe4dSAndroid Build Coastguard Worker #else
1137*a67afe4dSAndroid Build Coastguard Worker       png_app_error(png_ptr, "PNG_TRANSFORM_EXPAND not supported");
1138*a67afe4dSAndroid Build Coastguard Worker #endif
1139*a67afe4dSAndroid Build Coastguard Worker 
1140*a67afe4dSAndroid Build Coastguard Worker    /* We don't handle background color or gamma transformation or quantizing.
1141*a67afe4dSAndroid Build Coastguard Worker     */
1142*a67afe4dSAndroid Build Coastguard Worker 
1143*a67afe4dSAndroid Build Coastguard Worker    /* Invert monochrome files to have 0 as white and 1 as black
1144*a67afe4dSAndroid Build Coastguard Worker     */
1145*a67afe4dSAndroid Build Coastguard Worker    if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0)
1146*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_INVERT_SUPPORTED
1147*a67afe4dSAndroid Build Coastguard Worker       png_set_invert_mono(png_ptr);
1148*a67afe4dSAndroid Build Coastguard Worker #else
1149*a67afe4dSAndroid Build Coastguard Worker       png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported");
1150*a67afe4dSAndroid Build Coastguard Worker #endif
1151*a67afe4dSAndroid Build Coastguard Worker 
1152*a67afe4dSAndroid Build Coastguard Worker    /* If you want to shift the pixel values from the range [0,255] or
1153*a67afe4dSAndroid Build Coastguard Worker     * [0,65535] to the original [0,7] or [0,31], or whatever range the
1154*a67afe4dSAndroid Build Coastguard Worker     * colors were originally in:
1155*a67afe4dSAndroid Build Coastguard Worker     */
1156*a67afe4dSAndroid Build Coastguard Worker    if ((transforms & PNG_TRANSFORM_SHIFT) != 0)
1157*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_SHIFT_SUPPORTED
1158*a67afe4dSAndroid Build Coastguard Worker       if ((info_ptr->valid & PNG_INFO_sBIT) != 0)
1159*a67afe4dSAndroid Build Coastguard Worker          png_set_shift(png_ptr, &info_ptr->sig_bit);
1160*a67afe4dSAndroid Build Coastguard Worker #else
1161*a67afe4dSAndroid Build Coastguard Worker       png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported");
1162*a67afe4dSAndroid Build Coastguard Worker #endif
1163*a67afe4dSAndroid Build Coastguard Worker 
1164*a67afe4dSAndroid Build Coastguard Worker    /* Flip the RGB pixels to BGR (or RGBA to BGRA) */
1165*a67afe4dSAndroid Build Coastguard Worker    if ((transforms & PNG_TRANSFORM_BGR) != 0)
1166*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_BGR_SUPPORTED
1167*a67afe4dSAndroid Build Coastguard Worker       png_set_bgr(png_ptr);
1168*a67afe4dSAndroid Build Coastguard Worker #else
1169*a67afe4dSAndroid Build Coastguard Worker       png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported");
1170*a67afe4dSAndroid Build Coastguard Worker #endif
1171*a67afe4dSAndroid Build Coastguard Worker 
1172*a67afe4dSAndroid Build Coastguard Worker    /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
1173*a67afe4dSAndroid Build Coastguard Worker    if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0)
1174*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
1175*a67afe4dSAndroid Build Coastguard Worker       png_set_swap_alpha(png_ptr);
1176*a67afe4dSAndroid Build Coastguard Worker #else
1177*a67afe4dSAndroid Build Coastguard Worker       png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported");
1178*a67afe4dSAndroid Build Coastguard Worker #endif
1179*a67afe4dSAndroid Build Coastguard Worker 
1180*a67afe4dSAndroid Build Coastguard Worker    /* Swap bytes of 16-bit files to least significant byte first */
1181*a67afe4dSAndroid Build Coastguard Worker    if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0)
1182*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_SWAP_SUPPORTED
1183*a67afe4dSAndroid Build Coastguard Worker       png_set_swap(png_ptr);
1184*a67afe4dSAndroid Build Coastguard Worker #else
1185*a67afe4dSAndroid Build Coastguard Worker       png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported");
1186*a67afe4dSAndroid Build Coastguard Worker #endif
1187*a67afe4dSAndroid Build Coastguard Worker 
1188*a67afe4dSAndroid Build Coastguard Worker /* Added at libpng-1.2.41 */
1189*a67afe4dSAndroid Build Coastguard Worker    /* Invert the alpha channel from opacity to transparency */
1190*a67afe4dSAndroid Build Coastguard Worker    if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0)
1191*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
1192*a67afe4dSAndroid Build Coastguard Worker       png_set_invert_alpha(png_ptr);
1193*a67afe4dSAndroid Build Coastguard Worker #else
1194*a67afe4dSAndroid Build Coastguard Worker       png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported");
1195*a67afe4dSAndroid Build Coastguard Worker #endif
1196*a67afe4dSAndroid Build Coastguard Worker 
1197*a67afe4dSAndroid Build Coastguard Worker /* Added at libpng-1.2.41 */
1198*a67afe4dSAndroid Build Coastguard Worker    /* Expand grayscale image to RGB */
1199*a67afe4dSAndroid Build Coastguard Worker    if ((transforms & PNG_TRANSFORM_GRAY_TO_RGB) != 0)
1200*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
1201*a67afe4dSAndroid Build Coastguard Worker       png_set_gray_to_rgb(png_ptr);
1202*a67afe4dSAndroid Build Coastguard Worker #else
1203*a67afe4dSAndroid Build Coastguard Worker       png_app_error(png_ptr, "PNG_TRANSFORM_GRAY_TO_RGB not supported");
1204*a67afe4dSAndroid Build Coastguard Worker #endif
1205*a67afe4dSAndroid Build Coastguard Worker 
1206*a67afe4dSAndroid Build Coastguard Worker /* Added at libpng-1.5.4 */
1207*a67afe4dSAndroid Build Coastguard Worker    if ((transforms & PNG_TRANSFORM_EXPAND_16) != 0)
1208*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_EXPAND_16_SUPPORTED
1209*a67afe4dSAndroid Build Coastguard Worker       png_set_expand_16(png_ptr);
1210*a67afe4dSAndroid Build Coastguard Worker #else
1211*a67afe4dSAndroid Build Coastguard Worker       png_app_error(png_ptr, "PNG_TRANSFORM_EXPAND_16 not supported");
1212*a67afe4dSAndroid Build Coastguard Worker #endif
1213*a67afe4dSAndroid Build Coastguard Worker 
1214*a67afe4dSAndroid Build Coastguard Worker    /* We don't handle adding filler bytes */
1215*a67afe4dSAndroid Build Coastguard Worker 
1216*a67afe4dSAndroid Build Coastguard Worker    /* We use png_read_image and rely on that for interlace handling, but we also
1217*a67afe4dSAndroid Build Coastguard Worker     * call png_read_update_info therefore must turn on interlace handling now:
1218*a67afe4dSAndroid Build Coastguard Worker     */
1219*a67afe4dSAndroid Build Coastguard Worker    (void)png_set_interlace_handling(png_ptr);
1220*a67afe4dSAndroid Build Coastguard Worker 
1221*a67afe4dSAndroid Build Coastguard Worker    /* Optional call to gamma correct and add the background to the palette
1222*a67afe4dSAndroid Build Coastguard Worker     * and update info structure.  REQUIRED if you are expecting libpng to
1223*a67afe4dSAndroid Build Coastguard Worker     * update the palette for you (i.e., you selected such a transform above).
1224*a67afe4dSAndroid Build Coastguard Worker     */
1225*a67afe4dSAndroid Build Coastguard Worker    png_read_update_info(png_ptr, info_ptr);
1226*a67afe4dSAndroid Build Coastguard Worker 
1227*a67afe4dSAndroid Build Coastguard Worker    /* -------------- image transformations end here ------------------- */
1228*a67afe4dSAndroid Build Coastguard Worker 
1229*a67afe4dSAndroid Build Coastguard Worker    png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
1230*a67afe4dSAndroid Build Coastguard Worker    if (info_ptr->row_pointers == NULL)
1231*a67afe4dSAndroid Build Coastguard Worker    {
1232*a67afe4dSAndroid Build Coastguard Worker       png_uint_32 iptr;
1233*a67afe4dSAndroid Build Coastguard Worker 
1234*a67afe4dSAndroid Build Coastguard Worker       info_ptr->row_pointers = png_voidcast(png_bytepp, png_malloc(png_ptr,
1235*a67afe4dSAndroid Build Coastguard Worker           info_ptr->height * (sizeof (png_bytep))));
1236*a67afe4dSAndroid Build Coastguard Worker 
1237*a67afe4dSAndroid Build Coastguard Worker       for (iptr=0; iptr<info_ptr->height; iptr++)
1238*a67afe4dSAndroid Build Coastguard Worker          info_ptr->row_pointers[iptr] = NULL;
1239*a67afe4dSAndroid Build Coastguard Worker 
1240*a67afe4dSAndroid Build Coastguard Worker       info_ptr->free_me |= PNG_FREE_ROWS;
1241*a67afe4dSAndroid Build Coastguard Worker 
1242*a67afe4dSAndroid Build Coastguard Worker       for (iptr = 0; iptr < info_ptr->height; iptr++)
1243*a67afe4dSAndroid Build Coastguard Worker          info_ptr->row_pointers[iptr] = png_voidcast(png_bytep,
1244*a67afe4dSAndroid Build Coastguard Worker              png_malloc(png_ptr, info_ptr->rowbytes));
1245*a67afe4dSAndroid Build Coastguard Worker    }
1246*a67afe4dSAndroid Build Coastguard Worker 
1247*a67afe4dSAndroid Build Coastguard Worker    png_read_image(png_ptr, info_ptr->row_pointers);
1248*a67afe4dSAndroid Build Coastguard Worker    info_ptr->valid |= PNG_INFO_IDAT;
1249*a67afe4dSAndroid Build Coastguard Worker 
1250*a67afe4dSAndroid Build Coastguard Worker    /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */
1251*a67afe4dSAndroid Build Coastguard Worker    png_read_end(png_ptr, info_ptr);
1252*a67afe4dSAndroid Build Coastguard Worker 
1253*a67afe4dSAndroid Build Coastguard Worker    PNG_UNUSED(params)
1254*a67afe4dSAndroid Build Coastguard Worker }
1255*a67afe4dSAndroid Build Coastguard Worker #endif /* INFO_IMAGE */
1256*a67afe4dSAndroid Build Coastguard Worker #endif /* SEQUENTIAL_READ */
1257*a67afe4dSAndroid Build Coastguard Worker 
1258*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_SIMPLIFIED_READ_SUPPORTED
1259*a67afe4dSAndroid Build Coastguard Worker /* SIMPLIFIED READ
1260*a67afe4dSAndroid Build Coastguard Worker  *
1261*a67afe4dSAndroid Build Coastguard Worker  * This code currently relies on the sequential reader, though it could easily
1262*a67afe4dSAndroid Build Coastguard Worker  * be made to work with the progressive one.
1263*a67afe4dSAndroid Build Coastguard Worker  */
1264*a67afe4dSAndroid Build Coastguard Worker /* Arguments to png_image_finish_read: */
1265*a67afe4dSAndroid Build Coastguard Worker 
1266*a67afe4dSAndroid Build Coastguard Worker /* Encoding of PNG data (used by the color-map code) */
1267*a67afe4dSAndroid Build Coastguard Worker #  define P_NOTSET  0 /* File encoding not yet known */
1268*a67afe4dSAndroid Build Coastguard Worker #  define P_sRGB    1 /* 8-bit encoded to sRGB gamma */
1269*a67afe4dSAndroid Build Coastguard Worker #  define P_LINEAR  2 /* 16-bit linear: not encoded, NOT pre-multiplied! */
1270*a67afe4dSAndroid Build Coastguard Worker #  define P_FILE    3 /* 8-bit encoded to file gamma, not sRGB or linear */
1271*a67afe4dSAndroid Build Coastguard Worker #  define P_LINEAR8 4 /* 8-bit linear: only from a file value */
1272*a67afe4dSAndroid Build Coastguard Worker 
1273*a67afe4dSAndroid Build Coastguard Worker /* Color-map processing: after libpng has run on the PNG image further
1274*a67afe4dSAndroid Build Coastguard Worker  * processing may be needed to convert the data to color-map indices.
1275*a67afe4dSAndroid Build Coastguard Worker  */
1276*a67afe4dSAndroid Build Coastguard Worker #define PNG_CMAP_NONE      0
1277*a67afe4dSAndroid Build Coastguard Worker #define PNG_CMAP_GA        1 /* Process GA data to a color-map with alpha */
1278*a67afe4dSAndroid Build Coastguard Worker #define PNG_CMAP_TRANS     2 /* Process GA data to a background index */
1279*a67afe4dSAndroid Build Coastguard Worker #define PNG_CMAP_RGB       3 /* Process RGB data */
1280*a67afe4dSAndroid Build Coastguard Worker #define PNG_CMAP_RGB_ALPHA 4 /* Process RGBA data */
1281*a67afe4dSAndroid Build Coastguard Worker 
1282*a67afe4dSAndroid Build Coastguard Worker /* The following document where the background is for each processing case. */
1283*a67afe4dSAndroid Build Coastguard Worker #define PNG_CMAP_NONE_BACKGROUND      256
1284*a67afe4dSAndroid Build Coastguard Worker #define PNG_CMAP_GA_BACKGROUND        231
1285*a67afe4dSAndroid Build Coastguard Worker #define PNG_CMAP_TRANS_BACKGROUND     254
1286*a67afe4dSAndroid Build Coastguard Worker #define PNG_CMAP_RGB_BACKGROUND       256
1287*a67afe4dSAndroid Build Coastguard Worker #define PNG_CMAP_RGB_ALPHA_BACKGROUND 216
1288*a67afe4dSAndroid Build Coastguard Worker 
1289*a67afe4dSAndroid Build Coastguard Worker typedef struct
1290*a67afe4dSAndroid Build Coastguard Worker {
1291*a67afe4dSAndroid Build Coastguard Worker    /* Arguments: */
1292*a67afe4dSAndroid Build Coastguard Worker    png_imagep image;
1293*a67afe4dSAndroid Build Coastguard Worker    png_voidp  buffer;
1294*a67afe4dSAndroid Build Coastguard Worker    png_int_32 row_stride;
1295*a67afe4dSAndroid Build Coastguard Worker    png_voidp  colormap;
1296*a67afe4dSAndroid Build Coastguard Worker    png_const_colorp background;
1297*a67afe4dSAndroid Build Coastguard Worker    /* Local variables: */
1298*a67afe4dSAndroid Build Coastguard Worker    png_voidp       local_row;
1299*a67afe4dSAndroid Build Coastguard Worker    png_voidp       first_row;
1300*a67afe4dSAndroid Build Coastguard Worker    ptrdiff_t       row_bytes;           /* step between rows */
1301*a67afe4dSAndroid Build Coastguard Worker    int             file_encoding;       /* E_ values above */
1302*a67afe4dSAndroid Build Coastguard Worker    png_fixed_point gamma_to_linear;     /* For P_FILE, reciprocal of gamma */
1303*a67afe4dSAndroid Build Coastguard Worker    int             colormap_processing; /* PNG_CMAP_ values above */
1304*a67afe4dSAndroid Build Coastguard Worker } png_image_read_control;
1305*a67afe4dSAndroid Build Coastguard Worker 
1306*a67afe4dSAndroid Build Coastguard Worker /* Do all the *safe* initialization - 'safe' means that png_error won't be
1307*a67afe4dSAndroid Build Coastguard Worker  * called, so setting up the jmp_buf is not required.  This means that anything
1308*a67afe4dSAndroid Build Coastguard Worker  * called from here must *not* call png_malloc - it has to call png_malloc_warn
1309*a67afe4dSAndroid Build Coastguard Worker  * instead so that control is returned safely back to this routine.
1310*a67afe4dSAndroid Build Coastguard Worker  */
1311*a67afe4dSAndroid Build Coastguard Worker static int
png_image_read_init(png_imagep image)1312*a67afe4dSAndroid Build Coastguard Worker png_image_read_init(png_imagep image)
1313*a67afe4dSAndroid Build Coastguard Worker {
1314*a67afe4dSAndroid Build Coastguard Worker    if (image->opaque == NULL)
1315*a67afe4dSAndroid Build Coastguard Worker    {
1316*a67afe4dSAndroid Build Coastguard Worker       png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, image,
1317*a67afe4dSAndroid Build Coastguard Worker           png_safe_error, png_safe_warning);
1318*a67afe4dSAndroid Build Coastguard Worker 
1319*a67afe4dSAndroid Build Coastguard Worker       /* And set the rest of the structure to NULL to ensure that the various
1320*a67afe4dSAndroid Build Coastguard Worker        * fields are consistent.
1321*a67afe4dSAndroid Build Coastguard Worker        */
1322*a67afe4dSAndroid Build Coastguard Worker       memset(image, 0, (sizeof *image));
1323*a67afe4dSAndroid Build Coastguard Worker       image->version = PNG_IMAGE_VERSION;
1324*a67afe4dSAndroid Build Coastguard Worker 
1325*a67afe4dSAndroid Build Coastguard Worker       if (png_ptr != NULL)
1326*a67afe4dSAndroid Build Coastguard Worker       {
1327*a67afe4dSAndroid Build Coastguard Worker          png_infop info_ptr = png_create_info_struct(png_ptr);
1328*a67afe4dSAndroid Build Coastguard Worker 
1329*a67afe4dSAndroid Build Coastguard Worker          if (info_ptr != NULL)
1330*a67afe4dSAndroid Build Coastguard Worker          {
1331*a67afe4dSAndroid Build Coastguard Worker             png_controlp control = png_voidcast(png_controlp,
1332*a67afe4dSAndroid Build Coastguard Worker                 png_malloc_warn(png_ptr, (sizeof *control)));
1333*a67afe4dSAndroid Build Coastguard Worker 
1334*a67afe4dSAndroid Build Coastguard Worker             if (control != NULL)
1335*a67afe4dSAndroid Build Coastguard Worker             {
1336*a67afe4dSAndroid Build Coastguard Worker                memset(control, 0, (sizeof *control));
1337*a67afe4dSAndroid Build Coastguard Worker 
1338*a67afe4dSAndroid Build Coastguard Worker                control->png_ptr = png_ptr;
1339*a67afe4dSAndroid Build Coastguard Worker                control->info_ptr = info_ptr;
1340*a67afe4dSAndroid Build Coastguard Worker                control->for_write = 0;
1341*a67afe4dSAndroid Build Coastguard Worker 
1342*a67afe4dSAndroid Build Coastguard Worker                image->opaque = control;
1343*a67afe4dSAndroid Build Coastguard Worker                return 1;
1344*a67afe4dSAndroid Build Coastguard Worker             }
1345*a67afe4dSAndroid Build Coastguard Worker 
1346*a67afe4dSAndroid Build Coastguard Worker             /* Error clean up */
1347*a67afe4dSAndroid Build Coastguard Worker             png_destroy_info_struct(png_ptr, &info_ptr);
1348*a67afe4dSAndroid Build Coastguard Worker          }
1349*a67afe4dSAndroid Build Coastguard Worker 
1350*a67afe4dSAndroid Build Coastguard Worker          png_destroy_read_struct(&png_ptr, NULL, NULL);
1351*a67afe4dSAndroid Build Coastguard Worker       }
1352*a67afe4dSAndroid Build Coastguard Worker 
1353*a67afe4dSAndroid Build Coastguard Worker       return png_image_error(image, "png_image_read: out of memory");
1354*a67afe4dSAndroid Build Coastguard Worker    }
1355*a67afe4dSAndroid Build Coastguard Worker 
1356*a67afe4dSAndroid Build Coastguard Worker    return png_image_error(image, "png_image_read: opaque pointer not NULL");
1357*a67afe4dSAndroid Build Coastguard Worker }
1358*a67afe4dSAndroid Build Coastguard Worker 
1359*a67afe4dSAndroid Build Coastguard Worker /* Utility to find the base format of a PNG file from a png_struct. */
1360*a67afe4dSAndroid Build Coastguard Worker static png_uint_32
png_image_format(png_structrp png_ptr)1361*a67afe4dSAndroid Build Coastguard Worker png_image_format(png_structrp png_ptr)
1362*a67afe4dSAndroid Build Coastguard Worker {
1363*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 format = 0;
1364*a67afe4dSAndroid Build Coastguard Worker 
1365*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
1366*a67afe4dSAndroid Build Coastguard Worker       format |= PNG_FORMAT_FLAG_COLOR;
1367*a67afe4dSAndroid Build Coastguard Worker 
1368*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)
1369*a67afe4dSAndroid Build Coastguard Worker       format |= PNG_FORMAT_FLAG_ALPHA;
1370*a67afe4dSAndroid Build Coastguard Worker 
1371*a67afe4dSAndroid Build Coastguard Worker    /* Use png_ptr here, not info_ptr, because by examination png_handle_tRNS
1372*a67afe4dSAndroid Build Coastguard Worker     * sets the png_struct fields; that's all we are interested in here.  The
1373*a67afe4dSAndroid Build Coastguard Worker     * precise interaction with an app call to png_set_tRNS and PNG file reading
1374*a67afe4dSAndroid Build Coastguard Worker     * is unclear.
1375*a67afe4dSAndroid Build Coastguard Worker     */
1376*a67afe4dSAndroid Build Coastguard Worker    else if (png_ptr->num_trans > 0)
1377*a67afe4dSAndroid Build Coastguard Worker       format |= PNG_FORMAT_FLAG_ALPHA;
1378*a67afe4dSAndroid Build Coastguard Worker 
1379*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr->bit_depth == 16)
1380*a67afe4dSAndroid Build Coastguard Worker       format |= PNG_FORMAT_FLAG_LINEAR;
1381*a67afe4dSAndroid Build Coastguard Worker 
1382*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->color_type & PNG_COLOR_MASK_PALETTE) != 0)
1383*a67afe4dSAndroid Build Coastguard Worker       format |= PNG_FORMAT_FLAG_COLORMAP;
1384*a67afe4dSAndroid Build Coastguard Worker 
1385*a67afe4dSAndroid Build Coastguard Worker    return format;
1386*a67afe4dSAndroid Build Coastguard Worker }
1387*a67afe4dSAndroid Build Coastguard Worker 
1388*a67afe4dSAndroid Build Coastguard Worker /* Is the given gamma significantly different from sRGB?  The test is the same
1389*a67afe4dSAndroid Build Coastguard Worker  * one used in pngrtran.c when deciding whether to do gamma correction.  The
1390*a67afe4dSAndroid Build Coastguard Worker  * arithmetic optimizes the division by using the fact that the inverse of the
1391*a67afe4dSAndroid Build Coastguard Worker  * file sRGB gamma is 2.2
1392*a67afe4dSAndroid Build Coastguard Worker  */
1393*a67afe4dSAndroid Build Coastguard Worker static int
png_gamma_not_sRGB(png_fixed_point g)1394*a67afe4dSAndroid Build Coastguard Worker png_gamma_not_sRGB(png_fixed_point g)
1395*a67afe4dSAndroid Build Coastguard Worker {
1396*a67afe4dSAndroid Build Coastguard Worker    if (g < PNG_FP_1)
1397*a67afe4dSAndroid Build Coastguard Worker    {
1398*a67afe4dSAndroid Build Coastguard Worker       /* An uninitialized gamma is assumed to be sRGB for the simplified API. */
1399*a67afe4dSAndroid Build Coastguard Worker       if (g == 0)
1400*a67afe4dSAndroid Build Coastguard Worker          return 0;
1401*a67afe4dSAndroid Build Coastguard Worker 
1402*a67afe4dSAndroid Build Coastguard Worker       return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */);
1403*a67afe4dSAndroid Build Coastguard Worker    }
1404*a67afe4dSAndroid Build Coastguard Worker 
1405*a67afe4dSAndroid Build Coastguard Worker    return 1;
1406*a67afe4dSAndroid Build Coastguard Worker }
1407*a67afe4dSAndroid Build Coastguard Worker 
1408*a67afe4dSAndroid Build Coastguard Worker /* Do the main body of a 'png_image_begin_read' function; read the PNG file
1409*a67afe4dSAndroid Build Coastguard Worker  * header and fill in all the information.  This is executed in a safe context,
1410*a67afe4dSAndroid Build Coastguard Worker  * unlike the init routine above.
1411*a67afe4dSAndroid Build Coastguard Worker  */
1412*a67afe4dSAndroid Build Coastguard Worker static int
png_image_read_header(png_voidp argument)1413*a67afe4dSAndroid Build Coastguard Worker png_image_read_header(png_voidp argument)
1414*a67afe4dSAndroid Build Coastguard Worker {
1415*a67afe4dSAndroid Build Coastguard Worker    png_imagep image = png_voidcast(png_imagep, argument);
1416*a67afe4dSAndroid Build Coastguard Worker    png_structrp png_ptr = image->opaque->png_ptr;
1417*a67afe4dSAndroid Build Coastguard Worker    png_inforp info_ptr = image->opaque->info_ptr;
1418*a67afe4dSAndroid Build Coastguard Worker 
1419*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_BENIGN_ERRORS_SUPPORTED
1420*a67afe4dSAndroid Build Coastguard Worker    png_set_benign_errors(png_ptr, 1/*warn*/);
1421*a67afe4dSAndroid Build Coastguard Worker #endif
1422*a67afe4dSAndroid Build Coastguard Worker    png_read_info(png_ptr, info_ptr);
1423*a67afe4dSAndroid Build Coastguard Worker 
1424*a67afe4dSAndroid Build Coastguard Worker    /* Do this the fast way; just read directly out of png_struct. */
1425*a67afe4dSAndroid Build Coastguard Worker    image->width = png_ptr->width;
1426*a67afe4dSAndroid Build Coastguard Worker    image->height = png_ptr->height;
1427*a67afe4dSAndroid Build Coastguard Worker 
1428*a67afe4dSAndroid Build Coastguard Worker    {
1429*a67afe4dSAndroid Build Coastguard Worker       png_uint_32 format = png_image_format(png_ptr);
1430*a67afe4dSAndroid Build Coastguard Worker 
1431*a67afe4dSAndroid Build Coastguard Worker       image->format = format;
1432*a67afe4dSAndroid Build Coastguard Worker 
1433*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_COLORSPACE_SUPPORTED
1434*a67afe4dSAndroid Build Coastguard Worker       /* Does the colorspace match sRGB?  If there is no color endpoint
1435*a67afe4dSAndroid Build Coastguard Worker        * (colorant) information assume yes, otherwise require the
1436*a67afe4dSAndroid Build Coastguard Worker        * 'ENDPOINTS_MATCHP_sRGB' colorspace flag to have been set.  If the
1437*a67afe4dSAndroid Build Coastguard Worker        * colorspace has been determined to be invalid ignore it.
1438*a67afe4dSAndroid Build Coastguard Worker        */
1439*a67afe4dSAndroid Build Coastguard Worker       if ((format & PNG_FORMAT_FLAG_COLOR) != 0 && ((png_ptr->colorspace.flags
1440*a67afe4dSAndroid Build Coastguard Worker          & (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB|
1441*a67afe4dSAndroid Build Coastguard Worker             PNG_COLORSPACE_INVALID)) == PNG_COLORSPACE_HAVE_ENDPOINTS))
1442*a67afe4dSAndroid Build Coastguard Worker          image->flags |= PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB;
1443*a67afe4dSAndroid Build Coastguard Worker #endif
1444*a67afe4dSAndroid Build Coastguard Worker    }
1445*a67afe4dSAndroid Build Coastguard Worker 
1446*a67afe4dSAndroid Build Coastguard Worker    /* We need the maximum number of entries regardless of the format the
1447*a67afe4dSAndroid Build Coastguard Worker     * application sets here.
1448*a67afe4dSAndroid Build Coastguard Worker     */
1449*a67afe4dSAndroid Build Coastguard Worker    {
1450*a67afe4dSAndroid Build Coastguard Worker       png_uint_32 cmap_entries;
1451*a67afe4dSAndroid Build Coastguard Worker 
1452*a67afe4dSAndroid Build Coastguard Worker       switch (png_ptr->color_type)
1453*a67afe4dSAndroid Build Coastguard Worker       {
1454*a67afe4dSAndroid Build Coastguard Worker          case PNG_COLOR_TYPE_GRAY:
1455*a67afe4dSAndroid Build Coastguard Worker             cmap_entries = 1U << png_ptr->bit_depth;
1456*a67afe4dSAndroid Build Coastguard Worker             break;
1457*a67afe4dSAndroid Build Coastguard Worker 
1458*a67afe4dSAndroid Build Coastguard Worker          case PNG_COLOR_TYPE_PALETTE:
1459*a67afe4dSAndroid Build Coastguard Worker             cmap_entries = (png_uint_32)png_ptr->num_palette;
1460*a67afe4dSAndroid Build Coastguard Worker             break;
1461*a67afe4dSAndroid Build Coastguard Worker 
1462*a67afe4dSAndroid Build Coastguard Worker          default:
1463*a67afe4dSAndroid Build Coastguard Worker             cmap_entries = 256;
1464*a67afe4dSAndroid Build Coastguard Worker             break;
1465*a67afe4dSAndroid Build Coastguard Worker       }
1466*a67afe4dSAndroid Build Coastguard Worker 
1467*a67afe4dSAndroid Build Coastguard Worker       if (cmap_entries > 256)
1468*a67afe4dSAndroid Build Coastguard Worker          cmap_entries = 256;
1469*a67afe4dSAndroid Build Coastguard Worker 
1470*a67afe4dSAndroid Build Coastguard Worker       image->colormap_entries = cmap_entries;
1471*a67afe4dSAndroid Build Coastguard Worker    }
1472*a67afe4dSAndroid Build Coastguard Worker 
1473*a67afe4dSAndroid Build Coastguard Worker    return 1;
1474*a67afe4dSAndroid Build Coastguard Worker }
1475*a67afe4dSAndroid Build Coastguard Worker 
1476*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_STDIO_SUPPORTED
1477*a67afe4dSAndroid Build Coastguard Worker int PNGAPI
png_image_begin_read_from_stdio(png_imagep image,FILE * file)1478*a67afe4dSAndroid Build Coastguard Worker png_image_begin_read_from_stdio(png_imagep image, FILE* file)
1479*a67afe4dSAndroid Build Coastguard Worker {
1480*a67afe4dSAndroid Build Coastguard Worker    if (image != NULL && image->version == PNG_IMAGE_VERSION)
1481*a67afe4dSAndroid Build Coastguard Worker    {
1482*a67afe4dSAndroid Build Coastguard Worker       if (file != NULL)
1483*a67afe4dSAndroid Build Coastguard Worker       {
1484*a67afe4dSAndroid Build Coastguard Worker          if (png_image_read_init(image) != 0)
1485*a67afe4dSAndroid Build Coastguard Worker          {
1486*a67afe4dSAndroid Build Coastguard Worker             /* This is slightly evil, but png_init_io doesn't do anything other
1487*a67afe4dSAndroid Build Coastguard Worker              * than this and we haven't changed the standard IO functions so
1488*a67afe4dSAndroid Build Coastguard Worker              * this saves a 'safe' function.
1489*a67afe4dSAndroid Build Coastguard Worker              */
1490*a67afe4dSAndroid Build Coastguard Worker             image->opaque->png_ptr->io_ptr = file;
1491*a67afe4dSAndroid Build Coastguard Worker             return png_safe_execute(image, png_image_read_header, image);
1492*a67afe4dSAndroid Build Coastguard Worker          }
1493*a67afe4dSAndroid Build Coastguard Worker       }
1494*a67afe4dSAndroid Build Coastguard Worker 
1495*a67afe4dSAndroid Build Coastguard Worker       else
1496*a67afe4dSAndroid Build Coastguard Worker          return png_image_error(image,
1497*a67afe4dSAndroid Build Coastguard Worker              "png_image_begin_read_from_stdio: invalid argument");
1498*a67afe4dSAndroid Build Coastguard Worker    }
1499*a67afe4dSAndroid Build Coastguard Worker 
1500*a67afe4dSAndroid Build Coastguard Worker    else if (image != NULL)
1501*a67afe4dSAndroid Build Coastguard Worker       return png_image_error(image,
1502*a67afe4dSAndroid Build Coastguard Worker           "png_image_begin_read_from_stdio: incorrect PNG_IMAGE_VERSION");
1503*a67afe4dSAndroid Build Coastguard Worker 
1504*a67afe4dSAndroid Build Coastguard Worker    return 0;
1505*a67afe4dSAndroid Build Coastguard Worker }
1506*a67afe4dSAndroid Build Coastguard Worker 
1507*a67afe4dSAndroid Build Coastguard Worker int PNGAPI
png_image_begin_read_from_file(png_imagep image,const char * file_name)1508*a67afe4dSAndroid Build Coastguard Worker png_image_begin_read_from_file(png_imagep image, const char *file_name)
1509*a67afe4dSAndroid Build Coastguard Worker {
1510*a67afe4dSAndroid Build Coastguard Worker    if (image != NULL && image->version == PNG_IMAGE_VERSION)
1511*a67afe4dSAndroid Build Coastguard Worker    {
1512*a67afe4dSAndroid Build Coastguard Worker       if (file_name != NULL)
1513*a67afe4dSAndroid Build Coastguard Worker       {
1514*a67afe4dSAndroid Build Coastguard Worker          FILE *fp = fopen(file_name, "rb");
1515*a67afe4dSAndroid Build Coastguard Worker 
1516*a67afe4dSAndroid Build Coastguard Worker          if (fp != NULL)
1517*a67afe4dSAndroid Build Coastguard Worker          {
1518*a67afe4dSAndroid Build Coastguard Worker             if (png_image_read_init(image) != 0)
1519*a67afe4dSAndroid Build Coastguard Worker             {
1520*a67afe4dSAndroid Build Coastguard Worker                image->opaque->png_ptr->io_ptr = fp;
1521*a67afe4dSAndroid Build Coastguard Worker                image->opaque->owned_file = 1;
1522*a67afe4dSAndroid Build Coastguard Worker                return png_safe_execute(image, png_image_read_header, image);
1523*a67afe4dSAndroid Build Coastguard Worker             }
1524*a67afe4dSAndroid Build Coastguard Worker 
1525*a67afe4dSAndroid Build Coastguard Worker             /* Clean up: just the opened file. */
1526*a67afe4dSAndroid Build Coastguard Worker             (void)fclose(fp);
1527*a67afe4dSAndroid Build Coastguard Worker          }
1528*a67afe4dSAndroid Build Coastguard Worker 
1529*a67afe4dSAndroid Build Coastguard Worker          else
1530*a67afe4dSAndroid Build Coastguard Worker             return png_image_error(image, strerror(errno));
1531*a67afe4dSAndroid Build Coastguard Worker       }
1532*a67afe4dSAndroid Build Coastguard Worker 
1533*a67afe4dSAndroid Build Coastguard Worker       else
1534*a67afe4dSAndroid Build Coastguard Worker          return png_image_error(image,
1535*a67afe4dSAndroid Build Coastguard Worker              "png_image_begin_read_from_file: invalid argument");
1536*a67afe4dSAndroid Build Coastguard Worker    }
1537*a67afe4dSAndroid Build Coastguard Worker 
1538*a67afe4dSAndroid Build Coastguard Worker    else if (image != NULL)
1539*a67afe4dSAndroid Build Coastguard Worker       return png_image_error(image,
1540*a67afe4dSAndroid Build Coastguard Worker           "png_image_begin_read_from_file: incorrect PNG_IMAGE_VERSION");
1541*a67afe4dSAndroid Build Coastguard Worker 
1542*a67afe4dSAndroid Build Coastguard Worker    return 0;
1543*a67afe4dSAndroid Build Coastguard Worker }
1544*a67afe4dSAndroid Build Coastguard Worker #endif /* STDIO */
1545*a67afe4dSAndroid Build Coastguard Worker 
1546*a67afe4dSAndroid Build Coastguard Worker static void PNGCBAPI
png_image_memory_read(png_structp png_ptr,png_bytep out,size_t need)1547*a67afe4dSAndroid Build Coastguard Worker png_image_memory_read(png_structp png_ptr, png_bytep out, size_t need)
1548*a67afe4dSAndroid Build Coastguard Worker {
1549*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr != NULL)
1550*a67afe4dSAndroid Build Coastguard Worker    {
1551*a67afe4dSAndroid Build Coastguard Worker       png_imagep image = png_voidcast(png_imagep, png_ptr->io_ptr);
1552*a67afe4dSAndroid Build Coastguard Worker       if (image != NULL)
1553*a67afe4dSAndroid Build Coastguard Worker       {
1554*a67afe4dSAndroid Build Coastguard Worker          png_controlp cp = image->opaque;
1555*a67afe4dSAndroid Build Coastguard Worker          if (cp != NULL)
1556*a67afe4dSAndroid Build Coastguard Worker          {
1557*a67afe4dSAndroid Build Coastguard Worker             png_const_bytep memory = cp->memory;
1558*a67afe4dSAndroid Build Coastguard Worker             size_t size = cp->size;
1559*a67afe4dSAndroid Build Coastguard Worker 
1560*a67afe4dSAndroid Build Coastguard Worker             if (memory != NULL && size >= need)
1561*a67afe4dSAndroid Build Coastguard Worker             {
1562*a67afe4dSAndroid Build Coastguard Worker                memcpy(out, memory, need);
1563*a67afe4dSAndroid Build Coastguard Worker                cp->memory = memory + need;
1564*a67afe4dSAndroid Build Coastguard Worker                cp->size = size - need;
1565*a67afe4dSAndroid Build Coastguard Worker                return;
1566*a67afe4dSAndroid Build Coastguard Worker             }
1567*a67afe4dSAndroid Build Coastguard Worker 
1568*a67afe4dSAndroid Build Coastguard Worker             png_error(png_ptr, "read beyond end of data");
1569*a67afe4dSAndroid Build Coastguard Worker          }
1570*a67afe4dSAndroid Build Coastguard Worker       }
1571*a67afe4dSAndroid Build Coastguard Worker 
1572*a67afe4dSAndroid Build Coastguard Worker       png_error(png_ptr, "invalid memory read");
1573*a67afe4dSAndroid Build Coastguard Worker    }
1574*a67afe4dSAndroid Build Coastguard Worker }
1575*a67afe4dSAndroid Build Coastguard Worker 
png_image_begin_read_from_memory(png_imagep image,png_const_voidp memory,size_t size)1576*a67afe4dSAndroid Build Coastguard Worker int PNGAPI png_image_begin_read_from_memory(png_imagep image,
1577*a67afe4dSAndroid Build Coastguard Worker     png_const_voidp memory, size_t size)
1578*a67afe4dSAndroid Build Coastguard Worker {
1579*a67afe4dSAndroid Build Coastguard Worker    if (image != NULL && image->version == PNG_IMAGE_VERSION)
1580*a67afe4dSAndroid Build Coastguard Worker    {
1581*a67afe4dSAndroid Build Coastguard Worker       if (memory != NULL && size > 0)
1582*a67afe4dSAndroid Build Coastguard Worker       {
1583*a67afe4dSAndroid Build Coastguard Worker          if (png_image_read_init(image) != 0)
1584*a67afe4dSAndroid Build Coastguard Worker          {
1585*a67afe4dSAndroid Build Coastguard Worker             /* Now set the IO functions to read from the memory buffer and
1586*a67afe4dSAndroid Build Coastguard Worker              * store it into io_ptr.  Again do this in-place to avoid calling a
1587*a67afe4dSAndroid Build Coastguard Worker              * libpng function that requires error handling.
1588*a67afe4dSAndroid Build Coastguard Worker              */
1589*a67afe4dSAndroid Build Coastguard Worker             image->opaque->memory = png_voidcast(png_const_bytep, memory);
1590*a67afe4dSAndroid Build Coastguard Worker             image->opaque->size = size;
1591*a67afe4dSAndroid Build Coastguard Worker             image->opaque->png_ptr->io_ptr = image;
1592*a67afe4dSAndroid Build Coastguard Worker             image->opaque->png_ptr->read_data_fn = png_image_memory_read;
1593*a67afe4dSAndroid Build Coastguard Worker 
1594*a67afe4dSAndroid Build Coastguard Worker             return png_safe_execute(image, png_image_read_header, image);
1595*a67afe4dSAndroid Build Coastguard Worker          }
1596*a67afe4dSAndroid Build Coastguard Worker       }
1597*a67afe4dSAndroid Build Coastguard Worker 
1598*a67afe4dSAndroid Build Coastguard Worker       else
1599*a67afe4dSAndroid Build Coastguard Worker          return png_image_error(image,
1600*a67afe4dSAndroid Build Coastguard Worker              "png_image_begin_read_from_memory: invalid argument");
1601*a67afe4dSAndroid Build Coastguard Worker    }
1602*a67afe4dSAndroid Build Coastguard Worker 
1603*a67afe4dSAndroid Build Coastguard Worker    else if (image != NULL)
1604*a67afe4dSAndroid Build Coastguard Worker       return png_image_error(image,
1605*a67afe4dSAndroid Build Coastguard Worker           "png_image_begin_read_from_memory: incorrect PNG_IMAGE_VERSION");
1606*a67afe4dSAndroid Build Coastguard Worker 
1607*a67afe4dSAndroid Build Coastguard Worker    return 0;
1608*a67afe4dSAndroid Build Coastguard Worker }
1609*a67afe4dSAndroid Build Coastguard Worker 
1610*a67afe4dSAndroid Build Coastguard Worker /* Utility function to skip chunks that are not used by the simplified image
1611*a67afe4dSAndroid Build Coastguard Worker  * read functions and an appropriate macro to call it.
1612*a67afe4dSAndroid Build Coastguard Worker  */
1613*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
1614*a67afe4dSAndroid Build Coastguard Worker static void
png_image_skip_unused_chunks(png_structrp png_ptr)1615*a67afe4dSAndroid Build Coastguard Worker png_image_skip_unused_chunks(png_structrp png_ptr)
1616*a67afe4dSAndroid Build Coastguard Worker {
1617*a67afe4dSAndroid Build Coastguard Worker    /* Prepare the reader to ignore all recognized chunks whose data will not
1618*a67afe4dSAndroid Build Coastguard Worker     * be used, i.e., all chunks recognized by libpng except for those
1619*a67afe4dSAndroid Build Coastguard Worker     * involved in basic image reading:
1620*a67afe4dSAndroid Build Coastguard Worker     *
1621*a67afe4dSAndroid Build Coastguard Worker     *    IHDR, PLTE, IDAT, IEND
1622*a67afe4dSAndroid Build Coastguard Worker     *
1623*a67afe4dSAndroid Build Coastguard Worker     * Or image data handling:
1624*a67afe4dSAndroid Build Coastguard Worker     *
1625*a67afe4dSAndroid Build Coastguard Worker     *    tRNS, bKGD, gAMA, cHRM, sRGB, [iCCP] and sBIT.
1626*a67afe4dSAndroid Build Coastguard Worker     *
1627*a67afe4dSAndroid Build Coastguard Worker     * This provides a small performance improvement and eliminates any
1628*a67afe4dSAndroid Build Coastguard Worker     * potential vulnerability to security problems in the unused chunks.
1629*a67afe4dSAndroid Build Coastguard Worker     *
1630*a67afe4dSAndroid Build Coastguard Worker     * At present the iCCP chunk data isn't used, so iCCP chunk can be ignored
1631*a67afe4dSAndroid Build Coastguard Worker     * too.  This allows the simplified API to be compiled without iCCP support,
1632*a67afe4dSAndroid Build Coastguard Worker     * however if the support is there the chunk is still checked to detect
1633*a67afe4dSAndroid Build Coastguard Worker     * errors (which are unfortunately quite common.)
1634*a67afe4dSAndroid Build Coastguard Worker     */
1635*a67afe4dSAndroid Build Coastguard Worker    {
1636*a67afe4dSAndroid Build Coastguard Worker          static const png_byte chunks_to_process[] = {
1637*a67afe4dSAndroid Build Coastguard Worker             98,  75,  71,  68, '\0',  /* bKGD */
1638*a67afe4dSAndroid Build Coastguard Worker             99,  72,  82,  77, '\0',  /* cHRM */
1639*a67afe4dSAndroid Build Coastguard Worker            103,  65,  77,  65, '\0',  /* gAMA */
1640*a67afe4dSAndroid Build Coastguard Worker #        ifdef PNG_READ_iCCP_SUPPORTED
1641*a67afe4dSAndroid Build Coastguard Worker            105,  67,  67,  80, '\0',  /* iCCP */
1642*a67afe4dSAndroid Build Coastguard Worker #        endif
1643*a67afe4dSAndroid Build Coastguard Worker            115,  66,  73,  84, '\0',  /* sBIT */
1644*a67afe4dSAndroid Build Coastguard Worker            115,  82,  71,  66, '\0',  /* sRGB */
1645*a67afe4dSAndroid Build Coastguard Worker            };
1646*a67afe4dSAndroid Build Coastguard Worker 
1647*a67afe4dSAndroid Build Coastguard Worker        /* Ignore unknown chunks and all other chunks except for the
1648*a67afe4dSAndroid Build Coastguard Worker         * IHDR, PLTE, tRNS, IDAT, and IEND chunks.
1649*a67afe4dSAndroid Build Coastguard Worker         */
1650*a67afe4dSAndroid Build Coastguard Worker        png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER,
1651*a67afe4dSAndroid Build Coastguard Worker            NULL, -1);
1652*a67afe4dSAndroid Build Coastguard Worker 
1653*a67afe4dSAndroid Build Coastguard Worker        /* But do not ignore image data handling chunks */
1654*a67afe4dSAndroid Build Coastguard Worker        png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_AS_DEFAULT,
1655*a67afe4dSAndroid Build Coastguard Worker            chunks_to_process, (int)/*SAFE*/(sizeof chunks_to_process)/5);
1656*a67afe4dSAndroid Build Coastguard Worker    }
1657*a67afe4dSAndroid Build Coastguard Worker }
1658*a67afe4dSAndroid Build Coastguard Worker 
1659*a67afe4dSAndroid Build Coastguard Worker #  define PNG_SKIP_CHUNKS(p) png_image_skip_unused_chunks(p)
1660*a67afe4dSAndroid Build Coastguard Worker #else
1661*a67afe4dSAndroid Build Coastguard Worker #  define PNG_SKIP_CHUNKS(p) ((void)0)
1662*a67afe4dSAndroid Build Coastguard Worker #endif /* HANDLE_AS_UNKNOWN */
1663*a67afe4dSAndroid Build Coastguard Worker 
1664*a67afe4dSAndroid Build Coastguard Worker /* The following macro gives the exact rounded answer for all values in the
1665*a67afe4dSAndroid Build Coastguard Worker  * range 0..255 (it actually divides by 51.2, but the rounding still generates
1666*a67afe4dSAndroid Build Coastguard Worker  * the correct numbers 0..5
1667*a67afe4dSAndroid Build Coastguard Worker  */
1668*a67afe4dSAndroid Build Coastguard Worker #define PNG_DIV51(v8) (((v8) * 5 + 130) >> 8)
1669*a67afe4dSAndroid Build Coastguard Worker 
1670*a67afe4dSAndroid Build Coastguard Worker /* Utility functions to make particular color-maps */
1671*a67afe4dSAndroid Build Coastguard Worker static void
set_file_encoding(png_image_read_control * display)1672*a67afe4dSAndroid Build Coastguard Worker set_file_encoding(png_image_read_control *display)
1673*a67afe4dSAndroid Build Coastguard Worker {
1674*a67afe4dSAndroid Build Coastguard Worker    png_fixed_point g = display->image->opaque->png_ptr->colorspace.gamma;
1675*a67afe4dSAndroid Build Coastguard Worker    if (png_gamma_significant(g) != 0)
1676*a67afe4dSAndroid Build Coastguard Worker    {
1677*a67afe4dSAndroid Build Coastguard Worker       if (png_gamma_not_sRGB(g) != 0)
1678*a67afe4dSAndroid Build Coastguard Worker       {
1679*a67afe4dSAndroid Build Coastguard Worker          display->file_encoding = P_FILE;
1680*a67afe4dSAndroid Build Coastguard Worker          display->gamma_to_linear = png_reciprocal(g);
1681*a67afe4dSAndroid Build Coastguard Worker       }
1682*a67afe4dSAndroid Build Coastguard Worker 
1683*a67afe4dSAndroid Build Coastguard Worker       else
1684*a67afe4dSAndroid Build Coastguard Worker          display->file_encoding = P_sRGB;
1685*a67afe4dSAndroid Build Coastguard Worker    }
1686*a67afe4dSAndroid Build Coastguard Worker 
1687*a67afe4dSAndroid Build Coastguard Worker    else
1688*a67afe4dSAndroid Build Coastguard Worker       display->file_encoding = P_LINEAR8;
1689*a67afe4dSAndroid Build Coastguard Worker }
1690*a67afe4dSAndroid Build Coastguard Worker 
1691*a67afe4dSAndroid Build Coastguard Worker static unsigned int
decode_gamma(png_image_read_control * display,png_uint_32 value,int encoding)1692*a67afe4dSAndroid Build Coastguard Worker decode_gamma(png_image_read_control *display, png_uint_32 value, int encoding)
1693*a67afe4dSAndroid Build Coastguard Worker {
1694*a67afe4dSAndroid Build Coastguard Worker    if (encoding == P_FILE) /* double check */
1695*a67afe4dSAndroid Build Coastguard Worker       encoding = display->file_encoding;
1696*a67afe4dSAndroid Build Coastguard Worker 
1697*a67afe4dSAndroid Build Coastguard Worker    if (encoding == P_NOTSET) /* must be the file encoding */
1698*a67afe4dSAndroid Build Coastguard Worker    {
1699*a67afe4dSAndroid Build Coastguard Worker       set_file_encoding(display);
1700*a67afe4dSAndroid Build Coastguard Worker       encoding = display->file_encoding;
1701*a67afe4dSAndroid Build Coastguard Worker    }
1702*a67afe4dSAndroid Build Coastguard Worker 
1703*a67afe4dSAndroid Build Coastguard Worker    switch (encoding)
1704*a67afe4dSAndroid Build Coastguard Worker    {
1705*a67afe4dSAndroid Build Coastguard Worker       case P_FILE:
1706*a67afe4dSAndroid Build Coastguard Worker          value = png_gamma_16bit_correct(value*257, display->gamma_to_linear);
1707*a67afe4dSAndroid Build Coastguard Worker          break;
1708*a67afe4dSAndroid Build Coastguard Worker 
1709*a67afe4dSAndroid Build Coastguard Worker       case P_sRGB:
1710*a67afe4dSAndroid Build Coastguard Worker          value = png_sRGB_table[value];
1711*a67afe4dSAndroid Build Coastguard Worker          break;
1712*a67afe4dSAndroid Build Coastguard Worker 
1713*a67afe4dSAndroid Build Coastguard Worker       case P_LINEAR:
1714*a67afe4dSAndroid Build Coastguard Worker          break;
1715*a67afe4dSAndroid Build Coastguard Worker 
1716*a67afe4dSAndroid Build Coastguard Worker       case P_LINEAR8:
1717*a67afe4dSAndroid Build Coastguard Worker          value *= 257;
1718*a67afe4dSAndroid Build Coastguard Worker          break;
1719*a67afe4dSAndroid Build Coastguard Worker 
1720*a67afe4dSAndroid Build Coastguard Worker #ifdef __GNUC__
1721*a67afe4dSAndroid Build Coastguard Worker       default:
1722*a67afe4dSAndroid Build Coastguard Worker          png_error(display->image->opaque->png_ptr,
1723*a67afe4dSAndroid Build Coastguard Worker              "unexpected encoding (internal error)");
1724*a67afe4dSAndroid Build Coastguard Worker #endif
1725*a67afe4dSAndroid Build Coastguard Worker    }
1726*a67afe4dSAndroid Build Coastguard Worker 
1727*a67afe4dSAndroid Build Coastguard Worker    return value;
1728*a67afe4dSAndroid Build Coastguard Worker }
1729*a67afe4dSAndroid Build Coastguard Worker 
1730*a67afe4dSAndroid Build Coastguard Worker static png_uint_32
png_colormap_compose(png_image_read_control * display,png_uint_32 foreground,int foreground_encoding,png_uint_32 alpha,png_uint_32 background,int encoding)1731*a67afe4dSAndroid Build Coastguard Worker png_colormap_compose(png_image_read_control *display,
1732*a67afe4dSAndroid Build Coastguard Worker     png_uint_32 foreground, int foreground_encoding, png_uint_32 alpha,
1733*a67afe4dSAndroid Build Coastguard Worker     png_uint_32 background, int encoding)
1734*a67afe4dSAndroid Build Coastguard Worker {
1735*a67afe4dSAndroid Build Coastguard Worker    /* The file value is composed on the background, the background has the given
1736*a67afe4dSAndroid Build Coastguard Worker     * encoding and so does the result, the file is encoded with P_FILE and the
1737*a67afe4dSAndroid Build Coastguard Worker     * file and alpha are 8-bit values.  The (output) encoding will always be
1738*a67afe4dSAndroid Build Coastguard Worker     * P_LINEAR or P_sRGB.
1739*a67afe4dSAndroid Build Coastguard Worker     */
1740*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 f = decode_gamma(display, foreground, foreground_encoding);
1741*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 b = decode_gamma(display, background, encoding);
1742*a67afe4dSAndroid Build Coastguard Worker 
1743*a67afe4dSAndroid Build Coastguard Worker    /* The alpha is always an 8-bit value (it comes from the palette), the value
1744*a67afe4dSAndroid Build Coastguard Worker     * scaled by 255 is what PNG_sRGB_FROM_LINEAR requires.
1745*a67afe4dSAndroid Build Coastguard Worker     */
1746*a67afe4dSAndroid Build Coastguard Worker    f = f * alpha + b * (255-alpha);
1747*a67afe4dSAndroid Build Coastguard Worker 
1748*a67afe4dSAndroid Build Coastguard Worker    if (encoding == P_LINEAR)
1749*a67afe4dSAndroid Build Coastguard Worker    {
1750*a67afe4dSAndroid Build Coastguard Worker       /* Scale to 65535; divide by 255, approximately (in fact this is extremely
1751*a67afe4dSAndroid Build Coastguard Worker        * accurate, it divides by 255.00000005937181414556, with no overflow.)
1752*a67afe4dSAndroid Build Coastguard Worker        */
1753*a67afe4dSAndroid Build Coastguard Worker       f *= 257; /* Now scaled by 65535 */
1754*a67afe4dSAndroid Build Coastguard Worker       f += f >> 16;
1755*a67afe4dSAndroid Build Coastguard Worker       f = (f+32768) >> 16;
1756*a67afe4dSAndroid Build Coastguard Worker    }
1757*a67afe4dSAndroid Build Coastguard Worker 
1758*a67afe4dSAndroid Build Coastguard Worker    else /* P_sRGB */
1759*a67afe4dSAndroid Build Coastguard Worker       f = PNG_sRGB_FROM_LINEAR(f);
1760*a67afe4dSAndroid Build Coastguard Worker 
1761*a67afe4dSAndroid Build Coastguard Worker    return f;
1762*a67afe4dSAndroid Build Coastguard Worker }
1763*a67afe4dSAndroid Build Coastguard Worker 
1764*a67afe4dSAndroid Build Coastguard Worker /* NOTE: P_LINEAR values to this routine must be 16-bit, but P_FILE values must
1765*a67afe4dSAndroid Build Coastguard Worker  * be 8-bit.
1766*a67afe4dSAndroid Build Coastguard Worker  */
1767*a67afe4dSAndroid Build Coastguard Worker static void
png_create_colormap_entry(png_image_read_control * display,png_uint_32 ip,png_uint_32 red,png_uint_32 green,png_uint_32 blue,png_uint_32 alpha,int encoding)1768*a67afe4dSAndroid Build Coastguard Worker png_create_colormap_entry(png_image_read_control *display,
1769*a67afe4dSAndroid Build Coastguard Worker     png_uint_32 ip, png_uint_32 red, png_uint_32 green, png_uint_32 blue,
1770*a67afe4dSAndroid Build Coastguard Worker     png_uint_32 alpha, int encoding)
1771*a67afe4dSAndroid Build Coastguard Worker {
1772*a67afe4dSAndroid Build Coastguard Worker    png_imagep image = display->image;
1773*a67afe4dSAndroid Build Coastguard Worker    int output_encoding = (image->format & PNG_FORMAT_FLAG_LINEAR) != 0 ?
1774*a67afe4dSAndroid Build Coastguard Worker        P_LINEAR : P_sRGB;
1775*a67afe4dSAndroid Build Coastguard Worker    int convert_to_Y = (image->format & PNG_FORMAT_FLAG_COLOR) == 0 &&
1776*a67afe4dSAndroid Build Coastguard Worker        (red != green || green != blue);
1777*a67afe4dSAndroid Build Coastguard Worker 
1778*a67afe4dSAndroid Build Coastguard Worker    if (ip > 255)
1779*a67afe4dSAndroid Build Coastguard Worker       png_error(image->opaque->png_ptr, "color-map index out of range");
1780*a67afe4dSAndroid Build Coastguard Worker 
1781*a67afe4dSAndroid Build Coastguard Worker    /* Update the cache with whether the file gamma is significantly different
1782*a67afe4dSAndroid Build Coastguard Worker     * from sRGB.
1783*a67afe4dSAndroid Build Coastguard Worker     */
1784*a67afe4dSAndroid Build Coastguard Worker    if (encoding == P_FILE)
1785*a67afe4dSAndroid Build Coastguard Worker    {
1786*a67afe4dSAndroid Build Coastguard Worker       if (display->file_encoding == P_NOTSET)
1787*a67afe4dSAndroid Build Coastguard Worker          set_file_encoding(display);
1788*a67afe4dSAndroid Build Coastguard Worker 
1789*a67afe4dSAndroid Build Coastguard Worker       /* Note that the cached value may be P_FILE too, but if it is then the
1790*a67afe4dSAndroid Build Coastguard Worker        * gamma_to_linear member has been set.
1791*a67afe4dSAndroid Build Coastguard Worker        */
1792*a67afe4dSAndroid Build Coastguard Worker       encoding = display->file_encoding;
1793*a67afe4dSAndroid Build Coastguard Worker    }
1794*a67afe4dSAndroid Build Coastguard Worker 
1795*a67afe4dSAndroid Build Coastguard Worker    if (encoding == P_FILE)
1796*a67afe4dSAndroid Build Coastguard Worker    {
1797*a67afe4dSAndroid Build Coastguard Worker       png_fixed_point g = display->gamma_to_linear;
1798*a67afe4dSAndroid Build Coastguard Worker 
1799*a67afe4dSAndroid Build Coastguard Worker       red = png_gamma_16bit_correct(red*257, g);
1800*a67afe4dSAndroid Build Coastguard Worker       green = png_gamma_16bit_correct(green*257, g);
1801*a67afe4dSAndroid Build Coastguard Worker       blue = png_gamma_16bit_correct(blue*257, g);
1802*a67afe4dSAndroid Build Coastguard Worker 
1803*a67afe4dSAndroid Build Coastguard Worker       if (convert_to_Y != 0 || output_encoding == P_LINEAR)
1804*a67afe4dSAndroid Build Coastguard Worker       {
1805*a67afe4dSAndroid Build Coastguard Worker          alpha *= 257;
1806*a67afe4dSAndroid Build Coastguard Worker          encoding = P_LINEAR;
1807*a67afe4dSAndroid Build Coastguard Worker       }
1808*a67afe4dSAndroid Build Coastguard Worker 
1809*a67afe4dSAndroid Build Coastguard Worker       else
1810*a67afe4dSAndroid Build Coastguard Worker       {
1811*a67afe4dSAndroid Build Coastguard Worker          red = PNG_sRGB_FROM_LINEAR(red * 255);
1812*a67afe4dSAndroid Build Coastguard Worker          green = PNG_sRGB_FROM_LINEAR(green * 255);
1813*a67afe4dSAndroid Build Coastguard Worker          blue = PNG_sRGB_FROM_LINEAR(blue * 255);
1814*a67afe4dSAndroid Build Coastguard Worker          encoding = P_sRGB;
1815*a67afe4dSAndroid Build Coastguard Worker       }
1816*a67afe4dSAndroid Build Coastguard Worker    }
1817*a67afe4dSAndroid Build Coastguard Worker 
1818*a67afe4dSAndroid Build Coastguard Worker    else if (encoding == P_LINEAR8)
1819*a67afe4dSAndroid Build Coastguard Worker    {
1820*a67afe4dSAndroid Build Coastguard Worker       /* This encoding occurs quite frequently in test cases because PngSuite
1821*a67afe4dSAndroid Build Coastguard Worker        * includes a gAMA 1.0 chunk with most images.
1822*a67afe4dSAndroid Build Coastguard Worker        */
1823*a67afe4dSAndroid Build Coastguard Worker       red *= 257;
1824*a67afe4dSAndroid Build Coastguard Worker       green *= 257;
1825*a67afe4dSAndroid Build Coastguard Worker       blue *= 257;
1826*a67afe4dSAndroid Build Coastguard Worker       alpha *= 257;
1827*a67afe4dSAndroid Build Coastguard Worker       encoding = P_LINEAR;
1828*a67afe4dSAndroid Build Coastguard Worker    }
1829*a67afe4dSAndroid Build Coastguard Worker 
1830*a67afe4dSAndroid Build Coastguard Worker    else if (encoding == P_sRGB &&
1831*a67afe4dSAndroid Build Coastguard Worker        (convert_to_Y  != 0 || output_encoding == P_LINEAR))
1832*a67afe4dSAndroid Build Coastguard Worker    {
1833*a67afe4dSAndroid Build Coastguard Worker       /* The values are 8-bit sRGB values, but must be converted to 16-bit
1834*a67afe4dSAndroid Build Coastguard Worker        * linear.
1835*a67afe4dSAndroid Build Coastguard Worker        */
1836*a67afe4dSAndroid Build Coastguard Worker       red = png_sRGB_table[red];
1837*a67afe4dSAndroid Build Coastguard Worker       green = png_sRGB_table[green];
1838*a67afe4dSAndroid Build Coastguard Worker       blue = png_sRGB_table[blue];
1839*a67afe4dSAndroid Build Coastguard Worker       alpha *= 257;
1840*a67afe4dSAndroid Build Coastguard Worker       encoding = P_LINEAR;
1841*a67afe4dSAndroid Build Coastguard Worker    }
1842*a67afe4dSAndroid Build Coastguard Worker 
1843*a67afe4dSAndroid Build Coastguard Worker    /* This is set if the color isn't gray but the output is. */
1844*a67afe4dSAndroid Build Coastguard Worker    if (encoding == P_LINEAR)
1845*a67afe4dSAndroid Build Coastguard Worker    {
1846*a67afe4dSAndroid Build Coastguard Worker       if (convert_to_Y != 0)
1847*a67afe4dSAndroid Build Coastguard Worker       {
1848*a67afe4dSAndroid Build Coastguard Worker          /* NOTE: these values are copied from png_do_rgb_to_gray */
1849*a67afe4dSAndroid Build Coastguard Worker          png_uint_32 y = (png_uint_32)6968 * red  + (png_uint_32)23434 * green +
1850*a67afe4dSAndroid Build Coastguard Worker             (png_uint_32)2366 * blue;
1851*a67afe4dSAndroid Build Coastguard Worker 
1852*a67afe4dSAndroid Build Coastguard Worker          if (output_encoding == P_LINEAR)
1853*a67afe4dSAndroid Build Coastguard Worker             y = (y + 16384) >> 15;
1854*a67afe4dSAndroid Build Coastguard Worker 
1855*a67afe4dSAndroid Build Coastguard Worker          else
1856*a67afe4dSAndroid Build Coastguard Worker          {
1857*a67afe4dSAndroid Build Coastguard Worker             /* y is scaled by 32768, we need it scaled by 255: */
1858*a67afe4dSAndroid Build Coastguard Worker             y = (y + 128) >> 8;
1859*a67afe4dSAndroid Build Coastguard Worker             y *= 255;
1860*a67afe4dSAndroid Build Coastguard Worker             y = PNG_sRGB_FROM_LINEAR((y + 64) >> 7);
1861*a67afe4dSAndroid Build Coastguard Worker             alpha = PNG_DIV257(alpha);
1862*a67afe4dSAndroid Build Coastguard Worker             encoding = P_sRGB;
1863*a67afe4dSAndroid Build Coastguard Worker          }
1864*a67afe4dSAndroid Build Coastguard Worker 
1865*a67afe4dSAndroid Build Coastguard Worker          blue = red = green = y;
1866*a67afe4dSAndroid Build Coastguard Worker       }
1867*a67afe4dSAndroid Build Coastguard Worker 
1868*a67afe4dSAndroid Build Coastguard Worker       else if (output_encoding == P_sRGB)
1869*a67afe4dSAndroid Build Coastguard Worker       {
1870*a67afe4dSAndroid Build Coastguard Worker          red = PNG_sRGB_FROM_LINEAR(red * 255);
1871*a67afe4dSAndroid Build Coastguard Worker          green = PNG_sRGB_FROM_LINEAR(green * 255);
1872*a67afe4dSAndroid Build Coastguard Worker          blue = PNG_sRGB_FROM_LINEAR(blue * 255);
1873*a67afe4dSAndroid Build Coastguard Worker          alpha = PNG_DIV257(alpha);
1874*a67afe4dSAndroid Build Coastguard Worker          encoding = P_sRGB;
1875*a67afe4dSAndroid Build Coastguard Worker       }
1876*a67afe4dSAndroid Build Coastguard Worker    }
1877*a67afe4dSAndroid Build Coastguard Worker 
1878*a67afe4dSAndroid Build Coastguard Worker    if (encoding != output_encoding)
1879*a67afe4dSAndroid Build Coastguard Worker       png_error(image->opaque->png_ptr, "bad encoding (internal error)");
1880*a67afe4dSAndroid Build Coastguard Worker 
1881*a67afe4dSAndroid Build Coastguard Worker    /* Store the value. */
1882*a67afe4dSAndroid Build Coastguard Worker    {
1883*a67afe4dSAndroid Build Coastguard Worker #     ifdef PNG_FORMAT_AFIRST_SUPPORTED
1884*a67afe4dSAndroid Build Coastguard Worker          int afirst = (image->format & PNG_FORMAT_FLAG_AFIRST) != 0 &&
1885*a67afe4dSAndroid Build Coastguard Worker             (image->format & PNG_FORMAT_FLAG_ALPHA) != 0;
1886*a67afe4dSAndroid Build Coastguard Worker #     else
1887*a67afe4dSAndroid Build Coastguard Worker #        define afirst 0
1888*a67afe4dSAndroid Build Coastguard Worker #     endif
1889*a67afe4dSAndroid Build Coastguard Worker #     ifdef PNG_FORMAT_BGR_SUPPORTED
1890*a67afe4dSAndroid Build Coastguard Worker          int bgr = (image->format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0;
1891*a67afe4dSAndroid Build Coastguard Worker #     else
1892*a67afe4dSAndroid Build Coastguard Worker #        define bgr 0
1893*a67afe4dSAndroid Build Coastguard Worker #     endif
1894*a67afe4dSAndroid Build Coastguard Worker 
1895*a67afe4dSAndroid Build Coastguard Worker       if (output_encoding == P_LINEAR)
1896*a67afe4dSAndroid Build Coastguard Worker       {
1897*a67afe4dSAndroid Build Coastguard Worker          png_uint_16p entry = png_voidcast(png_uint_16p, display->colormap);
1898*a67afe4dSAndroid Build Coastguard Worker 
1899*a67afe4dSAndroid Build Coastguard Worker          entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format);
1900*a67afe4dSAndroid Build Coastguard Worker 
1901*a67afe4dSAndroid Build Coastguard Worker          /* The linear 16-bit values must be pre-multiplied by the alpha channel
1902*a67afe4dSAndroid Build Coastguard Worker           * value, if less than 65535 (this is, effectively, composite on black
1903*a67afe4dSAndroid Build Coastguard Worker           * if the alpha channel is removed.)
1904*a67afe4dSAndroid Build Coastguard Worker           */
1905*a67afe4dSAndroid Build Coastguard Worker          switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format))
1906*a67afe4dSAndroid Build Coastguard Worker          {
1907*a67afe4dSAndroid Build Coastguard Worker             case 4:
1908*a67afe4dSAndroid Build Coastguard Worker                entry[afirst ? 0 : 3] = (png_uint_16)alpha;
1909*a67afe4dSAndroid Build Coastguard Worker                /* FALLTHROUGH */
1910*a67afe4dSAndroid Build Coastguard Worker 
1911*a67afe4dSAndroid Build Coastguard Worker             case 3:
1912*a67afe4dSAndroid Build Coastguard Worker                if (alpha < 65535)
1913*a67afe4dSAndroid Build Coastguard Worker                {
1914*a67afe4dSAndroid Build Coastguard Worker                   if (alpha > 0)
1915*a67afe4dSAndroid Build Coastguard Worker                   {
1916*a67afe4dSAndroid Build Coastguard Worker                      blue = (blue * alpha + 32767U)/65535U;
1917*a67afe4dSAndroid Build Coastguard Worker                      green = (green * alpha + 32767U)/65535U;
1918*a67afe4dSAndroid Build Coastguard Worker                      red = (red * alpha + 32767U)/65535U;
1919*a67afe4dSAndroid Build Coastguard Worker                   }
1920*a67afe4dSAndroid Build Coastguard Worker 
1921*a67afe4dSAndroid Build Coastguard Worker                   else
1922*a67afe4dSAndroid Build Coastguard Worker                      red = green = blue = 0;
1923*a67afe4dSAndroid Build Coastguard Worker                }
1924*a67afe4dSAndroid Build Coastguard Worker                entry[afirst + (2 ^ bgr)] = (png_uint_16)blue;
1925*a67afe4dSAndroid Build Coastguard Worker                entry[afirst + 1] = (png_uint_16)green;
1926*a67afe4dSAndroid Build Coastguard Worker                entry[afirst + bgr] = (png_uint_16)red;
1927*a67afe4dSAndroid Build Coastguard Worker                break;
1928*a67afe4dSAndroid Build Coastguard Worker 
1929*a67afe4dSAndroid Build Coastguard Worker             case 2:
1930*a67afe4dSAndroid Build Coastguard Worker                entry[1 ^ afirst] = (png_uint_16)alpha;
1931*a67afe4dSAndroid Build Coastguard Worker                /* FALLTHROUGH */
1932*a67afe4dSAndroid Build Coastguard Worker 
1933*a67afe4dSAndroid Build Coastguard Worker             case 1:
1934*a67afe4dSAndroid Build Coastguard Worker                if (alpha < 65535)
1935*a67afe4dSAndroid Build Coastguard Worker                {
1936*a67afe4dSAndroid Build Coastguard Worker                   if (alpha > 0)
1937*a67afe4dSAndroid Build Coastguard Worker                      green = (green * alpha + 32767U)/65535U;
1938*a67afe4dSAndroid Build Coastguard Worker 
1939*a67afe4dSAndroid Build Coastguard Worker                   else
1940*a67afe4dSAndroid Build Coastguard Worker                      green = 0;
1941*a67afe4dSAndroid Build Coastguard Worker                }
1942*a67afe4dSAndroid Build Coastguard Worker                entry[afirst] = (png_uint_16)green;
1943*a67afe4dSAndroid Build Coastguard Worker                break;
1944*a67afe4dSAndroid Build Coastguard Worker 
1945*a67afe4dSAndroid Build Coastguard Worker             default:
1946*a67afe4dSAndroid Build Coastguard Worker                break;
1947*a67afe4dSAndroid Build Coastguard Worker          }
1948*a67afe4dSAndroid Build Coastguard Worker       }
1949*a67afe4dSAndroid Build Coastguard Worker 
1950*a67afe4dSAndroid Build Coastguard Worker       else /* output encoding is P_sRGB */
1951*a67afe4dSAndroid Build Coastguard Worker       {
1952*a67afe4dSAndroid Build Coastguard Worker          png_bytep entry = png_voidcast(png_bytep, display->colormap);
1953*a67afe4dSAndroid Build Coastguard Worker 
1954*a67afe4dSAndroid Build Coastguard Worker          entry += ip * PNG_IMAGE_SAMPLE_CHANNELS(image->format);
1955*a67afe4dSAndroid Build Coastguard Worker 
1956*a67afe4dSAndroid Build Coastguard Worker          switch (PNG_IMAGE_SAMPLE_CHANNELS(image->format))
1957*a67afe4dSAndroid Build Coastguard Worker          {
1958*a67afe4dSAndroid Build Coastguard Worker             case 4:
1959*a67afe4dSAndroid Build Coastguard Worker                entry[afirst ? 0 : 3] = (png_byte)alpha;
1960*a67afe4dSAndroid Build Coastguard Worker                /* FALLTHROUGH */
1961*a67afe4dSAndroid Build Coastguard Worker             case 3:
1962*a67afe4dSAndroid Build Coastguard Worker                entry[afirst + (2 ^ bgr)] = (png_byte)blue;
1963*a67afe4dSAndroid Build Coastguard Worker                entry[afirst + 1] = (png_byte)green;
1964*a67afe4dSAndroid Build Coastguard Worker                entry[afirst + bgr] = (png_byte)red;
1965*a67afe4dSAndroid Build Coastguard Worker                break;
1966*a67afe4dSAndroid Build Coastguard Worker 
1967*a67afe4dSAndroid Build Coastguard Worker             case 2:
1968*a67afe4dSAndroid Build Coastguard Worker                entry[1 ^ afirst] = (png_byte)alpha;
1969*a67afe4dSAndroid Build Coastguard Worker                /* FALLTHROUGH */
1970*a67afe4dSAndroid Build Coastguard Worker             case 1:
1971*a67afe4dSAndroid Build Coastguard Worker                entry[afirst] = (png_byte)green;
1972*a67afe4dSAndroid Build Coastguard Worker                break;
1973*a67afe4dSAndroid Build Coastguard Worker 
1974*a67afe4dSAndroid Build Coastguard Worker             default:
1975*a67afe4dSAndroid Build Coastguard Worker                break;
1976*a67afe4dSAndroid Build Coastguard Worker          }
1977*a67afe4dSAndroid Build Coastguard Worker       }
1978*a67afe4dSAndroid Build Coastguard Worker 
1979*a67afe4dSAndroid Build Coastguard Worker #     ifdef afirst
1980*a67afe4dSAndroid Build Coastguard Worker #        undef afirst
1981*a67afe4dSAndroid Build Coastguard Worker #     endif
1982*a67afe4dSAndroid Build Coastguard Worker #     ifdef bgr
1983*a67afe4dSAndroid Build Coastguard Worker #        undef bgr
1984*a67afe4dSAndroid Build Coastguard Worker #     endif
1985*a67afe4dSAndroid Build Coastguard Worker    }
1986*a67afe4dSAndroid Build Coastguard Worker }
1987*a67afe4dSAndroid Build Coastguard Worker 
1988*a67afe4dSAndroid Build Coastguard Worker static int
make_gray_file_colormap(png_image_read_control * display)1989*a67afe4dSAndroid Build Coastguard Worker make_gray_file_colormap(png_image_read_control *display)
1990*a67afe4dSAndroid Build Coastguard Worker {
1991*a67afe4dSAndroid Build Coastguard Worker    unsigned int i;
1992*a67afe4dSAndroid Build Coastguard Worker 
1993*a67afe4dSAndroid Build Coastguard Worker    for (i=0; i<256; ++i)
1994*a67afe4dSAndroid Build Coastguard Worker       png_create_colormap_entry(display, i, i, i, i, 255, P_FILE);
1995*a67afe4dSAndroid Build Coastguard Worker 
1996*a67afe4dSAndroid Build Coastguard Worker    return (int)i;
1997*a67afe4dSAndroid Build Coastguard Worker }
1998*a67afe4dSAndroid Build Coastguard Worker 
1999*a67afe4dSAndroid Build Coastguard Worker static int
make_gray_colormap(png_image_read_control * display)2000*a67afe4dSAndroid Build Coastguard Worker make_gray_colormap(png_image_read_control *display)
2001*a67afe4dSAndroid Build Coastguard Worker {
2002*a67afe4dSAndroid Build Coastguard Worker    unsigned int i;
2003*a67afe4dSAndroid Build Coastguard Worker 
2004*a67afe4dSAndroid Build Coastguard Worker    for (i=0; i<256; ++i)
2005*a67afe4dSAndroid Build Coastguard Worker       png_create_colormap_entry(display, i, i, i, i, 255, P_sRGB);
2006*a67afe4dSAndroid Build Coastguard Worker 
2007*a67afe4dSAndroid Build Coastguard Worker    return (int)i;
2008*a67afe4dSAndroid Build Coastguard Worker }
2009*a67afe4dSAndroid Build Coastguard Worker #define PNG_GRAY_COLORMAP_ENTRIES 256
2010*a67afe4dSAndroid Build Coastguard Worker 
2011*a67afe4dSAndroid Build Coastguard Worker static int
make_ga_colormap(png_image_read_control * display)2012*a67afe4dSAndroid Build Coastguard Worker make_ga_colormap(png_image_read_control *display)
2013*a67afe4dSAndroid Build Coastguard Worker {
2014*a67afe4dSAndroid Build Coastguard Worker    unsigned int i, a;
2015*a67afe4dSAndroid Build Coastguard Worker 
2016*a67afe4dSAndroid Build Coastguard Worker    /* Alpha is retained, the output will be a color-map with entries
2017*a67afe4dSAndroid Build Coastguard Worker     * selected by six levels of alpha.  One transparent entry, 6 gray
2018*a67afe4dSAndroid Build Coastguard Worker     * levels for all the intermediate alpha values, leaving 230 entries
2019*a67afe4dSAndroid Build Coastguard Worker     * for the opaque grays.  The color-map entries are the six values
2020*a67afe4dSAndroid Build Coastguard Worker     * [0..5]*51, the GA processing uses PNG_DIV51(value) to find the
2021*a67afe4dSAndroid Build Coastguard Worker     * relevant entry.
2022*a67afe4dSAndroid Build Coastguard Worker     *
2023*a67afe4dSAndroid Build Coastguard Worker     * if (alpha > 229) // opaque
2024*a67afe4dSAndroid Build Coastguard Worker     * {
2025*a67afe4dSAndroid Build Coastguard Worker     *    // The 231 entries are selected to make the math below work:
2026*a67afe4dSAndroid Build Coastguard Worker     *    base = 0;
2027*a67afe4dSAndroid Build Coastguard Worker     *    entry = (231 * gray + 128) >> 8;
2028*a67afe4dSAndroid Build Coastguard Worker     * }
2029*a67afe4dSAndroid Build Coastguard Worker     * else if (alpha < 26) // transparent
2030*a67afe4dSAndroid Build Coastguard Worker     * {
2031*a67afe4dSAndroid Build Coastguard Worker     *    base = 231;
2032*a67afe4dSAndroid Build Coastguard Worker     *    entry = 0;
2033*a67afe4dSAndroid Build Coastguard Worker     * }
2034*a67afe4dSAndroid Build Coastguard Worker     * else // partially opaque
2035*a67afe4dSAndroid Build Coastguard Worker     * {
2036*a67afe4dSAndroid Build Coastguard Worker     *    base = 226 + 6 * PNG_DIV51(alpha);
2037*a67afe4dSAndroid Build Coastguard Worker     *    entry = PNG_DIV51(gray);
2038*a67afe4dSAndroid Build Coastguard Worker     * }
2039*a67afe4dSAndroid Build Coastguard Worker     */
2040*a67afe4dSAndroid Build Coastguard Worker    i = 0;
2041*a67afe4dSAndroid Build Coastguard Worker    while (i < 231)
2042*a67afe4dSAndroid Build Coastguard Worker    {
2043*a67afe4dSAndroid Build Coastguard Worker       unsigned int gray = (i * 256 + 115) / 231;
2044*a67afe4dSAndroid Build Coastguard Worker       png_create_colormap_entry(display, i++, gray, gray, gray, 255, P_sRGB);
2045*a67afe4dSAndroid Build Coastguard Worker    }
2046*a67afe4dSAndroid Build Coastguard Worker 
2047*a67afe4dSAndroid Build Coastguard Worker    /* 255 is used here for the component values for consistency with the code
2048*a67afe4dSAndroid Build Coastguard Worker     * that undoes premultiplication in pngwrite.c.
2049*a67afe4dSAndroid Build Coastguard Worker     */
2050*a67afe4dSAndroid Build Coastguard Worker    png_create_colormap_entry(display, i++, 255, 255, 255, 0, P_sRGB);
2051*a67afe4dSAndroid Build Coastguard Worker 
2052*a67afe4dSAndroid Build Coastguard Worker    for (a=1; a<5; ++a)
2053*a67afe4dSAndroid Build Coastguard Worker    {
2054*a67afe4dSAndroid Build Coastguard Worker       unsigned int g;
2055*a67afe4dSAndroid Build Coastguard Worker 
2056*a67afe4dSAndroid Build Coastguard Worker       for (g=0; g<6; ++g)
2057*a67afe4dSAndroid Build Coastguard Worker          png_create_colormap_entry(display, i++, g*51, g*51, g*51, a*51,
2058*a67afe4dSAndroid Build Coastguard Worker              P_sRGB);
2059*a67afe4dSAndroid Build Coastguard Worker    }
2060*a67afe4dSAndroid Build Coastguard Worker 
2061*a67afe4dSAndroid Build Coastguard Worker    return (int)i;
2062*a67afe4dSAndroid Build Coastguard Worker }
2063*a67afe4dSAndroid Build Coastguard Worker 
2064*a67afe4dSAndroid Build Coastguard Worker #define PNG_GA_COLORMAP_ENTRIES 256
2065*a67afe4dSAndroid Build Coastguard Worker 
2066*a67afe4dSAndroid Build Coastguard Worker static int
make_rgb_colormap(png_image_read_control * display)2067*a67afe4dSAndroid Build Coastguard Worker make_rgb_colormap(png_image_read_control *display)
2068*a67afe4dSAndroid Build Coastguard Worker {
2069*a67afe4dSAndroid Build Coastguard Worker    unsigned int i, r;
2070*a67afe4dSAndroid Build Coastguard Worker 
2071*a67afe4dSAndroid Build Coastguard Worker    /* Build a 6x6x6 opaque RGB cube */
2072*a67afe4dSAndroid Build Coastguard Worker    for (i=r=0; r<6; ++r)
2073*a67afe4dSAndroid Build Coastguard Worker    {
2074*a67afe4dSAndroid Build Coastguard Worker       unsigned int g;
2075*a67afe4dSAndroid Build Coastguard Worker 
2076*a67afe4dSAndroid Build Coastguard Worker       for (g=0; g<6; ++g)
2077*a67afe4dSAndroid Build Coastguard Worker       {
2078*a67afe4dSAndroid Build Coastguard Worker          unsigned int b;
2079*a67afe4dSAndroid Build Coastguard Worker 
2080*a67afe4dSAndroid Build Coastguard Worker          for (b=0; b<6; ++b)
2081*a67afe4dSAndroid Build Coastguard Worker             png_create_colormap_entry(display, i++, r*51, g*51, b*51, 255,
2082*a67afe4dSAndroid Build Coastguard Worker                 P_sRGB);
2083*a67afe4dSAndroid Build Coastguard Worker       }
2084*a67afe4dSAndroid Build Coastguard Worker    }
2085*a67afe4dSAndroid Build Coastguard Worker 
2086*a67afe4dSAndroid Build Coastguard Worker    return (int)i;
2087*a67afe4dSAndroid Build Coastguard Worker }
2088*a67afe4dSAndroid Build Coastguard Worker 
2089*a67afe4dSAndroid Build Coastguard Worker #define PNG_RGB_COLORMAP_ENTRIES 216
2090*a67afe4dSAndroid Build Coastguard Worker 
2091*a67afe4dSAndroid Build Coastguard Worker /* Return a palette index to the above palette given three 8-bit sRGB values. */
2092*a67afe4dSAndroid Build Coastguard Worker #define PNG_RGB_INDEX(r,g,b) \
2093*a67afe4dSAndroid Build Coastguard Worker    ((png_byte)(6 * (6 * PNG_DIV51(r) + PNG_DIV51(g)) + PNG_DIV51(b)))
2094*a67afe4dSAndroid Build Coastguard Worker 
2095*a67afe4dSAndroid Build Coastguard Worker static int
png_image_read_colormap(png_voidp argument)2096*a67afe4dSAndroid Build Coastguard Worker png_image_read_colormap(png_voidp argument)
2097*a67afe4dSAndroid Build Coastguard Worker {
2098*a67afe4dSAndroid Build Coastguard Worker    png_image_read_control *display =
2099*a67afe4dSAndroid Build Coastguard Worker       png_voidcast(png_image_read_control*, argument);
2100*a67afe4dSAndroid Build Coastguard Worker    png_imagep image = display->image;
2101*a67afe4dSAndroid Build Coastguard Worker 
2102*a67afe4dSAndroid Build Coastguard Worker    png_structrp png_ptr = image->opaque->png_ptr;
2103*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 output_format = image->format;
2104*a67afe4dSAndroid Build Coastguard Worker    int output_encoding = (output_format & PNG_FORMAT_FLAG_LINEAR) != 0 ?
2105*a67afe4dSAndroid Build Coastguard Worker       P_LINEAR : P_sRGB;
2106*a67afe4dSAndroid Build Coastguard Worker 
2107*a67afe4dSAndroid Build Coastguard Worker    unsigned int cmap_entries;
2108*a67afe4dSAndroid Build Coastguard Worker    unsigned int output_processing;        /* Output processing option */
2109*a67afe4dSAndroid Build Coastguard Worker    unsigned int data_encoding = P_NOTSET; /* Encoding libpng must produce */
2110*a67afe4dSAndroid Build Coastguard Worker 
2111*a67afe4dSAndroid Build Coastguard Worker    /* Background information; the background color and the index of this color
2112*a67afe4dSAndroid Build Coastguard Worker     * in the color-map if it exists (else 256).
2113*a67afe4dSAndroid Build Coastguard Worker     */
2114*a67afe4dSAndroid Build Coastguard Worker    unsigned int background_index = 256;
2115*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 back_r, back_g, back_b;
2116*a67afe4dSAndroid Build Coastguard Worker 
2117*a67afe4dSAndroid Build Coastguard Worker    /* Flags to accumulate things that need to be done to the input. */
2118*a67afe4dSAndroid Build Coastguard Worker    int expand_tRNS = 0;
2119*a67afe4dSAndroid Build Coastguard Worker 
2120*a67afe4dSAndroid Build Coastguard Worker    /* Exclude the NYI feature of compositing onto a color-mapped buffer; it is
2121*a67afe4dSAndroid Build Coastguard Worker     * very difficult to do, the results look awful, and it is difficult to see
2122*a67afe4dSAndroid Build Coastguard Worker     * what possible use it is because the application can't control the
2123*a67afe4dSAndroid Build Coastguard Worker     * color-map.
2124*a67afe4dSAndroid Build Coastguard Worker     */
2125*a67afe4dSAndroid Build Coastguard Worker    if (((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0 ||
2126*a67afe4dSAndroid Build Coastguard Worker          png_ptr->num_trans > 0) /* alpha in input */ &&
2127*a67afe4dSAndroid Build Coastguard Worker       ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) /* no alpha in output */)
2128*a67afe4dSAndroid Build Coastguard Worker    {
2129*a67afe4dSAndroid Build Coastguard Worker       if (output_encoding == P_LINEAR) /* compose on black */
2130*a67afe4dSAndroid Build Coastguard Worker          back_b = back_g = back_r = 0;
2131*a67afe4dSAndroid Build Coastguard Worker 
2132*a67afe4dSAndroid Build Coastguard Worker       else if (display->background == NULL /* no way to remove it */)
2133*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr,
2134*a67afe4dSAndroid Build Coastguard Worker              "background color must be supplied to remove alpha/transparency");
2135*a67afe4dSAndroid Build Coastguard Worker 
2136*a67afe4dSAndroid Build Coastguard Worker       /* Get a copy of the background color (this avoids repeating the checks
2137*a67afe4dSAndroid Build Coastguard Worker        * below.)  The encoding is 8-bit sRGB or 16-bit linear, depending on the
2138*a67afe4dSAndroid Build Coastguard Worker        * output format.
2139*a67afe4dSAndroid Build Coastguard Worker        */
2140*a67afe4dSAndroid Build Coastguard Worker       else
2141*a67afe4dSAndroid Build Coastguard Worker       {
2142*a67afe4dSAndroid Build Coastguard Worker          back_g = display->background->green;
2143*a67afe4dSAndroid Build Coastguard Worker          if ((output_format & PNG_FORMAT_FLAG_COLOR) != 0)
2144*a67afe4dSAndroid Build Coastguard Worker          {
2145*a67afe4dSAndroid Build Coastguard Worker             back_r = display->background->red;
2146*a67afe4dSAndroid Build Coastguard Worker             back_b = display->background->blue;
2147*a67afe4dSAndroid Build Coastguard Worker          }
2148*a67afe4dSAndroid Build Coastguard Worker          else
2149*a67afe4dSAndroid Build Coastguard Worker             back_b = back_r = back_g;
2150*a67afe4dSAndroid Build Coastguard Worker       }
2151*a67afe4dSAndroid Build Coastguard Worker    }
2152*a67afe4dSAndroid Build Coastguard Worker 
2153*a67afe4dSAndroid Build Coastguard Worker    else if (output_encoding == P_LINEAR)
2154*a67afe4dSAndroid Build Coastguard Worker       back_b = back_r = back_g = 65535;
2155*a67afe4dSAndroid Build Coastguard Worker 
2156*a67afe4dSAndroid Build Coastguard Worker    else
2157*a67afe4dSAndroid Build Coastguard Worker       back_b = back_r = back_g = 255;
2158*a67afe4dSAndroid Build Coastguard Worker 
2159*a67afe4dSAndroid Build Coastguard Worker    /* Default the input file gamma if required - this is necessary because
2160*a67afe4dSAndroid Build Coastguard Worker     * libpng assumes that if no gamma information is present the data is in the
2161*a67afe4dSAndroid Build Coastguard Worker     * output format, but the simplified API deduces the gamma from the input
2162*a67afe4dSAndroid Build Coastguard Worker     * format.
2163*a67afe4dSAndroid Build Coastguard Worker     */
2164*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) == 0)
2165*a67afe4dSAndroid Build Coastguard Worker    {
2166*a67afe4dSAndroid Build Coastguard Worker       /* Do this directly, not using the png_colorspace functions, to ensure
2167*a67afe4dSAndroid Build Coastguard Worker        * that it happens even if the colorspace is invalid (though probably if
2168*a67afe4dSAndroid Build Coastguard Worker        * it is the setting will be ignored)  Note that the same thing can be
2169*a67afe4dSAndroid Build Coastguard Worker        * achieved at the application interface with png_set_gAMA.
2170*a67afe4dSAndroid Build Coastguard Worker        */
2171*a67afe4dSAndroid Build Coastguard Worker       if (png_ptr->bit_depth == 16 &&
2172*a67afe4dSAndroid Build Coastguard Worker          (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0)
2173*a67afe4dSAndroid Build Coastguard Worker          png_ptr->colorspace.gamma = PNG_GAMMA_LINEAR;
2174*a67afe4dSAndroid Build Coastguard Worker 
2175*a67afe4dSAndroid Build Coastguard Worker       else
2176*a67afe4dSAndroid Build Coastguard Worker          png_ptr->colorspace.gamma = PNG_GAMMA_sRGB_INVERSE;
2177*a67afe4dSAndroid Build Coastguard Worker 
2178*a67afe4dSAndroid Build Coastguard Worker       png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
2179*a67afe4dSAndroid Build Coastguard Worker    }
2180*a67afe4dSAndroid Build Coastguard Worker 
2181*a67afe4dSAndroid Build Coastguard Worker    /* Decide what to do based on the PNG color type of the input data.  The
2182*a67afe4dSAndroid Build Coastguard Worker     * utility function png_create_colormap_entry deals with most aspects of the
2183*a67afe4dSAndroid Build Coastguard Worker     * output transformations; this code works out how to produce bytes of
2184*a67afe4dSAndroid Build Coastguard Worker     * color-map entries from the original format.
2185*a67afe4dSAndroid Build Coastguard Worker     */
2186*a67afe4dSAndroid Build Coastguard Worker    switch (png_ptr->color_type)
2187*a67afe4dSAndroid Build Coastguard Worker    {
2188*a67afe4dSAndroid Build Coastguard Worker       case PNG_COLOR_TYPE_GRAY:
2189*a67afe4dSAndroid Build Coastguard Worker          if (png_ptr->bit_depth <= 8)
2190*a67afe4dSAndroid Build Coastguard Worker          {
2191*a67afe4dSAndroid Build Coastguard Worker             /* There at most 256 colors in the output, regardless of
2192*a67afe4dSAndroid Build Coastguard Worker              * transparency.
2193*a67afe4dSAndroid Build Coastguard Worker              */
2194*a67afe4dSAndroid Build Coastguard Worker             unsigned int step, i, val, trans = 256/*ignore*/, back_alpha = 0;
2195*a67afe4dSAndroid Build Coastguard Worker 
2196*a67afe4dSAndroid Build Coastguard Worker             cmap_entries = 1U << png_ptr->bit_depth;
2197*a67afe4dSAndroid Build Coastguard Worker             if (cmap_entries > image->colormap_entries)
2198*a67afe4dSAndroid Build Coastguard Worker                png_error(png_ptr, "gray[8] color-map: too few entries");
2199*a67afe4dSAndroid Build Coastguard Worker 
2200*a67afe4dSAndroid Build Coastguard Worker             step = 255 / (cmap_entries - 1);
2201*a67afe4dSAndroid Build Coastguard Worker             output_processing = PNG_CMAP_NONE;
2202*a67afe4dSAndroid Build Coastguard Worker 
2203*a67afe4dSAndroid Build Coastguard Worker             /* If there is a tRNS chunk then this either selects a transparent
2204*a67afe4dSAndroid Build Coastguard Worker              * value or, if the output has no alpha, the background color.
2205*a67afe4dSAndroid Build Coastguard Worker              */
2206*a67afe4dSAndroid Build Coastguard Worker             if (png_ptr->num_trans > 0)
2207*a67afe4dSAndroid Build Coastguard Worker             {
2208*a67afe4dSAndroid Build Coastguard Worker                trans = png_ptr->trans_color.gray;
2209*a67afe4dSAndroid Build Coastguard Worker 
2210*a67afe4dSAndroid Build Coastguard Worker                if ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0)
2211*a67afe4dSAndroid Build Coastguard Worker                   back_alpha = output_encoding == P_LINEAR ? 65535 : 255;
2212*a67afe4dSAndroid Build Coastguard Worker             }
2213*a67afe4dSAndroid Build Coastguard Worker 
2214*a67afe4dSAndroid Build Coastguard Worker             /* png_create_colormap_entry just takes an RGBA and writes the
2215*a67afe4dSAndroid Build Coastguard Worker              * corresponding color-map entry using the format from 'image',
2216*a67afe4dSAndroid Build Coastguard Worker              * including the required conversion to sRGB or linear as
2217*a67afe4dSAndroid Build Coastguard Worker              * appropriate.  The input values are always either sRGB (if the
2218*a67afe4dSAndroid Build Coastguard Worker              * gamma correction flag is 0) or 0..255 scaled file encoded values
2219*a67afe4dSAndroid Build Coastguard Worker              * (if the function must gamma correct them).
2220*a67afe4dSAndroid Build Coastguard Worker              */
2221*a67afe4dSAndroid Build Coastguard Worker             for (i=val=0; i<cmap_entries; ++i, val += step)
2222*a67afe4dSAndroid Build Coastguard Worker             {
2223*a67afe4dSAndroid Build Coastguard Worker                /* 'i' is a file value.  While this will result in duplicated
2224*a67afe4dSAndroid Build Coastguard Worker                 * entries for 8-bit non-sRGB encoded files it is necessary to
2225*a67afe4dSAndroid Build Coastguard Worker                 * have non-gamma corrected values to do tRNS handling.
2226*a67afe4dSAndroid Build Coastguard Worker                 */
2227*a67afe4dSAndroid Build Coastguard Worker                if (i != trans)
2228*a67afe4dSAndroid Build Coastguard Worker                   png_create_colormap_entry(display, i, val, val, val, 255,
2229*a67afe4dSAndroid Build Coastguard Worker                       P_FILE/*8-bit with file gamma*/);
2230*a67afe4dSAndroid Build Coastguard Worker 
2231*a67afe4dSAndroid Build Coastguard Worker                /* Else this entry is transparent.  The colors don't matter if
2232*a67afe4dSAndroid Build Coastguard Worker                 * there is an alpha channel (back_alpha == 0), but it does no
2233*a67afe4dSAndroid Build Coastguard Worker                 * harm to pass them in; the values are not set above so this
2234*a67afe4dSAndroid Build Coastguard Worker                 * passes in white.
2235*a67afe4dSAndroid Build Coastguard Worker                 *
2236*a67afe4dSAndroid Build Coastguard Worker                 * NOTE: this preserves the full precision of the application
2237*a67afe4dSAndroid Build Coastguard Worker                 * supplied background color when it is used.
2238*a67afe4dSAndroid Build Coastguard Worker                 */
2239*a67afe4dSAndroid Build Coastguard Worker                else
2240*a67afe4dSAndroid Build Coastguard Worker                   png_create_colormap_entry(display, i, back_r, back_g, back_b,
2241*a67afe4dSAndroid Build Coastguard Worker                       back_alpha, output_encoding);
2242*a67afe4dSAndroid Build Coastguard Worker             }
2243*a67afe4dSAndroid Build Coastguard Worker 
2244*a67afe4dSAndroid Build Coastguard Worker             /* We need libpng to preserve the original encoding. */
2245*a67afe4dSAndroid Build Coastguard Worker             data_encoding = P_FILE;
2246*a67afe4dSAndroid Build Coastguard Worker 
2247*a67afe4dSAndroid Build Coastguard Worker             /* The rows from libpng, while technically gray values, are now also
2248*a67afe4dSAndroid Build Coastguard Worker              * color-map indices; however, they may need to be expanded to 1
2249*a67afe4dSAndroid Build Coastguard Worker              * byte per pixel.  This is what png_set_packing does (i.e., it
2250*a67afe4dSAndroid Build Coastguard Worker              * unpacks the bit values into bytes.)
2251*a67afe4dSAndroid Build Coastguard Worker              */
2252*a67afe4dSAndroid Build Coastguard Worker             if (png_ptr->bit_depth < 8)
2253*a67afe4dSAndroid Build Coastguard Worker                png_set_packing(png_ptr);
2254*a67afe4dSAndroid Build Coastguard Worker          }
2255*a67afe4dSAndroid Build Coastguard Worker 
2256*a67afe4dSAndroid Build Coastguard Worker          else /* bit depth is 16 */
2257*a67afe4dSAndroid Build Coastguard Worker          {
2258*a67afe4dSAndroid Build Coastguard Worker             /* The 16-bit input values can be converted directly to 8-bit gamma
2259*a67afe4dSAndroid Build Coastguard Worker              * encoded values; however, if a tRNS chunk is present 257 color-map
2260*a67afe4dSAndroid Build Coastguard Worker              * entries are required.  This means that the extra entry requires
2261*a67afe4dSAndroid Build Coastguard Worker              * special processing; add an alpha channel, sacrifice gray level
2262*a67afe4dSAndroid Build Coastguard Worker              * 254 and convert transparent (alpha==0) entries to that.
2263*a67afe4dSAndroid Build Coastguard Worker              *
2264*a67afe4dSAndroid Build Coastguard Worker              * Use libpng to chop the data to 8 bits.  Convert it to sRGB at the
2265*a67afe4dSAndroid Build Coastguard Worker              * same time to minimize quality loss.  If a tRNS chunk is present
2266*a67afe4dSAndroid Build Coastguard Worker              * this means libpng must handle it too; otherwise it is impossible
2267*a67afe4dSAndroid Build Coastguard Worker              * to do the exact match on the 16-bit value.
2268*a67afe4dSAndroid Build Coastguard Worker              *
2269*a67afe4dSAndroid Build Coastguard Worker              * If the output has no alpha channel *and* the background color is
2270*a67afe4dSAndroid Build Coastguard Worker              * gray then it is possible to let libpng handle the substitution by
2271*a67afe4dSAndroid Build Coastguard Worker              * ensuring that the corresponding gray level matches the background
2272*a67afe4dSAndroid Build Coastguard Worker              * color exactly.
2273*a67afe4dSAndroid Build Coastguard Worker              */
2274*a67afe4dSAndroid Build Coastguard Worker             data_encoding = P_sRGB;
2275*a67afe4dSAndroid Build Coastguard Worker 
2276*a67afe4dSAndroid Build Coastguard Worker             if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)
2277*a67afe4dSAndroid Build Coastguard Worker                png_error(png_ptr, "gray[16] color-map: too few entries");
2278*a67afe4dSAndroid Build Coastguard Worker 
2279*a67afe4dSAndroid Build Coastguard Worker             cmap_entries = (unsigned int)make_gray_colormap(display);
2280*a67afe4dSAndroid Build Coastguard Worker 
2281*a67afe4dSAndroid Build Coastguard Worker             if (png_ptr->num_trans > 0)
2282*a67afe4dSAndroid Build Coastguard Worker             {
2283*a67afe4dSAndroid Build Coastguard Worker                unsigned int back_alpha;
2284*a67afe4dSAndroid Build Coastguard Worker 
2285*a67afe4dSAndroid Build Coastguard Worker                if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0)
2286*a67afe4dSAndroid Build Coastguard Worker                   back_alpha = 0;
2287*a67afe4dSAndroid Build Coastguard Worker 
2288*a67afe4dSAndroid Build Coastguard Worker                else
2289*a67afe4dSAndroid Build Coastguard Worker                {
2290*a67afe4dSAndroid Build Coastguard Worker                   if (back_r == back_g && back_g == back_b)
2291*a67afe4dSAndroid Build Coastguard Worker                   {
2292*a67afe4dSAndroid Build Coastguard Worker                      /* Background is gray; no special processing will be
2293*a67afe4dSAndroid Build Coastguard Worker                       * required.
2294*a67afe4dSAndroid Build Coastguard Worker                       */
2295*a67afe4dSAndroid Build Coastguard Worker                      png_color_16 c;
2296*a67afe4dSAndroid Build Coastguard Worker                      png_uint_32 gray = back_g;
2297*a67afe4dSAndroid Build Coastguard Worker 
2298*a67afe4dSAndroid Build Coastguard Worker                      if (output_encoding == P_LINEAR)
2299*a67afe4dSAndroid Build Coastguard Worker                      {
2300*a67afe4dSAndroid Build Coastguard Worker                         gray = PNG_sRGB_FROM_LINEAR(gray * 255);
2301*a67afe4dSAndroid Build Coastguard Worker 
2302*a67afe4dSAndroid Build Coastguard Worker                         /* And make sure the corresponding palette entry
2303*a67afe4dSAndroid Build Coastguard Worker                          * matches.
2304*a67afe4dSAndroid Build Coastguard Worker                          */
2305*a67afe4dSAndroid Build Coastguard Worker                         png_create_colormap_entry(display, gray, back_g, back_g,
2306*a67afe4dSAndroid Build Coastguard Worker                             back_g, 65535, P_LINEAR);
2307*a67afe4dSAndroid Build Coastguard Worker                      }
2308*a67afe4dSAndroid Build Coastguard Worker 
2309*a67afe4dSAndroid Build Coastguard Worker                      /* The background passed to libpng, however, must be the
2310*a67afe4dSAndroid Build Coastguard Worker                       * sRGB value.
2311*a67afe4dSAndroid Build Coastguard Worker                       */
2312*a67afe4dSAndroid Build Coastguard Worker                      c.index = 0; /*unused*/
2313*a67afe4dSAndroid Build Coastguard Worker                      c.gray = c.red = c.green = c.blue = (png_uint_16)gray;
2314*a67afe4dSAndroid Build Coastguard Worker 
2315*a67afe4dSAndroid Build Coastguard Worker                      /* NOTE: does this work without expanding tRNS to alpha?
2316*a67afe4dSAndroid Build Coastguard Worker                       * It should be the color->gray case below apparently
2317*a67afe4dSAndroid Build Coastguard Worker                       * doesn't.
2318*a67afe4dSAndroid Build Coastguard Worker                       */
2319*a67afe4dSAndroid Build Coastguard Worker                      png_set_background_fixed(png_ptr, &c,
2320*a67afe4dSAndroid Build Coastguard Worker                          PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,
2321*a67afe4dSAndroid Build Coastguard Worker                          0/*gamma: not used*/);
2322*a67afe4dSAndroid Build Coastguard Worker 
2323*a67afe4dSAndroid Build Coastguard Worker                      output_processing = PNG_CMAP_NONE;
2324*a67afe4dSAndroid Build Coastguard Worker                      break;
2325*a67afe4dSAndroid Build Coastguard Worker                   }
2326*a67afe4dSAndroid Build Coastguard Worker #ifdef __COVERITY__
2327*a67afe4dSAndroid Build Coastguard Worker                  /* Coverity claims that output_encoding cannot be 2 (P_LINEAR)
2328*a67afe4dSAndroid Build Coastguard Worker                   * here.
2329*a67afe4dSAndroid Build Coastguard Worker                   */
2330*a67afe4dSAndroid Build Coastguard Worker                   back_alpha = 255;
2331*a67afe4dSAndroid Build Coastguard Worker #else
2332*a67afe4dSAndroid Build Coastguard Worker                   back_alpha = output_encoding == P_LINEAR ? 65535 : 255;
2333*a67afe4dSAndroid Build Coastguard Worker #endif
2334*a67afe4dSAndroid Build Coastguard Worker                }
2335*a67afe4dSAndroid Build Coastguard Worker 
2336*a67afe4dSAndroid Build Coastguard Worker                /* output_processing means that the libpng-processed row will be
2337*a67afe4dSAndroid Build Coastguard Worker                 * 8-bit GA and it has to be processing to single byte color-map
2338*a67afe4dSAndroid Build Coastguard Worker                 * values.  Entry 254 is replaced by either a completely
2339*a67afe4dSAndroid Build Coastguard Worker                 * transparent entry or by the background color at full
2340*a67afe4dSAndroid Build Coastguard Worker                 * precision (and the background color is not a simple gray
2341*a67afe4dSAndroid Build Coastguard Worker                 * level in this case.)
2342*a67afe4dSAndroid Build Coastguard Worker                 */
2343*a67afe4dSAndroid Build Coastguard Worker                expand_tRNS = 1;
2344*a67afe4dSAndroid Build Coastguard Worker                output_processing = PNG_CMAP_TRANS;
2345*a67afe4dSAndroid Build Coastguard Worker                background_index = 254;
2346*a67afe4dSAndroid Build Coastguard Worker 
2347*a67afe4dSAndroid Build Coastguard Worker                /* And set (overwrite) color-map entry 254 to the actual
2348*a67afe4dSAndroid Build Coastguard Worker                 * background color at full precision.
2349*a67afe4dSAndroid Build Coastguard Worker                 */
2350*a67afe4dSAndroid Build Coastguard Worker                png_create_colormap_entry(display, 254, back_r, back_g, back_b,
2351*a67afe4dSAndroid Build Coastguard Worker                    back_alpha, output_encoding);
2352*a67afe4dSAndroid Build Coastguard Worker             }
2353*a67afe4dSAndroid Build Coastguard Worker 
2354*a67afe4dSAndroid Build Coastguard Worker             else
2355*a67afe4dSAndroid Build Coastguard Worker                output_processing = PNG_CMAP_NONE;
2356*a67afe4dSAndroid Build Coastguard Worker          }
2357*a67afe4dSAndroid Build Coastguard Worker          break;
2358*a67afe4dSAndroid Build Coastguard Worker 
2359*a67afe4dSAndroid Build Coastguard Worker       case PNG_COLOR_TYPE_GRAY_ALPHA:
2360*a67afe4dSAndroid Build Coastguard Worker          /* 8-bit or 16-bit PNG with two channels - gray and alpha.  A minimum
2361*a67afe4dSAndroid Build Coastguard Worker           * of 65536 combinations.  If, however, the alpha channel is to be
2362*a67afe4dSAndroid Build Coastguard Worker           * removed there are only 256 possibilities if the background is gray.
2363*a67afe4dSAndroid Build Coastguard Worker           * (Otherwise there is a subset of the 65536 possibilities defined by
2364*a67afe4dSAndroid Build Coastguard Worker           * the triangle between black, white and the background color.)
2365*a67afe4dSAndroid Build Coastguard Worker           *
2366*a67afe4dSAndroid Build Coastguard Worker           * Reduce 16-bit files to 8-bit and sRGB encode the result.  No need to
2367*a67afe4dSAndroid Build Coastguard Worker           * worry about tRNS matching - tRNS is ignored if there is an alpha
2368*a67afe4dSAndroid Build Coastguard Worker           * channel.
2369*a67afe4dSAndroid Build Coastguard Worker           */
2370*a67afe4dSAndroid Build Coastguard Worker          data_encoding = P_sRGB;
2371*a67afe4dSAndroid Build Coastguard Worker 
2372*a67afe4dSAndroid Build Coastguard Worker          if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0)
2373*a67afe4dSAndroid Build Coastguard Worker          {
2374*a67afe4dSAndroid Build Coastguard Worker             if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)
2375*a67afe4dSAndroid Build Coastguard Worker                png_error(png_ptr, "gray+alpha color-map: too few entries");
2376*a67afe4dSAndroid Build Coastguard Worker 
2377*a67afe4dSAndroid Build Coastguard Worker             cmap_entries = (unsigned int)make_ga_colormap(display);
2378*a67afe4dSAndroid Build Coastguard Worker 
2379*a67afe4dSAndroid Build Coastguard Worker             background_index = PNG_CMAP_GA_BACKGROUND;
2380*a67afe4dSAndroid Build Coastguard Worker             output_processing = PNG_CMAP_GA;
2381*a67afe4dSAndroid Build Coastguard Worker          }
2382*a67afe4dSAndroid Build Coastguard Worker 
2383*a67afe4dSAndroid Build Coastguard Worker          else /* alpha is removed */
2384*a67afe4dSAndroid Build Coastguard Worker          {
2385*a67afe4dSAndroid Build Coastguard Worker             /* Alpha must be removed as the PNG data is processed when the
2386*a67afe4dSAndroid Build Coastguard Worker              * background is a color because the G and A channels are
2387*a67afe4dSAndroid Build Coastguard Worker              * independent and the vector addition (non-parallel vectors) is a
2388*a67afe4dSAndroid Build Coastguard Worker              * 2-D problem.
2389*a67afe4dSAndroid Build Coastguard Worker              *
2390*a67afe4dSAndroid Build Coastguard Worker              * This can be reduced to the same algorithm as above by making a
2391*a67afe4dSAndroid Build Coastguard Worker              * colormap containing gray levels (for the opaque grays), a
2392*a67afe4dSAndroid Build Coastguard Worker              * background entry (for a transparent pixel) and a set of four six
2393*a67afe4dSAndroid Build Coastguard Worker              * level color values, one set for each intermediate alpha value.
2394*a67afe4dSAndroid Build Coastguard Worker              * See the comments in make_ga_colormap for how this works in the
2395*a67afe4dSAndroid Build Coastguard Worker              * per-pixel processing.
2396*a67afe4dSAndroid Build Coastguard Worker              *
2397*a67afe4dSAndroid Build Coastguard Worker              * If the background is gray, however, we only need a 256 entry gray
2398*a67afe4dSAndroid Build Coastguard Worker              * level color map.  It is sufficient to make the entry generated
2399*a67afe4dSAndroid Build Coastguard Worker              * for the background color be exactly the color specified.
2400*a67afe4dSAndroid Build Coastguard Worker              */
2401*a67afe4dSAndroid Build Coastguard Worker             if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0 ||
2402*a67afe4dSAndroid Build Coastguard Worker                (back_r == back_g && back_g == back_b))
2403*a67afe4dSAndroid Build Coastguard Worker             {
2404*a67afe4dSAndroid Build Coastguard Worker                /* Background is gray; no special processing will be required. */
2405*a67afe4dSAndroid Build Coastguard Worker                png_color_16 c;
2406*a67afe4dSAndroid Build Coastguard Worker                png_uint_32 gray = back_g;
2407*a67afe4dSAndroid Build Coastguard Worker 
2408*a67afe4dSAndroid Build Coastguard Worker                if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)
2409*a67afe4dSAndroid Build Coastguard Worker                   png_error(png_ptr, "gray-alpha color-map: too few entries");
2410*a67afe4dSAndroid Build Coastguard Worker 
2411*a67afe4dSAndroid Build Coastguard Worker                cmap_entries = (unsigned int)make_gray_colormap(display);
2412*a67afe4dSAndroid Build Coastguard Worker 
2413*a67afe4dSAndroid Build Coastguard Worker                if (output_encoding == P_LINEAR)
2414*a67afe4dSAndroid Build Coastguard Worker                {
2415*a67afe4dSAndroid Build Coastguard Worker                   gray = PNG_sRGB_FROM_LINEAR(gray * 255);
2416*a67afe4dSAndroid Build Coastguard Worker 
2417*a67afe4dSAndroid Build Coastguard Worker                   /* And make sure the corresponding palette entry matches. */
2418*a67afe4dSAndroid Build Coastguard Worker                   png_create_colormap_entry(display, gray, back_g, back_g,
2419*a67afe4dSAndroid Build Coastguard Worker                       back_g, 65535, P_LINEAR);
2420*a67afe4dSAndroid Build Coastguard Worker                }
2421*a67afe4dSAndroid Build Coastguard Worker 
2422*a67afe4dSAndroid Build Coastguard Worker                /* The background passed to libpng, however, must be the sRGB
2423*a67afe4dSAndroid Build Coastguard Worker                 * value.
2424*a67afe4dSAndroid Build Coastguard Worker                 */
2425*a67afe4dSAndroid Build Coastguard Worker                c.index = 0; /*unused*/
2426*a67afe4dSAndroid Build Coastguard Worker                c.gray = c.red = c.green = c.blue = (png_uint_16)gray;
2427*a67afe4dSAndroid Build Coastguard Worker 
2428*a67afe4dSAndroid Build Coastguard Worker                png_set_background_fixed(png_ptr, &c,
2429*a67afe4dSAndroid Build Coastguard Worker                    PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,
2430*a67afe4dSAndroid Build Coastguard Worker                    0/*gamma: not used*/);
2431*a67afe4dSAndroid Build Coastguard Worker 
2432*a67afe4dSAndroid Build Coastguard Worker                output_processing = PNG_CMAP_NONE;
2433*a67afe4dSAndroid Build Coastguard Worker             }
2434*a67afe4dSAndroid Build Coastguard Worker 
2435*a67afe4dSAndroid Build Coastguard Worker             else
2436*a67afe4dSAndroid Build Coastguard Worker             {
2437*a67afe4dSAndroid Build Coastguard Worker                png_uint_32 i, a;
2438*a67afe4dSAndroid Build Coastguard Worker 
2439*a67afe4dSAndroid Build Coastguard Worker                /* This is the same as png_make_ga_colormap, above, except that
2440*a67afe4dSAndroid Build Coastguard Worker                 * the entries are all opaque.
2441*a67afe4dSAndroid Build Coastguard Worker                 */
2442*a67afe4dSAndroid Build Coastguard Worker                if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)
2443*a67afe4dSAndroid Build Coastguard Worker                   png_error(png_ptr, "ga-alpha color-map: too few entries");
2444*a67afe4dSAndroid Build Coastguard Worker 
2445*a67afe4dSAndroid Build Coastguard Worker                i = 0;
2446*a67afe4dSAndroid Build Coastguard Worker                while (i < 231)
2447*a67afe4dSAndroid Build Coastguard Worker                {
2448*a67afe4dSAndroid Build Coastguard Worker                   png_uint_32 gray = (i * 256 + 115) / 231;
2449*a67afe4dSAndroid Build Coastguard Worker                   png_create_colormap_entry(display, i++, gray, gray, gray,
2450*a67afe4dSAndroid Build Coastguard Worker                       255, P_sRGB);
2451*a67afe4dSAndroid Build Coastguard Worker                }
2452*a67afe4dSAndroid Build Coastguard Worker 
2453*a67afe4dSAndroid Build Coastguard Worker                /* NOTE: this preserves the full precision of the application
2454*a67afe4dSAndroid Build Coastguard Worker                 * background color.
2455*a67afe4dSAndroid Build Coastguard Worker                 */
2456*a67afe4dSAndroid Build Coastguard Worker                background_index = i;
2457*a67afe4dSAndroid Build Coastguard Worker                png_create_colormap_entry(display, i++, back_r, back_g, back_b,
2458*a67afe4dSAndroid Build Coastguard Worker #ifdef __COVERITY__
2459*a67afe4dSAndroid Build Coastguard Worker                    /* Coverity claims that output_encoding
2460*a67afe4dSAndroid Build Coastguard Worker                     * cannot be 2 (P_LINEAR) here.
2461*a67afe4dSAndroid Build Coastguard Worker                     */ 255U,
2462*a67afe4dSAndroid Build Coastguard Worker #else
2463*a67afe4dSAndroid Build Coastguard Worker                     output_encoding == P_LINEAR ? 65535U : 255U,
2464*a67afe4dSAndroid Build Coastguard Worker #endif
2465*a67afe4dSAndroid Build Coastguard Worker                     output_encoding);
2466*a67afe4dSAndroid Build Coastguard Worker 
2467*a67afe4dSAndroid Build Coastguard Worker                /* For non-opaque input composite on the sRGB background - this
2468*a67afe4dSAndroid Build Coastguard Worker                 * requires inverting the encoding for each component.  The input
2469*a67afe4dSAndroid Build Coastguard Worker                 * is still converted to the sRGB encoding because this is a
2470*a67afe4dSAndroid Build Coastguard Worker                 * reasonable approximate to the logarithmic curve of human
2471*a67afe4dSAndroid Build Coastguard Worker                 * visual sensitivity, at least over the narrow range which PNG
2472*a67afe4dSAndroid Build Coastguard Worker                 * represents.  Consequently 'G' is always sRGB encoded, while
2473*a67afe4dSAndroid Build Coastguard Worker                 * 'A' is linear.  We need the linear background colors.
2474*a67afe4dSAndroid Build Coastguard Worker                 */
2475*a67afe4dSAndroid Build Coastguard Worker                if (output_encoding == P_sRGB) /* else already linear */
2476*a67afe4dSAndroid Build Coastguard Worker                {
2477*a67afe4dSAndroid Build Coastguard Worker                   /* This may produce a value not exactly matching the
2478*a67afe4dSAndroid Build Coastguard Worker                    * background, but that's ok because these numbers are only
2479*a67afe4dSAndroid Build Coastguard Worker                    * used when alpha != 0
2480*a67afe4dSAndroid Build Coastguard Worker                    */
2481*a67afe4dSAndroid Build Coastguard Worker                   back_r = png_sRGB_table[back_r];
2482*a67afe4dSAndroid Build Coastguard Worker                   back_g = png_sRGB_table[back_g];
2483*a67afe4dSAndroid Build Coastguard Worker                   back_b = png_sRGB_table[back_b];
2484*a67afe4dSAndroid Build Coastguard Worker                }
2485*a67afe4dSAndroid Build Coastguard Worker 
2486*a67afe4dSAndroid Build Coastguard Worker                for (a=1; a<5; ++a)
2487*a67afe4dSAndroid Build Coastguard Worker                {
2488*a67afe4dSAndroid Build Coastguard Worker                   unsigned int g;
2489*a67afe4dSAndroid Build Coastguard Worker 
2490*a67afe4dSAndroid Build Coastguard Worker                   /* PNG_sRGB_FROM_LINEAR expects a 16-bit linear value scaled
2491*a67afe4dSAndroid Build Coastguard Worker                    * by an 8-bit alpha value (0..255).
2492*a67afe4dSAndroid Build Coastguard Worker                    */
2493*a67afe4dSAndroid Build Coastguard Worker                   png_uint_32 alpha = 51 * a;
2494*a67afe4dSAndroid Build Coastguard Worker                   png_uint_32 back_rx = (255-alpha) * back_r;
2495*a67afe4dSAndroid Build Coastguard Worker                   png_uint_32 back_gx = (255-alpha) * back_g;
2496*a67afe4dSAndroid Build Coastguard Worker                   png_uint_32 back_bx = (255-alpha) * back_b;
2497*a67afe4dSAndroid Build Coastguard Worker 
2498*a67afe4dSAndroid Build Coastguard Worker                   for (g=0; g<6; ++g)
2499*a67afe4dSAndroid Build Coastguard Worker                   {
2500*a67afe4dSAndroid Build Coastguard Worker                      png_uint_32 gray = png_sRGB_table[g*51] * alpha;
2501*a67afe4dSAndroid Build Coastguard Worker 
2502*a67afe4dSAndroid Build Coastguard Worker                      png_create_colormap_entry(display, i++,
2503*a67afe4dSAndroid Build Coastguard Worker                          PNG_sRGB_FROM_LINEAR(gray + back_rx),
2504*a67afe4dSAndroid Build Coastguard Worker                          PNG_sRGB_FROM_LINEAR(gray + back_gx),
2505*a67afe4dSAndroid Build Coastguard Worker                          PNG_sRGB_FROM_LINEAR(gray + back_bx), 255, P_sRGB);
2506*a67afe4dSAndroid Build Coastguard Worker                   }
2507*a67afe4dSAndroid Build Coastguard Worker                }
2508*a67afe4dSAndroid Build Coastguard Worker 
2509*a67afe4dSAndroid Build Coastguard Worker                cmap_entries = i;
2510*a67afe4dSAndroid Build Coastguard Worker                output_processing = PNG_CMAP_GA;
2511*a67afe4dSAndroid Build Coastguard Worker             }
2512*a67afe4dSAndroid Build Coastguard Worker          }
2513*a67afe4dSAndroid Build Coastguard Worker          break;
2514*a67afe4dSAndroid Build Coastguard Worker 
2515*a67afe4dSAndroid Build Coastguard Worker       case PNG_COLOR_TYPE_RGB:
2516*a67afe4dSAndroid Build Coastguard Worker       case PNG_COLOR_TYPE_RGB_ALPHA:
2517*a67afe4dSAndroid Build Coastguard Worker          /* Exclude the case where the output is gray; we can always handle this
2518*a67afe4dSAndroid Build Coastguard Worker           * with the cases above.
2519*a67afe4dSAndroid Build Coastguard Worker           */
2520*a67afe4dSAndroid Build Coastguard Worker          if ((output_format & PNG_FORMAT_FLAG_COLOR) == 0)
2521*a67afe4dSAndroid Build Coastguard Worker          {
2522*a67afe4dSAndroid Build Coastguard Worker             /* The color-map will be grayscale, so we may as well convert the
2523*a67afe4dSAndroid Build Coastguard Worker              * input RGB values to a simple grayscale and use the grayscale
2524*a67afe4dSAndroid Build Coastguard Worker              * code above.
2525*a67afe4dSAndroid Build Coastguard Worker              *
2526*a67afe4dSAndroid Build Coastguard Worker              * NOTE: calling this apparently damages the recognition of the
2527*a67afe4dSAndroid Build Coastguard Worker              * transparent color in background color handling; call
2528*a67afe4dSAndroid Build Coastguard Worker              * png_set_tRNS_to_alpha before png_set_background_fixed.
2529*a67afe4dSAndroid Build Coastguard Worker              */
2530*a67afe4dSAndroid Build Coastguard Worker             png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, -1,
2531*a67afe4dSAndroid Build Coastguard Worker                 -1);
2532*a67afe4dSAndroid Build Coastguard Worker             data_encoding = P_sRGB;
2533*a67afe4dSAndroid Build Coastguard Worker 
2534*a67afe4dSAndroid Build Coastguard Worker             /* The output will now be one or two 8-bit gray or gray+alpha
2535*a67afe4dSAndroid Build Coastguard Worker              * channels.  The more complex case arises when the input has alpha.
2536*a67afe4dSAndroid Build Coastguard Worker              */
2537*a67afe4dSAndroid Build Coastguard Worker             if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
2538*a67afe4dSAndroid Build Coastguard Worker                png_ptr->num_trans > 0) &&
2539*a67afe4dSAndroid Build Coastguard Worker                (output_format & PNG_FORMAT_FLAG_ALPHA) != 0)
2540*a67afe4dSAndroid Build Coastguard Worker             {
2541*a67afe4dSAndroid Build Coastguard Worker                /* Both input and output have an alpha channel, so no background
2542*a67afe4dSAndroid Build Coastguard Worker                 * processing is required; just map the GA bytes to the right
2543*a67afe4dSAndroid Build Coastguard Worker                 * color-map entry.
2544*a67afe4dSAndroid Build Coastguard Worker                 */
2545*a67afe4dSAndroid Build Coastguard Worker                expand_tRNS = 1;
2546*a67afe4dSAndroid Build Coastguard Worker 
2547*a67afe4dSAndroid Build Coastguard Worker                if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries)
2548*a67afe4dSAndroid Build Coastguard Worker                   png_error(png_ptr, "rgb[ga] color-map: too few entries");
2549*a67afe4dSAndroid Build Coastguard Worker 
2550*a67afe4dSAndroid Build Coastguard Worker                cmap_entries = (unsigned int)make_ga_colormap(display);
2551*a67afe4dSAndroid Build Coastguard Worker                background_index = PNG_CMAP_GA_BACKGROUND;
2552*a67afe4dSAndroid Build Coastguard Worker                output_processing = PNG_CMAP_GA;
2553*a67afe4dSAndroid Build Coastguard Worker             }
2554*a67afe4dSAndroid Build Coastguard Worker 
2555*a67afe4dSAndroid Build Coastguard Worker             else
2556*a67afe4dSAndroid Build Coastguard Worker             {
2557*a67afe4dSAndroid Build Coastguard Worker                /* Either the input or the output has no alpha channel, so there
2558*a67afe4dSAndroid Build Coastguard Worker                 * will be no non-opaque pixels in the color-map; it will just be
2559*a67afe4dSAndroid Build Coastguard Worker                 * grayscale.
2560*a67afe4dSAndroid Build Coastguard Worker                 */
2561*a67afe4dSAndroid Build Coastguard Worker                if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries)
2562*a67afe4dSAndroid Build Coastguard Worker                   png_error(png_ptr, "rgb[gray] color-map: too few entries");
2563*a67afe4dSAndroid Build Coastguard Worker 
2564*a67afe4dSAndroid Build Coastguard Worker                /* Ideally this code would use libpng to do the gamma correction,
2565*a67afe4dSAndroid Build Coastguard Worker                 * but if an input alpha channel is to be removed we will hit the
2566*a67afe4dSAndroid Build Coastguard Worker                 * libpng bug in gamma+compose+rgb-to-gray (the double gamma
2567*a67afe4dSAndroid Build Coastguard Worker                 * correction bug).  Fix this by dropping the gamma correction in
2568*a67afe4dSAndroid Build Coastguard Worker                 * this case and doing it in the palette; this will result in
2569*a67afe4dSAndroid Build Coastguard Worker                 * duplicate palette entries, but that's better than the
2570*a67afe4dSAndroid Build Coastguard Worker                 * alternative of double gamma correction.
2571*a67afe4dSAndroid Build Coastguard Worker                 */
2572*a67afe4dSAndroid Build Coastguard Worker                if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
2573*a67afe4dSAndroid Build Coastguard Worker                   png_ptr->num_trans > 0) &&
2574*a67afe4dSAndroid Build Coastguard Worker                   png_gamma_not_sRGB(png_ptr->colorspace.gamma) != 0)
2575*a67afe4dSAndroid Build Coastguard Worker                {
2576*a67afe4dSAndroid Build Coastguard Worker                   cmap_entries = (unsigned int)make_gray_file_colormap(display);
2577*a67afe4dSAndroid Build Coastguard Worker                   data_encoding = P_FILE;
2578*a67afe4dSAndroid Build Coastguard Worker                }
2579*a67afe4dSAndroid Build Coastguard Worker 
2580*a67afe4dSAndroid Build Coastguard Worker                else
2581*a67afe4dSAndroid Build Coastguard Worker                   cmap_entries = (unsigned int)make_gray_colormap(display);
2582*a67afe4dSAndroid Build Coastguard Worker 
2583*a67afe4dSAndroid Build Coastguard Worker                /* But if the input has alpha or transparency it must be removed
2584*a67afe4dSAndroid Build Coastguard Worker                 */
2585*a67afe4dSAndroid Build Coastguard Worker                if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
2586*a67afe4dSAndroid Build Coastguard Worker                   png_ptr->num_trans > 0)
2587*a67afe4dSAndroid Build Coastguard Worker                {
2588*a67afe4dSAndroid Build Coastguard Worker                   png_color_16 c;
2589*a67afe4dSAndroid Build Coastguard Worker                   png_uint_32 gray = back_g;
2590*a67afe4dSAndroid Build Coastguard Worker 
2591*a67afe4dSAndroid Build Coastguard Worker                   /* We need to ensure that the application background exists in
2592*a67afe4dSAndroid Build Coastguard Worker                    * the colormap and that completely transparent pixels map to
2593*a67afe4dSAndroid Build Coastguard Worker                    * it.  Achieve this simply by ensuring that the entry
2594*a67afe4dSAndroid Build Coastguard Worker                    * selected for the background really is the background color.
2595*a67afe4dSAndroid Build Coastguard Worker                    */
2596*a67afe4dSAndroid Build Coastguard Worker                   if (data_encoding == P_FILE) /* from the fixup above */
2597*a67afe4dSAndroid Build Coastguard Worker                   {
2598*a67afe4dSAndroid Build Coastguard Worker                      /* The app supplied a gray which is in output_encoding, we
2599*a67afe4dSAndroid Build Coastguard Worker                       * need to convert it to a value of the input (P_FILE)
2600*a67afe4dSAndroid Build Coastguard Worker                       * encoding then set this palette entry to the required
2601*a67afe4dSAndroid Build Coastguard Worker                       * output encoding.
2602*a67afe4dSAndroid Build Coastguard Worker                       */
2603*a67afe4dSAndroid Build Coastguard Worker                      if (output_encoding == P_sRGB)
2604*a67afe4dSAndroid Build Coastguard Worker                         gray = png_sRGB_table[gray]; /* now P_LINEAR */
2605*a67afe4dSAndroid Build Coastguard Worker 
2606*a67afe4dSAndroid Build Coastguard Worker                      gray = PNG_DIV257(png_gamma_16bit_correct(gray,
2607*a67afe4dSAndroid Build Coastguard Worker                          png_ptr->colorspace.gamma)); /* now P_FILE */
2608*a67afe4dSAndroid Build Coastguard Worker 
2609*a67afe4dSAndroid Build Coastguard Worker                      /* And make sure the corresponding palette entry contains
2610*a67afe4dSAndroid Build Coastguard Worker                       * exactly the required sRGB value.
2611*a67afe4dSAndroid Build Coastguard Worker                       */
2612*a67afe4dSAndroid Build Coastguard Worker                      png_create_colormap_entry(display, gray, back_g, back_g,
2613*a67afe4dSAndroid Build Coastguard Worker                          back_g, 0/*unused*/, output_encoding);
2614*a67afe4dSAndroid Build Coastguard Worker                   }
2615*a67afe4dSAndroid Build Coastguard Worker 
2616*a67afe4dSAndroid Build Coastguard Worker                   else if (output_encoding == P_LINEAR)
2617*a67afe4dSAndroid Build Coastguard Worker                   {
2618*a67afe4dSAndroid Build Coastguard Worker                      gray = PNG_sRGB_FROM_LINEAR(gray * 255);
2619*a67afe4dSAndroid Build Coastguard Worker 
2620*a67afe4dSAndroid Build Coastguard Worker                      /* And make sure the corresponding palette entry matches.
2621*a67afe4dSAndroid Build Coastguard Worker                       */
2622*a67afe4dSAndroid Build Coastguard Worker                      png_create_colormap_entry(display, gray, back_g, back_g,
2623*a67afe4dSAndroid Build Coastguard Worker                         back_g, 0/*unused*/, P_LINEAR);
2624*a67afe4dSAndroid Build Coastguard Worker                   }
2625*a67afe4dSAndroid Build Coastguard Worker 
2626*a67afe4dSAndroid Build Coastguard Worker                   /* The background passed to libpng, however, must be the
2627*a67afe4dSAndroid Build Coastguard Worker                    * output (normally sRGB) value.
2628*a67afe4dSAndroid Build Coastguard Worker                    */
2629*a67afe4dSAndroid Build Coastguard Worker                   c.index = 0; /*unused*/
2630*a67afe4dSAndroid Build Coastguard Worker                   c.gray = c.red = c.green = c.blue = (png_uint_16)gray;
2631*a67afe4dSAndroid Build Coastguard Worker 
2632*a67afe4dSAndroid Build Coastguard Worker                   /* NOTE: the following is apparently a bug in libpng. Without
2633*a67afe4dSAndroid Build Coastguard Worker                    * it the transparent color recognition in
2634*a67afe4dSAndroid Build Coastguard Worker                    * png_set_background_fixed seems to go wrong.
2635*a67afe4dSAndroid Build Coastguard Worker                    */
2636*a67afe4dSAndroid Build Coastguard Worker                   expand_tRNS = 1;
2637*a67afe4dSAndroid Build Coastguard Worker                   png_set_background_fixed(png_ptr, &c,
2638*a67afe4dSAndroid Build Coastguard Worker                       PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,
2639*a67afe4dSAndroid Build Coastguard Worker                       0/*gamma: not used*/);
2640*a67afe4dSAndroid Build Coastguard Worker                }
2641*a67afe4dSAndroid Build Coastguard Worker 
2642*a67afe4dSAndroid Build Coastguard Worker                output_processing = PNG_CMAP_NONE;
2643*a67afe4dSAndroid Build Coastguard Worker             }
2644*a67afe4dSAndroid Build Coastguard Worker          }
2645*a67afe4dSAndroid Build Coastguard Worker 
2646*a67afe4dSAndroid Build Coastguard Worker          else /* output is color */
2647*a67afe4dSAndroid Build Coastguard Worker          {
2648*a67afe4dSAndroid Build Coastguard Worker             /* We could use png_quantize here so long as there is no transparent
2649*a67afe4dSAndroid Build Coastguard Worker              * color or alpha; png_quantize ignores alpha.  Easier overall just
2650*a67afe4dSAndroid Build Coastguard Worker              * to do it once and using PNG_DIV51 on the 6x6x6 reduced RGB cube.
2651*a67afe4dSAndroid Build Coastguard Worker              * Consequently we always want libpng to produce sRGB data.
2652*a67afe4dSAndroid Build Coastguard Worker              */
2653*a67afe4dSAndroid Build Coastguard Worker             data_encoding = P_sRGB;
2654*a67afe4dSAndroid Build Coastguard Worker 
2655*a67afe4dSAndroid Build Coastguard Worker             /* Is there any transparency or alpha? */
2656*a67afe4dSAndroid Build Coastguard Worker             if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
2657*a67afe4dSAndroid Build Coastguard Worker                png_ptr->num_trans > 0)
2658*a67afe4dSAndroid Build Coastguard Worker             {
2659*a67afe4dSAndroid Build Coastguard Worker                /* Is there alpha in the output too?  If so all four channels are
2660*a67afe4dSAndroid Build Coastguard Worker                 * processed into a special RGB cube with alpha support.
2661*a67afe4dSAndroid Build Coastguard Worker                 */
2662*a67afe4dSAndroid Build Coastguard Worker                if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0)
2663*a67afe4dSAndroid Build Coastguard Worker                {
2664*a67afe4dSAndroid Build Coastguard Worker                   png_uint_32 r;
2665*a67afe4dSAndroid Build Coastguard Worker 
2666*a67afe4dSAndroid Build Coastguard Worker                   if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries)
2667*a67afe4dSAndroid Build Coastguard Worker                      png_error(png_ptr, "rgb+alpha color-map: too few entries");
2668*a67afe4dSAndroid Build Coastguard Worker 
2669*a67afe4dSAndroid Build Coastguard Worker                   cmap_entries = (unsigned int)make_rgb_colormap(display);
2670*a67afe4dSAndroid Build Coastguard Worker 
2671*a67afe4dSAndroid Build Coastguard Worker                   /* Add a transparent entry. */
2672*a67afe4dSAndroid Build Coastguard Worker                   png_create_colormap_entry(display, cmap_entries, 255, 255,
2673*a67afe4dSAndroid Build Coastguard Worker                       255, 0, P_sRGB);
2674*a67afe4dSAndroid Build Coastguard Worker 
2675*a67afe4dSAndroid Build Coastguard Worker                   /* This is stored as the background index for the processing
2676*a67afe4dSAndroid Build Coastguard Worker                    * algorithm.
2677*a67afe4dSAndroid Build Coastguard Worker                    */
2678*a67afe4dSAndroid Build Coastguard Worker                   background_index = cmap_entries++;
2679*a67afe4dSAndroid Build Coastguard Worker 
2680*a67afe4dSAndroid Build Coastguard Worker                   /* Add 27 r,g,b entries each with alpha 0.5. */
2681*a67afe4dSAndroid Build Coastguard Worker                   for (r=0; r<256; r = (r << 1) | 0x7f)
2682*a67afe4dSAndroid Build Coastguard Worker                   {
2683*a67afe4dSAndroid Build Coastguard Worker                      png_uint_32 g;
2684*a67afe4dSAndroid Build Coastguard Worker 
2685*a67afe4dSAndroid Build Coastguard Worker                      for (g=0; g<256; g = (g << 1) | 0x7f)
2686*a67afe4dSAndroid Build Coastguard Worker                      {
2687*a67afe4dSAndroid Build Coastguard Worker                         png_uint_32 b;
2688*a67afe4dSAndroid Build Coastguard Worker 
2689*a67afe4dSAndroid Build Coastguard Worker                         /* This generates components with the values 0, 127 and
2690*a67afe4dSAndroid Build Coastguard Worker                          * 255
2691*a67afe4dSAndroid Build Coastguard Worker                          */
2692*a67afe4dSAndroid Build Coastguard Worker                         for (b=0; b<256; b = (b << 1) | 0x7f)
2693*a67afe4dSAndroid Build Coastguard Worker                            png_create_colormap_entry(display, cmap_entries++,
2694*a67afe4dSAndroid Build Coastguard Worker                                r, g, b, 128, P_sRGB);
2695*a67afe4dSAndroid Build Coastguard Worker                      }
2696*a67afe4dSAndroid Build Coastguard Worker                   }
2697*a67afe4dSAndroid Build Coastguard Worker 
2698*a67afe4dSAndroid Build Coastguard Worker                   expand_tRNS = 1;
2699*a67afe4dSAndroid Build Coastguard Worker                   output_processing = PNG_CMAP_RGB_ALPHA;
2700*a67afe4dSAndroid Build Coastguard Worker                }
2701*a67afe4dSAndroid Build Coastguard Worker 
2702*a67afe4dSAndroid Build Coastguard Worker                else
2703*a67afe4dSAndroid Build Coastguard Worker                {
2704*a67afe4dSAndroid Build Coastguard Worker                   /* Alpha/transparency must be removed.  The background must
2705*a67afe4dSAndroid Build Coastguard Worker                    * exist in the color map (achieved by setting adding it after
2706*a67afe4dSAndroid Build Coastguard Worker                    * the 666 color-map).  If the standard processing code will
2707*a67afe4dSAndroid Build Coastguard Worker                    * pick up this entry automatically that's all that is
2708*a67afe4dSAndroid Build Coastguard Worker                    * required; libpng can be called to do the background
2709*a67afe4dSAndroid Build Coastguard Worker                    * processing.
2710*a67afe4dSAndroid Build Coastguard Worker                    */
2711*a67afe4dSAndroid Build Coastguard Worker                   unsigned int sample_size =
2712*a67afe4dSAndroid Build Coastguard Worker                      PNG_IMAGE_SAMPLE_SIZE(output_format);
2713*a67afe4dSAndroid Build Coastguard Worker                   png_uint_32 r, g, b; /* sRGB background */
2714*a67afe4dSAndroid Build Coastguard Worker 
2715*a67afe4dSAndroid Build Coastguard Worker                   if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries)
2716*a67afe4dSAndroid Build Coastguard Worker                      png_error(png_ptr, "rgb-alpha color-map: too few entries");
2717*a67afe4dSAndroid Build Coastguard Worker 
2718*a67afe4dSAndroid Build Coastguard Worker                   cmap_entries = (unsigned int)make_rgb_colormap(display);
2719*a67afe4dSAndroid Build Coastguard Worker 
2720*a67afe4dSAndroid Build Coastguard Worker                   png_create_colormap_entry(display, cmap_entries, back_r,
2721*a67afe4dSAndroid Build Coastguard Worker                       back_g, back_b, 0/*unused*/, output_encoding);
2722*a67afe4dSAndroid Build Coastguard Worker 
2723*a67afe4dSAndroid Build Coastguard Worker                   if (output_encoding == P_LINEAR)
2724*a67afe4dSAndroid Build Coastguard Worker                   {
2725*a67afe4dSAndroid Build Coastguard Worker                      r = PNG_sRGB_FROM_LINEAR(back_r * 255);
2726*a67afe4dSAndroid Build Coastguard Worker                      g = PNG_sRGB_FROM_LINEAR(back_g * 255);
2727*a67afe4dSAndroid Build Coastguard Worker                      b = PNG_sRGB_FROM_LINEAR(back_b * 255);
2728*a67afe4dSAndroid Build Coastguard Worker                   }
2729*a67afe4dSAndroid Build Coastguard Worker 
2730*a67afe4dSAndroid Build Coastguard Worker                   else
2731*a67afe4dSAndroid Build Coastguard Worker                   {
2732*a67afe4dSAndroid Build Coastguard Worker                      r = back_r;
2733*a67afe4dSAndroid Build Coastguard Worker                      g = back_g;
2734*a67afe4dSAndroid Build Coastguard Worker                      b = back_g;
2735*a67afe4dSAndroid Build Coastguard Worker                   }
2736*a67afe4dSAndroid Build Coastguard Worker 
2737*a67afe4dSAndroid Build Coastguard Worker                   /* Compare the newly-created color-map entry with the one the
2738*a67afe4dSAndroid Build Coastguard Worker                    * PNG_CMAP_RGB algorithm will use.  If the two entries don't
2739*a67afe4dSAndroid Build Coastguard Worker                    * match, add the new one and set this as the background
2740*a67afe4dSAndroid Build Coastguard Worker                    * index.
2741*a67afe4dSAndroid Build Coastguard Worker                    */
2742*a67afe4dSAndroid Build Coastguard Worker                   if (memcmp((png_const_bytep)display->colormap +
2743*a67afe4dSAndroid Build Coastguard Worker                       sample_size * cmap_entries,
2744*a67afe4dSAndroid Build Coastguard Worker                       (png_const_bytep)display->colormap +
2745*a67afe4dSAndroid Build Coastguard Worker                           sample_size * PNG_RGB_INDEX(r,g,b),
2746*a67afe4dSAndroid Build Coastguard Worker                      sample_size) != 0)
2747*a67afe4dSAndroid Build Coastguard Worker                   {
2748*a67afe4dSAndroid Build Coastguard Worker                      /* The background color must be added. */
2749*a67afe4dSAndroid Build Coastguard Worker                      background_index = cmap_entries++;
2750*a67afe4dSAndroid Build Coastguard Worker 
2751*a67afe4dSAndroid Build Coastguard Worker                      /* Add 27 r,g,b entries each with created by composing with
2752*a67afe4dSAndroid Build Coastguard Worker                       * the background at alpha 0.5.
2753*a67afe4dSAndroid Build Coastguard Worker                       */
2754*a67afe4dSAndroid Build Coastguard Worker                      for (r=0; r<256; r = (r << 1) | 0x7f)
2755*a67afe4dSAndroid Build Coastguard Worker                      {
2756*a67afe4dSAndroid Build Coastguard Worker                         for (g=0; g<256; g = (g << 1) | 0x7f)
2757*a67afe4dSAndroid Build Coastguard Worker                         {
2758*a67afe4dSAndroid Build Coastguard Worker                            /* This generates components with the values 0, 127
2759*a67afe4dSAndroid Build Coastguard Worker                             * and 255
2760*a67afe4dSAndroid Build Coastguard Worker                             */
2761*a67afe4dSAndroid Build Coastguard Worker                            for (b=0; b<256; b = (b << 1) | 0x7f)
2762*a67afe4dSAndroid Build Coastguard Worker                               png_create_colormap_entry(display, cmap_entries++,
2763*a67afe4dSAndroid Build Coastguard Worker                                   png_colormap_compose(display, r, P_sRGB, 128,
2764*a67afe4dSAndroid Build Coastguard Worker                                       back_r, output_encoding),
2765*a67afe4dSAndroid Build Coastguard Worker                                   png_colormap_compose(display, g, P_sRGB, 128,
2766*a67afe4dSAndroid Build Coastguard Worker                                       back_g, output_encoding),
2767*a67afe4dSAndroid Build Coastguard Worker                                   png_colormap_compose(display, b, P_sRGB, 128,
2768*a67afe4dSAndroid Build Coastguard Worker                                       back_b, output_encoding),
2769*a67afe4dSAndroid Build Coastguard Worker                                   0/*unused*/, output_encoding);
2770*a67afe4dSAndroid Build Coastguard Worker                         }
2771*a67afe4dSAndroid Build Coastguard Worker                      }
2772*a67afe4dSAndroid Build Coastguard Worker 
2773*a67afe4dSAndroid Build Coastguard Worker                      expand_tRNS = 1;
2774*a67afe4dSAndroid Build Coastguard Worker                      output_processing = PNG_CMAP_RGB_ALPHA;
2775*a67afe4dSAndroid Build Coastguard Worker                   }
2776*a67afe4dSAndroid Build Coastguard Worker 
2777*a67afe4dSAndroid Build Coastguard Worker                   else /* background color is in the standard color-map */
2778*a67afe4dSAndroid Build Coastguard Worker                   {
2779*a67afe4dSAndroid Build Coastguard Worker                      png_color_16 c;
2780*a67afe4dSAndroid Build Coastguard Worker 
2781*a67afe4dSAndroid Build Coastguard Worker                      c.index = 0; /*unused*/
2782*a67afe4dSAndroid Build Coastguard Worker                      c.red = (png_uint_16)back_r;
2783*a67afe4dSAndroid Build Coastguard Worker                      c.gray = c.green = (png_uint_16)back_g;
2784*a67afe4dSAndroid Build Coastguard Worker                      c.blue = (png_uint_16)back_b;
2785*a67afe4dSAndroid Build Coastguard Worker 
2786*a67afe4dSAndroid Build Coastguard Worker                      png_set_background_fixed(png_ptr, &c,
2787*a67afe4dSAndroid Build Coastguard Worker                          PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,
2788*a67afe4dSAndroid Build Coastguard Worker                          0/*gamma: not used*/);
2789*a67afe4dSAndroid Build Coastguard Worker 
2790*a67afe4dSAndroid Build Coastguard Worker                      output_processing = PNG_CMAP_RGB;
2791*a67afe4dSAndroid Build Coastguard Worker                   }
2792*a67afe4dSAndroid Build Coastguard Worker                }
2793*a67afe4dSAndroid Build Coastguard Worker             }
2794*a67afe4dSAndroid Build Coastguard Worker 
2795*a67afe4dSAndroid Build Coastguard Worker             else /* no alpha or transparency in the input */
2796*a67afe4dSAndroid Build Coastguard Worker             {
2797*a67afe4dSAndroid Build Coastguard Worker                /* Alpha in the output is irrelevant, simply map the opaque input
2798*a67afe4dSAndroid Build Coastguard Worker                 * pixels to the 6x6x6 color-map.
2799*a67afe4dSAndroid Build Coastguard Worker                 */
2800*a67afe4dSAndroid Build Coastguard Worker                if (PNG_RGB_COLORMAP_ENTRIES > image->colormap_entries)
2801*a67afe4dSAndroid Build Coastguard Worker                   png_error(png_ptr, "rgb color-map: too few entries");
2802*a67afe4dSAndroid Build Coastguard Worker 
2803*a67afe4dSAndroid Build Coastguard Worker                cmap_entries = (unsigned int)make_rgb_colormap(display);
2804*a67afe4dSAndroid Build Coastguard Worker                output_processing = PNG_CMAP_RGB;
2805*a67afe4dSAndroid Build Coastguard Worker             }
2806*a67afe4dSAndroid Build Coastguard Worker          }
2807*a67afe4dSAndroid Build Coastguard Worker          break;
2808*a67afe4dSAndroid Build Coastguard Worker 
2809*a67afe4dSAndroid Build Coastguard Worker       case PNG_COLOR_TYPE_PALETTE:
2810*a67afe4dSAndroid Build Coastguard Worker          /* It's already got a color-map.  It may be necessary to eliminate the
2811*a67afe4dSAndroid Build Coastguard Worker           * tRNS entries though.
2812*a67afe4dSAndroid Build Coastguard Worker           */
2813*a67afe4dSAndroid Build Coastguard Worker          {
2814*a67afe4dSAndroid Build Coastguard Worker             unsigned int num_trans = png_ptr->num_trans;
2815*a67afe4dSAndroid Build Coastguard Worker             png_const_bytep trans = num_trans > 0 ? png_ptr->trans_alpha : NULL;
2816*a67afe4dSAndroid Build Coastguard Worker             png_const_colorp colormap = png_ptr->palette;
2817*a67afe4dSAndroid Build Coastguard Worker             int do_background = trans != NULL &&
2818*a67afe4dSAndroid Build Coastguard Worker                (output_format & PNG_FORMAT_FLAG_ALPHA) == 0;
2819*a67afe4dSAndroid Build Coastguard Worker             unsigned int i;
2820*a67afe4dSAndroid Build Coastguard Worker 
2821*a67afe4dSAndroid Build Coastguard Worker             /* Just in case: */
2822*a67afe4dSAndroid Build Coastguard Worker             if (trans == NULL)
2823*a67afe4dSAndroid Build Coastguard Worker                num_trans = 0;
2824*a67afe4dSAndroid Build Coastguard Worker 
2825*a67afe4dSAndroid Build Coastguard Worker             output_processing = PNG_CMAP_NONE;
2826*a67afe4dSAndroid Build Coastguard Worker             data_encoding = P_FILE; /* Don't change from color-map indices */
2827*a67afe4dSAndroid Build Coastguard Worker             cmap_entries = (unsigned int)png_ptr->num_palette;
2828*a67afe4dSAndroid Build Coastguard Worker             if (cmap_entries > 256)
2829*a67afe4dSAndroid Build Coastguard Worker                cmap_entries = 256;
2830*a67afe4dSAndroid Build Coastguard Worker 
2831*a67afe4dSAndroid Build Coastguard Worker             if (cmap_entries > (unsigned int)image->colormap_entries)
2832*a67afe4dSAndroid Build Coastguard Worker                png_error(png_ptr, "palette color-map: too few entries");
2833*a67afe4dSAndroid Build Coastguard Worker 
2834*a67afe4dSAndroid Build Coastguard Worker             for (i=0; i < cmap_entries; ++i)
2835*a67afe4dSAndroid Build Coastguard Worker             {
2836*a67afe4dSAndroid Build Coastguard Worker                if (do_background != 0 && i < num_trans && trans[i] < 255)
2837*a67afe4dSAndroid Build Coastguard Worker                {
2838*a67afe4dSAndroid Build Coastguard Worker                   if (trans[i] == 0)
2839*a67afe4dSAndroid Build Coastguard Worker                      png_create_colormap_entry(display, i, back_r, back_g,
2840*a67afe4dSAndroid Build Coastguard Worker                          back_b, 0, output_encoding);
2841*a67afe4dSAndroid Build Coastguard Worker 
2842*a67afe4dSAndroid Build Coastguard Worker                   else
2843*a67afe4dSAndroid Build Coastguard Worker                   {
2844*a67afe4dSAndroid Build Coastguard Worker                      /* Must compose the PNG file color in the color-map entry
2845*a67afe4dSAndroid Build Coastguard Worker                       * on the sRGB color in 'back'.
2846*a67afe4dSAndroid Build Coastguard Worker                       */
2847*a67afe4dSAndroid Build Coastguard Worker                      png_create_colormap_entry(display, i,
2848*a67afe4dSAndroid Build Coastguard Worker                          png_colormap_compose(display, colormap[i].red,
2849*a67afe4dSAndroid Build Coastguard Worker                              P_FILE, trans[i], back_r, output_encoding),
2850*a67afe4dSAndroid Build Coastguard Worker                          png_colormap_compose(display, colormap[i].green,
2851*a67afe4dSAndroid Build Coastguard Worker                              P_FILE, trans[i], back_g, output_encoding),
2852*a67afe4dSAndroid Build Coastguard Worker                          png_colormap_compose(display, colormap[i].blue,
2853*a67afe4dSAndroid Build Coastguard Worker                              P_FILE, trans[i], back_b, output_encoding),
2854*a67afe4dSAndroid Build Coastguard Worker                          output_encoding == P_LINEAR ? trans[i] * 257U :
2855*a67afe4dSAndroid Build Coastguard Worker                              trans[i],
2856*a67afe4dSAndroid Build Coastguard Worker                          output_encoding);
2857*a67afe4dSAndroid Build Coastguard Worker                   }
2858*a67afe4dSAndroid Build Coastguard Worker                }
2859*a67afe4dSAndroid Build Coastguard Worker 
2860*a67afe4dSAndroid Build Coastguard Worker                else
2861*a67afe4dSAndroid Build Coastguard Worker                   png_create_colormap_entry(display, i, colormap[i].red,
2862*a67afe4dSAndroid Build Coastguard Worker                       colormap[i].green, colormap[i].blue,
2863*a67afe4dSAndroid Build Coastguard Worker                       i < num_trans ? trans[i] : 255U, P_FILE/*8-bit*/);
2864*a67afe4dSAndroid Build Coastguard Worker             }
2865*a67afe4dSAndroid Build Coastguard Worker 
2866*a67afe4dSAndroid Build Coastguard Worker             /* The PNG data may have indices packed in fewer than 8 bits, it
2867*a67afe4dSAndroid Build Coastguard Worker              * must be expanded if so.
2868*a67afe4dSAndroid Build Coastguard Worker              */
2869*a67afe4dSAndroid Build Coastguard Worker             if (png_ptr->bit_depth < 8)
2870*a67afe4dSAndroid Build Coastguard Worker                png_set_packing(png_ptr);
2871*a67afe4dSAndroid Build Coastguard Worker          }
2872*a67afe4dSAndroid Build Coastguard Worker          break;
2873*a67afe4dSAndroid Build Coastguard Worker 
2874*a67afe4dSAndroid Build Coastguard Worker       default:
2875*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr, "invalid PNG color type");
2876*a67afe4dSAndroid Build Coastguard Worker          /*NOT REACHED*/
2877*a67afe4dSAndroid Build Coastguard Worker    }
2878*a67afe4dSAndroid Build Coastguard Worker 
2879*a67afe4dSAndroid Build Coastguard Worker    /* Now deal with the output processing */
2880*a67afe4dSAndroid Build Coastguard Worker    if (expand_tRNS != 0 && png_ptr->num_trans > 0 &&
2881*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) == 0)
2882*a67afe4dSAndroid Build Coastguard Worker       png_set_tRNS_to_alpha(png_ptr);
2883*a67afe4dSAndroid Build Coastguard Worker 
2884*a67afe4dSAndroid Build Coastguard Worker    switch (data_encoding)
2885*a67afe4dSAndroid Build Coastguard Worker    {
2886*a67afe4dSAndroid Build Coastguard Worker       case P_sRGB:
2887*a67afe4dSAndroid Build Coastguard Worker          /* Change to 8-bit sRGB */
2888*a67afe4dSAndroid Build Coastguard Worker          png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, PNG_GAMMA_sRGB);
2889*a67afe4dSAndroid Build Coastguard Worker          /* FALLTHROUGH */
2890*a67afe4dSAndroid Build Coastguard Worker 
2891*a67afe4dSAndroid Build Coastguard Worker       case P_FILE:
2892*a67afe4dSAndroid Build Coastguard Worker          if (png_ptr->bit_depth > 8)
2893*a67afe4dSAndroid Build Coastguard Worker             png_set_scale_16(png_ptr);
2894*a67afe4dSAndroid Build Coastguard Worker          break;
2895*a67afe4dSAndroid Build Coastguard Worker 
2896*a67afe4dSAndroid Build Coastguard Worker #ifdef __GNUC__
2897*a67afe4dSAndroid Build Coastguard Worker       default:
2898*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr, "bad data option (internal error)");
2899*a67afe4dSAndroid Build Coastguard Worker #endif
2900*a67afe4dSAndroid Build Coastguard Worker    }
2901*a67afe4dSAndroid Build Coastguard Worker 
2902*a67afe4dSAndroid Build Coastguard Worker    if (cmap_entries > 256 || cmap_entries > image->colormap_entries)
2903*a67afe4dSAndroid Build Coastguard Worker       png_error(png_ptr, "color map overflow (BAD internal error)");
2904*a67afe4dSAndroid Build Coastguard Worker 
2905*a67afe4dSAndroid Build Coastguard Worker    image->colormap_entries = cmap_entries;
2906*a67afe4dSAndroid Build Coastguard Worker 
2907*a67afe4dSAndroid Build Coastguard Worker    /* Double check using the recorded background index */
2908*a67afe4dSAndroid Build Coastguard Worker    switch (output_processing)
2909*a67afe4dSAndroid Build Coastguard Worker    {
2910*a67afe4dSAndroid Build Coastguard Worker       case PNG_CMAP_NONE:
2911*a67afe4dSAndroid Build Coastguard Worker          if (background_index != PNG_CMAP_NONE_BACKGROUND)
2912*a67afe4dSAndroid Build Coastguard Worker             goto bad_background;
2913*a67afe4dSAndroid Build Coastguard Worker          break;
2914*a67afe4dSAndroid Build Coastguard Worker 
2915*a67afe4dSAndroid Build Coastguard Worker       case PNG_CMAP_GA:
2916*a67afe4dSAndroid Build Coastguard Worker          if (background_index != PNG_CMAP_GA_BACKGROUND)
2917*a67afe4dSAndroid Build Coastguard Worker             goto bad_background;
2918*a67afe4dSAndroid Build Coastguard Worker          break;
2919*a67afe4dSAndroid Build Coastguard Worker 
2920*a67afe4dSAndroid Build Coastguard Worker       case PNG_CMAP_TRANS:
2921*a67afe4dSAndroid Build Coastguard Worker          if (background_index >= cmap_entries ||
2922*a67afe4dSAndroid Build Coastguard Worker             background_index != PNG_CMAP_TRANS_BACKGROUND)
2923*a67afe4dSAndroid Build Coastguard Worker             goto bad_background;
2924*a67afe4dSAndroid Build Coastguard Worker          break;
2925*a67afe4dSAndroid Build Coastguard Worker 
2926*a67afe4dSAndroid Build Coastguard Worker       case PNG_CMAP_RGB:
2927*a67afe4dSAndroid Build Coastguard Worker          if (background_index != PNG_CMAP_RGB_BACKGROUND)
2928*a67afe4dSAndroid Build Coastguard Worker             goto bad_background;
2929*a67afe4dSAndroid Build Coastguard Worker          break;
2930*a67afe4dSAndroid Build Coastguard Worker 
2931*a67afe4dSAndroid Build Coastguard Worker       case PNG_CMAP_RGB_ALPHA:
2932*a67afe4dSAndroid Build Coastguard Worker          if (background_index != PNG_CMAP_RGB_ALPHA_BACKGROUND)
2933*a67afe4dSAndroid Build Coastguard Worker             goto bad_background;
2934*a67afe4dSAndroid Build Coastguard Worker          break;
2935*a67afe4dSAndroid Build Coastguard Worker 
2936*a67afe4dSAndroid Build Coastguard Worker       default:
2937*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr, "bad processing option (internal error)");
2938*a67afe4dSAndroid Build Coastguard Worker 
2939*a67afe4dSAndroid Build Coastguard Worker       bad_background:
2940*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr, "bad background index (internal error)");
2941*a67afe4dSAndroid Build Coastguard Worker    }
2942*a67afe4dSAndroid Build Coastguard Worker 
2943*a67afe4dSAndroid Build Coastguard Worker    display->colormap_processing = (int)output_processing;
2944*a67afe4dSAndroid Build Coastguard Worker 
2945*a67afe4dSAndroid Build Coastguard Worker    return 1/*ok*/;
2946*a67afe4dSAndroid Build Coastguard Worker }
2947*a67afe4dSAndroid Build Coastguard Worker 
2948*a67afe4dSAndroid Build Coastguard Worker /* The final part of the color-map read called from png_image_finish_read. */
2949*a67afe4dSAndroid Build Coastguard Worker static int
png_image_read_and_map(png_voidp argument)2950*a67afe4dSAndroid Build Coastguard Worker png_image_read_and_map(png_voidp argument)
2951*a67afe4dSAndroid Build Coastguard Worker {
2952*a67afe4dSAndroid Build Coastguard Worker    png_image_read_control *display = png_voidcast(png_image_read_control*,
2953*a67afe4dSAndroid Build Coastguard Worker        argument);
2954*a67afe4dSAndroid Build Coastguard Worker    png_imagep image = display->image;
2955*a67afe4dSAndroid Build Coastguard Worker    png_structrp png_ptr = image->opaque->png_ptr;
2956*a67afe4dSAndroid Build Coastguard Worker    int passes;
2957*a67afe4dSAndroid Build Coastguard Worker 
2958*a67afe4dSAndroid Build Coastguard Worker    /* Called when the libpng data must be transformed into the color-mapped
2959*a67afe4dSAndroid Build Coastguard Worker     * form.  There is a local row buffer in display->local and this routine must
2960*a67afe4dSAndroid Build Coastguard Worker     * do the interlace handling.
2961*a67afe4dSAndroid Build Coastguard Worker     */
2962*a67afe4dSAndroid Build Coastguard Worker    switch (png_ptr->interlaced)
2963*a67afe4dSAndroid Build Coastguard Worker    {
2964*a67afe4dSAndroid Build Coastguard Worker       case PNG_INTERLACE_NONE:
2965*a67afe4dSAndroid Build Coastguard Worker          passes = 1;
2966*a67afe4dSAndroid Build Coastguard Worker          break;
2967*a67afe4dSAndroid Build Coastguard Worker 
2968*a67afe4dSAndroid Build Coastguard Worker       case PNG_INTERLACE_ADAM7:
2969*a67afe4dSAndroid Build Coastguard Worker          passes = PNG_INTERLACE_ADAM7_PASSES;
2970*a67afe4dSAndroid Build Coastguard Worker          break;
2971*a67afe4dSAndroid Build Coastguard Worker 
2972*a67afe4dSAndroid Build Coastguard Worker       default:
2973*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr, "unknown interlace type");
2974*a67afe4dSAndroid Build Coastguard Worker    }
2975*a67afe4dSAndroid Build Coastguard Worker 
2976*a67afe4dSAndroid Build Coastguard Worker    {
2977*a67afe4dSAndroid Build Coastguard Worker       png_uint_32  height = image->height;
2978*a67afe4dSAndroid Build Coastguard Worker       png_uint_32  width = image->width;
2979*a67afe4dSAndroid Build Coastguard Worker       int          proc = display->colormap_processing;
2980*a67afe4dSAndroid Build Coastguard Worker       png_bytep    first_row = png_voidcast(png_bytep, display->first_row);
2981*a67afe4dSAndroid Build Coastguard Worker       ptrdiff_t    step_row = display->row_bytes;
2982*a67afe4dSAndroid Build Coastguard Worker       int pass;
2983*a67afe4dSAndroid Build Coastguard Worker 
2984*a67afe4dSAndroid Build Coastguard Worker       for (pass = 0; pass < passes; ++pass)
2985*a67afe4dSAndroid Build Coastguard Worker       {
2986*a67afe4dSAndroid Build Coastguard Worker          unsigned int     startx, stepx, stepy;
2987*a67afe4dSAndroid Build Coastguard Worker          png_uint_32      y;
2988*a67afe4dSAndroid Build Coastguard Worker 
2989*a67afe4dSAndroid Build Coastguard Worker          if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)
2990*a67afe4dSAndroid Build Coastguard Worker          {
2991*a67afe4dSAndroid Build Coastguard Worker             /* The row may be empty for a short image: */
2992*a67afe4dSAndroid Build Coastguard Worker             if (PNG_PASS_COLS(width, pass) == 0)
2993*a67afe4dSAndroid Build Coastguard Worker                continue;
2994*a67afe4dSAndroid Build Coastguard Worker 
2995*a67afe4dSAndroid Build Coastguard Worker             startx = PNG_PASS_START_COL(pass);
2996*a67afe4dSAndroid Build Coastguard Worker             stepx = PNG_PASS_COL_OFFSET(pass);
2997*a67afe4dSAndroid Build Coastguard Worker             y = PNG_PASS_START_ROW(pass);
2998*a67afe4dSAndroid Build Coastguard Worker             stepy = PNG_PASS_ROW_OFFSET(pass);
2999*a67afe4dSAndroid Build Coastguard Worker          }
3000*a67afe4dSAndroid Build Coastguard Worker 
3001*a67afe4dSAndroid Build Coastguard Worker          else
3002*a67afe4dSAndroid Build Coastguard Worker          {
3003*a67afe4dSAndroid Build Coastguard Worker             y = 0;
3004*a67afe4dSAndroid Build Coastguard Worker             startx = 0;
3005*a67afe4dSAndroid Build Coastguard Worker             stepx = stepy = 1;
3006*a67afe4dSAndroid Build Coastguard Worker          }
3007*a67afe4dSAndroid Build Coastguard Worker 
3008*a67afe4dSAndroid Build Coastguard Worker          for (; y<height; y += stepy)
3009*a67afe4dSAndroid Build Coastguard Worker          {
3010*a67afe4dSAndroid Build Coastguard Worker             png_bytep inrow = png_voidcast(png_bytep, display->local_row);
3011*a67afe4dSAndroid Build Coastguard Worker             png_bytep outrow = first_row + y * step_row;
3012*a67afe4dSAndroid Build Coastguard Worker             png_const_bytep end_row = outrow + width;
3013*a67afe4dSAndroid Build Coastguard Worker 
3014*a67afe4dSAndroid Build Coastguard Worker             /* Read read the libpng data into the temporary buffer. */
3015*a67afe4dSAndroid Build Coastguard Worker             png_read_row(png_ptr, inrow, NULL);
3016*a67afe4dSAndroid Build Coastguard Worker 
3017*a67afe4dSAndroid Build Coastguard Worker             /* Now process the row according to the processing option, note
3018*a67afe4dSAndroid Build Coastguard Worker              * that the caller verifies that the format of the libpng output
3019*a67afe4dSAndroid Build Coastguard Worker              * data is as required.
3020*a67afe4dSAndroid Build Coastguard Worker              */
3021*a67afe4dSAndroid Build Coastguard Worker             outrow += startx;
3022*a67afe4dSAndroid Build Coastguard Worker             switch (proc)
3023*a67afe4dSAndroid Build Coastguard Worker             {
3024*a67afe4dSAndroid Build Coastguard Worker                case PNG_CMAP_GA:
3025*a67afe4dSAndroid Build Coastguard Worker                   for (; outrow < end_row; outrow += stepx)
3026*a67afe4dSAndroid Build Coastguard Worker                   {
3027*a67afe4dSAndroid Build Coastguard Worker                      /* The data is always in the PNG order */
3028*a67afe4dSAndroid Build Coastguard Worker                      unsigned int gray = *inrow++;
3029*a67afe4dSAndroid Build Coastguard Worker                      unsigned int alpha = *inrow++;
3030*a67afe4dSAndroid Build Coastguard Worker                      unsigned int entry;
3031*a67afe4dSAndroid Build Coastguard Worker 
3032*a67afe4dSAndroid Build Coastguard Worker                      /* NOTE: this code is copied as a comment in
3033*a67afe4dSAndroid Build Coastguard Worker                       * make_ga_colormap above.  Please update the
3034*a67afe4dSAndroid Build Coastguard Worker                       * comment if you change this code!
3035*a67afe4dSAndroid Build Coastguard Worker                       */
3036*a67afe4dSAndroid Build Coastguard Worker                      if (alpha > 229) /* opaque */
3037*a67afe4dSAndroid Build Coastguard Worker                      {
3038*a67afe4dSAndroid Build Coastguard Worker                         entry = (231 * gray + 128) >> 8;
3039*a67afe4dSAndroid Build Coastguard Worker                      }
3040*a67afe4dSAndroid Build Coastguard Worker                      else if (alpha < 26) /* transparent */
3041*a67afe4dSAndroid Build Coastguard Worker                      {
3042*a67afe4dSAndroid Build Coastguard Worker                         entry = 231;
3043*a67afe4dSAndroid Build Coastguard Worker                      }
3044*a67afe4dSAndroid Build Coastguard Worker                      else /* partially opaque */
3045*a67afe4dSAndroid Build Coastguard Worker                      {
3046*a67afe4dSAndroid Build Coastguard Worker                         entry = 226 + 6 * PNG_DIV51(alpha) + PNG_DIV51(gray);
3047*a67afe4dSAndroid Build Coastguard Worker                      }
3048*a67afe4dSAndroid Build Coastguard Worker 
3049*a67afe4dSAndroid Build Coastguard Worker                      *outrow = (png_byte)entry;
3050*a67afe4dSAndroid Build Coastguard Worker                   }
3051*a67afe4dSAndroid Build Coastguard Worker                   break;
3052*a67afe4dSAndroid Build Coastguard Worker 
3053*a67afe4dSAndroid Build Coastguard Worker                case PNG_CMAP_TRANS:
3054*a67afe4dSAndroid Build Coastguard Worker                   for (; outrow < end_row; outrow += stepx)
3055*a67afe4dSAndroid Build Coastguard Worker                   {
3056*a67afe4dSAndroid Build Coastguard Worker                      png_byte gray = *inrow++;
3057*a67afe4dSAndroid Build Coastguard Worker                      png_byte alpha = *inrow++;
3058*a67afe4dSAndroid Build Coastguard Worker 
3059*a67afe4dSAndroid Build Coastguard Worker                      if (alpha == 0)
3060*a67afe4dSAndroid Build Coastguard Worker                         *outrow = PNG_CMAP_TRANS_BACKGROUND;
3061*a67afe4dSAndroid Build Coastguard Worker 
3062*a67afe4dSAndroid Build Coastguard Worker                      else if (gray != PNG_CMAP_TRANS_BACKGROUND)
3063*a67afe4dSAndroid Build Coastguard Worker                         *outrow = gray;
3064*a67afe4dSAndroid Build Coastguard Worker 
3065*a67afe4dSAndroid Build Coastguard Worker                      else
3066*a67afe4dSAndroid Build Coastguard Worker                         *outrow = (png_byte)(PNG_CMAP_TRANS_BACKGROUND+1);
3067*a67afe4dSAndroid Build Coastguard Worker                   }
3068*a67afe4dSAndroid Build Coastguard Worker                   break;
3069*a67afe4dSAndroid Build Coastguard Worker 
3070*a67afe4dSAndroid Build Coastguard Worker                case PNG_CMAP_RGB:
3071*a67afe4dSAndroid Build Coastguard Worker                   for (; outrow < end_row; outrow += stepx)
3072*a67afe4dSAndroid Build Coastguard Worker                   {
3073*a67afe4dSAndroid Build Coastguard Worker                      *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], inrow[2]);
3074*a67afe4dSAndroid Build Coastguard Worker                      inrow += 3;
3075*a67afe4dSAndroid Build Coastguard Worker                   }
3076*a67afe4dSAndroid Build Coastguard Worker                   break;
3077*a67afe4dSAndroid Build Coastguard Worker 
3078*a67afe4dSAndroid Build Coastguard Worker                case PNG_CMAP_RGB_ALPHA:
3079*a67afe4dSAndroid Build Coastguard Worker                   for (; outrow < end_row; outrow += stepx)
3080*a67afe4dSAndroid Build Coastguard Worker                   {
3081*a67afe4dSAndroid Build Coastguard Worker                      unsigned int alpha = inrow[3];
3082*a67afe4dSAndroid Build Coastguard Worker 
3083*a67afe4dSAndroid Build Coastguard Worker                      /* Because the alpha entries only hold alpha==0.5 values
3084*a67afe4dSAndroid Build Coastguard Worker                       * split the processing at alpha==0.25 (64) and 0.75
3085*a67afe4dSAndroid Build Coastguard Worker                       * (196).
3086*a67afe4dSAndroid Build Coastguard Worker                       */
3087*a67afe4dSAndroid Build Coastguard Worker 
3088*a67afe4dSAndroid Build Coastguard Worker                      if (alpha >= 196)
3089*a67afe4dSAndroid Build Coastguard Worker                         *outrow = PNG_RGB_INDEX(inrow[0], inrow[1],
3090*a67afe4dSAndroid Build Coastguard Worker                             inrow[2]);
3091*a67afe4dSAndroid Build Coastguard Worker 
3092*a67afe4dSAndroid Build Coastguard Worker                      else if (alpha < 64)
3093*a67afe4dSAndroid Build Coastguard Worker                         *outrow = PNG_CMAP_RGB_ALPHA_BACKGROUND;
3094*a67afe4dSAndroid Build Coastguard Worker 
3095*a67afe4dSAndroid Build Coastguard Worker                      else
3096*a67afe4dSAndroid Build Coastguard Worker                      {
3097*a67afe4dSAndroid Build Coastguard Worker                         /* Likewise there are three entries for each of r, g
3098*a67afe4dSAndroid Build Coastguard Worker                          * and b.  We could select the entry by popcount on
3099*a67afe4dSAndroid Build Coastguard Worker                          * the top two bits on those architectures that
3100*a67afe4dSAndroid Build Coastguard Worker                          * support it, this is what the code below does,
3101*a67afe4dSAndroid Build Coastguard Worker                          * crudely.
3102*a67afe4dSAndroid Build Coastguard Worker                          */
3103*a67afe4dSAndroid Build Coastguard Worker                         unsigned int back_i = PNG_CMAP_RGB_ALPHA_BACKGROUND+1;
3104*a67afe4dSAndroid Build Coastguard Worker 
3105*a67afe4dSAndroid Build Coastguard Worker                         /* Here are how the values map:
3106*a67afe4dSAndroid Build Coastguard Worker                          *
3107*a67afe4dSAndroid Build Coastguard Worker                          * 0x00 .. 0x3f -> 0
3108*a67afe4dSAndroid Build Coastguard Worker                          * 0x40 .. 0xbf -> 1
3109*a67afe4dSAndroid Build Coastguard Worker                          * 0xc0 .. 0xff -> 2
3110*a67afe4dSAndroid Build Coastguard Worker                          *
3111*a67afe4dSAndroid Build Coastguard Worker                          * So, as above with the explicit alpha checks, the
3112*a67afe4dSAndroid Build Coastguard Worker                          * breakpoints are at 64 and 196.
3113*a67afe4dSAndroid Build Coastguard Worker                          */
3114*a67afe4dSAndroid Build Coastguard Worker                         if (inrow[0] & 0x80) back_i += 9; /* red */
3115*a67afe4dSAndroid Build Coastguard Worker                         if (inrow[0] & 0x40) back_i += 9;
3116*a67afe4dSAndroid Build Coastguard Worker                         if (inrow[0] & 0x80) back_i += 3; /* green */
3117*a67afe4dSAndroid Build Coastguard Worker                         if (inrow[0] & 0x40) back_i += 3;
3118*a67afe4dSAndroid Build Coastguard Worker                         if (inrow[0] & 0x80) back_i += 1; /* blue */
3119*a67afe4dSAndroid Build Coastguard Worker                         if (inrow[0] & 0x40) back_i += 1;
3120*a67afe4dSAndroid Build Coastguard Worker 
3121*a67afe4dSAndroid Build Coastguard Worker                         *outrow = (png_byte)back_i;
3122*a67afe4dSAndroid Build Coastguard Worker                      }
3123*a67afe4dSAndroid Build Coastguard Worker 
3124*a67afe4dSAndroid Build Coastguard Worker                      inrow += 4;
3125*a67afe4dSAndroid Build Coastguard Worker                   }
3126*a67afe4dSAndroid Build Coastguard Worker                   break;
3127*a67afe4dSAndroid Build Coastguard Worker 
3128*a67afe4dSAndroid Build Coastguard Worker                default:
3129*a67afe4dSAndroid Build Coastguard Worker                   break;
3130*a67afe4dSAndroid Build Coastguard Worker             }
3131*a67afe4dSAndroid Build Coastguard Worker          }
3132*a67afe4dSAndroid Build Coastguard Worker       }
3133*a67afe4dSAndroid Build Coastguard Worker    }
3134*a67afe4dSAndroid Build Coastguard Worker 
3135*a67afe4dSAndroid Build Coastguard Worker    return 1;
3136*a67afe4dSAndroid Build Coastguard Worker }
3137*a67afe4dSAndroid Build Coastguard Worker 
3138*a67afe4dSAndroid Build Coastguard Worker static int
png_image_read_colormapped(png_voidp argument)3139*a67afe4dSAndroid Build Coastguard Worker png_image_read_colormapped(png_voidp argument)
3140*a67afe4dSAndroid Build Coastguard Worker {
3141*a67afe4dSAndroid Build Coastguard Worker    png_image_read_control *display = png_voidcast(png_image_read_control*,
3142*a67afe4dSAndroid Build Coastguard Worker        argument);
3143*a67afe4dSAndroid Build Coastguard Worker    png_imagep image = display->image;
3144*a67afe4dSAndroid Build Coastguard Worker    png_controlp control = image->opaque;
3145*a67afe4dSAndroid Build Coastguard Worker    png_structrp png_ptr = control->png_ptr;
3146*a67afe4dSAndroid Build Coastguard Worker    png_inforp info_ptr = control->info_ptr;
3147*a67afe4dSAndroid Build Coastguard Worker 
3148*a67afe4dSAndroid Build Coastguard Worker    int passes = 0; /* As a flag */
3149*a67afe4dSAndroid Build Coastguard Worker 
3150*a67afe4dSAndroid Build Coastguard Worker    PNG_SKIP_CHUNKS(png_ptr);
3151*a67afe4dSAndroid Build Coastguard Worker 
3152*a67afe4dSAndroid Build Coastguard Worker    /* Update the 'info' structure and make sure the result is as required; first
3153*a67afe4dSAndroid Build Coastguard Worker     * make sure to turn on the interlace handling if it will be required
3154*a67afe4dSAndroid Build Coastguard Worker     * (because it can't be turned on *after* the call to png_read_update_info!)
3155*a67afe4dSAndroid Build Coastguard Worker     */
3156*a67afe4dSAndroid Build Coastguard Worker    if (display->colormap_processing == PNG_CMAP_NONE)
3157*a67afe4dSAndroid Build Coastguard Worker       passes = png_set_interlace_handling(png_ptr);
3158*a67afe4dSAndroid Build Coastguard Worker 
3159*a67afe4dSAndroid Build Coastguard Worker    png_read_update_info(png_ptr, info_ptr);
3160*a67afe4dSAndroid Build Coastguard Worker 
3161*a67afe4dSAndroid Build Coastguard Worker    /* The expected output can be deduced from the colormap_processing option. */
3162*a67afe4dSAndroid Build Coastguard Worker    switch (display->colormap_processing)
3163*a67afe4dSAndroid Build Coastguard Worker    {
3164*a67afe4dSAndroid Build Coastguard Worker       case PNG_CMAP_NONE:
3165*a67afe4dSAndroid Build Coastguard Worker          /* Output must be one channel and one byte per pixel, the output
3166*a67afe4dSAndroid Build Coastguard Worker           * encoding can be anything.
3167*a67afe4dSAndroid Build Coastguard Worker           */
3168*a67afe4dSAndroid Build Coastguard Worker          if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
3169*a67afe4dSAndroid Build Coastguard Worker             info_ptr->color_type == PNG_COLOR_TYPE_GRAY) &&
3170*a67afe4dSAndroid Build Coastguard Worker             info_ptr->bit_depth == 8)
3171*a67afe4dSAndroid Build Coastguard Worker             break;
3172*a67afe4dSAndroid Build Coastguard Worker 
3173*a67afe4dSAndroid Build Coastguard Worker          goto bad_output;
3174*a67afe4dSAndroid Build Coastguard Worker 
3175*a67afe4dSAndroid Build Coastguard Worker       case PNG_CMAP_TRANS:
3176*a67afe4dSAndroid Build Coastguard Worker       case PNG_CMAP_GA:
3177*a67afe4dSAndroid Build Coastguard Worker          /* Output must be two channels and the 'G' one must be sRGB, the latter
3178*a67afe4dSAndroid Build Coastguard Worker           * can be checked with an exact number because it should have been set
3179*a67afe4dSAndroid Build Coastguard Worker           * to this number above!
3180*a67afe4dSAndroid Build Coastguard Worker           */
3181*a67afe4dSAndroid Build Coastguard Worker          if (info_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&
3182*a67afe4dSAndroid Build Coastguard Worker             info_ptr->bit_depth == 8 &&
3183*a67afe4dSAndroid Build Coastguard Worker             png_ptr->screen_gamma == PNG_GAMMA_sRGB &&
3184*a67afe4dSAndroid Build Coastguard Worker             image->colormap_entries == 256)
3185*a67afe4dSAndroid Build Coastguard Worker             break;
3186*a67afe4dSAndroid Build Coastguard Worker 
3187*a67afe4dSAndroid Build Coastguard Worker          goto bad_output;
3188*a67afe4dSAndroid Build Coastguard Worker 
3189*a67afe4dSAndroid Build Coastguard Worker       case PNG_CMAP_RGB:
3190*a67afe4dSAndroid Build Coastguard Worker          /* Output must be 8-bit sRGB encoded RGB */
3191*a67afe4dSAndroid Build Coastguard Worker          if (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
3192*a67afe4dSAndroid Build Coastguard Worker             info_ptr->bit_depth == 8 &&
3193*a67afe4dSAndroid Build Coastguard Worker             png_ptr->screen_gamma == PNG_GAMMA_sRGB &&
3194*a67afe4dSAndroid Build Coastguard Worker             image->colormap_entries == 216)
3195*a67afe4dSAndroid Build Coastguard Worker             break;
3196*a67afe4dSAndroid Build Coastguard Worker 
3197*a67afe4dSAndroid Build Coastguard Worker          goto bad_output;
3198*a67afe4dSAndroid Build Coastguard Worker 
3199*a67afe4dSAndroid Build Coastguard Worker       case PNG_CMAP_RGB_ALPHA:
3200*a67afe4dSAndroid Build Coastguard Worker          /* Output must be 8-bit sRGB encoded RGBA */
3201*a67afe4dSAndroid Build Coastguard Worker          if (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
3202*a67afe4dSAndroid Build Coastguard Worker             info_ptr->bit_depth == 8 &&
3203*a67afe4dSAndroid Build Coastguard Worker             png_ptr->screen_gamma == PNG_GAMMA_sRGB &&
3204*a67afe4dSAndroid Build Coastguard Worker             image->colormap_entries == 244 /* 216 + 1 + 27 */)
3205*a67afe4dSAndroid Build Coastguard Worker             break;
3206*a67afe4dSAndroid Build Coastguard Worker 
3207*a67afe4dSAndroid Build Coastguard Worker          goto bad_output;
3208*a67afe4dSAndroid Build Coastguard Worker 
3209*a67afe4dSAndroid Build Coastguard Worker       default:
3210*a67afe4dSAndroid Build Coastguard Worker       bad_output:
3211*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr, "bad color-map processing (internal error)");
3212*a67afe4dSAndroid Build Coastguard Worker    }
3213*a67afe4dSAndroid Build Coastguard Worker 
3214*a67afe4dSAndroid Build Coastguard Worker    /* Now read the rows.  Do this here if it is possible to read directly into
3215*a67afe4dSAndroid Build Coastguard Worker     * the output buffer, otherwise allocate a local row buffer of the maximum
3216*a67afe4dSAndroid Build Coastguard Worker     * size libpng requires and call the relevant processing routine safely.
3217*a67afe4dSAndroid Build Coastguard Worker     */
3218*a67afe4dSAndroid Build Coastguard Worker    {
3219*a67afe4dSAndroid Build Coastguard Worker       png_voidp first_row = display->buffer;
3220*a67afe4dSAndroid Build Coastguard Worker       ptrdiff_t row_bytes = display->row_stride;
3221*a67afe4dSAndroid Build Coastguard Worker 
3222*a67afe4dSAndroid Build Coastguard Worker       /* The following expression is designed to work correctly whether it gives
3223*a67afe4dSAndroid Build Coastguard Worker        * a signed or an unsigned result.
3224*a67afe4dSAndroid Build Coastguard Worker        */
3225*a67afe4dSAndroid Build Coastguard Worker       if (row_bytes < 0)
3226*a67afe4dSAndroid Build Coastguard Worker       {
3227*a67afe4dSAndroid Build Coastguard Worker          char *ptr = png_voidcast(char*, first_row);
3228*a67afe4dSAndroid Build Coastguard Worker          ptr += (image->height-1) * (-row_bytes);
3229*a67afe4dSAndroid Build Coastguard Worker          first_row = png_voidcast(png_voidp, ptr);
3230*a67afe4dSAndroid Build Coastguard Worker       }
3231*a67afe4dSAndroid Build Coastguard Worker 
3232*a67afe4dSAndroid Build Coastguard Worker       display->first_row = first_row;
3233*a67afe4dSAndroid Build Coastguard Worker       display->row_bytes = row_bytes;
3234*a67afe4dSAndroid Build Coastguard Worker    }
3235*a67afe4dSAndroid Build Coastguard Worker 
3236*a67afe4dSAndroid Build Coastguard Worker    if (passes == 0)
3237*a67afe4dSAndroid Build Coastguard Worker    {
3238*a67afe4dSAndroid Build Coastguard Worker       int result;
3239*a67afe4dSAndroid Build Coastguard Worker       png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
3240*a67afe4dSAndroid Build Coastguard Worker 
3241*a67afe4dSAndroid Build Coastguard Worker       display->local_row = row;
3242*a67afe4dSAndroid Build Coastguard Worker       result = png_safe_execute(image, png_image_read_and_map, display);
3243*a67afe4dSAndroid Build Coastguard Worker       display->local_row = NULL;
3244*a67afe4dSAndroid Build Coastguard Worker       png_free(png_ptr, row);
3245*a67afe4dSAndroid Build Coastguard Worker 
3246*a67afe4dSAndroid Build Coastguard Worker       return result;
3247*a67afe4dSAndroid Build Coastguard Worker    }
3248*a67afe4dSAndroid Build Coastguard Worker 
3249*a67afe4dSAndroid Build Coastguard Worker    else
3250*a67afe4dSAndroid Build Coastguard Worker    {
3251*a67afe4dSAndroid Build Coastguard Worker       png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes;
3252*a67afe4dSAndroid Build Coastguard Worker 
3253*a67afe4dSAndroid Build Coastguard Worker       while (--passes >= 0)
3254*a67afe4dSAndroid Build Coastguard Worker       {
3255*a67afe4dSAndroid Build Coastguard Worker          png_uint_32      y = image->height;
3256*a67afe4dSAndroid Build Coastguard Worker          png_bytep        row = png_voidcast(png_bytep, display->first_row);
3257*a67afe4dSAndroid Build Coastguard Worker 
3258*a67afe4dSAndroid Build Coastguard Worker          for (; y > 0; --y)
3259*a67afe4dSAndroid Build Coastguard Worker          {
3260*a67afe4dSAndroid Build Coastguard Worker             png_read_row(png_ptr, row, NULL);
3261*a67afe4dSAndroid Build Coastguard Worker             row += row_bytes;
3262*a67afe4dSAndroid Build Coastguard Worker          }
3263*a67afe4dSAndroid Build Coastguard Worker       }
3264*a67afe4dSAndroid Build Coastguard Worker 
3265*a67afe4dSAndroid Build Coastguard Worker       return 1;
3266*a67afe4dSAndroid Build Coastguard Worker    }
3267*a67afe4dSAndroid Build Coastguard Worker }
3268*a67afe4dSAndroid Build Coastguard Worker 
3269*a67afe4dSAndroid Build Coastguard Worker /* Just the row reading part of png_image_read. */
3270*a67afe4dSAndroid Build Coastguard Worker static int
png_image_read_composite(png_voidp argument)3271*a67afe4dSAndroid Build Coastguard Worker png_image_read_composite(png_voidp argument)
3272*a67afe4dSAndroid Build Coastguard Worker {
3273*a67afe4dSAndroid Build Coastguard Worker    png_image_read_control *display = png_voidcast(png_image_read_control*,
3274*a67afe4dSAndroid Build Coastguard Worker        argument);
3275*a67afe4dSAndroid Build Coastguard Worker    png_imagep image = display->image;
3276*a67afe4dSAndroid Build Coastguard Worker    png_structrp png_ptr = image->opaque->png_ptr;
3277*a67afe4dSAndroid Build Coastguard Worker    int passes;
3278*a67afe4dSAndroid Build Coastguard Worker 
3279*a67afe4dSAndroid Build Coastguard Worker    switch (png_ptr->interlaced)
3280*a67afe4dSAndroid Build Coastguard Worker    {
3281*a67afe4dSAndroid Build Coastguard Worker       case PNG_INTERLACE_NONE:
3282*a67afe4dSAndroid Build Coastguard Worker          passes = 1;
3283*a67afe4dSAndroid Build Coastguard Worker          break;
3284*a67afe4dSAndroid Build Coastguard Worker 
3285*a67afe4dSAndroid Build Coastguard Worker       case PNG_INTERLACE_ADAM7:
3286*a67afe4dSAndroid Build Coastguard Worker          passes = PNG_INTERLACE_ADAM7_PASSES;
3287*a67afe4dSAndroid Build Coastguard Worker          break;
3288*a67afe4dSAndroid Build Coastguard Worker 
3289*a67afe4dSAndroid Build Coastguard Worker       default:
3290*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr, "unknown interlace type");
3291*a67afe4dSAndroid Build Coastguard Worker    }
3292*a67afe4dSAndroid Build Coastguard Worker 
3293*a67afe4dSAndroid Build Coastguard Worker    {
3294*a67afe4dSAndroid Build Coastguard Worker       png_uint_32  height = image->height;
3295*a67afe4dSAndroid Build Coastguard Worker       png_uint_32  width = image->width;
3296*a67afe4dSAndroid Build Coastguard Worker       ptrdiff_t    step_row = display->row_bytes;
3297*a67afe4dSAndroid Build Coastguard Worker       unsigned int channels =
3298*a67afe4dSAndroid Build Coastguard Worker           (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1;
3299*a67afe4dSAndroid Build Coastguard Worker       int pass;
3300*a67afe4dSAndroid Build Coastguard Worker 
3301*a67afe4dSAndroid Build Coastguard Worker       for (pass = 0; pass < passes; ++pass)
3302*a67afe4dSAndroid Build Coastguard Worker       {
3303*a67afe4dSAndroid Build Coastguard Worker          unsigned int     startx, stepx, stepy;
3304*a67afe4dSAndroid Build Coastguard Worker          png_uint_32      y;
3305*a67afe4dSAndroid Build Coastguard Worker 
3306*a67afe4dSAndroid Build Coastguard Worker          if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)
3307*a67afe4dSAndroid Build Coastguard Worker          {
3308*a67afe4dSAndroid Build Coastguard Worker             /* The row may be empty for a short image: */
3309*a67afe4dSAndroid Build Coastguard Worker             if (PNG_PASS_COLS(width, pass) == 0)
3310*a67afe4dSAndroid Build Coastguard Worker                continue;
3311*a67afe4dSAndroid Build Coastguard Worker 
3312*a67afe4dSAndroid Build Coastguard Worker             startx = PNG_PASS_START_COL(pass) * channels;
3313*a67afe4dSAndroid Build Coastguard Worker             stepx = PNG_PASS_COL_OFFSET(pass) * channels;
3314*a67afe4dSAndroid Build Coastguard Worker             y = PNG_PASS_START_ROW(pass);
3315*a67afe4dSAndroid Build Coastguard Worker             stepy = PNG_PASS_ROW_OFFSET(pass);
3316*a67afe4dSAndroid Build Coastguard Worker          }
3317*a67afe4dSAndroid Build Coastguard Worker 
3318*a67afe4dSAndroid Build Coastguard Worker          else
3319*a67afe4dSAndroid Build Coastguard Worker          {
3320*a67afe4dSAndroid Build Coastguard Worker             y = 0;
3321*a67afe4dSAndroid Build Coastguard Worker             startx = 0;
3322*a67afe4dSAndroid Build Coastguard Worker             stepx = channels;
3323*a67afe4dSAndroid Build Coastguard Worker             stepy = 1;
3324*a67afe4dSAndroid Build Coastguard Worker          }
3325*a67afe4dSAndroid Build Coastguard Worker 
3326*a67afe4dSAndroid Build Coastguard Worker          for (; y<height; y += stepy)
3327*a67afe4dSAndroid Build Coastguard Worker          {
3328*a67afe4dSAndroid Build Coastguard Worker             png_bytep inrow = png_voidcast(png_bytep, display->local_row);
3329*a67afe4dSAndroid Build Coastguard Worker             png_bytep outrow;
3330*a67afe4dSAndroid Build Coastguard Worker             png_const_bytep end_row;
3331*a67afe4dSAndroid Build Coastguard Worker 
3332*a67afe4dSAndroid Build Coastguard Worker             /* Read the row, which is packed: */
3333*a67afe4dSAndroid Build Coastguard Worker             png_read_row(png_ptr, inrow, NULL);
3334*a67afe4dSAndroid Build Coastguard Worker 
3335*a67afe4dSAndroid Build Coastguard Worker             outrow = png_voidcast(png_bytep, display->first_row);
3336*a67afe4dSAndroid Build Coastguard Worker             outrow += y * step_row;
3337*a67afe4dSAndroid Build Coastguard Worker             end_row = outrow + width * channels;
3338*a67afe4dSAndroid Build Coastguard Worker 
3339*a67afe4dSAndroid Build Coastguard Worker             /* Now do the composition on each pixel in this row. */
3340*a67afe4dSAndroid Build Coastguard Worker             outrow += startx;
3341*a67afe4dSAndroid Build Coastguard Worker             for (; outrow < end_row; outrow += stepx)
3342*a67afe4dSAndroid Build Coastguard Worker             {
3343*a67afe4dSAndroid Build Coastguard Worker                png_byte alpha = inrow[channels];
3344*a67afe4dSAndroid Build Coastguard Worker 
3345*a67afe4dSAndroid Build Coastguard Worker                if (alpha > 0) /* else no change to the output */
3346*a67afe4dSAndroid Build Coastguard Worker                {
3347*a67afe4dSAndroid Build Coastguard Worker                   unsigned int c;
3348*a67afe4dSAndroid Build Coastguard Worker 
3349*a67afe4dSAndroid Build Coastguard Worker                   for (c=0; c<channels; ++c)
3350*a67afe4dSAndroid Build Coastguard Worker                   {
3351*a67afe4dSAndroid Build Coastguard Worker                      png_uint_32 component = inrow[c];
3352*a67afe4dSAndroid Build Coastguard Worker 
3353*a67afe4dSAndroid Build Coastguard Worker                      if (alpha < 255) /* else just use component */
3354*a67afe4dSAndroid Build Coastguard Worker                      {
3355*a67afe4dSAndroid Build Coastguard Worker                         /* This is PNG_OPTIMIZED_ALPHA, the component value
3356*a67afe4dSAndroid Build Coastguard Worker                          * is a linear 8-bit value.  Combine this with the
3357*a67afe4dSAndroid Build Coastguard Worker                          * current outrow[c] value which is sRGB encoded.
3358*a67afe4dSAndroid Build Coastguard Worker                          * Arithmetic here is 16-bits to preserve the output
3359*a67afe4dSAndroid Build Coastguard Worker                          * values correctly.
3360*a67afe4dSAndroid Build Coastguard Worker                          */
3361*a67afe4dSAndroid Build Coastguard Worker                         component *= 257*255; /* =65535 */
3362*a67afe4dSAndroid Build Coastguard Worker                         component += (255-alpha)*png_sRGB_table[outrow[c]];
3363*a67afe4dSAndroid Build Coastguard Worker 
3364*a67afe4dSAndroid Build Coastguard Worker                         /* So 'component' is scaled by 255*65535 and is
3365*a67afe4dSAndroid Build Coastguard Worker                          * therefore appropriate for the sRGB to linear
3366*a67afe4dSAndroid Build Coastguard Worker                          * conversion table.
3367*a67afe4dSAndroid Build Coastguard Worker                          */
3368*a67afe4dSAndroid Build Coastguard Worker                         component = PNG_sRGB_FROM_LINEAR(component);
3369*a67afe4dSAndroid Build Coastguard Worker                      }
3370*a67afe4dSAndroid Build Coastguard Worker 
3371*a67afe4dSAndroid Build Coastguard Worker                      outrow[c] = (png_byte)component;
3372*a67afe4dSAndroid Build Coastguard Worker                   }
3373*a67afe4dSAndroid Build Coastguard Worker                }
3374*a67afe4dSAndroid Build Coastguard Worker 
3375*a67afe4dSAndroid Build Coastguard Worker                inrow += channels+1; /* components and alpha channel */
3376*a67afe4dSAndroid Build Coastguard Worker             }
3377*a67afe4dSAndroid Build Coastguard Worker          }
3378*a67afe4dSAndroid Build Coastguard Worker       }
3379*a67afe4dSAndroid Build Coastguard Worker    }
3380*a67afe4dSAndroid Build Coastguard Worker 
3381*a67afe4dSAndroid Build Coastguard Worker    return 1;
3382*a67afe4dSAndroid Build Coastguard Worker }
3383*a67afe4dSAndroid Build Coastguard Worker 
3384*a67afe4dSAndroid Build Coastguard Worker /* The do_local_background case; called when all the following transforms are to
3385*a67afe4dSAndroid Build Coastguard Worker  * be done:
3386*a67afe4dSAndroid Build Coastguard Worker  *
3387*a67afe4dSAndroid Build Coastguard Worker  * PNG_RGB_TO_GRAY
3388*a67afe4dSAndroid Build Coastguard Worker  * PNG_COMPOSITE
3389*a67afe4dSAndroid Build Coastguard Worker  * PNG_GAMMA
3390*a67afe4dSAndroid Build Coastguard Worker  *
3391*a67afe4dSAndroid Build Coastguard Worker  * This is a work-around for the fact that both the PNG_RGB_TO_GRAY and
3392*a67afe4dSAndroid Build Coastguard Worker  * PNG_COMPOSITE code performs gamma correction, so we get double gamma
3393*a67afe4dSAndroid Build Coastguard Worker  * correction.  The fix-up is to prevent the PNG_COMPOSITE operation from
3394*a67afe4dSAndroid Build Coastguard Worker  * happening inside libpng, so this routine sees an 8 or 16-bit gray+alpha
3395*a67afe4dSAndroid Build Coastguard Worker  * row and handles the removal or pre-multiplication of the alpha channel.
3396*a67afe4dSAndroid Build Coastguard Worker  */
3397*a67afe4dSAndroid Build Coastguard Worker static int
png_image_read_background(png_voidp argument)3398*a67afe4dSAndroid Build Coastguard Worker png_image_read_background(png_voidp argument)
3399*a67afe4dSAndroid Build Coastguard Worker {
3400*a67afe4dSAndroid Build Coastguard Worker    png_image_read_control *display = png_voidcast(png_image_read_control*,
3401*a67afe4dSAndroid Build Coastguard Worker        argument);
3402*a67afe4dSAndroid Build Coastguard Worker    png_imagep image = display->image;
3403*a67afe4dSAndroid Build Coastguard Worker    png_structrp png_ptr = image->opaque->png_ptr;
3404*a67afe4dSAndroid Build Coastguard Worker    png_inforp info_ptr = image->opaque->info_ptr;
3405*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 height = image->height;
3406*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 width = image->width;
3407*a67afe4dSAndroid Build Coastguard Worker    int pass, passes;
3408*a67afe4dSAndroid Build Coastguard Worker 
3409*a67afe4dSAndroid Build Coastguard Worker    /* Double check the convoluted logic below.  We expect to get here with
3410*a67afe4dSAndroid Build Coastguard Worker     * libpng doing rgb to gray and gamma correction but background processing
3411*a67afe4dSAndroid Build Coastguard Worker     * left to the png_image_read_background function.  The rows libpng produce
3412*a67afe4dSAndroid Build Coastguard Worker     * might be 8 or 16-bit but should always have two channels; gray plus alpha.
3413*a67afe4dSAndroid Build Coastguard Worker     */
3414*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0)
3415*a67afe4dSAndroid Build Coastguard Worker       png_error(png_ptr, "lost rgb to gray");
3416*a67afe4dSAndroid Build Coastguard Worker 
3417*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_COMPOSE) != 0)
3418*a67afe4dSAndroid Build Coastguard Worker       png_error(png_ptr, "unexpected compose");
3419*a67afe4dSAndroid Build Coastguard Worker 
3420*a67afe4dSAndroid Build Coastguard Worker    if (png_get_channels(png_ptr, info_ptr) != 2)
3421*a67afe4dSAndroid Build Coastguard Worker       png_error(png_ptr, "lost/gained channels");
3422*a67afe4dSAndroid Build Coastguard Worker 
3423*a67afe4dSAndroid Build Coastguard Worker    /* Expect the 8-bit case to always remove the alpha channel */
3424*a67afe4dSAndroid Build Coastguard Worker    if ((image->format & PNG_FORMAT_FLAG_LINEAR) == 0 &&
3425*a67afe4dSAndroid Build Coastguard Worker       (image->format & PNG_FORMAT_FLAG_ALPHA) != 0)
3426*a67afe4dSAndroid Build Coastguard Worker       png_error(png_ptr, "unexpected 8-bit transformation");
3427*a67afe4dSAndroid Build Coastguard Worker 
3428*a67afe4dSAndroid Build Coastguard Worker    switch (png_ptr->interlaced)
3429*a67afe4dSAndroid Build Coastguard Worker    {
3430*a67afe4dSAndroid Build Coastguard Worker       case PNG_INTERLACE_NONE:
3431*a67afe4dSAndroid Build Coastguard Worker          passes = 1;
3432*a67afe4dSAndroid Build Coastguard Worker          break;
3433*a67afe4dSAndroid Build Coastguard Worker 
3434*a67afe4dSAndroid Build Coastguard Worker       case PNG_INTERLACE_ADAM7:
3435*a67afe4dSAndroid Build Coastguard Worker          passes = PNG_INTERLACE_ADAM7_PASSES;
3436*a67afe4dSAndroid Build Coastguard Worker          break;
3437*a67afe4dSAndroid Build Coastguard Worker 
3438*a67afe4dSAndroid Build Coastguard Worker       default:
3439*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr, "unknown interlace type");
3440*a67afe4dSAndroid Build Coastguard Worker    }
3441*a67afe4dSAndroid Build Coastguard Worker 
3442*a67afe4dSAndroid Build Coastguard Worker    /* Use direct access to info_ptr here because otherwise the simplified API
3443*a67afe4dSAndroid Build Coastguard Worker     * would require PNG_EASY_ACCESS_SUPPORTED (just for this.)  Note this is
3444*a67afe4dSAndroid Build Coastguard Worker     * checking the value after libpng expansions, not the original value in the
3445*a67afe4dSAndroid Build Coastguard Worker     * PNG.
3446*a67afe4dSAndroid Build Coastguard Worker     */
3447*a67afe4dSAndroid Build Coastguard Worker    switch (info_ptr->bit_depth)
3448*a67afe4dSAndroid Build Coastguard Worker    {
3449*a67afe4dSAndroid Build Coastguard Worker       case 8:
3450*a67afe4dSAndroid Build Coastguard Worker          /* 8-bit sRGB gray values with an alpha channel; the alpha channel is
3451*a67afe4dSAndroid Build Coastguard Worker           * to be removed by composing on a background: either the row if
3452*a67afe4dSAndroid Build Coastguard Worker           * display->background is NULL or display->background->green if not.
3453*a67afe4dSAndroid Build Coastguard Worker           * Unlike the code above ALPHA_OPTIMIZED has *not* been done.
3454*a67afe4dSAndroid Build Coastguard Worker           */
3455*a67afe4dSAndroid Build Coastguard Worker          {
3456*a67afe4dSAndroid Build Coastguard Worker             png_bytep first_row = png_voidcast(png_bytep, display->first_row);
3457*a67afe4dSAndroid Build Coastguard Worker             ptrdiff_t step_row = display->row_bytes;
3458*a67afe4dSAndroid Build Coastguard Worker 
3459*a67afe4dSAndroid Build Coastguard Worker             for (pass = 0; pass < passes; ++pass)
3460*a67afe4dSAndroid Build Coastguard Worker             {
3461*a67afe4dSAndroid Build Coastguard Worker                unsigned int     startx, stepx, stepy;
3462*a67afe4dSAndroid Build Coastguard Worker                png_uint_32      y;
3463*a67afe4dSAndroid Build Coastguard Worker 
3464*a67afe4dSAndroid Build Coastguard Worker                if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)
3465*a67afe4dSAndroid Build Coastguard Worker                {
3466*a67afe4dSAndroid Build Coastguard Worker                   /* The row may be empty for a short image: */
3467*a67afe4dSAndroid Build Coastguard Worker                   if (PNG_PASS_COLS(width, pass) == 0)
3468*a67afe4dSAndroid Build Coastguard Worker                      continue;
3469*a67afe4dSAndroid Build Coastguard Worker 
3470*a67afe4dSAndroid Build Coastguard Worker                   startx = PNG_PASS_START_COL(pass);
3471*a67afe4dSAndroid Build Coastguard Worker                   stepx = PNG_PASS_COL_OFFSET(pass);
3472*a67afe4dSAndroid Build Coastguard Worker                   y = PNG_PASS_START_ROW(pass);
3473*a67afe4dSAndroid Build Coastguard Worker                   stepy = PNG_PASS_ROW_OFFSET(pass);
3474*a67afe4dSAndroid Build Coastguard Worker                }
3475*a67afe4dSAndroid Build Coastguard Worker 
3476*a67afe4dSAndroid Build Coastguard Worker                else
3477*a67afe4dSAndroid Build Coastguard Worker                {
3478*a67afe4dSAndroid Build Coastguard Worker                   y = 0;
3479*a67afe4dSAndroid Build Coastguard Worker                   startx = 0;
3480*a67afe4dSAndroid Build Coastguard Worker                   stepx = stepy = 1;
3481*a67afe4dSAndroid Build Coastguard Worker                }
3482*a67afe4dSAndroid Build Coastguard Worker 
3483*a67afe4dSAndroid Build Coastguard Worker                if (display->background == NULL)
3484*a67afe4dSAndroid Build Coastguard Worker                {
3485*a67afe4dSAndroid Build Coastguard Worker                   for (; y<height; y += stepy)
3486*a67afe4dSAndroid Build Coastguard Worker                   {
3487*a67afe4dSAndroid Build Coastguard Worker                      png_bytep inrow = png_voidcast(png_bytep,
3488*a67afe4dSAndroid Build Coastguard Worker                          display->local_row);
3489*a67afe4dSAndroid Build Coastguard Worker                      png_bytep outrow = first_row + y * step_row;
3490*a67afe4dSAndroid Build Coastguard Worker                      png_const_bytep end_row = outrow + width;
3491*a67afe4dSAndroid Build Coastguard Worker 
3492*a67afe4dSAndroid Build Coastguard Worker                      /* Read the row, which is packed: */
3493*a67afe4dSAndroid Build Coastguard Worker                      png_read_row(png_ptr, inrow, NULL);
3494*a67afe4dSAndroid Build Coastguard Worker 
3495*a67afe4dSAndroid Build Coastguard Worker                      /* Now do the composition on each pixel in this row. */
3496*a67afe4dSAndroid Build Coastguard Worker                      outrow += startx;
3497*a67afe4dSAndroid Build Coastguard Worker                      for (; outrow < end_row; outrow += stepx)
3498*a67afe4dSAndroid Build Coastguard Worker                      {
3499*a67afe4dSAndroid Build Coastguard Worker                         png_byte alpha = inrow[1];
3500*a67afe4dSAndroid Build Coastguard Worker 
3501*a67afe4dSAndroid Build Coastguard Worker                         if (alpha > 0) /* else no change to the output */
3502*a67afe4dSAndroid Build Coastguard Worker                         {
3503*a67afe4dSAndroid Build Coastguard Worker                            png_uint_32 component = inrow[0];
3504*a67afe4dSAndroid Build Coastguard Worker 
3505*a67afe4dSAndroid Build Coastguard Worker                            if (alpha < 255) /* else just use component */
3506*a67afe4dSAndroid Build Coastguard Worker                            {
3507*a67afe4dSAndroid Build Coastguard Worker                               /* Since PNG_OPTIMIZED_ALPHA was not set it is
3508*a67afe4dSAndroid Build Coastguard Worker                                * necessary to invert the sRGB transfer
3509*a67afe4dSAndroid Build Coastguard Worker                                * function and multiply the alpha out.
3510*a67afe4dSAndroid Build Coastguard Worker                                */
3511*a67afe4dSAndroid Build Coastguard Worker                               component = png_sRGB_table[component] * alpha;
3512*a67afe4dSAndroid Build Coastguard Worker                               component += png_sRGB_table[outrow[0]] *
3513*a67afe4dSAndroid Build Coastguard Worker                                  (255-alpha);
3514*a67afe4dSAndroid Build Coastguard Worker                               component = PNG_sRGB_FROM_LINEAR(component);
3515*a67afe4dSAndroid Build Coastguard Worker                            }
3516*a67afe4dSAndroid Build Coastguard Worker 
3517*a67afe4dSAndroid Build Coastguard Worker                            outrow[0] = (png_byte)component;
3518*a67afe4dSAndroid Build Coastguard Worker                         }
3519*a67afe4dSAndroid Build Coastguard Worker 
3520*a67afe4dSAndroid Build Coastguard Worker                         inrow += 2; /* gray and alpha channel */
3521*a67afe4dSAndroid Build Coastguard Worker                      }
3522*a67afe4dSAndroid Build Coastguard Worker                   }
3523*a67afe4dSAndroid Build Coastguard Worker                }
3524*a67afe4dSAndroid Build Coastguard Worker 
3525*a67afe4dSAndroid Build Coastguard Worker                else /* constant background value */
3526*a67afe4dSAndroid Build Coastguard Worker                {
3527*a67afe4dSAndroid Build Coastguard Worker                   png_byte background8 = display->background->green;
3528*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 background = png_sRGB_table[background8];
3529*a67afe4dSAndroid Build Coastguard Worker 
3530*a67afe4dSAndroid Build Coastguard Worker                   for (; y<height; y += stepy)
3531*a67afe4dSAndroid Build Coastguard Worker                   {
3532*a67afe4dSAndroid Build Coastguard Worker                      png_bytep inrow = png_voidcast(png_bytep,
3533*a67afe4dSAndroid Build Coastguard Worker                          display->local_row);
3534*a67afe4dSAndroid Build Coastguard Worker                      png_bytep outrow = first_row + y * step_row;
3535*a67afe4dSAndroid Build Coastguard Worker                      png_const_bytep end_row = outrow + width;
3536*a67afe4dSAndroid Build Coastguard Worker 
3537*a67afe4dSAndroid Build Coastguard Worker                      /* Read the row, which is packed: */
3538*a67afe4dSAndroid Build Coastguard Worker                      png_read_row(png_ptr, inrow, NULL);
3539*a67afe4dSAndroid Build Coastguard Worker 
3540*a67afe4dSAndroid Build Coastguard Worker                      /* Now do the composition on each pixel in this row. */
3541*a67afe4dSAndroid Build Coastguard Worker                      outrow += startx;
3542*a67afe4dSAndroid Build Coastguard Worker                      for (; outrow < end_row; outrow += stepx)
3543*a67afe4dSAndroid Build Coastguard Worker                      {
3544*a67afe4dSAndroid Build Coastguard Worker                         png_byte alpha = inrow[1];
3545*a67afe4dSAndroid Build Coastguard Worker 
3546*a67afe4dSAndroid Build Coastguard Worker                         if (alpha > 0) /* else use background */
3547*a67afe4dSAndroid Build Coastguard Worker                         {
3548*a67afe4dSAndroid Build Coastguard Worker                            png_uint_32 component = inrow[0];
3549*a67afe4dSAndroid Build Coastguard Worker 
3550*a67afe4dSAndroid Build Coastguard Worker                            if (alpha < 255) /* else just use component */
3551*a67afe4dSAndroid Build Coastguard Worker                            {
3552*a67afe4dSAndroid Build Coastguard Worker                               component = png_sRGB_table[component] * alpha;
3553*a67afe4dSAndroid Build Coastguard Worker                               component += background * (255-alpha);
3554*a67afe4dSAndroid Build Coastguard Worker                               component = PNG_sRGB_FROM_LINEAR(component);
3555*a67afe4dSAndroid Build Coastguard Worker                            }
3556*a67afe4dSAndroid Build Coastguard Worker 
3557*a67afe4dSAndroid Build Coastguard Worker                            outrow[0] = (png_byte)component;
3558*a67afe4dSAndroid Build Coastguard Worker                         }
3559*a67afe4dSAndroid Build Coastguard Worker 
3560*a67afe4dSAndroid Build Coastguard Worker                         else
3561*a67afe4dSAndroid Build Coastguard Worker                            outrow[0] = background8;
3562*a67afe4dSAndroid Build Coastguard Worker 
3563*a67afe4dSAndroid Build Coastguard Worker                         inrow += 2; /* gray and alpha channel */
3564*a67afe4dSAndroid Build Coastguard Worker                      }
3565*a67afe4dSAndroid Build Coastguard Worker                   }
3566*a67afe4dSAndroid Build Coastguard Worker                }
3567*a67afe4dSAndroid Build Coastguard Worker             }
3568*a67afe4dSAndroid Build Coastguard Worker          }
3569*a67afe4dSAndroid Build Coastguard Worker          break;
3570*a67afe4dSAndroid Build Coastguard Worker 
3571*a67afe4dSAndroid Build Coastguard Worker       case 16:
3572*a67afe4dSAndroid Build Coastguard Worker          /* 16-bit linear with pre-multiplied alpha; the pre-multiplication must
3573*a67afe4dSAndroid Build Coastguard Worker           * still be done and, maybe, the alpha channel removed.  This code also
3574*a67afe4dSAndroid Build Coastguard Worker           * handles the alpha-first option.
3575*a67afe4dSAndroid Build Coastguard Worker           */
3576*a67afe4dSAndroid Build Coastguard Worker          {
3577*a67afe4dSAndroid Build Coastguard Worker             png_uint_16p first_row = png_voidcast(png_uint_16p,
3578*a67afe4dSAndroid Build Coastguard Worker                 display->first_row);
3579*a67afe4dSAndroid Build Coastguard Worker             /* The division by two is safe because the caller passed in a
3580*a67afe4dSAndroid Build Coastguard Worker              * stride which was multiplied by 2 (below) to get row_bytes.
3581*a67afe4dSAndroid Build Coastguard Worker              */
3582*a67afe4dSAndroid Build Coastguard Worker             ptrdiff_t    step_row = display->row_bytes / 2;
3583*a67afe4dSAndroid Build Coastguard Worker             unsigned int preserve_alpha = (image->format &
3584*a67afe4dSAndroid Build Coastguard Worker                 PNG_FORMAT_FLAG_ALPHA) != 0;
3585*a67afe4dSAndroid Build Coastguard Worker             unsigned int outchannels = 1U+preserve_alpha;
3586*a67afe4dSAndroid Build Coastguard Worker             int swap_alpha = 0;
3587*a67afe4dSAndroid Build Coastguard Worker 
3588*a67afe4dSAndroid Build Coastguard Worker #           ifdef PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED
3589*a67afe4dSAndroid Build Coastguard Worker                if (preserve_alpha != 0 &&
3590*a67afe4dSAndroid Build Coastguard Worker                    (image->format & PNG_FORMAT_FLAG_AFIRST) != 0)
3591*a67afe4dSAndroid Build Coastguard Worker                   swap_alpha = 1;
3592*a67afe4dSAndroid Build Coastguard Worker #           endif
3593*a67afe4dSAndroid Build Coastguard Worker 
3594*a67afe4dSAndroid Build Coastguard Worker             for (pass = 0; pass < passes; ++pass)
3595*a67afe4dSAndroid Build Coastguard Worker             {
3596*a67afe4dSAndroid Build Coastguard Worker                unsigned int     startx, stepx, stepy;
3597*a67afe4dSAndroid Build Coastguard Worker                png_uint_32      y;
3598*a67afe4dSAndroid Build Coastguard Worker 
3599*a67afe4dSAndroid Build Coastguard Worker                /* The 'x' start and step are adjusted to output components here.
3600*a67afe4dSAndroid Build Coastguard Worker                 */
3601*a67afe4dSAndroid Build Coastguard Worker                if (png_ptr->interlaced == PNG_INTERLACE_ADAM7)
3602*a67afe4dSAndroid Build Coastguard Worker                {
3603*a67afe4dSAndroid Build Coastguard Worker                   /* The row may be empty for a short image: */
3604*a67afe4dSAndroid Build Coastguard Worker                   if (PNG_PASS_COLS(width, pass) == 0)
3605*a67afe4dSAndroid Build Coastguard Worker                      continue;
3606*a67afe4dSAndroid Build Coastguard Worker 
3607*a67afe4dSAndroid Build Coastguard Worker                   startx = PNG_PASS_START_COL(pass) * outchannels;
3608*a67afe4dSAndroid Build Coastguard Worker                   stepx = PNG_PASS_COL_OFFSET(pass) * outchannels;
3609*a67afe4dSAndroid Build Coastguard Worker                   y = PNG_PASS_START_ROW(pass);
3610*a67afe4dSAndroid Build Coastguard Worker                   stepy = PNG_PASS_ROW_OFFSET(pass);
3611*a67afe4dSAndroid Build Coastguard Worker                }
3612*a67afe4dSAndroid Build Coastguard Worker 
3613*a67afe4dSAndroid Build Coastguard Worker                else
3614*a67afe4dSAndroid Build Coastguard Worker                {
3615*a67afe4dSAndroid Build Coastguard Worker                   y = 0;
3616*a67afe4dSAndroid Build Coastguard Worker                   startx = 0;
3617*a67afe4dSAndroid Build Coastguard Worker                   stepx = outchannels;
3618*a67afe4dSAndroid Build Coastguard Worker                   stepy = 1;
3619*a67afe4dSAndroid Build Coastguard Worker                }
3620*a67afe4dSAndroid Build Coastguard Worker 
3621*a67afe4dSAndroid Build Coastguard Worker                for (; y<height; y += stepy)
3622*a67afe4dSAndroid Build Coastguard Worker                {
3623*a67afe4dSAndroid Build Coastguard Worker                   png_const_uint_16p inrow;
3624*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16p outrow = first_row + y*step_row;
3625*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16p end_row = outrow + width * outchannels;
3626*a67afe4dSAndroid Build Coastguard Worker 
3627*a67afe4dSAndroid Build Coastguard Worker                   /* Read the row, which is packed: */
3628*a67afe4dSAndroid Build Coastguard Worker                   png_read_row(png_ptr, png_voidcast(png_bytep,
3629*a67afe4dSAndroid Build Coastguard Worker                       display->local_row), NULL);
3630*a67afe4dSAndroid Build Coastguard Worker                   inrow = png_voidcast(png_const_uint_16p, display->local_row);
3631*a67afe4dSAndroid Build Coastguard Worker 
3632*a67afe4dSAndroid Build Coastguard Worker                   /* Now do the pre-multiplication on each pixel in this row.
3633*a67afe4dSAndroid Build Coastguard Worker                    */
3634*a67afe4dSAndroid Build Coastguard Worker                   outrow += startx;
3635*a67afe4dSAndroid Build Coastguard Worker                   for (; outrow < end_row; outrow += stepx)
3636*a67afe4dSAndroid Build Coastguard Worker                   {
3637*a67afe4dSAndroid Build Coastguard Worker                      png_uint_32 component = inrow[0];
3638*a67afe4dSAndroid Build Coastguard Worker                      png_uint_16 alpha = inrow[1];
3639*a67afe4dSAndroid Build Coastguard Worker 
3640*a67afe4dSAndroid Build Coastguard Worker                      if (alpha > 0) /* else 0 */
3641*a67afe4dSAndroid Build Coastguard Worker                      {
3642*a67afe4dSAndroid Build Coastguard Worker                         if (alpha < 65535) /* else just use component */
3643*a67afe4dSAndroid Build Coastguard Worker                         {
3644*a67afe4dSAndroid Build Coastguard Worker                            component *= alpha;
3645*a67afe4dSAndroid Build Coastguard Worker                            component += 32767;
3646*a67afe4dSAndroid Build Coastguard Worker                            component /= 65535;
3647*a67afe4dSAndroid Build Coastguard Worker                         }
3648*a67afe4dSAndroid Build Coastguard Worker                      }
3649*a67afe4dSAndroid Build Coastguard Worker 
3650*a67afe4dSAndroid Build Coastguard Worker                      else
3651*a67afe4dSAndroid Build Coastguard Worker                         component = 0;
3652*a67afe4dSAndroid Build Coastguard Worker 
3653*a67afe4dSAndroid Build Coastguard Worker                      outrow[swap_alpha] = (png_uint_16)component;
3654*a67afe4dSAndroid Build Coastguard Worker                      if (preserve_alpha != 0)
3655*a67afe4dSAndroid Build Coastguard Worker                         outrow[1 ^ swap_alpha] = alpha;
3656*a67afe4dSAndroid Build Coastguard Worker 
3657*a67afe4dSAndroid Build Coastguard Worker                      inrow += 2; /* components and alpha channel */
3658*a67afe4dSAndroid Build Coastguard Worker                   }
3659*a67afe4dSAndroid Build Coastguard Worker                }
3660*a67afe4dSAndroid Build Coastguard Worker             }
3661*a67afe4dSAndroid Build Coastguard Worker          }
3662*a67afe4dSAndroid Build Coastguard Worker          break;
3663*a67afe4dSAndroid Build Coastguard Worker 
3664*a67afe4dSAndroid Build Coastguard Worker #ifdef __GNUC__
3665*a67afe4dSAndroid Build Coastguard Worker       default:
3666*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr, "unexpected bit depth");
3667*a67afe4dSAndroid Build Coastguard Worker #endif
3668*a67afe4dSAndroid Build Coastguard Worker    }
3669*a67afe4dSAndroid Build Coastguard Worker 
3670*a67afe4dSAndroid Build Coastguard Worker    return 1;
3671*a67afe4dSAndroid Build Coastguard Worker }
3672*a67afe4dSAndroid Build Coastguard Worker 
3673*a67afe4dSAndroid Build Coastguard Worker /* The guts of png_image_finish_read as a png_safe_execute callback. */
3674*a67afe4dSAndroid Build Coastguard Worker static int
png_image_read_direct(png_voidp argument)3675*a67afe4dSAndroid Build Coastguard Worker png_image_read_direct(png_voidp argument)
3676*a67afe4dSAndroid Build Coastguard Worker {
3677*a67afe4dSAndroid Build Coastguard Worker    png_image_read_control *display = png_voidcast(png_image_read_control*,
3678*a67afe4dSAndroid Build Coastguard Worker        argument);
3679*a67afe4dSAndroid Build Coastguard Worker    png_imagep image = display->image;
3680*a67afe4dSAndroid Build Coastguard Worker    png_structrp png_ptr = image->opaque->png_ptr;
3681*a67afe4dSAndroid Build Coastguard Worker    png_inforp info_ptr = image->opaque->info_ptr;
3682*a67afe4dSAndroid Build Coastguard Worker 
3683*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 format = image->format;
3684*a67afe4dSAndroid Build Coastguard Worker    int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0;
3685*a67afe4dSAndroid Build Coastguard Worker    int do_local_compose = 0;
3686*a67afe4dSAndroid Build Coastguard Worker    int do_local_background = 0; /* to avoid double gamma correction bug */
3687*a67afe4dSAndroid Build Coastguard Worker    int passes = 0;
3688*a67afe4dSAndroid Build Coastguard Worker 
3689*a67afe4dSAndroid Build Coastguard Worker    /* Add transforms to ensure the correct output format is produced then check
3690*a67afe4dSAndroid Build Coastguard Worker     * that the required implementation support is there.  Always expand; always
3691*a67afe4dSAndroid Build Coastguard Worker     * need 8 bits minimum, no palette and expanded tRNS.
3692*a67afe4dSAndroid Build Coastguard Worker     */
3693*a67afe4dSAndroid Build Coastguard Worker    png_set_expand(png_ptr);
3694*a67afe4dSAndroid Build Coastguard Worker 
3695*a67afe4dSAndroid Build Coastguard Worker    /* Now check the format to see if it was modified. */
3696*a67afe4dSAndroid Build Coastguard Worker    {
3697*a67afe4dSAndroid Build Coastguard Worker       png_uint_32 base_format = png_image_format(png_ptr) &
3698*a67afe4dSAndroid Build Coastguard Worker          ~PNG_FORMAT_FLAG_COLORMAP /* removed by png_set_expand */;
3699*a67afe4dSAndroid Build Coastguard Worker       png_uint_32 change = format ^ base_format;
3700*a67afe4dSAndroid Build Coastguard Worker       png_fixed_point output_gamma;
3701*a67afe4dSAndroid Build Coastguard Worker       int mode; /* alpha mode */
3702*a67afe4dSAndroid Build Coastguard Worker 
3703*a67afe4dSAndroid Build Coastguard Worker       /* Do this first so that we have a record if rgb to gray is happening. */
3704*a67afe4dSAndroid Build Coastguard Worker       if ((change & PNG_FORMAT_FLAG_COLOR) != 0)
3705*a67afe4dSAndroid Build Coastguard Worker       {
3706*a67afe4dSAndroid Build Coastguard Worker          /* gray<->color transformation required. */
3707*a67afe4dSAndroid Build Coastguard Worker          if ((format & PNG_FORMAT_FLAG_COLOR) != 0)
3708*a67afe4dSAndroid Build Coastguard Worker             png_set_gray_to_rgb(png_ptr);
3709*a67afe4dSAndroid Build Coastguard Worker 
3710*a67afe4dSAndroid Build Coastguard Worker          else
3711*a67afe4dSAndroid Build Coastguard Worker          {
3712*a67afe4dSAndroid Build Coastguard Worker             /* libpng can't do both rgb to gray and
3713*a67afe4dSAndroid Build Coastguard Worker              * background/pre-multiplication if there is also significant gamma
3714*a67afe4dSAndroid Build Coastguard Worker              * correction, because both operations require linear colors and
3715*a67afe4dSAndroid Build Coastguard Worker              * the code only supports one transform doing the gamma correction.
3716*a67afe4dSAndroid Build Coastguard Worker              * Handle this by doing the pre-multiplication or background
3717*a67afe4dSAndroid Build Coastguard Worker              * operation in this code, if necessary.
3718*a67afe4dSAndroid Build Coastguard Worker              *
3719*a67afe4dSAndroid Build Coastguard Worker              * TODO: fix this by rewriting pngrtran.c (!)
3720*a67afe4dSAndroid Build Coastguard Worker              *
3721*a67afe4dSAndroid Build Coastguard Worker              * For the moment (given that fixing this in pngrtran.c is an
3722*a67afe4dSAndroid Build Coastguard Worker              * enormous change) 'do_local_background' is used to indicate that
3723*a67afe4dSAndroid Build Coastguard Worker              * the problem exists.
3724*a67afe4dSAndroid Build Coastguard Worker              */
3725*a67afe4dSAndroid Build Coastguard Worker             if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0)
3726*a67afe4dSAndroid Build Coastguard Worker                do_local_background = 1/*maybe*/;
3727*a67afe4dSAndroid Build Coastguard Worker 
3728*a67afe4dSAndroid Build Coastguard Worker             png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE,
3729*a67afe4dSAndroid Build Coastguard Worker                 PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT);
3730*a67afe4dSAndroid Build Coastguard Worker          }
3731*a67afe4dSAndroid Build Coastguard Worker 
3732*a67afe4dSAndroid Build Coastguard Worker          change &= ~PNG_FORMAT_FLAG_COLOR;
3733*a67afe4dSAndroid Build Coastguard Worker       }
3734*a67afe4dSAndroid Build Coastguard Worker 
3735*a67afe4dSAndroid Build Coastguard Worker       /* Set the gamma appropriately, linear for 16-bit input, sRGB otherwise.
3736*a67afe4dSAndroid Build Coastguard Worker        */
3737*a67afe4dSAndroid Build Coastguard Worker       {
3738*a67afe4dSAndroid Build Coastguard Worker          png_fixed_point input_gamma_default;
3739*a67afe4dSAndroid Build Coastguard Worker 
3740*a67afe4dSAndroid Build Coastguard Worker          if ((base_format & PNG_FORMAT_FLAG_LINEAR) != 0 &&
3741*a67afe4dSAndroid Build Coastguard Worker              (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0)
3742*a67afe4dSAndroid Build Coastguard Worker             input_gamma_default = PNG_GAMMA_LINEAR;
3743*a67afe4dSAndroid Build Coastguard Worker          else
3744*a67afe4dSAndroid Build Coastguard Worker             input_gamma_default = PNG_DEFAULT_sRGB;
3745*a67afe4dSAndroid Build Coastguard Worker 
3746*a67afe4dSAndroid Build Coastguard Worker          /* Call png_set_alpha_mode to set the default for the input gamma; the
3747*a67afe4dSAndroid Build Coastguard Worker           * output gamma is set by a second call below.
3748*a67afe4dSAndroid Build Coastguard Worker           */
3749*a67afe4dSAndroid Build Coastguard Worker          png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, input_gamma_default);
3750*a67afe4dSAndroid Build Coastguard Worker       }
3751*a67afe4dSAndroid Build Coastguard Worker 
3752*a67afe4dSAndroid Build Coastguard Worker       if (linear != 0)
3753*a67afe4dSAndroid Build Coastguard Worker       {
3754*a67afe4dSAndroid Build Coastguard Worker          /* If there *is* an alpha channel in the input it must be multiplied
3755*a67afe4dSAndroid Build Coastguard Worker           * out; use PNG_ALPHA_STANDARD, otherwise just use PNG_ALPHA_PNG.
3756*a67afe4dSAndroid Build Coastguard Worker           */
3757*a67afe4dSAndroid Build Coastguard Worker          if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0)
3758*a67afe4dSAndroid Build Coastguard Worker             mode = PNG_ALPHA_STANDARD; /* associated alpha */
3759*a67afe4dSAndroid Build Coastguard Worker 
3760*a67afe4dSAndroid Build Coastguard Worker          else
3761*a67afe4dSAndroid Build Coastguard Worker             mode = PNG_ALPHA_PNG;
3762*a67afe4dSAndroid Build Coastguard Worker 
3763*a67afe4dSAndroid Build Coastguard Worker          output_gamma = PNG_GAMMA_LINEAR;
3764*a67afe4dSAndroid Build Coastguard Worker       }
3765*a67afe4dSAndroid Build Coastguard Worker 
3766*a67afe4dSAndroid Build Coastguard Worker       else
3767*a67afe4dSAndroid Build Coastguard Worker       {
3768*a67afe4dSAndroid Build Coastguard Worker          mode = PNG_ALPHA_PNG;
3769*a67afe4dSAndroid Build Coastguard Worker          output_gamma = PNG_DEFAULT_sRGB;
3770*a67afe4dSAndroid Build Coastguard Worker       }
3771*a67afe4dSAndroid Build Coastguard Worker 
3772*a67afe4dSAndroid Build Coastguard Worker       if ((change & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0)
3773*a67afe4dSAndroid Build Coastguard Worker       {
3774*a67afe4dSAndroid Build Coastguard Worker          mode = PNG_ALPHA_OPTIMIZED;
3775*a67afe4dSAndroid Build Coastguard Worker          change &= ~PNG_FORMAT_FLAG_ASSOCIATED_ALPHA;
3776*a67afe4dSAndroid Build Coastguard Worker       }
3777*a67afe4dSAndroid Build Coastguard Worker 
3778*a67afe4dSAndroid Build Coastguard Worker       /* If 'do_local_background' is set check for the presence of gamma
3779*a67afe4dSAndroid Build Coastguard Worker        * correction; this is part of the work-round for the libpng bug
3780*a67afe4dSAndroid Build Coastguard Worker        * described above.
3781*a67afe4dSAndroid Build Coastguard Worker        *
3782*a67afe4dSAndroid Build Coastguard Worker        * TODO: fix libpng and remove this.
3783*a67afe4dSAndroid Build Coastguard Worker        */
3784*a67afe4dSAndroid Build Coastguard Worker       if (do_local_background != 0)
3785*a67afe4dSAndroid Build Coastguard Worker       {
3786*a67afe4dSAndroid Build Coastguard Worker          png_fixed_point gtest;
3787*a67afe4dSAndroid Build Coastguard Worker 
3788*a67afe4dSAndroid Build Coastguard Worker          /* This is 'png_gamma_threshold' from pngrtran.c; the test used for
3789*a67afe4dSAndroid Build Coastguard Worker           * gamma correction, the screen gamma hasn't been set on png_struct
3790*a67afe4dSAndroid Build Coastguard Worker           * yet; it's set below.  png_struct::gamma, however, is set to the
3791*a67afe4dSAndroid Build Coastguard Worker           * final value.
3792*a67afe4dSAndroid Build Coastguard Worker           */
3793*a67afe4dSAndroid Build Coastguard Worker          if (png_muldiv(&gtest, output_gamma, png_ptr->colorspace.gamma,
3794*a67afe4dSAndroid Build Coastguard Worker              PNG_FP_1) != 0 && png_gamma_significant(gtest) == 0)
3795*a67afe4dSAndroid Build Coastguard Worker             do_local_background = 0;
3796*a67afe4dSAndroid Build Coastguard Worker 
3797*a67afe4dSAndroid Build Coastguard Worker          else if (mode == PNG_ALPHA_STANDARD)
3798*a67afe4dSAndroid Build Coastguard Worker          {
3799*a67afe4dSAndroid Build Coastguard Worker             do_local_background = 2/*required*/;
3800*a67afe4dSAndroid Build Coastguard Worker             mode = PNG_ALPHA_PNG; /* prevent libpng doing it */
3801*a67afe4dSAndroid Build Coastguard Worker          }
3802*a67afe4dSAndroid Build Coastguard Worker 
3803*a67afe4dSAndroid Build Coastguard Worker          /* else leave as 1 for the checks below */
3804*a67afe4dSAndroid Build Coastguard Worker       }
3805*a67afe4dSAndroid Build Coastguard Worker 
3806*a67afe4dSAndroid Build Coastguard Worker       /* If the bit-depth changes then handle that here. */
3807*a67afe4dSAndroid Build Coastguard Worker       if ((change & PNG_FORMAT_FLAG_LINEAR) != 0)
3808*a67afe4dSAndroid Build Coastguard Worker       {
3809*a67afe4dSAndroid Build Coastguard Worker          if (linear != 0 /*16-bit output*/)
3810*a67afe4dSAndroid Build Coastguard Worker             png_set_expand_16(png_ptr);
3811*a67afe4dSAndroid Build Coastguard Worker 
3812*a67afe4dSAndroid Build Coastguard Worker          else /* 8-bit output */
3813*a67afe4dSAndroid Build Coastguard Worker             png_set_scale_16(png_ptr);
3814*a67afe4dSAndroid Build Coastguard Worker 
3815*a67afe4dSAndroid Build Coastguard Worker          change &= ~PNG_FORMAT_FLAG_LINEAR;
3816*a67afe4dSAndroid Build Coastguard Worker       }
3817*a67afe4dSAndroid Build Coastguard Worker 
3818*a67afe4dSAndroid Build Coastguard Worker       /* Now the background/alpha channel changes. */
3819*a67afe4dSAndroid Build Coastguard Worker       if ((change & PNG_FORMAT_FLAG_ALPHA) != 0)
3820*a67afe4dSAndroid Build Coastguard Worker       {
3821*a67afe4dSAndroid Build Coastguard Worker          /* Removing an alpha channel requires composition for the 8-bit
3822*a67afe4dSAndroid Build Coastguard Worker           * formats; for the 16-bit it is already done, above, by the
3823*a67afe4dSAndroid Build Coastguard Worker           * pre-multiplication and the channel just needs to be stripped.
3824*a67afe4dSAndroid Build Coastguard Worker           */
3825*a67afe4dSAndroid Build Coastguard Worker          if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0)
3826*a67afe4dSAndroid Build Coastguard Worker          {
3827*a67afe4dSAndroid Build Coastguard Worker             /* If RGB->gray is happening the alpha channel must be left and the
3828*a67afe4dSAndroid Build Coastguard Worker              * operation completed locally.
3829*a67afe4dSAndroid Build Coastguard Worker              *
3830*a67afe4dSAndroid Build Coastguard Worker              * TODO: fix libpng and remove this.
3831*a67afe4dSAndroid Build Coastguard Worker              */
3832*a67afe4dSAndroid Build Coastguard Worker             if (do_local_background != 0)
3833*a67afe4dSAndroid Build Coastguard Worker                do_local_background = 2/*required*/;
3834*a67afe4dSAndroid Build Coastguard Worker 
3835*a67afe4dSAndroid Build Coastguard Worker             /* 16-bit output: just remove the channel */
3836*a67afe4dSAndroid Build Coastguard Worker             else if (linear != 0) /* compose on black (well, pre-multiply) */
3837*a67afe4dSAndroid Build Coastguard Worker                png_set_strip_alpha(png_ptr);
3838*a67afe4dSAndroid Build Coastguard Worker 
3839*a67afe4dSAndroid Build Coastguard Worker             /* 8-bit output: do an appropriate compose */
3840*a67afe4dSAndroid Build Coastguard Worker             else if (display->background != NULL)
3841*a67afe4dSAndroid Build Coastguard Worker             {
3842*a67afe4dSAndroid Build Coastguard Worker                png_color_16 c;
3843*a67afe4dSAndroid Build Coastguard Worker 
3844*a67afe4dSAndroid Build Coastguard Worker                c.index = 0; /*unused*/
3845*a67afe4dSAndroid Build Coastguard Worker                c.red = display->background->red;
3846*a67afe4dSAndroid Build Coastguard Worker                c.green = display->background->green;
3847*a67afe4dSAndroid Build Coastguard Worker                c.blue = display->background->blue;
3848*a67afe4dSAndroid Build Coastguard Worker                c.gray = display->background->green;
3849*a67afe4dSAndroid Build Coastguard Worker 
3850*a67afe4dSAndroid Build Coastguard Worker                /* This is always an 8-bit sRGB value, using the 'green' channel
3851*a67afe4dSAndroid Build Coastguard Worker                 * for gray is much better than calculating the luminance here;
3852*a67afe4dSAndroid Build Coastguard Worker                 * we can get off-by-one errors in that calculation relative to
3853*a67afe4dSAndroid Build Coastguard Worker                 * the app expectations and that will show up in transparent
3854*a67afe4dSAndroid Build Coastguard Worker                 * pixels.
3855*a67afe4dSAndroid Build Coastguard Worker                 */
3856*a67afe4dSAndroid Build Coastguard Worker                png_set_background_fixed(png_ptr, &c,
3857*a67afe4dSAndroid Build Coastguard Worker                    PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/,
3858*a67afe4dSAndroid Build Coastguard Worker                    0/*gamma: not used*/);
3859*a67afe4dSAndroid Build Coastguard Worker             }
3860*a67afe4dSAndroid Build Coastguard Worker 
3861*a67afe4dSAndroid Build Coastguard Worker             else /* compose on row: implemented below. */
3862*a67afe4dSAndroid Build Coastguard Worker             {
3863*a67afe4dSAndroid Build Coastguard Worker                do_local_compose = 1;
3864*a67afe4dSAndroid Build Coastguard Worker                /* This leaves the alpha channel in the output, so it has to be
3865*a67afe4dSAndroid Build Coastguard Worker                 * removed by the code below.  Set the encoding to the 'OPTIMIZE'
3866*a67afe4dSAndroid Build Coastguard Worker                 * one so the code only has to hack on the pixels that require
3867*a67afe4dSAndroid Build Coastguard Worker                 * composition.
3868*a67afe4dSAndroid Build Coastguard Worker                 */
3869*a67afe4dSAndroid Build Coastguard Worker                mode = PNG_ALPHA_OPTIMIZED;
3870*a67afe4dSAndroid Build Coastguard Worker             }
3871*a67afe4dSAndroid Build Coastguard Worker          }
3872*a67afe4dSAndroid Build Coastguard Worker 
3873*a67afe4dSAndroid Build Coastguard Worker          else /* output needs an alpha channel */
3874*a67afe4dSAndroid Build Coastguard Worker          {
3875*a67afe4dSAndroid Build Coastguard Worker             /* This is tricky because it happens before the swap operation has
3876*a67afe4dSAndroid Build Coastguard Worker              * been accomplished; however, the swap does *not* swap the added
3877*a67afe4dSAndroid Build Coastguard Worker              * alpha channel (weird API), so it must be added in the correct
3878*a67afe4dSAndroid Build Coastguard Worker              * place.
3879*a67afe4dSAndroid Build Coastguard Worker              */
3880*a67afe4dSAndroid Build Coastguard Worker             png_uint_32 filler; /* opaque filler */
3881*a67afe4dSAndroid Build Coastguard Worker             int where;
3882*a67afe4dSAndroid Build Coastguard Worker 
3883*a67afe4dSAndroid Build Coastguard Worker             if (linear != 0)
3884*a67afe4dSAndroid Build Coastguard Worker                filler = 65535;
3885*a67afe4dSAndroid Build Coastguard Worker 
3886*a67afe4dSAndroid Build Coastguard Worker             else
3887*a67afe4dSAndroid Build Coastguard Worker                filler = 255;
3888*a67afe4dSAndroid Build Coastguard Worker 
3889*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_FORMAT_AFIRST_SUPPORTED
3890*a67afe4dSAndroid Build Coastguard Worker             if ((format & PNG_FORMAT_FLAG_AFIRST) != 0)
3891*a67afe4dSAndroid Build Coastguard Worker             {
3892*a67afe4dSAndroid Build Coastguard Worker                where = PNG_FILLER_BEFORE;
3893*a67afe4dSAndroid Build Coastguard Worker                change &= ~PNG_FORMAT_FLAG_AFIRST;
3894*a67afe4dSAndroid Build Coastguard Worker             }
3895*a67afe4dSAndroid Build Coastguard Worker 
3896*a67afe4dSAndroid Build Coastguard Worker             else
3897*a67afe4dSAndroid Build Coastguard Worker #endif
3898*a67afe4dSAndroid Build Coastguard Worker             where = PNG_FILLER_AFTER;
3899*a67afe4dSAndroid Build Coastguard Worker 
3900*a67afe4dSAndroid Build Coastguard Worker             png_set_add_alpha(png_ptr, filler, where);
3901*a67afe4dSAndroid Build Coastguard Worker          }
3902*a67afe4dSAndroid Build Coastguard Worker 
3903*a67afe4dSAndroid Build Coastguard Worker          /* This stops the (irrelevant) call to swap_alpha below. */
3904*a67afe4dSAndroid Build Coastguard Worker          change &= ~PNG_FORMAT_FLAG_ALPHA;
3905*a67afe4dSAndroid Build Coastguard Worker       }
3906*a67afe4dSAndroid Build Coastguard Worker 
3907*a67afe4dSAndroid Build Coastguard Worker       /* Now set the alpha mode correctly; this is always done, even if there is
3908*a67afe4dSAndroid Build Coastguard Worker        * no alpha channel in either the input or the output because it correctly
3909*a67afe4dSAndroid Build Coastguard Worker        * sets the output gamma.
3910*a67afe4dSAndroid Build Coastguard Worker        */
3911*a67afe4dSAndroid Build Coastguard Worker       png_set_alpha_mode_fixed(png_ptr, mode, output_gamma);
3912*a67afe4dSAndroid Build Coastguard Worker 
3913*a67afe4dSAndroid Build Coastguard Worker #     ifdef PNG_FORMAT_BGR_SUPPORTED
3914*a67afe4dSAndroid Build Coastguard Worker          if ((change & PNG_FORMAT_FLAG_BGR) != 0)
3915*a67afe4dSAndroid Build Coastguard Worker          {
3916*a67afe4dSAndroid Build Coastguard Worker             /* Check only the output format; PNG is never BGR; don't do this if
3917*a67afe4dSAndroid Build Coastguard Worker              * the output is gray, but fix up the 'format' value in that case.
3918*a67afe4dSAndroid Build Coastguard Worker              */
3919*a67afe4dSAndroid Build Coastguard Worker             if ((format & PNG_FORMAT_FLAG_COLOR) != 0)
3920*a67afe4dSAndroid Build Coastguard Worker                png_set_bgr(png_ptr);
3921*a67afe4dSAndroid Build Coastguard Worker 
3922*a67afe4dSAndroid Build Coastguard Worker             else
3923*a67afe4dSAndroid Build Coastguard Worker                format &= ~PNG_FORMAT_FLAG_BGR;
3924*a67afe4dSAndroid Build Coastguard Worker 
3925*a67afe4dSAndroid Build Coastguard Worker             change &= ~PNG_FORMAT_FLAG_BGR;
3926*a67afe4dSAndroid Build Coastguard Worker          }
3927*a67afe4dSAndroid Build Coastguard Worker #     endif
3928*a67afe4dSAndroid Build Coastguard Worker 
3929*a67afe4dSAndroid Build Coastguard Worker #     ifdef PNG_FORMAT_AFIRST_SUPPORTED
3930*a67afe4dSAndroid Build Coastguard Worker          if ((change & PNG_FORMAT_FLAG_AFIRST) != 0)
3931*a67afe4dSAndroid Build Coastguard Worker          {
3932*a67afe4dSAndroid Build Coastguard Worker             /* Only relevant if there is an alpha channel - it's particularly
3933*a67afe4dSAndroid Build Coastguard Worker              * important to handle this correctly because do_local_compose may
3934*a67afe4dSAndroid Build Coastguard Worker              * be set above and then libpng will keep the alpha channel for this
3935*a67afe4dSAndroid Build Coastguard Worker              * code to remove.
3936*a67afe4dSAndroid Build Coastguard Worker              */
3937*a67afe4dSAndroid Build Coastguard Worker             if ((format & PNG_FORMAT_FLAG_ALPHA) != 0)
3938*a67afe4dSAndroid Build Coastguard Worker             {
3939*a67afe4dSAndroid Build Coastguard Worker                /* Disable this if doing a local background,
3940*a67afe4dSAndroid Build Coastguard Worker                 * TODO: remove this when local background is no longer required.
3941*a67afe4dSAndroid Build Coastguard Worker                 */
3942*a67afe4dSAndroid Build Coastguard Worker                if (do_local_background != 2)
3943*a67afe4dSAndroid Build Coastguard Worker                   png_set_swap_alpha(png_ptr);
3944*a67afe4dSAndroid Build Coastguard Worker             }
3945*a67afe4dSAndroid Build Coastguard Worker 
3946*a67afe4dSAndroid Build Coastguard Worker             else
3947*a67afe4dSAndroid Build Coastguard Worker                format &= ~PNG_FORMAT_FLAG_AFIRST;
3948*a67afe4dSAndroid Build Coastguard Worker 
3949*a67afe4dSAndroid Build Coastguard Worker             change &= ~PNG_FORMAT_FLAG_AFIRST;
3950*a67afe4dSAndroid Build Coastguard Worker          }
3951*a67afe4dSAndroid Build Coastguard Worker #     endif
3952*a67afe4dSAndroid Build Coastguard Worker 
3953*a67afe4dSAndroid Build Coastguard Worker       /* If the *output* is 16-bit then we need to check for a byte-swap on this
3954*a67afe4dSAndroid Build Coastguard Worker        * architecture.
3955*a67afe4dSAndroid Build Coastguard Worker        */
3956*a67afe4dSAndroid Build Coastguard Worker       if (linear != 0)
3957*a67afe4dSAndroid Build Coastguard Worker       {
3958*a67afe4dSAndroid Build Coastguard Worker          png_uint_16 le = 0x0001;
3959*a67afe4dSAndroid Build Coastguard Worker 
3960*a67afe4dSAndroid Build Coastguard Worker          if ((*(png_const_bytep) & le) != 0)
3961*a67afe4dSAndroid Build Coastguard Worker             png_set_swap(png_ptr);
3962*a67afe4dSAndroid Build Coastguard Worker       }
3963*a67afe4dSAndroid Build Coastguard Worker 
3964*a67afe4dSAndroid Build Coastguard Worker       /* If change is not now 0 some transformation is missing - error out. */
3965*a67afe4dSAndroid Build Coastguard Worker       if (change != 0)
3966*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr, "png_read_image: unsupported transformation");
3967*a67afe4dSAndroid Build Coastguard Worker    }
3968*a67afe4dSAndroid Build Coastguard Worker 
3969*a67afe4dSAndroid Build Coastguard Worker    PNG_SKIP_CHUNKS(png_ptr);
3970*a67afe4dSAndroid Build Coastguard Worker 
3971*a67afe4dSAndroid Build Coastguard Worker    /* Update the 'info' structure and make sure the result is as required; first
3972*a67afe4dSAndroid Build Coastguard Worker     * make sure to turn on the interlace handling if it will be required
3973*a67afe4dSAndroid Build Coastguard Worker     * (because it can't be turned on *after* the call to png_read_update_info!)
3974*a67afe4dSAndroid Build Coastguard Worker     *
3975*a67afe4dSAndroid Build Coastguard Worker     * TODO: remove the do_local_background fixup below.
3976*a67afe4dSAndroid Build Coastguard Worker     */
3977*a67afe4dSAndroid Build Coastguard Worker    if (do_local_compose == 0 && do_local_background != 2)
3978*a67afe4dSAndroid Build Coastguard Worker       passes = png_set_interlace_handling(png_ptr);
3979*a67afe4dSAndroid Build Coastguard Worker 
3980*a67afe4dSAndroid Build Coastguard Worker    png_read_update_info(png_ptr, info_ptr);
3981*a67afe4dSAndroid Build Coastguard Worker 
3982*a67afe4dSAndroid Build Coastguard Worker    {
3983*a67afe4dSAndroid Build Coastguard Worker       png_uint_32 info_format = 0;
3984*a67afe4dSAndroid Build Coastguard Worker 
3985*a67afe4dSAndroid Build Coastguard Worker       if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
3986*a67afe4dSAndroid Build Coastguard Worker          info_format |= PNG_FORMAT_FLAG_COLOR;
3987*a67afe4dSAndroid Build Coastguard Worker 
3988*a67afe4dSAndroid Build Coastguard Worker       if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)
3989*a67afe4dSAndroid Build Coastguard Worker       {
3990*a67afe4dSAndroid Build Coastguard Worker          /* do_local_compose removes this channel below. */
3991*a67afe4dSAndroid Build Coastguard Worker          if (do_local_compose == 0)
3992*a67afe4dSAndroid Build Coastguard Worker          {
3993*a67afe4dSAndroid Build Coastguard Worker             /* do_local_background does the same if required. */
3994*a67afe4dSAndroid Build Coastguard Worker             if (do_local_background != 2 ||
3995*a67afe4dSAndroid Build Coastguard Worker                (format & PNG_FORMAT_FLAG_ALPHA) != 0)
3996*a67afe4dSAndroid Build Coastguard Worker                info_format |= PNG_FORMAT_FLAG_ALPHA;
3997*a67afe4dSAndroid Build Coastguard Worker          }
3998*a67afe4dSAndroid Build Coastguard Worker       }
3999*a67afe4dSAndroid Build Coastguard Worker 
4000*a67afe4dSAndroid Build Coastguard Worker       else if (do_local_compose != 0) /* internal error */
4001*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr, "png_image_read: alpha channel lost");
4002*a67afe4dSAndroid Build Coastguard Worker 
4003*a67afe4dSAndroid Build Coastguard Worker       if ((format & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0) {
4004*a67afe4dSAndroid Build Coastguard Worker          info_format |= PNG_FORMAT_FLAG_ASSOCIATED_ALPHA;
4005*a67afe4dSAndroid Build Coastguard Worker       }
4006*a67afe4dSAndroid Build Coastguard Worker 
4007*a67afe4dSAndroid Build Coastguard Worker       if (info_ptr->bit_depth == 16)
4008*a67afe4dSAndroid Build Coastguard Worker          info_format |= PNG_FORMAT_FLAG_LINEAR;
4009*a67afe4dSAndroid Build Coastguard Worker 
4010*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_FORMAT_BGR_SUPPORTED
4011*a67afe4dSAndroid Build Coastguard Worker       if ((png_ptr->transformations & PNG_BGR) != 0)
4012*a67afe4dSAndroid Build Coastguard Worker          info_format |= PNG_FORMAT_FLAG_BGR;
4013*a67afe4dSAndroid Build Coastguard Worker #endif
4014*a67afe4dSAndroid Build Coastguard Worker 
4015*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_FORMAT_AFIRST_SUPPORTED
4016*a67afe4dSAndroid Build Coastguard Worker          if (do_local_background == 2)
4017*a67afe4dSAndroid Build Coastguard Worker          {
4018*a67afe4dSAndroid Build Coastguard Worker             if ((format & PNG_FORMAT_FLAG_AFIRST) != 0)
4019*a67afe4dSAndroid Build Coastguard Worker                info_format |= PNG_FORMAT_FLAG_AFIRST;
4020*a67afe4dSAndroid Build Coastguard Worker          }
4021*a67afe4dSAndroid Build Coastguard Worker 
4022*a67afe4dSAndroid Build Coastguard Worker          if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0 ||
4023*a67afe4dSAndroid Build Coastguard Worker             ((png_ptr->transformations & PNG_ADD_ALPHA) != 0 &&
4024*a67afe4dSAndroid Build Coastguard Worker             (png_ptr->flags & PNG_FLAG_FILLER_AFTER) == 0))
4025*a67afe4dSAndroid Build Coastguard Worker          {
4026*a67afe4dSAndroid Build Coastguard Worker             if (do_local_background == 2)
4027*a67afe4dSAndroid Build Coastguard Worker                png_error(png_ptr, "unexpected alpha swap transformation");
4028*a67afe4dSAndroid Build Coastguard Worker 
4029*a67afe4dSAndroid Build Coastguard Worker             info_format |= PNG_FORMAT_FLAG_AFIRST;
4030*a67afe4dSAndroid Build Coastguard Worker          }
4031*a67afe4dSAndroid Build Coastguard Worker #     endif
4032*a67afe4dSAndroid Build Coastguard Worker 
4033*a67afe4dSAndroid Build Coastguard Worker       /* This is actually an internal error. */
4034*a67afe4dSAndroid Build Coastguard Worker       if (info_format != format)
4035*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr, "png_read_image: invalid transformations");
4036*a67afe4dSAndroid Build Coastguard Worker    }
4037*a67afe4dSAndroid Build Coastguard Worker 
4038*a67afe4dSAndroid Build Coastguard Worker    /* Now read the rows.  If do_local_compose is set then it is necessary to use
4039*a67afe4dSAndroid Build Coastguard Worker     * a local row buffer.  The output will be GA, RGBA or BGRA and must be
4040*a67afe4dSAndroid Build Coastguard Worker     * converted to G, RGB or BGR as appropriate.  The 'local_row' member of the
4041*a67afe4dSAndroid Build Coastguard Worker     * display acts as a flag.
4042*a67afe4dSAndroid Build Coastguard Worker     */
4043*a67afe4dSAndroid Build Coastguard Worker    {
4044*a67afe4dSAndroid Build Coastguard Worker       png_voidp first_row = display->buffer;
4045*a67afe4dSAndroid Build Coastguard Worker       ptrdiff_t row_bytes = display->row_stride;
4046*a67afe4dSAndroid Build Coastguard Worker 
4047*a67afe4dSAndroid Build Coastguard Worker       if (linear != 0)
4048*a67afe4dSAndroid Build Coastguard Worker          row_bytes *= 2;
4049*a67afe4dSAndroid Build Coastguard Worker 
4050*a67afe4dSAndroid Build Coastguard Worker       /* The following expression is designed to work correctly whether it gives
4051*a67afe4dSAndroid Build Coastguard Worker        * a signed or an unsigned result.
4052*a67afe4dSAndroid Build Coastguard Worker        */
4053*a67afe4dSAndroid Build Coastguard Worker       if (row_bytes < 0)
4054*a67afe4dSAndroid Build Coastguard Worker       {
4055*a67afe4dSAndroid Build Coastguard Worker          char *ptr = png_voidcast(char*, first_row);
4056*a67afe4dSAndroid Build Coastguard Worker          ptr += (image->height-1) * (-row_bytes);
4057*a67afe4dSAndroid Build Coastguard Worker          first_row = png_voidcast(png_voidp, ptr);
4058*a67afe4dSAndroid Build Coastguard Worker       }
4059*a67afe4dSAndroid Build Coastguard Worker 
4060*a67afe4dSAndroid Build Coastguard Worker       display->first_row = first_row;
4061*a67afe4dSAndroid Build Coastguard Worker       display->row_bytes = row_bytes;
4062*a67afe4dSAndroid Build Coastguard Worker    }
4063*a67afe4dSAndroid Build Coastguard Worker 
4064*a67afe4dSAndroid Build Coastguard Worker    if (do_local_compose != 0)
4065*a67afe4dSAndroid Build Coastguard Worker    {
4066*a67afe4dSAndroid Build Coastguard Worker       int result;
4067*a67afe4dSAndroid Build Coastguard Worker       png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
4068*a67afe4dSAndroid Build Coastguard Worker 
4069*a67afe4dSAndroid Build Coastguard Worker       display->local_row = row;
4070*a67afe4dSAndroid Build Coastguard Worker       result = png_safe_execute(image, png_image_read_composite, display);
4071*a67afe4dSAndroid Build Coastguard Worker       display->local_row = NULL;
4072*a67afe4dSAndroid Build Coastguard Worker       png_free(png_ptr, row);
4073*a67afe4dSAndroid Build Coastguard Worker 
4074*a67afe4dSAndroid Build Coastguard Worker       return result;
4075*a67afe4dSAndroid Build Coastguard Worker    }
4076*a67afe4dSAndroid Build Coastguard Worker 
4077*a67afe4dSAndroid Build Coastguard Worker    else if (do_local_background == 2)
4078*a67afe4dSAndroid Build Coastguard Worker    {
4079*a67afe4dSAndroid Build Coastguard Worker       int result;
4080*a67afe4dSAndroid Build Coastguard Worker       png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr));
4081*a67afe4dSAndroid Build Coastguard Worker 
4082*a67afe4dSAndroid Build Coastguard Worker       display->local_row = row;
4083*a67afe4dSAndroid Build Coastguard Worker       result = png_safe_execute(image, png_image_read_background, display);
4084*a67afe4dSAndroid Build Coastguard Worker       display->local_row = NULL;
4085*a67afe4dSAndroid Build Coastguard Worker       png_free(png_ptr, row);
4086*a67afe4dSAndroid Build Coastguard Worker 
4087*a67afe4dSAndroid Build Coastguard Worker       return result;
4088*a67afe4dSAndroid Build Coastguard Worker    }
4089*a67afe4dSAndroid Build Coastguard Worker 
4090*a67afe4dSAndroid Build Coastguard Worker    else
4091*a67afe4dSAndroid Build Coastguard Worker    {
4092*a67afe4dSAndroid Build Coastguard Worker       png_alloc_size_t row_bytes = (png_alloc_size_t)display->row_bytes;
4093*a67afe4dSAndroid Build Coastguard Worker 
4094*a67afe4dSAndroid Build Coastguard Worker       while (--passes >= 0)
4095*a67afe4dSAndroid Build Coastguard Worker       {
4096*a67afe4dSAndroid Build Coastguard Worker          png_uint_32      y = image->height;
4097*a67afe4dSAndroid Build Coastguard Worker          png_bytep        row = png_voidcast(png_bytep, display->first_row);
4098*a67afe4dSAndroid Build Coastguard Worker 
4099*a67afe4dSAndroid Build Coastguard Worker          for (; y > 0; --y)
4100*a67afe4dSAndroid Build Coastguard Worker          {
4101*a67afe4dSAndroid Build Coastguard Worker             png_read_row(png_ptr, row, NULL);
4102*a67afe4dSAndroid Build Coastguard Worker             row += row_bytes;
4103*a67afe4dSAndroid Build Coastguard Worker          }
4104*a67afe4dSAndroid Build Coastguard Worker       }
4105*a67afe4dSAndroid Build Coastguard Worker 
4106*a67afe4dSAndroid Build Coastguard Worker       return 1;
4107*a67afe4dSAndroid Build Coastguard Worker    }
4108*a67afe4dSAndroid Build Coastguard Worker }
4109*a67afe4dSAndroid Build Coastguard Worker 
4110*a67afe4dSAndroid Build Coastguard Worker int PNGAPI
png_image_finish_read(png_imagep image,png_const_colorp background,void * buffer,png_int_32 row_stride,void * colormap)4111*a67afe4dSAndroid Build Coastguard Worker png_image_finish_read(png_imagep image, png_const_colorp background,
4112*a67afe4dSAndroid Build Coastguard Worker     void *buffer, png_int_32 row_stride, void *colormap)
4113*a67afe4dSAndroid Build Coastguard Worker {
4114*a67afe4dSAndroid Build Coastguard Worker    if (image != NULL && image->version == PNG_IMAGE_VERSION)
4115*a67afe4dSAndroid Build Coastguard Worker    {
4116*a67afe4dSAndroid Build Coastguard Worker       /* Check for row_stride overflow.  This check is not performed on the
4117*a67afe4dSAndroid Build Coastguard Worker        * original PNG format because it may not occur in the output PNG format
4118*a67afe4dSAndroid Build Coastguard Worker        * and libpng deals with the issues of reading the original.
4119*a67afe4dSAndroid Build Coastguard Worker        */
4120*a67afe4dSAndroid Build Coastguard Worker       unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format);
4121*a67afe4dSAndroid Build Coastguard Worker 
4122*a67afe4dSAndroid Build Coastguard Worker       /* The following checks just the 'row_stride' calculation to ensure it
4123*a67afe4dSAndroid Build Coastguard Worker        * fits in a signed 32-bit value.  Because channels/components can be
4124*a67afe4dSAndroid Build Coastguard Worker        * either 1 or 2 bytes in size the length of a row can still overflow 32
4125*a67afe4dSAndroid Build Coastguard Worker        * bits; this is just to verify that the 'row_stride' argument can be
4126*a67afe4dSAndroid Build Coastguard Worker        * represented.
4127*a67afe4dSAndroid Build Coastguard Worker        */
4128*a67afe4dSAndroid Build Coastguard Worker       if (image->width <= 0x7fffffffU/channels) /* no overflow */
4129*a67afe4dSAndroid Build Coastguard Worker       {
4130*a67afe4dSAndroid Build Coastguard Worker          png_uint_32 check;
4131*a67afe4dSAndroid Build Coastguard Worker          png_uint_32 png_row_stride = image->width * channels;
4132*a67afe4dSAndroid Build Coastguard Worker 
4133*a67afe4dSAndroid Build Coastguard Worker          if (row_stride == 0)
4134*a67afe4dSAndroid Build Coastguard Worker             row_stride = (png_int_32)/*SAFE*/png_row_stride;
4135*a67afe4dSAndroid Build Coastguard Worker 
4136*a67afe4dSAndroid Build Coastguard Worker          if (row_stride < 0)
4137*a67afe4dSAndroid Build Coastguard Worker             check = (png_uint_32)(-row_stride);
4138*a67afe4dSAndroid Build Coastguard Worker 
4139*a67afe4dSAndroid Build Coastguard Worker          else
4140*a67afe4dSAndroid Build Coastguard Worker             check = (png_uint_32)row_stride;
4141*a67afe4dSAndroid Build Coastguard Worker 
4142*a67afe4dSAndroid Build Coastguard Worker          /* This verifies 'check', the absolute value of the actual stride
4143*a67afe4dSAndroid Build Coastguard Worker           * passed in and detects overflow in the application calculation (i.e.
4144*a67afe4dSAndroid Build Coastguard Worker           * if the app did actually pass in a non-zero 'row_stride'.
4145*a67afe4dSAndroid Build Coastguard Worker           */
4146*a67afe4dSAndroid Build Coastguard Worker          if (image->opaque != NULL && buffer != NULL && check >= png_row_stride)
4147*a67afe4dSAndroid Build Coastguard Worker          {
4148*a67afe4dSAndroid Build Coastguard Worker             /* Now check for overflow of the image buffer calculation; this
4149*a67afe4dSAndroid Build Coastguard Worker              * limits the whole image size to 32 bits for API compatibility with
4150*a67afe4dSAndroid Build Coastguard Worker              * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro.
4151*a67afe4dSAndroid Build Coastguard Worker              *
4152*a67afe4dSAndroid Build Coastguard Worker              * The PNG_IMAGE_BUFFER_SIZE macro is:
4153*a67afe4dSAndroid Build Coastguard Worker              *
4154*a67afe4dSAndroid Build Coastguard Worker              *    (PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)*height*(row_stride))
4155*a67afe4dSAndroid Build Coastguard Worker              *
4156*a67afe4dSAndroid Build Coastguard Worker              * And the component size is always 1 or 2, so make sure that the
4157*a67afe4dSAndroid Build Coastguard Worker              * number of *bytes* that the application is saying are available
4158*a67afe4dSAndroid Build Coastguard Worker              * does actually fit into a 32-bit number.
4159*a67afe4dSAndroid Build Coastguard Worker              *
4160*a67afe4dSAndroid Build Coastguard Worker              * NOTE: this will be changed in 1.7 because PNG_IMAGE_BUFFER_SIZE
4161*a67afe4dSAndroid Build Coastguard Worker              * will be changed to use png_alloc_size_t; bigger images can be
4162*a67afe4dSAndroid Build Coastguard Worker              * accommodated on 64-bit systems.
4163*a67afe4dSAndroid Build Coastguard Worker              */
4164*a67afe4dSAndroid Build Coastguard Worker             if (image->height <=
4165*a67afe4dSAndroid Build Coastguard Worker                 0xffffffffU/PNG_IMAGE_PIXEL_COMPONENT_SIZE(image->format)/check)
4166*a67afe4dSAndroid Build Coastguard Worker             {
4167*a67afe4dSAndroid Build Coastguard Worker                if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 ||
4168*a67afe4dSAndroid Build Coastguard Worker                   (image->colormap_entries > 0 && colormap != NULL))
4169*a67afe4dSAndroid Build Coastguard Worker                {
4170*a67afe4dSAndroid Build Coastguard Worker                   int result;
4171*a67afe4dSAndroid Build Coastguard Worker                   png_image_read_control display;
4172*a67afe4dSAndroid Build Coastguard Worker 
4173*a67afe4dSAndroid Build Coastguard Worker                   memset(&display, 0, (sizeof display));
4174*a67afe4dSAndroid Build Coastguard Worker                   display.image = image;
4175*a67afe4dSAndroid Build Coastguard Worker                   display.buffer = buffer;
4176*a67afe4dSAndroid Build Coastguard Worker                   display.row_stride = row_stride;
4177*a67afe4dSAndroid Build Coastguard Worker                   display.colormap = colormap;
4178*a67afe4dSAndroid Build Coastguard Worker                   display.background = background;
4179*a67afe4dSAndroid Build Coastguard Worker                   display.local_row = NULL;
4180*a67afe4dSAndroid Build Coastguard Worker 
4181*a67afe4dSAndroid Build Coastguard Worker                   /* Choose the correct 'end' routine; for the color-map case
4182*a67afe4dSAndroid Build Coastguard Worker                    * all the setup has already been done.
4183*a67afe4dSAndroid Build Coastguard Worker                    */
4184*a67afe4dSAndroid Build Coastguard Worker                   if ((image->format & PNG_FORMAT_FLAG_COLORMAP) != 0)
4185*a67afe4dSAndroid Build Coastguard Worker                      result =
4186*a67afe4dSAndroid Build Coastguard Worker                          png_safe_execute(image,
4187*a67afe4dSAndroid Build Coastguard Worker                              png_image_read_colormap, &display) &&
4188*a67afe4dSAndroid Build Coastguard Worker                              png_safe_execute(image,
4189*a67afe4dSAndroid Build Coastguard Worker                              png_image_read_colormapped, &display);
4190*a67afe4dSAndroid Build Coastguard Worker 
4191*a67afe4dSAndroid Build Coastguard Worker                   else
4192*a67afe4dSAndroid Build Coastguard Worker                      result =
4193*a67afe4dSAndroid Build Coastguard Worker                         png_safe_execute(image,
4194*a67afe4dSAndroid Build Coastguard Worker                             png_image_read_direct, &display);
4195*a67afe4dSAndroid Build Coastguard Worker 
4196*a67afe4dSAndroid Build Coastguard Worker                   png_image_free(image);
4197*a67afe4dSAndroid Build Coastguard Worker                   return result;
4198*a67afe4dSAndroid Build Coastguard Worker                }
4199*a67afe4dSAndroid Build Coastguard Worker 
4200*a67afe4dSAndroid Build Coastguard Worker                else
4201*a67afe4dSAndroid Build Coastguard Worker                   return png_image_error(image,
4202*a67afe4dSAndroid Build Coastguard Worker                       "png_image_finish_read[color-map]: no color-map");
4203*a67afe4dSAndroid Build Coastguard Worker             }
4204*a67afe4dSAndroid Build Coastguard Worker 
4205*a67afe4dSAndroid Build Coastguard Worker             else
4206*a67afe4dSAndroid Build Coastguard Worker                return png_image_error(image,
4207*a67afe4dSAndroid Build Coastguard Worker                    "png_image_finish_read: image too large");
4208*a67afe4dSAndroid Build Coastguard Worker          }
4209*a67afe4dSAndroid Build Coastguard Worker 
4210*a67afe4dSAndroid Build Coastguard Worker          else
4211*a67afe4dSAndroid Build Coastguard Worker             return png_image_error(image,
4212*a67afe4dSAndroid Build Coastguard Worker                 "png_image_finish_read: invalid argument");
4213*a67afe4dSAndroid Build Coastguard Worker       }
4214*a67afe4dSAndroid Build Coastguard Worker 
4215*a67afe4dSAndroid Build Coastguard Worker       else
4216*a67afe4dSAndroid Build Coastguard Worker          return png_image_error(image,
4217*a67afe4dSAndroid Build Coastguard Worker              "png_image_finish_read: row_stride too large");
4218*a67afe4dSAndroid Build Coastguard Worker    }
4219*a67afe4dSAndroid Build Coastguard Worker 
4220*a67afe4dSAndroid Build Coastguard Worker    else if (image != NULL)
4221*a67afe4dSAndroid Build Coastguard Worker       return png_image_error(image,
4222*a67afe4dSAndroid Build Coastguard Worker           "png_image_finish_read: damaged PNG_IMAGE_VERSION");
4223*a67afe4dSAndroid Build Coastguard Worker 
4224*a67afe4dSAndroid Build Coastguard Worker    return 0;
4225*a67afe4dSAndroid Build Coastguard Worker }
4226*a67afe4dSAndroid Build Coastguard Worker 
4227*a67afe4dSAndroid Build Coastguard Worker #endif /* SIMPLIFIED_READ */
4228*a67afe4dSAndroid Build Coastguard Worker #endif /* READ */
4229