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(>est, 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