xref: /aosp_15_r20/external/libpng/pngrtran.c (revision a67afe4df73cf47866eedc69947994b8ff839aba)
1*a67afe4dSAndroid Build Coastguard Worker 
2*a67afe4dSAndroid Build Coastguard Worker /* pngrtran.c - transforms the data in a row for PNG readers
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 functions optionally called by an application
14*a67afe4dSAndroid Build Coastguard Worker  * in order to tell libpng how to handle data when reading a PNG.
15*a67afe4dSAndroid Build Coastguard Worker  * Transformations that are used in both reading and writing are
16*a67afe4dSAndroid Build Coastguard Worker  * in pngtrans.c.
17*a67afe4dSAndroid Build Coastguard Worker  */
18*a67afe4dSAndroid Build Coastguard Worker 
19*a67afe4dSAndroid Build Coastguard Worker #include "pngpriv.h"
20*a67afe4dSAndroid Build Coastguard Worker 
21*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_ARM_NEON_IMPLEMENTATION
22*a67afe4dSAndroid Build Coastguard Worker #  if PNG_ARM_NEON_IMPLEMENTATION == 1
23*a67afe4dSAndroid Build Coastguard Worker #    define PNG_ARM_NEON_INTRINSICS_AVAILABLE
24*a67afe4dSAndroid Build Coastguard Worker #    if defined(_MSC_VER) && !defined(__clang__) && defined(_M_ARM64)
25*a67afe4dSAndroid Build Coastguard Worker #      include <arm64_neon.h>
26*a67afe4dSAndroid Build Coastguard Worker #    else
27*a67afe4dSAndroid Build Coastguard Worker #      include <arm_neon.h>
28*a67afe4dSAndroid Build Coastguard Worker #    endif
29*a67afe4dSAndroid Build Coastguard Worker #  endif
30*a67afe4dSAndroid Build Coastguard Worker #endif
31*a67afe4dSAndroid Build Coastguard Worker 
32*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_SUPPORTED
33*a67afe4dSAndroid Build Coastguard Worker 
34*a67afe4dSAndroid Build Coastguard Worker /* Set the action on getting a CRC error for an ancillary or critical chunk. */
35*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_set_crc_action(png_structrp png_ptr,int crit_action,int ancil_action)36*a67afe4dSAndroid Build Coastguard Worker png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action)
37*a67afe4dSAndroid Build Coastguard Worker {
38*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_set_crc_action");
39*a67afe4dSAndroid Build Coastguard Worker 
40*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr == NULL)
41*a67afe4dSAndroid Build Coastguard Worker       return;
42*a67afe4dSAndroid Build Coastguard Worker 
43*a67afe4dSAndroid Build Coastguard Worker    /* Tell libpng how we react to CRC errors in critical chunks */
44*a67afe4dSAndroid Build Coastguard Worker    switch (crit_action)
45*a67afe4dSAndroid Build Coastguard Worker    {
46*a67afe4dSAndroid Build Coastguard Worker       case PNG_CRC_NO_CHANGE:                        /* Leave setting as is */
47*a67afe4dSAndroid Build Coastguard Worker          break;
48*a67afe4dSAndroid Build Coastguard Worker 
49*a67afe4dSAndroid Build Coastguard Worker       case PNG_CRC_WARN_USE:                               /* Warn/use data */
50*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
51*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;
52*a67afe4dSAndroid Build Coastguard Worker          break;
53*a67afe4dSAndroid Build Coastguard Worker 
54*a67afe4dSAndroid Build Coastguard Worker       case PNG_CRC_QUIET_USE:                             /* Quiet/use data */
55*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
56*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |
57*a67afe4dSAndroid Build Coastguard Worker                            PNG_FLAG_CRC_CRITICAL_IGNORE;
58*a67afe4dSAndroid Build Coastguard Worker          break;
59*a67afe4dSAndroid Build Coastguard Worker 
60*a67afe4dSAndroid Build Coastguard Worker       case PNG_CRC_WARN_DISCARD:    /* Not a valid action for critical data */
61*a67afe4dSAndroid Build Coastguard Worker          png_warning(png_ptr,
62*a67afe4dSAndroid Build Coastguard Worker              "Can't discard critical data on CRC error");
63*a67afe4dSAndroid Build Coastguard Worker          /* FALLTHROUGH */
64*a67afe4dSAndroid Build Coastguard Worker       case PNG_CRC_ERROR_QUIT:                                /* Error/quit */
65*a67afe4dSAndroid Build Coastguard Worker 
66*a67afe4dSAndroid Build Coastguard Worker       case PNG_CRC_DEFAULT:
67*a67afe4dSAndroid Build Coastguard Worker       default:
68*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
69*a67afe4dSAndroid Build Coastguard Worker          break;
70*a67afe4dSAndroid Build Coastguard Worker    }
71*a67afe4dSAndroid Build Coastguard Worker 
72*a67afe4dSAndroid Build Coastguard Worker    /* Tell libpng how we react to CRC errors in ancillary chunks */
73*a67afe4dSAndroid Build Coastguard Worker    switch (ancil_action)
74*a67afe4dSAndroid Build Coastguard Worker    {
75*a67afe4dSAndroid Build Coastguard Worker       case PNG_CRC_NO_CHANGE:                       /* Leave setting as is */
76*a67afe4dSAndroid Build Coastguard Worker          break;
77*a67afe4dSAndroid Build Coastguard Worker 
78*a67afe4dSAndroid Build Coastguard Worker       case PNG_CRC_WARN_USE:                              /* Warn/use data */
79*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
80*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
81*a67afe4dSAndroid Build Coastguard Worker          break;
82*a67afe4dSAndroid Build Coastguard Worker 
83*a67afe4dSAndroid Build Coastguard Worker       case PNG_CRC_QUIET_USE:                            /* Quiet/use data */
84*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
85*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |
86*a67afe4dSAndroid Build Coastguard Worker                            PNG_FLAG_CRC_ANCILLARY_NOWARN;
87*a67afe4dSAndroid Build Coastguard Worker          break;
88*a67afe4dSAndroid Build Coastguard Worker 
89*a67afe4dSAndroid Build Coastguard Worker       case PNG_CRC_ERROR_QUIT:                               /* Error/quit */
90*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
91*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;
92*a67afe4dSAndroid Build Coastguard Worker          break;
93*a67afe4dSAndroid Build Coastguard Worker 
94*a67afe4dSAndroid Build Coastguard Worker       case PNG_CRC_WARN_DISCARD:                      /* Warn/discard data */
95*a67afe4dSAndroid Build Coastguard Worker 
96*a67afe4dSAndroid Build Coastguard Worker       case PNG_CRC_DEFAULT:
97*a67afe4dSAndroid Build Coastguard Worker       default:
98*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
99*a67afe4dSAndroid Build Coastguard Worker          break;
100*a67afe4dSAndroid Build Coastguard Worker    }
101*a67afe4dSAndroid Build Coastguard Worker }
102*a67afe4dSAndroid Build Coastguard Worker 
103*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_TRANSFORMS_SUPPORTED
104*a67afe4dSAndroid Build Coastguard Worker /* Is it OK to set a transformation now?  Only if png_start_read_image or
105*a67afe4dSAndroid Build Coastguard Worker  * png_read_update_info have not been called.  It is not necessary for the IHDR
106*a67afe4dSAndroid Build Coastguard Worker  * to have been read in all cases; the need_IHDR parameter allows for this
107*a67afe4dSAndroid Build Coastguard Worker  * check too.
108*a67afe4dSAndroid Build Coastguard Worker  */
109*a67afe4dSAndroid Build Coastguard Worker static int
png_rtran_ok(png_structrp png_ptr,int need_IHDR)110*a67afe4dSAndroid Build Coastguard Worker png_rtran_ok(png_structrp png_ptr, int need_IHDR)
111*a67afe4dSAndroid Build Coastguard Worker {
112*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr != NULL)
113*a67afe4dSAndroid Build Coastguard Worker    {
114*a67afe4dSAndroid Build Coastguard Worker       if ((png_ptr->flags & PNG_FLAG_ROW_INIT) != 0)
115*a67afe4dSAndroid Build Coastguard Worker          png_app_error(png_ptr,
116*a67afe4dSAndroid Build Coastguard Worker              "invalid after png_start_read_image or png_read_update_info");
117*a67afe4dSAndroid Build Coastguard Worker 
118*a67afe4dSAndroid Build Coastguard Worker       else if (need_IHDR && (png_ptr->mode & PNG_HAVE_IHDR) == 0)
119*a67afe4dSAndroid Build Coastguard Worker          png_app_error(png_ptr, "invalid before the PNG header has been read");
120*a67afe4dSAndroid Build Coastguard Worker 
121*a67afe4dSAndroid Build Coastguard Worker       else
122*a67afe4dSAndroid Build Coastguard Worker       {
123*a67afe4dSAndroid Build Coastguard Worker          /* Turn on failure to initialize correctly for all transforms. */
124*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED;
125*a67afe4dSAndroid Build Coastguard Worker 
126*a67afe4dSAndroid Build Coastguard Worker          return 1; /* Ok */
127*a67afe4dSAndroid Build Coastguard Worker       }
128*a67afe4dSAndroid Build Coastguard Worker    }
129*a67afe4dSAndroid Build Coastguard Worker 
130*a67afe4dSAndroid Build Coastguard Worker    return 0; /* no png_error possible! */
131*a67afe4dSAndroid Build Coastguard Worker }
132*a67afe4dSAndroid Build Coastguard Worker #endif
133*a67afe4dSAndroid Build Coastguard Worker 
134*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_BACKGROUND_SUPPORTED
135*a67afe4dSAndroid Build Coastguard Worker /* Handle alpha and tRNS via a background color */
136*a67afe4dSAndroid Build Coastguard Worker void PNGFAPI
png_set_background_fixed(png_structrp png_ptr,png_const_color_16p background_color,int background_gamma_code,int need_expand,png_fixed_point background_gamma)137*a67afe4dSAndroid Build Coastguard Worker png_set_background_fixed(png_structrp png_ptr,
138*a67afe4dSAndroid Build Coastguard Worker     png_const_color_16p background_color, int background_gamma_code,
139*a67afe4dSAndroid Build Coastguard Worker     int need_expand, png_fixed_point background_gamma)
140*a67afe4dSAndroid Build Coastguard Worker {
141*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_set_background_fixed");
142*a67afe4dSAndroid Build Coastguard Worker 
143*a67afe4dSAndroid Build Coastguard Worker    if (png_rtran_ok(png_ptr, 0) == 0 || background_color == NULL)
144*a67afe4dSAndroid Build Coastguard Worker       return;
145*a67afe4dSAndroid Build Coastguard Worker 
146*a67afe4dSAndroid Build Coastguard Worker    if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
147*a67afe4dSAndroid Build Coastguard Worker    {
148*a67afe4dSAndroid Build Coastguard Worker       png_warning(png_ptr, "Application must supply a known background gamma");
149*a67afe4dSAndroid Build Coastguard Worker       return;
150*a67afe4dSAndroid Build Coastguard Worker    }
151*a67afe4dSAndroid Build Coastguard Worker 
152*a67afe4dSAndroid Build Coastguard Worker    png_ptr->transformations |= PNG_COMPOSE | PNG_STRIP_ALPHA;
153*a67afe4dSAndroid Build Coastguard Worker    png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
154*a67afe4dSAndroid Build Coastguard Worker    png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
155*a67afe4dSAndroid Build Coastguard Worker 
156*a67afe4dSAndroid Build Coastguard Worker    png_ptr->background = *background_color;
157*a67afe4dSAndroid Build Coastguard Worker    png_ptr->background_gamma = background_gamma;
158*a67afe4dSAndroid Build Coastguard Worker    png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
159*a67afe4dSAndroid Build Coastguard Worker    if (need_expand != 0)
160*a67afe4dSAndroid Build Coastguard Worker       png_ptr->transformations |= PNG_BACKGROUND_EXPAND;
161*a67afe4dSAndroid Build Coastguard Worker    else
162*a67afe4dSAndroid Build Coastguard Worker       png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;
163*a67afe4dSAndroid Build Coastguard Worker }
164*a67afe4dSAndroid Build Coastguard Worker 
165*a67afe4dSAndroid Build Coastguard Worker #  ifdef PNG_FLOATING_POINT_SUPPORTED
166*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_set_background(png_structrp png_ptr,png_const_color_16p background_color,int background_gamma_code,int need_expand,double background_gamma)167*a67afe4dSAndroid Build Coastguard Worker png_set_background(png_structrp png_ptr,
168*a67afe4dSAndroid Build Coastguard Worker     png_const_color_16p background_color, int background_gamma_code,
169*a67afe4dSAndroid Build Coastguard Worker     int need_expand, double background_gamma)
170*a67afe4dSAndroid Build Coastguard Worker {
171*a67afe4dSAndroid Build Coastguard Worker    png_set_background_fixed(png_ptr, background_color, background_gamma_code,
172*a67afe4dSAndroid Build Coastguard Worker       need_expand, png_fixed(png_ptr, background_gamma, "png_set_background"));
173*a67afe4dSAndroid Build Coastguard Worker }
174*a67afe4dSAndroid Build Coastguard Worker #  endif /* FLOATING_POINT */
175*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_BACKGROUND */
176*a67afe4dSAndroid Build Coastguard Worker 
177*a67afe4dSAndroid Build Coastguard Worker /* Scale 16-bit depth files to 8-bit depth.  If both of these are set then the
178*a67afe4dSAndroid Build Coastguard Worker  * one that pngrtran does first (scale) happens.  This is necessary to allow the
179*a67afe4dSAndroid Build Coastguard Worker  * TRANSFORM and API behavior to be somewhat consistent, and it's simpler.
180*a67afe4dSAndroid Build Coastguard Worker  */
181*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
182*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_set_scale_16(png_structrp png_ptr)183*a67afe4dSAndroid Build Coastguard Worker png_set_scale_16(png_structrp png_ptr)
184*a67afe4dSAndroid Build Coastguard Worker {
185*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_set_scale_16");
186*a67afe4dSAndroid Build Coastguard Worker 
187*a67afe4dSAndroid Build Coastguard Worker    if (png_rtran_ok(png_ptr, 0) == 0)
188*a67afe4dSAndroid Build Coastguard Worker       return;
189*a67afe4dSAndroid Build Coastguard Worker 
190*a67afe4dSAndroid Build Coastguard Worker    png_ptr->transformations |= PNG_SCALE_16_TO_8;
191*a67afe4dSAndroid Build Coastguard Worker }
192*a67afe4dSAndroid Build Coastguard Worker #endif
193*a67afe4dSAndroid Build Coastguard Worker 
194*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
195*a67afe4dSAndroid Build Coastguard Worker /* Chop 16-bit depth files to 8-bit depth */
196*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_set_strip_16(png_structrp png_ptr)197*a67afe4dSAndroid Build Coastguard Worker png_set_strip_16(png_structrp png_ptr)
198*a67afe4dSAndroid Build Coastguard Worker {
199*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_set_strip_16");
200*a67afe4dSAndroid Build Coastguard Worker 
201*a67afe4dSAndroid Build Coastguard Worker    if (png_rtran_ok(png_ptr, 0) == 0)
202*a67afe4dSAndroid Build Coastguard Worker       return;
203*a67afe4dSAndroid Build Coastguard Worker 
204*a67afe4dSAndroid Build Coastguard Worker    png_ptr->transformations |= PNG_16_TO_8;
205*a67afe4dSAndroid Build Coastguard Worker }
206*a67afe4dSAndroid Build Coastguard Worker #endif
207*a67afe4dSAndroid Build Coastguard Worker 
208*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
209*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_set_strip_alpha(png_structrp png_ptr)210*a67afe4dSAndroid Build Coastguard Worker png_set_strip_alpha(png_structrp png_ptr)
211*a67afe4dSAndroid Build Coastguard Worker {
212*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_set_strip_alpha");
213*a67afe4dSAndroid Build Coastguard Worker 
214*a67afe4dSAndroid Build Coastguard Worker    if (png_rtran_ok(png_ptr, 0) == 0)
215*a67afe4dSAndroid Build Coastguard Worker       return;
216*a67afe4dSAndroid Build Coastguard Worker 
217*a67afe4dSAndroid Build Coastguard Worker    png_ptr->transformations |= PNG_STRIP_ALPHA;
218*a67afe4dSAndroid Build Coastguard Worker }
219*a67afe4dSAndroid Build Coastguard Worker #endif
220*a67afe4dSAndroid Build Coastguard Worker 
221*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED)
222*a67afe4dSAndroid Build Coastguard Worker static png_fixed_point
translate_gamma_flags(png_structrp png_ptr,png_fixed_point output_gamma,int is_screen)223*a67afe4dSAndroid Build Coastguard Worker translate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma,
224*a67afe4dSAndroid Build Coastguard Worker     int is_screen)
225*a67afe4dSAndroid Build Coastguard Worker {
226*a67afe4dSAndroid Build Coastguard Worker    /* Check for flag values.  The main reason for having the old Mac value as a
227*a67afe4dSAndroid Build Coastguard Worker     * flag is that it is pretty near impossible to work out what the correct
228*a67afe4dSAndroid Build Coastguard Worker     * value is from Apple documentation - a working Mac system is needed to
229*a67afe4dSAndroid Build Coastguard Worker     * discover the value!
230*a67afe4dSAndroid Build Coastguard Worker     */
231*a67afe4dSAndroid Build Coastguard Worker    if (output_gamma == PNG_DEFAULT_sRGB ||
232*a67afe4dSAndroid Build Coastguard Worker       output_gamma == PNG_FP_1 / PNG_DEFAULT_sRGB)
233*a67afe4dSAndroid Build Coastguard Worker    {
234*a67afe4dSAndroid Build Coastguard Worker       /* If there is no sRGB support this just sets the gamma to the standard
235*a67afe4dSAndroid Build Coastguard Worker        * sRGB value.  (This is a side effect of using this function!)
236*a67afe4dSAndroid Build Coastguard Worker        */
237*a67afe4dSAndroid Build Coastguard Worker #     ifdef PNG_READ_sRGB_SUPPORTED
238*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags |= PNG_FLAG_ASSUME_sRGB;
239*a67afe4dSAndroid Build Coastguard Worker #     else
240*a67afe4dSAndroid Build Coastguard Worker          PNG_UNUSED(png_ptr)
241*a67afe4dSAndroid Build Coastguard Worker #     endif
242*a67afe4dSAndroid Build Coastguard Worker       if (is_screen != 0)
243*a67afe4dSAndroid Build Coastguard Worker          output_gamma = PNG_GAMMA_sRGB;
244*a67afe4dSAndroid Build Coastguard Worker       else
245*a67afe4dSAndroid Build Coastguard Worker          output_gamma = PNG_GAMMA_sRGB_INVERSE;
246*a67afe4dSAndroid Build Coastguard Worker    }
247*a67afe4dSAndroid Build Coastguard Worker 
248*a67afe4dSAndroid Build Coastguard Worker    else if (output_gamma == PNG_GAMMA_MAC_18 ||
249*a67afe4dSAndroid Build Coastguard Worker       output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18)
250*a67afe4dSAndroid Build Coastguard Worker    {
251*a67afe4dSAndroid Build Coastguard Worker       if (is_screen != 0)
252*a67afe4dSAndroid Build Coastguard Worker          output_gamma = PNG_GAMMA_MAC_OLD;
253*a67afe4dSAndroid Build Coastguard Worker       else
254*a67afe4dSAndroid Build Coastguard Worker          output_gamma = PNG_GAMMA_MAC_INVERSE;
255*a67afe4dSAndroid Build Coastguard Worker    }
256*a67afe4dSAndroid Build Coastguard Worker 
257*a67afe4dSAndroid Build Coastguard Worker    return output_gamma;
258*a67afe4dSAndroid Build Coastguard Worker }
259*a67afe4dSAndroid Build Coastguard Worker 
260*a67afe4dSAndroid Build Coastguard Worker #  ifdef PNG_FLOATING_POINT_SUPPORTED
261*a67afe4dSAndroid Build Coastguard Worker static png_fixed_point
convert_gamma_value(png_structrp png_ptr,double output_gamma)262*a67afe4dSAndroid Build Coastguard Worker convert_gamma_value(png_structrp png_ptr, double output_gamma)
263*a67afe4dSAndroid Build Coastguard Worker {
264*a67afe4dSAndroid Build Coastguard Worker    /* The following silently ignores cases where fixed point (times 100,000)
265*a67afe4dSAndroid Build Coastguard Worker     * gamma values are passed to the floating point API.  This is safe and it
266*a67afe4dSAndroid Build Coastguard Worker     * means the fixed point constants work just fine with the floating point
267*a67afe4dSAndroid Build Coastguard Worker     * API.  The alternative would just lead to undetected errors and spurious
268*a67afe4dSAndroid Build Coastguard Worker     * bug reports.  Negative values fail inside the _fixed API unless they
269*a67afe4dSAndroid Build Coastguard Worker     * correspond to the flag values.
270*a67afe4dSAndroid Build Coastguard Worker     */
271*a67afe4dSAndroid Build Coastguard Worker    if (output_gamma > 0 && output_gamma < 128)
272*a67afe4dSAndroid Build Coastguard Worker       output_gamma *= PNG_FP_1;
273*a67afe4dSAndroid Build Coastguard Worker 
274*a67afe4dSAndroid Build Coastguard Worker    /* This preserves -1 and -2 exactly: */
275*a67afe4dSAndroid Build Coastguard Worker    output_gamma = floor(output_gamma + .5);
276*a67afe4dSAndroid Build Coastguard Worker 
277*a67afe4dSAndroid Build Coastguard Worker    if (output_gamma > PNG_FP_MAX || output_gamma < PNG_FP_MIN)
278*a67afe4dSAndroid Build Coastguard Worker       png_fixed_error(png_ptr, "gamma value");
279*a67afe4dSAndroid Build Coastguard Worker 
280*a67afe4dSAndroid Build Coastguard Worker    return (png_fixed_point)output_gamma;
281*a67afe4dSAndroid Build Coastguard Worker }
282*a67afe4dSAndroid Build Coastguard Worker #  endif
283*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_ALPHA_MODE || READ_GAMMA */
284*a67afe4dSAndroid Build Coastguard Worker 
285*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_ALPHA_MODE_SUPPORTED
286*a67afe4dSAndroid Build Coastguard Worker void PNGFAPI
png_set_alpha_mode_fixed(png_structrp png_ptr,int mode,png_fixed_point output_gamma)287*a67afe4dSAndroid Build Coastguard Worker png_set_alpha_mode_fixed(png_structrp png_ptr, int mode,
288*a67afe4dSAndroid Build Coastguard Worker     png_fixed_point output_gamma)
289*a67afe4dSAndroid Build Coastguard Worker {
290*a67afe4dSAndroid Build Coastguard Worker    int compose = 0;
291*a67afe4dSAndroid Build Coastguard Worker    png_fixed_point file_gamma;
292*a67afe4dSAndroid Build Coastguard Worker 
293*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_set_alpha_mode_fixed");
294*a67afe4dSAndroid Build Coastguard Worker 
295*a67afe4dSAndroid Build Coastguard Worker    if (png_rtran_ok(png_ptr, 0) == 0)
296*a67afe4dSAndroid Build Coastguard Worker       return;
297*a67afe4dSAndroid Build Coastguard Worker 
298*a67afe4dSAndroid Build Coastguard Worker    output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/);
299*a67afe4dSAndroid Build Coastguard Worker 
300*a67afe4dSAndroid Build Coastguard Worker    /* Validate the value to ensure it is in a reasonable range.  The value
301*a67afe4dSAndroid Build Coastguard Worker     * is expected to be 1 or greater, but this range test allows for some
302*a67afe4dSAndroid Build Coastguard Worker     * viewing correction values.  The intent is to weed out the API users
303*a67afe4dSAndroid Build Coastguard Worker     * who might use the inverse of the gamma value accidentally!
304*a67afe4dSAndroid Build Coastguard Worker     *
305*a67afe4dSAndroid Build Coastguard Worker     * In libpng 1.6.0, we changed from 0.07..3 to 0.01..100, to accommodate
306*a67afe4dSAndroid Build Coastguard Worker     * the optimal 16-bit gamma of 36 and its reciprocal.
307*a67afe4dSAndroid Build Coastguard Worker     */
308*a67afe4dSAndroid Build Coastguard Worker    if (output_gamma < 1000 || output_gamma > 10000000)
309*a67afe4dSAndroid Build Coastguard Worker       png_error(png_ptr, "output gamma out of expected range");
310*a67afe4dSAndroid Build Coastguard Worker 
311*a67afe4dSAndroid Build Coastguard Worker    /* The default file gamma is the inverse of the output gamma; the output
312*a67afe4dSAndroid Build Coastguard Worker     * gamma may be changed below so get the file value first:
313*a67afe4dSAndroid Build Coastguard Worker     */
314*a67afe4dSAndroid Build Coastguard Worker    file_gamma = png_reciprocal(output_gamma);
315*a67afe4dSAndroid Build Coastguard Worker 
316*a67afe4dSAndroid Build Coastguard Worker    /* There are really 8 possibilities here, composed of any combination
317*a67afe4dSAndroid Build Coastguard Worker     * of:
318*a67afe4dSAndroid Build Coastguard Worker     *
319*a67afe4dSAndroid Build Coastguard Worker     *    premultiply the color channels
320*a67afe4dSAndroid Build Coastguard Worker     *    do not encode non-opaque pixels
321*a67afe4dSAndroid Build Coastguard Worker     *    encode the alpha as well as the color channels
322*a67afe4dSAndroid Build Coastguard Worker     *
323*a67afe4dSAndroid Build Coastguard Worker     * The differences disappear if the input/output ('screen') gamma is 1.0,
324*a67afe4dSAndroid Build Coastguard Worker     * because then the encoding is a no-op and there is only the choice of
325*a67afe4dSAndroid Build Coastguard Worker     * premultiplying the color channels or not.
326*a67afe4dSAndroid Build Coastguard Worker     *
327*a67afe4dSAndroid Build Coastguard Worker     * png_set_alpha_mode and png_set_background interact because both use
328*a67afe4dSAndroid Build Coastguard Worker     * png_compose to do the work.  Calling both is only useful when
329*a67afe4dSAndroid Build Coastguard Worker     * png_set_alpha_mode is used to set the default mode - PNG_ALPHA_PNG - along
330*a67afe4dSAndroid Build Coastguard Worker     * with a default gamma value.  Otherwise PNG_COMPOSE must not be set.
331*a67afe4dSAndroid Build Coastguard Worker     */
332*a67afe4dSAndroid Build Coastguard Worker    switch (mode)
333*a67afe4dSAndroid Build Coastguard Worker    {
334*a67afe4dSAndroid Build Coastguard Worker       case PNG_ALPHA_PNG:        /* default: png standard */
335*a67afe4dSAndroid Build Coastguard Worker          /* No compose, but it may be set by png_set_background! */
336*a67afe4dSAndroid Build Coastguard Worker          png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
337*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
338*a67afe4dSAndroid Build Coastguard Worker          break;
339*a67afe4dSAndroid Build Coastguard Worker 
340*a67afe4dSAndroid Build Coastguard Worker       case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */
341*a67afe4dSAndroid Build Coastguard Worker          compose = 1;
342*a67afe4dSAndroid Build Coastguard Worker          png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
343*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
344*a67afe4dSAndroid Build Coastguard Worker          /* The output is linear: */
345*a67afe4dSAndroid Build Coastguard Worker          output_gamma = PNG_FP_1;
346*a67afe4dSAndroid Build Coastguard Worker          break;
347*a67afe4dSAndroid Build Coastguard Worker 
348*a67afe4dSAndroid Build Coastguard Worker       case PNG_ALPHA_OPTIMIZED:  /* associated, non-opaque pixels linear */
349*a67afe4dSAndroid Build Coastguard Worker          compose = 1;
350*a67afe4dSAndroid Build Coastguard Worker          png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
351*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags |= PNG_FLAG_OPTIMIZE_ALPHA;
352*a67afe4dSAndroid Build Coastguard Worker          /* output_gamma records the encoding of opaque pixels! */
353*a67afe4dSAndroid Build Coastguard Worker          break;
354*a67afe4dSAndroid Build Coastguard Worker 
355*a67afe4dSAndroid Build Coastguard Worker       case PNG_ALPHA_BROKEN:     /* associated, non-linear, alpha encoded */
356*a67afe4dSAndroid Build Coastguard Worker          compose = 1;
357*a67afe4dSAndroid Build Coastguard Worker          png_ptr->transformations |= PNG_ENCODE_ALPHA;
358*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
359*a67afe4dSAndroid Build Coastguard Worker          break;
360*a67afe4dSAndroid Build Coastguard Worker 
361*a67afe4dSAndroid Build Coastguard Worker       default:
362*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr, "invalid alpha mode");
363*a67afe4dSAndroid Build Coastguard Worker    }
364*a67afe4dSAndroid Build Coastguard Worker 
365*a67afe4dSAndroid Build Coastguard Worker    /* Only set the default gamma if the file gamma has not been set (this has
366*a67afe4dSAndroid Build Coastguard Worker     * the side effect that the gamma in a second call to png_set_alpha_mode will
367*a67afe4dSAndroid Build Coastguard Worker     * be ignored.)
368*a67afe4dSAndroid Build Coastguard Worker     */
369*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr->colorspace.gamma == 0)
370*a67afe4dSAndroid Build Coastguard Worker    {
371*a67afe4dSAndroid Build Coastguard Worker       png_ptr->colorspace.gamma = file_gamma;
372*a67afe4dSAndroid Build Coastguard Worker       png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
373*a67afe4dSAndroid Build Coastguard Worker    }
374*a67afe4dSAndroid Build Coastguard Worker 
375*a67afe4dSAndroid Build Coastguard Worker    /* But always set the output gamma: */
376*a67afe4dSAndroid Build Coastguard Worker    png_ptr->screen_gamma = output_gamma;
377*a67afe4dSAndroid Build Coastguard Worker 
378*a67afe4dSAndroid Build Coastguard Worker    /* Finally, if pre-multiplying, set the background fields to achieve the
379*a67afe4dSAndroid Build Coastguard Worker     * desired result.
380*a67afe4dSAndroid Build Coastguard Worker     */
381*a67afe4dSAndroid Build Coastguard Worker    if (compose != 0)
382*a67afe4dSAndroid Build Coastguard Worker    {
383*a67afe4dSAndroid Build Coastguard Worker       /* And obtain alpha pre-multiplication by composing on black: */
384*a67afe4dSAndroid Build Coastguard Worker       memset(&png_ptr->background, 0, (sizeof png_ptr->background));
385*a67afe4dSAndroid Build Coastguard Worker       png_ptr->background_gamma = png_ptr->colorspace.gamma; /* just in case */
386*a67afe4dSAndroid Build Coastguard Worker       png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_FILE;
387*a67afe4dSAndroid Build Coastguard Worker       png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;
388*a67afe4dSAndroid Build Coastguard Worker 
389*a67afe4dSAndroid Build Coastguard Worker       if ((png_ptr->transformations & PNG_COMPOSE) != 0)
390*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr,
391*a67afe4dSAndroid Build Coastguard Worker              "conflicting calls to set alpha mode and background");
392*a67afe4dSAndroid Build Coastguard Worker 
393*a67afe4dSAndroid Build Coastguard Worker       png_ptr->transformations |= PNG_COMPOSE;
394*a67afe4dSAndroid Build Coastguard Worker    }
395*a67afe4dSAndroid Build Coastguard Worker }
396*a67afe4dSAndroid Build Coastguard Worker 
397*a67afe4dSAndroid Build Coastguard Worker #  ifdef PNG_FLOATING_POINT_SUPPORTED
398*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_set_alpha_mode(png_structrp png_ptr,int mode,double output_gamma)399*a67afe4dSAndroid Build Coastguard Worker png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma)
400*a67afe4dSAndroid Build Coastguard Worker {
401*a67afe4dSAndroid Build Coastguard Worker    png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr,
402*a67afe4dSAndroid Build Coastguard Worker        output_gamma));
403*a67afe4dSAndroid Build Coastguard Worker }
404*a67afe4dSAndroid Build Coastguard Worker #  endif
405*a67afe4dSAndroid Build Coastguard Worker #endif
406*a67afe4dSAndroid Build Coastguard Worker 
407*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_QUANTIZE_SUPPORTED
408*a67afe4dSAndroid Build Coastguard Worker /* Dither file to 8-bit.  Supply a palette, the current number
409*a67afe4dSAndroid Build Coastguard Worker  * of elements in the palette, the maximum number of elements
410*a67afe4dSAndroid Build Coastguard Worker  * allowed, and a histogram if possible.  If the current number
411*a67afe4dSAndroid Build Coastguard Worker  * of colors is greater than the maximum number, the palette will be
412*a67afe4dSAndroid Build Coastguard Worker  * modified to fit in the maximum number.  "full_quantize" indicates
413*a67afe4dSAndroid Build Coastguard Worker  * whether we need a quantizing cube set up for RGB images, or if we
414*a67afe4dSAndroid Build Coastguard Worker  * simply are reducing the number of colors in a paletted image.
415*a67afe4dSAndroid Build Coastguard Worker  */
416*a67afe4dSAndroid Build Coastguard Worker 
417*a67afe4dSAndroid Build Coastguard Worker typedef struct png_dsort_struct
418*a67afe4dSAndroid Build Coastguard Worker {
419*a67afe4dSAndroid Build Coastguard Worker    struct png_dsort_struct * next;
420*a67afe4dSAndroid Build Coastguard Worker    png_byte left;
421*a67afe4dSAndroid Build Coastguard Worker    png_byte right;
422*a67afe4dSAndroid Build Coastguard Worker } png_dsort;
423*a67afe4dSAndroid Build Coastguard Worker typedef png_dsort *   png_dsortp;
424*a67afe4dSAndroid Build Coastguard Worker typedef png_dsort * * png_dsortpp;
425*a67afe4dSAndroid Build Coastguard Worker 
426*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_set_quantize(png_structrp png_ptr,png_colorp palette,int num_palette,int maximum_colors,png_const_uint_16p histogram,int full_quantize)427*a67afe4dSAndroid Build Coastguard Worker png_set_quantize(png_structrp png_ptr, png_colorp palette,
428*a67afe4dSAndroid Build Coastguard Worker     int num_palette, int maximum_colors, png_const_uint_16p histogram,
429*a67afe4dSAndroid Build Coastguard Worker     int full_quantize)
430*a67afe4dSAndroid Build Coastguard Worker {
431*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_set_quantize");
432*a67afe4dSAndroid Build Coastguard Worker 
433*a67afe4dSAndroid Build Coastguard Worker    if (png_rtran_ok(png_ptr, 0) == 0)
434*a67afe4dSAndroid Build Coastguard Worker       return;
435*a67afe4dSAndroid Build Coastguard Worker 
436*a67afe4dSAndroid Build Coastguard Worker    png_ptr->transformations |= PNG_QUANTIZE;
437*a67afe4dSAndroid Build Coastguard Worker 
438*a67afe4dSAndroid Build Coastguard Worker    if (full_quantize == 0)
439*a67afe4dSAndroid Build Coastguard Worker    {
440*a67afe4dSAndroid Build Coastguard Worker       int i;
441*a67afe4dSAndroid Build Coastguard Worker 
442*a67afe4dSAndroid Build Coastguard Worker       png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
443*a67afe4dSAndroid Build Coastguard Worker           (png_alloc_size_t)num_palette);
444*a67afe4dSAndroid Build Coastguard Worker       for (i = 0; i < num_palette; i++)
445*a67afe4dSAndroid Build Coastguard Worker          png_ptr->quantize_index[i] = (png_byte)i;
446*a67afe4dSAndroid Build Coastguard Worker    }
447*a67afe4dSAndroid Build Coastguard Worker 
448*a67afe4dSAndroid Build Coastguard Worker    if (num_palette > maximum_colors)
449*a67afe4dSAndroid Build Coastguard Worker    {
450*a67afe4dSAndroid Build Coastguard Worker       if (histogram != NULL)
451*a67afe4dSAndroid Build Coastguard Worker       {
452*a67afe4dSAndroid Build Coastguard Worker          /* This is easy enough, just throw out the least used colors.
453*a67afe4dSAndroid Build Coastguard Worker           * Perhaps not the best solution, but good enough.
454*a67afe4dSAndroid Build Coastguard Worker           */
455*a67afe4dSAndroid Build Coastguard Worker 
456*a67afe4dSAndroid Build Coastguard Worker          int i;
457*a67afe4dSAndroid Build Coastguard Worker 
458*a67afe4dSAndroid Build Coastguard Worker          /* Initialize an array to sort colors */
459*a67afe4dSAndroid Build Coastguard Worker          png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,
460*a67afe4dSAndroid Build Coastguard Worker              (png_alloc_size_t)num_palette);
461*a67afe4dSAndroid Build Coastguard Worker 
462*a67afe4dSAndroid Build Coastguard Worker          /* Initialize the quantize_sort array */
463*a67afe4dSAndroid Build Coastguard Worker          for (i = 0; i < num_palette; i++)
464*a67afe4dSAndroid Build Coastguard Worker             png_ptr->quantize_sort[i] = (png_byte)i;
465*a67afe4dSAndroid Build Coastguard Worker 
466*a67afe4dSAndroid Build Coastguard Worker          /* Find the least used palette entries by starting a
467*a67afe4dSAndroid Build Coastguard Worker           * bubble sort, and running it until we have sorted
468*a67afe4dSAndroid Build Coastguard Worker           * out enough colors.  Note that we don't care about
469*a67afe4dSAndroid Build Coastguard Worker           * sorting all the colors, just finding which are
470*a67afe4dSAndroid Build Coastguard Worker           * least used.
471*a67afe4dSAndroid Build Coastguard Worker           */
472*a67afe4dSAndroid Build Coastguard Worker 
473*a67afe4dSAndroid Build Coastguard Worker          for (i = num_palette - 1; i >= maximum_colors; i--)
474*a67afe4dSAndroid Build Coastguard Worker          {
475*a67afe4dSAndroid Build Coastguard Worker             int done; /* To stop early if the list is pre-sorted */
476*a67afe4dSAndroid Build Coastguard Worker             int j;
477*a67afe4dSAndroid Build Coastguard Worker 
478*a67afe4dSAndroid Build Coastguard Worker             done = 1;
479*a67afe4dSAndroid Build Coastguard Worker             for (j = 0; j < i; j++)
480*a67afe4dSAndroid Build Coastguard Worker             {
481*a67afe4dSAndroid Build Coastguard Worker                if (histogram[png_ptr->quantize_sort[j]]
482*a67afe4dSAndroid Build Coastguard Worker                    < histogram[png_ptr->quantize_sort[j + 1]])
483*a67afe4dSAndroid Build Coastguard Worker                {
484*a67afe4dSAndroid Build Coastguard Worker                   png_byte t;
485*a67afe4dSAndroid Build Coastguard Worker 
486*a67afe4dSAndroid Build Coastguard Worker                   t = png_ptr->quantize_sort[j];
487*a67afe4dSAndroid Build Coastguard Worker                   png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1];
488*a67afe4dSAndroid Build Coastguard Worker                   png_ptr->quantize_sort[j + 1] = t;
489*a67afe4dSAndroid Build Coastguard Worker                   done = 0;
490*a67afe4dSAndroid Build Coastguard Worker                }
491*a67afe4dSAndroid Build Coastguard Worker             }
492*a67afe4dSAndroid Build Coastguard Worker 
493*a67afe4dSAndroid Build Coastguard Worker             if (done != 0)
494*a67afe4dSAndroid Build Coastguard Worker                break;
495*a67afe4dSAndroid Build Coastguard Worker          }
496*a67afe4dSAndroid Build Coastguard Worker 
497*a67afe4dSAndroid Build Coastguard Worker          /* Swap the palette around, and set up a table, if necessary */
498*a67afe4dSAndroid Build Coastguard Worker          if (full_quantize != 0)
499*a67afe4dSAndroid Build Coastguard Worker          {
500*a67afe4dSAndroid Build Coastguard Worker             int j = num_palette;
501*a67afe4dSAndroid Build Coastguard Worker 
502*a67afe4dSAndroid Build Coastguard Worker             /* Put all the useful colors within the max, but don't
503*a67afe4dSAndroid Build Coastguard Worker              * move the others.
504*a67afe4dSAndroid Build Coastguard Worker              */
505*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < maximum_colors; i++)
506*a67afe4dSAndroid Build Coastguard Worker             {
507*a67afe4dSAndroid Build Coastguard Worker                if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
508*a67afe4dSAndroid Build Coastguard Worker                {
509*a67afe4dSAndroid Build Coastguard Worker                   do
510*a67afe4dSAndroid Build Coastguard Worker                      j--;
511*a67afe4dSAndroid Build Coastguard Worker                   while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
512*a67afe4dSAndroid Build Coastguard Worker 
513*a67afe4dSAndroid Build Coastguard Worker                   palette[i] = palette[j];
514*a67afe4dSAndroid Build Coastguard Worker                }
515*a67afe4dSAndroid Build Coastguard Worker             }
516*a67afe4dSAndroid Build Coastguard Worker          }
517*a67afe4dSAndroid Build Coastguard Worker          else
518*a67afe4dSAndroid Build Coastguard Worker          {
519*a67afe4dSAndroid Build Coastguard Worker             int j = num_palette;
520*a67afe4dSAndroid Build Coastguard Worker 
521*a67afe4dSAndroid Build Coastguard Worker             /* Move all the used colors inside the max limit, and
522*a67afe4dSAndroid Build Coastguard Worker              * develop a translation table.
523*a67afe4dSAndroid Build Coastguard Worker              */
524*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < maximum_colors; i++)
525*a67afe4dSAndroid Build Coastguard Worker             {
526*a67afe4dSAndroid Build Coastguard Worker                /* Only move the colors we need to */
527*a67afe4dSAndroid Build Coastguard Worker                if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
528*a67afe4dSAndroid Build Coastguard Worker                {
529*a67afe4dSAndroid Build Coastguard Worker                   png_color tmp_color;
530*a67afe4dSAndroid Build Coastguard Worker 
531*a67afe4dSAndroid Build Coastguard Worker                   do
532*a67afe4dSAndroid Build Coastguard Worker                      j--;
533*a67afe4dSAndroid Build Coastguard Worker                   while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
534*a67afe4dSAndroid Build Coastguard Worker 
535*a67afe4dSAndroid Build Coastguard Worker                   tmp_color = palette[j];
536*a67afe4dSAndroid Build Coastguard Worker                   palette[j] = palette[i];
537*a67afe4dSAndroid Build Coastguard Worker                   palette[i] = tmp_color;
538*a67afe4dSAndroid Build Coastguard Worker                   /* Indicate where the color went */
539*a67afe4dSAndroid Build Coastguard Worker                   png_ptr->quantize_index[j] = (png_byte)i;
540*a67afe4dSAndroid Build Coastguard Worker                   png_ptr->quantize_index[i] = (png_byte)j;
541*a67afe4dSAndroid Build Coastguard Worker                }
542*a67afe4dSAndroid Build Coastguard Worker             }
543*a67afe4dSAndroid Build Coastguard Worker 
544*a67afe4dSAndroid Build Coastguard Worker             /* Find closest color for those colors we are not using */
545*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < num_palette; i++)
546*a67afe4dSAndroid Build Coastguard Worker             {
547*a67afe4dSAndroid Build Coastguard Worker                if ((int)png_ptr->quantize_index[i] >= maximum_colors)
548*a67afe4dSAndroid Build Coastguard Worker                {
549*a67afe4dSAndroid Build Coastguard Worker                   int min_d, k, min_k, d_index;
550*a67afe4dSAndroid Build Coastguard Worker 
551*a67afe4dSAndroid Build Coastguard Worker                   /* Find the closest color to one we threw out */
552*a67afe4dSAndroid Build Coastguard Worker                   d_index = png_ptr->quantize_index[i];
553*a67afe4dSAndroid Build Coastguard Worker                   min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
554*a67afe4dSAndroid Build Coastguard Worker                   for (k = 1, min_k = 0; k < maximum_colors; k++)
555*a67afe4dSAndroid Build Coastguard Worker                   {
556*a67afe4dSAndroid Build Coastguard Worker                      int d;
557*a67afe4dSAndroid Build Coastguard Worker 
558*a67afe4dSAndroid Build Coastguard Worker                      d = PNG_COLOR_DIST(palette[d_index], palette[k]);
559*a67afe4dSAndroid Build Coastguard Worker 
560*a67afe4dSAndroid Build Coastguard Worker                      if (d < min_d)
561*a67afe4dSAndroid Build Coastguard Worker                      {
562*a67afe4dSAndroid Build Coastguard Worker                         min_d = d;
563*a67afe4dSAndroid Build Coastguard Worker                         min_k = k;
564*a67afe4dSAndroid Build Coastguard Worker                      }
565*a67afe4dSAndroid Build Coastguard Worker                   }
566*a67afe4dSAndroid Build Coastguard Worker                   /* Point to closest color */
567*a67afe4dSAndroid Build Coastguard Worker                   png_ptr->quantize_index[i] = (png_byte)min_k;
568*a67afe4dSAndroid Build Coastguard Worker                }
569*a67afe4dSAndroid Build Coastguard Worker             }
570*a67afe4dSAndroid Build Coastguard Worker          }
571*a67afe4dSAndroid Build Coastguard Worker          png_free(png_ptr, png_ptr->quantize_sort);
572*a67afe4dSAndroid Build Coastguard Worker          png_ptr->quantize_sort = NULL;
573*a67afe4dSAndroid Build Coastguard Worker       }
574*a67afe4dSAndroid Build Coastguard Worker       else
575*a67afe4dSAndroid Build Coastguard Worker       {
576*a67afe4dSAndroid Build Coastguard Worker          /* This is much harder to do simply (and quickly).  Perhaps
577*a67afe4dSAndroid Build Coastguard Worker           * we need to go through a median cut routine, but those
578*a67afe4dSAndroid Build Coastguard Worker           * don't always behave themselves with only a few colors
579*a67afe4dSAndroid Build Coastguard Worker           * as input.  So we will just find the closest two colors,
580*a67afe4dSAndroid Build Coastguard Worker           * and throw out one of them (chosen somewhat randomly).
581*a67afe4dSAndroid Build Coastguard Worker           * [We don't understand this at all, so if someone wants to
582*a67afe4dSAndroid Build Coastguard Worker           *  work on improving it, be our guest - AED, GRP]
583*a67afe4dSAndroid Build Coastguard Worker           */
584*a67afe4dSAndroid Build Coastguard Worker          int i;
585*a67afe4dSAndroid Build Coastguard Worker          int max_d;
586*a67afe4dSAndroid Build Coastguard Worker          int num_new_palette;
587*a67afe4dSAndroid Build Coastguard Worker          png_dsortp t;
588*a67afe4dSAndroid Build Coastguard Worker          png_dsortpp hash;
589*a67afe4dSAndroid Build Coastguard Worker 
590*a67afe4dSAndroid Build Coastguard Worker          t = NULL;
591*a67afe4dSAndroid Build Coastguard Worker 
592*a67afe4dSAndroid Build Coastguard Worker          /* Initialize palette index arrays */
593*a67afe4dSAndroid Build Coastguard Worker          png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
594*a67afe4dSAndroid Build Coastguard Worker              (png_alloc_size_t)num_palette);
595*a67afe4dSAndroid Build Coastguard Worker          png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
596*a67afe4dSAndroid Build Coastguard Worker              (png_alloc_size_t)num_palette);
597*a67afe4dSAndroid Build Coastguard Worker 
598*a67afe4dSAndroid Build Coastguard Worker          /* Initialize the sort array */
599*a67afe4dSAndroid Build Coastguard Worker          for (i = 0; i < num_palette; i++)
600*a67afe4dSAndroid Build Coastguard Worker          {
601*a67afe4dSAndroid Build Coastguard Worker             png_ptr->index_to_palette[i] = (png_byte)i;
602*a67afe4dSAndroid Build Coastguard Worker             png_ptr->palette_to_index[i] = (png_byte)i;
603*a67afe4dSAndroid Build Coastguard Worker          }
604*a67afe4dSAndroid Build Coastguard Worker 
605*a67afe4dSAndroid Build Coastguard Worker          hash = (png_dsortpp)png_calloc(png_ptr, (png_alloc_size_t)(769 *
606*a67afe4dSAndroid Build Coastguard Worker              (sizeof (png_dsortp))));
607*a67afe4dSAndroid Build Coastguard Worker 
608*a67afe4dSAndroid Build Coastguard Worker          num_new_palette = num_palette;
609*a67afe4dSAndroid Build Coastguard Worker 
610*a67afe4dSAndroid Build Coastguard Worker          /* Initial wild guess at how far apart the farthest pixel
611*a67afe4dSAndroid Build Coastguard Worker           * pair we will be eliminating will be.  Larger
612*a67afe4dSAndroid Build Coastguard Worker           * numbers mean more areas will be allocated, Smaller
613*a67afe4dSAndroid Build Coastguard Worker           * numbers run the risk of not saving enough data, and
614*a67afe4dSAndroid Build Coastguard Worker           * having to do this all over again.
615*a67afe4dSAndroid Build Coastguard Worker           *
616*a67afe4dSAndroid Build Coastguard Worker           * I have not done extensive checking on this number.
617*a67afe4dSAndroid Build Coastguard Worker           */
618*a67afe4dSAndroid Build Coastguard Worker          max_d = 96;
619*a67afe4dSAndroid Build Coastguard Worker 
620*a67afe4dSAndroid Build Coastguard Worker          while (num_new_palette > maximum_colors)
621*a67afe4dSAndroid Build Coastguard Worker          {
622*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < num_new_palette - 1; i++)
623*a67afe4dSAndroid Build Coastguard Worker             {
624*a67afe4dSAndroid Build Coastguard Worker                int j;
625*a67afe4dSAndroid Build Coastguard Worker 
626*a67afe4dSAndroid Build Coastguard Worker                for (j = i + 1; j < num_new_palette; j++)
627*a67afe4dSAndroid Build Coastguard Worker                {
628*a67afe4dSAndroid Build Coastguard Worker                   int d;
629*a67afe4dSAndroid Build Coastguard Worker 
630*a67afe4dSAndroid Build Coastguard Worker                   d = PNG_COLOR_DIST(palette[i], palette[j]);
631*a67afe4dSAndroid Build Coastguard Worker 
632*a67afe4dSAndroid Build Coastguard Worker                   if (d <= max_d)
633*a67afe4dSAndroid Build Coastguard Worker                   {
634*a67afe4dSAndroid Build Coastguard Worker 
635*a67afe4dSAndroid Build Coastguard Worker                      t = (png_dsortp)png_malloc_warn(png_ptr,
636*a67afe4dSAndroid Build Coastguard Worker                          (png_alloc_size_t)(sizeof (png_dsort)));
637*a67afe4dSAndroid Build Coastguard Worker 
638*a67afe4dSAndroid Build Coastguard Worker                      if (t == NULL)
639*a67afe4dSAndroid Build Coastguard Worker                          break;
640*a67afe4dSAndroid Build Coastguard Worker 
641*a67afe4dSAndroid Build Coastguard Worker                      t->next = hash[d];
642*a67afe4dSAndroid Build Coastguard Worker                      t->left = (png_byte)i;
643*a67afe4dSAndroid Build Coastguard Worker                      t->right = (png_byte)j;
644*a67afe4dSAndroid Build Coastguard Worker                      hash[d] = t;
645*a67afe4dSAndroid Build Coastguard Worker                   }
646*a67afe4dSAndroid Build Coastguard Worker                }
647*a67afe4dSAndroid Build Coastguard Worker                if (t == NULL)
648*a67afe4dSAndroid Build Coastguard Worker                   break;
649*a67afe4dSAndroid Build Coastguard Worker             }
650*a67afe4dSAndroid Build Coastguard Worker 
651*a67afe4dSAndroid Build Coastguard Worker             if (t != NULL)
652*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i <= max_d; i++)
653*a67afe4dSAndroid Build Coastguard Worker             {
654*a67afe4dSAndroid Build Coastguard Worker                if (hash[i] != NULL)
655*a67afe4dSAndroid Build Coastguard Worker                {
656*a67afe4dSAndroid Build Coastguard Worker                   png_dsortp p;
657*a67afe4dSAndroid Build Coastguard Worker 
658*a67afe4dSAndroid Build Coastguard Worker                   for (p = hash[i]; p; p = p->next)
659*a67afe4dSAndroid Build Coastguard Worker                   {
660*a67afe4dSAndroid Build Coastguard Worker                      if ((int)png_ptr->index_to_palette[p->left]
661*a67afe4dSAndroid Build Coastguard Worker                          < num_new_palette &&
662*a67afe4dSAndroid Build Coastguard Worker                          (int)png_ptr->index_to_palette[p->right]
663*a67afe4dSAndroid Build Coastguard Worker                          < num_new_palette)
664*a67afe4dSAndroid Build Coastguard Worker                      {
665*a67afe4dSAndroid Build Coastguard Worker                         int j, next_j;
666*a67afe4dSAndroid Build Coastguard Worker 
667*a67afe4dSAndroid Build Coastguard Worker                         if (num_new_palette & 0x01)
668*a67afe4dSAndroid Build Coastguard Worker                         {
669*a67afe4dSAndroid Build Coastguard Worker                            j = p->left;
670*a67afe4dSAndroid Build Coastguard Worker                            next_j = p->right;
671*a67afe4dSAndroid Build Coastguard Worker                         }
672*a67afe4dSAndroid Build Coastguard Worker                         else
673*a67afe4dSAndroid Build Coastguard Worker                         {
674*a67afe4dSAndroid Build Coastguard Worker                            j = p->right;
675*a67afe4dSAndroid Build Coastguard Worker                            next_j = p->left;
676*a67afe4dSAndroid Build Coastguard Worker                         }
677*a67afe4dSAndroid Build Coastguard Worker 
678*a67afe4dSAndroid Build Coastguard Worker                         num_new_palette--;
679*a67afe4dSAndroid Build Coastguard Worker                         palette[png_ptr->index_to_palette[j]]
680*a67afe4dSAndroid Build Coastguard Worker                             = palette[num_new_palette];
681*a67afe4dSAndroid Build Coastguard Worker                         if (full_quantize == 0)
682*a67afe4dSAndroid Build Coastguard Worker                         {
683*a67afe4dSAndroid Build Coastguard Worker                            int k;
684*a67afe4dSAndroid Build Coastguard Worker 
685*a67afe4dSAndroid Build Coastguard Worker                            for (k = 0; k < num_palette; k++)
686*a67afe4dSAndroid Build Coastguard Worker                            {
687*a67afe4dSAndroid Build Coastguard Worker                               if (png_ptr->quantize_index[k] ==
688*a67afe4dSAndroid Build Coastguard Worker                                   png_ptr->index_to_palette[j])
689*a67afe4dSAndroid Build Coastguard Worker                                  png_ptr->quantize_index[k] =
690*a67afe4dSAndroid Build Coastguard Worker                                      png_ptr->index_to_palette[next_j];
691*a67afe4dSAndroid Build Coastguard Worker 
692*a67afe4dSAndroid Build Coastguard Worker                               if ((int)png_ptr->quantize_index[k] ==
693*a67afe4dSAndroid Build Coastguard Worker                                   num_new_palette)
694*a67afe4dSAndroid Build Coastguard Worker                                  png_ptr->quantize_index[k] =
695*a67afe4dSAndroid Build Coastguard Worker                                      png_ptr->index_to_palette[j];
696*a67afe4dSAndroid Build Coastguard Worker                            }
697*a67afe4dSAndroid Build Coastguard Worker                         }
698*a67afe4dSAndroid Build Coastguard Worker 
699*a67afe4dSAndroid Build Coastguard Worker                         png_ptr->index_to_palette[png_ptr->palette_to_index
700*a67afe4dSAndroid Build Coastguard Worker                             [num_new_palette]] = png_ptr->index_to_palette[j];
701*a67afe4dSAndroid Build Coastguard Worker 
702*a67afe4dSAndroid Build Coastguard Worker                         png_ptr->palette_to_index[png_ptr->index_to_palette[j]]
703*a67afe4dSAndroid Build Coastguard Worker                             = png_ptr->palette_to_index[num_new_palette];
704*a67afe4dSAndroid Build Coastguard Worker 
705*a67afe4dSAndroid Build Coastguard Worker                         png_ptr->index_to_palette[j] =
706*a67afe4dSAndroid Build Coastguard Worker                             (png_byte)num_new_palette;
707*a67afe4dSAndroid Build Coastguard Worker 
708*a67afe4dSAndroid Build Coastguard Worker                         png_ptr->palette_to_index[num_new_palette] =
709*a67afe4dSAndroid Build Coastguard Worker                             (png_byte)j;
710*a67afe4dSAndroid Build Coastguard Worker                      }
711*a67afe4dSAndroid Build Coastguard Worker                      if (num_new_palette <= maximum_colors)
712*a67afe4dSAndroid Build Coastguard Worker                         break;
713*a67afe4dSAndroid Build Coastguard Worker                   }
714*a67afe4dSAndroid Build Coastguard Worker                   if (num_new_palette <= maximum_colors)
715*a67afe4dSAndroid Build Coastguard Worker                      break;
716*a67afe4dSAndroid Build Coastguard Worker                }
717*a67afe4dSAndroid Build Coastguard Worker             }
718*a67afe4dSAndroid Build Coastguard Worker 
719*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < 769; i++)
720*a67afe4dSAndroid Build Coastguard Worker             {
721*a67afe4dSAndroid Build Coastguard Worker                if (hash[i] != NULL)
722*a67afe4dSAndroid Build Coastguard Worker                {
723*a67afe4dSAndroid Build Coastguard Worker                   png_dsortp p = hash[i];
724*a67afe4dSAndroid Build Coastguard Worker                   while (p)
725*a67afe4dSAndroid Build Coastguard Worker                   {
726*a67afe4dSAndroid Build Coastguard Worker                      t = p->next;
727*a67afe4dSAndroid Build Coastguard Worker                      png_free(png_ptr, p);
728*a67afe4dSAndroid Build Coastguard Worker                      p = t;
729*a67afe4dSAndroid Build Coastguard Worker                   }
730*a67afe4dSAndroid Build Coastguard Worker                }
731*a67afe4dSAndroid Build Coastguard Worker                hash[i] = 0;
732*a67afe4dSAndroid Build Coastguard Worker             }
733*a67afe4dSAndroid Build Coastguard Worker             max_d += 96;
734*a67afe4dSAndroid Build Coastguard Worker          }
735*a67afe4dSAndroid Build Coastguard Worker          png_free(png_ptr, hash);
736*a67afe4dSAndroid Build Coastguard Worker          png_free(png_ptr, png_ptr->palette_to_index);
737*a67afe4dSAndroid Build Coastguard Worker          png_free(png_ptr, png_ptr->index_to_palette);
738*a67afe4dSAndroid Build Coastguard Worker          png_ptr->palette_to_index = NULL;
739*a67afe4dSAndroid Build Coastguard Worker          png_ptr->index_to_palette = NULL;
740*a67afe4dSAndroid Build Coastguard Worker       }
741*a67afe4dSAndroid Build Coastguard Worker       num_palette = maximum_colors;
742*a67afe4dSAndroid Build Coastguard Worker    }
743*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr->palette == NULL)
744*a67afe4dSAndroid Build Coastguard Worker    {
745*a67afe4dSAndroid Build Coastguard Worker       png_ptr->palette = palette;
746*a67afe4dSAndroid Build Coastguard Worker    }
747*a67afe4dSAndroid Build Coastguard Worker    png_ptr->num_palette = (png_uint_16)num_palette;
748*a67afe4dSAndroid Build Coastguard Worker 
749*a67afe4dSAndroid Build Coastguard Worker    if (full_quantize != 0)
750*a67afe4dSAndroid Build Coastguard Worker    {
751*a67afe4dSAndroid Build Coastguard Worker       int i;
752*a67afe4dSAndroid Build Coastguard Worker       png_bytep distance;
753*a67afe4dSAndroid Build Coastguard Worker       int total_bits = PNG_QUANTIZE_RED_BITS + PNG_QUANTIZE_GREEN_BITS +
754*a67afe4dSAndroid Build Coastguard Worker           PNG_QUANTIZE_BLUE_BITS;
755*a67afe4dSAndroid Build Coastguard Worker       int num_red = (1 << PNG_QUANTIZE_RED_BITS);
756*a67afe4dSAndroid Build Coastguard Worker       int num_green = (1 << PNG_QUANTIZE_GREEN_BITS);
757*a67afe4dSAndroid Build Coastguard Worker       int num_blue = (1 << PNG_QUANTIZE_BLUE_BITS);
758*a67afe4dSAndroid Build Coastguard Worker       size_t num_entries = ((size_t)1 << total_bits);
759*a67afe4dSAndroid Build Coastguard Worker 
760*a67afe4dSAndroid Build Coastguard Worker       png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr,
761*a67afe4dSAndroid Build Coastguard Worker           (png_alloc_size_t)(num_entries));
762*a67afe4dSAndroid Build Coastguard Worker 
763*a67afe4dSAndroid Build Coastguard Worker       distance = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)num_entries);
764*a67afe4dSAndroid Build Coastguard Worker 
765*a67afe4dSAndroid Build Coastguard Worker       memset(distance, 0xff, num_entries);
766*a67afe4dSAndroid Build Coastguard Worker 
767*a67afe4dSAndroid Build Coastguard Worker       for (i = 0; i < num_palette; i++)
768*a67afe4dSAndroid Build Coastguard Worker       {
769*a67afe4dSAndroid Build Coastguard Worker          int ir, ig, ib;
770*a67afe4dSAndroid Build Coastguard Worker          int r = (palette[i].red >> (8 - PNG_QUANTIZE_RED_BITS));
771*a67afe4dSAndroid Build Coastguard Worker          int g = (palette[i].green >> (8 - PNG_QUANTIZE_GREEN_BITS));
772*a67afe4dSAndroid Build Coastguard Worker          int b = (palette[i].blue >> (8 - PNG_QUANTIZE_BLUE_BITS));
773*a67afe4dSAndroid Build Coastguard Worker 
774*a67afe4dSAndroid Build Coastguard Worker          for (ir = 0; ir < num_red; ir++)
775*a67afe4dSAndroid Build Coastguard Worker          {
776*a67afe4dSAndroid Build Coastguard Worker             /* int dr = abs(ir - r); */
777*a67afe4dSAndroid Build Coastguard Worker             int dr = ((ir > r) ? ir - r : r - ir);
778*a67afe4dSAndroid Build Coastguard Worker             int index_r = (ir << (PNG_QUANTIZE_BLUE_BITS +
779*a67afe4dSAndroid Build Coastguard Worker                 PNG_QUANTIZE_GREEN_BITS));
780*a67afe4dSAndroid Build Coastguard Worker 
781*a67afe4dSAndroid Build Coastguard Worker             for (ig = 0; ig < num_green; ig++)
782*a67afe4dSAndroid Build Coastguard Worker             {
783*a67afe4dSAndroid Build Coastguard Worker                /* int dg = abs(ig - g); */
784*a67afe4dSAndroid Build Coastguard Worker                int dg = ((ig > g) ? ig - g : g - ig);
785*a67afe4dSAndroid Build Coastguard Worker                int dt = dr + dg;
786*a67afe4dSAndroid Build Coastguard Worker                int dm = ((dr > dg) ? dr : dg);
787*a67afe4dSAndroid Build Coastguard Worker                int index_g = index_r | (ig << PNG_QUANTIZE_BLUE_BITS);
788*a67afe4dSAndroid Build Coastguard Worker 
789*a67afe4dSAndroid Build Coastguard Worker                for (ib = 0; ib < num_blue; ib++)
790*a67afe4dSAndroid Build Coastguard Worker                {
791*a67afe4dSAndroid Build Coastguard Worker                   int d_index = index_g | ib;
792*a67afe4dSAndroid Build Coastguard Worker                   /* int db = abs(ib - b); */
793*a67afe4dSAndroid Build Coastguard Worker                   int db = ((ib > b) ? ib - b : b - ib);
794*a67afe4dSAndroid Build Coastguard Worker                   int dmax = ((dm > db) ? dm : db);
795*a67afe4dSAndroid Build Coastguard Worker                   int d = dmax + dt + db;
796*a67afe4dSAndroid Build Coastguard Worker 
797*a67afe4dSAndroid Build Coastguard Worker                   if (d < (int)distance[d_index])
798*a67afe4dSAndroid Build Coastguard Worker                   {
799*a67afe4dSAndroid Build Coastguard Worker                      distance[d_index] = (png_byte)d;
800*a67afe4dSAndroid Build Coastguard Worker                      png_ptr->palette_lookup[d_index] = (png_byte)i;
801*a67afe4dSAndroid Build Coastguard Worker                   }
802*a67afe4dSAndroid Build Coastguard Worker                }
803*a67afe4dSAndroid Build Coastguard Worker             }
804*a67afe4dSAndroid Build Coastguard Worker          }
805*a67afe4dSAndroid Build Coastguard Worker       }
806*a67afe4dSAndroid Build Coastguard Worker 
807*a67afe4dSAndroid Build Coastguard Worker       png_free(png_ptr, distance);
808*a67afe4dSAndroid Build Coastguard Worker    }
809*a67afe4dSAndroid Build Coastguard Worker }
810*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_QUANTIZE */
811*a67afe4dSAndroid Build Coastguard Worker 
812*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
813*a67afe4dSAndroid Build Coastguard Worker void PNGFAPI
png_set_gamma_fixed(png_structrp png_ptr,png_fixed_point scrn_gamma,png_fixed_point file_gamma)814*a67afe4dSAndroid Build Coastguard Worker png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma,
815*a67afe4dSAndroid Build Coastguard Worker     png_fixed_point file_gamma)
816*a67afe4dSAndroid Build Coastguard Worker {
817*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_set_gamma_fixed");
818*a67afe4dSAndroid Build Coastguard Worker 
819*a67afe4dSAndroid Build Coastguard Worker    if (png_rtran_ok(png_ptr, 0) == 0)
820*a67afe4dSAndroid Build Coastguard Worker       return;
821*a67afe4dSAndroid Build Coastguard Worker 
822*a67afe4dSAndroid Build Coastguard Worker    /* New in libpng-1.5.4 - reserve particular negative values as flags. */
823*a67afe4dSAndroid Build Coastguard Worker    scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/);
824*a67afe4dSAndroid Build Coastguard Worker    file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/);
825*a67afe4dSAndroid Build Coastguard Worker 
826*a67afe4dSAndroid Build Coastguard Worker    /* Checking the gamma values for being >0 was added in 1.5.4 along with the
827*a67afe4dSAndroid Build Coastguard Worker     * premultiplied alpha support; this actually hides an undocumented feature
828*a67afe4dSAndroid Build Coastguard Worker     * of the previous implementation which allowed gamma processing to be
829*a67afe4dSAndroid Build Coastguard Worker     * disabled in background handling.  There is no evidence (so far) that this
830*a67afe4dSAndroid Build Coastguard Worker     * was being used; however, png_set_background itself accepted and must still
831*a67afe4dSAndroid Build Coastguard Worker     * accept '0' for the gamma value it takes, because it isn't always used.
832*a67afe4dSAndroid Build Coastguard Worker     *
833*a67afe4dSAndroid Build Coastguard Worker     * Since this is an API change (albeit a very minor one that removes an
834*a67afe4dSAndroid Build Coastguard Worker     * undocumented API feature) the following checks were only enabled in
835*a67afe4dSAndroid Build Coastguard Worker     * libpng-1.6.0.
836*a67afe4dSAndroid Build Coastguard Worker     */
837*a67afe4dSAndroid Build Coastguard Worker    if (file_gamma <= 0)
838*a67afe4dSAndroid Build Coastguard Worker       png_error(png_ptr, "invalid file gamma in png_set_gamma");
839*a67afe4dSAndroid Build Coastguard Worker 
840*a67afe4dSAndroid Build Coastguard Worker    if (scrn_gamma <= 0)
841*a67afe4dSAndroid Build Coastguard Worker       png_error(png_ptr, "invalid screen gamma in png_set_gamma");
842*a67afe4dSAndroid Build Coastguard Worker 
843*a67afe4dSAndroid Build Coastguard Worker    /* Set the gamma values unconditionally - this overrides the value in the PNG
844*a67afe4dSAndroid Build Coastguard Worker     * file if a gAMA chunk was present.  png_set_alpha_mode provides a
845*a67afe4dSAndroid Build Coastguard Worker     * different, easier, way to default the file gamma.
846*a67afe4dSAndroid Build Coastguard Worker     */
847*a67afe4dSAndroid Build Coastguard Worker    png_ptr->colorspace.gamma = file_gamma;
848*a67afe4dSAndroid Build Coastguard Worker    png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
849*a67afe4dSAndroid Build Coastguard Worker    png_ptr->screen_gamma = scrn_gamma;
850*a67afe4dSAndroid Build Coastguard Worker }
851*a67afe4dSAndroid Build Coastguard Worker 
852*a67afe4dSAndroid Build Coastguard Worker #  ifdef PNG_FLOATING_POINT_SUPPORTED
853*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_set_gamma(png_structrp png_ptr,double scrn_gamma,double file_gamma)854*a67afe4dSAndroid Build Coastguard Worker png_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma)
855*a67afe4dSAndroid Build Coastguard Worker {
856*a67afe4dSAndroid Build Coastguard Worker    png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma),
857*a67afe4dSAndroid Build Coastguard Worker        convert_gamma_value(png_ptr, file_gamma));
858*a67afe4dSAndroid Build Coastguard Worker }
859*a67afe4dSAndroid Build Coastguard Worker #  endif /* FLOATING_POINT */
860*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_GAMMA */
861*a67afe4dSAndroid Build Coastguard Worker 
862*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_EXPAND_SUPPORTED
863*a67afe4dSAndroid Build Coastguard Worker /* Expand paletted images to RGB, expand grayscale images of
864*a67afe4dSAndroid Build Coastguard Worker  * less than 8-bit depth to 8-bit depth, and expand tRNS chunks
865*a67afe4dSAndroid Build Coastguard Worker  * to alpha channels.
866*a67afe4dSAndroid Build Coastguard Worker  */
867*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_set_expand(png_structrp png_ptr)868*a67afe4dSAndroid Build Coastguard Worker png_set_expand(png_structrp png_ptr)
869*a67afe4dSAndroid Build Coastguard Worker {
870*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_set_expand");
871*a67afe4dSAndroid Build Coastguard Worker 
872*a67afe4dSAndroid Build Coastguard Worker    if (png_rtran_ok(png_ptr, 0) == 0)
873*a67afe4dSAndroid Build Coastguard Worker       return;
874*a67afe4dSAndroid Build Coastguard Worker 
875*a67afe4dSAndroid Build Coastguard Worker    png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
876*a67afe4dSAndroid Build Coastguard Worker }
877*a67afe4dSAndroid Build Coastguard Worker 
878*a67afe4dSAndroid Build Coastguard Worker /* GRR 19990627:  the following three functions currently are identical
879*a67afe4dSAndroid Build Coastguard Worker  *  to png_set_expand().  However, it is entirely reasonable that someone
880*a67afe4dSAndroid Build Coastguard Worker  *  might wish to expand an indexed image to RGB but *not* expand a single,
881*a67afe4dSAndroid Build Coastguard Worker  *  fully transparent palette entry to a full alpha channel--perhaps instead
882*a67afe4dSAndroid Build Coastguard Worker  *  convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace
883*a67afe4dSAndroid Build Coastguard Worker  *  the transparent color with a particular RGB value, or drop tRNS entirely.
884*a67afe4dSAndroid Build Coastguard Worker  *  IOW, a future version of the library may make the transformations flag
885*a67afe4dSAndroid Build Coastguard Worker  *  a bit more fine-grained, with separate bits for each of these three
886*a67afe4dSAndroid Build Coastguard Worker  *  functions.
887*a67afe4dSAndroid Build Coastguard Worker  *
888*a67afe4dSAndroid Build Coastguard Worker  *  More to the point, these functions make it obvious what libpng will be
889*a67afe4dSAndroid Build Coastguard Worker  *  doing, whereas "expand" can (and does) mean any number of things.
890*a67afe4dSAndroid Build Coastguard Worker  *
891*a67afe4dSAndroid Build Coastguard Worker  *  GRP 20060307: In libpng-1.2.9, png_set_gray_1_2_4_to_8() was modified
892*a67afe4dSAndroid Build Coastguard Worker  *  to expand only the sample depth but not to expand the tRNS to alpha
893*a67afe4dSAndroid Build Coastguard Worker  *  and its name was changed to png_set_expand_gray_1_2_4_to_8().
894*a67afe4dSAndroid Build Coastguard Worker  */
895*a67afe4dSAndroid Build Coastguard Worker 
896*a67afe4dSAndroid Build Coastguard Worker /* Expand paletted images to RGB. */
897*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_set_palette_to_rgb(png_structrp png_ptr)898*a67afe4dSAndroid Build Coastguard Worker png_set_palette_to_rgb(png_structrp png_ptr)
899*a67afe4dSAndroid Build Coastguard Worker {
900*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_set_palette_to_rgb");
901*a67afe4dSAndroid Build Coastguard Worker 
902*a67afe4dSAndroid Build Coastguard Worker    if (png_rtran_ok(png_ptr, 0) == 0)
903*a67afe4dSAndroid Build Coastguard Worker       return;
904*a67afe4dSAndroid Build Coastguard Worker 
905*a67afe4dSAndroid Build Coastguard Worker    png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
906*a67afe4dSAndroid Build Coastguard Worker }
907*a67afe4dSAndroid Build Coastguard Worker 
908*a67afe4dSAndroid Build Coastguard Worker /* Expand grayscale images of less than 8-bit depth to 8 bits. */
909*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr)910*a67afe4dSAndroid Build Coastguard Worker png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr)
911*a67afe4dSAndroid Build Coastguard Worker {
912*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_set_expand_gray_1_2_4_to_8");
913*a67afe4dSAndroid Build Coastguard Worker 
914*a67afe4dSAndroid Build Coastguard Worker    if (png_rtran_ok(png_ptr, 0) == 0)
915*a67afe4dSAndroid Build Coastguard Worker       return;
916*a67afe4dSAndroid Build Coastguard Worker 
917*a67afe4dSAndroid Build Coastguard Worker    png_ptr->transformations |= PNG_EXPAND;
918*a67afe4dSAndroid Build Coastguard Worker }
919*a67afe4dSAndroid Build Coastguard Worker 
920*a67afe4dSAndroid Build Coastguard Worker /* Expand tRNS chunks to alpha channels. */
921*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_set_tRNS_to_alpha(png_structrp png_ptr)922*a67afe4dSAndroid Build Coastguard Worker png_set_tRNS_to_alpha(png_structrp png_ptr)
923*a67afe4dSAndroid Build Coastguard Worker {
924*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_set_tRNS_to_alpha");
925*a67afe4dSAndroid Build Coastguard Worker 
926*a67afe4dSAndroid Build Coastguard Worker    if (png_rtran_ok(png_ptr, 0) == 0)
927*a67afe4dSAndroid Build Coastguard Worker       return;
928*a67afe4dSAndroid Build Coastguard Worker 
929*a67afe4dSAndroid Build Coastguard Worker    png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
930*a67afe4dSAndroid Build Coastguard Worker }
931*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_EXPAND */
932*a67afe4dSAndroid Build Coastguard Worker 
933*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_EXPAND_16_SUPPORTED
934*a67afe4dSAndroid Build Coastguard Worker /* Expand to 16-bit channels, expand the tRNS chunk too (because otherwise
935*a67afe4dSAndroid Build Coastguard Worker  * it may not work correctly.)
936*a67afe4dSAndroid Build Coastguard Worker  */
937*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_set_expand_16(png_structrp png_ptr)938*a67afe4dSAndroid Build Coastguard Worker png_set_expand_16(png_structrp png_ptr)
939*a67afe4dSAndroid Build Coastguard Worker {
940*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_set_expand_16");
941*a67afe4dSAndroid Build Coastguard Worker 
942*a67afe4dSAndroid Build Coastguard Worker    if (png_rtran_ok(png_ptr, 0) == 0)
943*a67afe4dSAndroid Build Coastguard Worker       return;
944*a67afe4dSAndroid Build Coastguard Worker 
945*a67afe4dSAndroid Build Coastguard Worker    png_ptr->transformations |= (PNG_EXPAND_16 | PNG_EXPAND | PNG_EXPAND_tRNS);
946*a67afe4dSAndroid Build Coastguard Worker }
947*a67afe4dSAndroid Build Coastguard Worker #endif
948*a67afe4dSAndroid Build Coastguard Worker 
949*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
950*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_set_gray_to_rgb(png_structrp png_ptr)951*a67afe4dSAndroid Build Coastguard Worker png_set_gray_to_rgb(png_structrp png_ptr)
952*a67afe4dSAndroid Build Coastguard Worker {
953*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_set_gray_to_rgb");
954*a67afe4dSAndroid Build Coastguard Worker 
955*a67afe4dSAndroid Build Coastguard Worker    if (png_rtran_ok(png_ptr, 0) == 0)
956*a67afe4dSAndroid Build Coastguard Worker       return;
957*a67afe4dSAndroid Build Coastguard Worker 
958*a67afe4dSAndroid Build Coastguard Worker    /* Because rgb must be 8 bits or more: */
959*a67afe4dSAndroid Build Coastguard Worker    png_set_expand_gray_1_2_4_to_8(png_ptr);
960*a67afe4dSAndroid Build Coastguard Worker    png_ptr->transformations |= PNG_GRAY_TO_RGB;
961*a67afe4dSAndroid Build Coastguard Worker }
962*a67afe4dSAndroid Build Coastguard Worker #endif
963*a67afe4dSAndroid Build Coastguard Worker 
964*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
965*a67afe4dSAndroid Build Coastguard Worker void PNGFAPI
png_set_rgb_to_gray_fixed(png_structrp png_ptr,int error_action,png_fixed_point red,png_fixed_point green)966*a67afe4dSAndroid Build Coastguard Worker png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action,
967*a67afe4dSAndroid Build Coastguard Worker     png_fixed_point red, png_fixed_point green)
968*a67afe4dSAndroid Build Coastguard Worker {
969*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_set_rgb_to_gray_fixed");
970*a67afe4dSAndroid Build Coastguard Worker 
971*a67afe4dSAndroid Build Coastguard Worker    /* Need the IHDR here because of the check on color_type below. */
972*a67afe4dSAndroid Build Coastguard Worker    /* TODO: fix this */
973*a67afe4dSAndroid Build Coastguard Worker    if (png_rtran_ok(png_ptr, 1) == 0)
974*a67afe4dSAndroid Build Coastguard Worker       return;
975*a67afe4dSAndroid Build Coastguard Worker 
976*a67afe4dSAndroid Build Coastguard Worker    switch (error_action)
977*a67afe4dSAndroid Build Coastguard Worker    {
978*a67afe4dSAndroid Build Coastguard Worker       case PNG_ERROR_ACTION_NONE:
979*a67afe4dSAndroid Build Coastguard Worker          png_ptr->transformations |= PNG_RGB_TO_GRAY;
980*a67afe4dSAndroid Build Coastguard Worker          break;
981*a67afe4dSAndroid Build Coastguard Worker 
982*a67afe4dSAndroid Build Coastguard Worker       case PNG_ERROR_ACTION_WARN:
983*a67afe4dSAndroid Build Coastguard Worker          png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;
984*a67afe4dSAndroid Build Coastguard Worker          break;
985*a67afe4dSAndroid Build Coastguard Worker 
986*a67afe4dSAndroid Build Coastguard Worker       case PNG_ERROR_ACTION_ERROR:
987*a67afe4dSAndroid Build Coastguard Worker          png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;
988*a67afe4dSAndroid Build Coastguard Worker          break;
989*a67afe4dSAndroid Build Coastguard Worker 
990*a67afe4dSAndroid Build Coastguard Worker       default:
991*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr, "invalid error action to rgb_to_gray");
992*a67afe4dSAndroid Build Coastguard Worker    }
993*a67afe4dSAndroid Build Coastguard Worker 
994*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
995*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_EXPAND_SUPPORTED
996*a67afe4dSAndroid Build Coastguard Worker       png_ptr->transformations |= PNG_EXPAND;
997*a67afe4dSAndroid Build Coastguard Worker #else
998*a67afe4dSAndroid Build Coastguard Worker    {
999*a67afe4dSAndroid Build Coastguard Worker       /* Make this an error in 1.6 because otherwise the application may assume
1000*a67afe4dSAndroid Build Coastguard Worker        * that it just worked and get a memory overwrite.
1001*a67afe4dSAndroid Build Coastguard Worker        */
1002*a67afe4dSAndroid Build Coastguard Worker       png_error(png_ptr,
1003*a67afe4dSAndroid Build Coastguard Worker           "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED");
1004*a67afe4dSAndroid Build Coastguard Worker 
1005*a67afe4dSAndroid Build Coastguard Worker       /* png_ptr->transformations &= ~PNG_RGB_TO_GRAY; */
1006*a67afe4dSAndroid Build Coastguard Worker    }
1007*a67afe4dSAndroid Build Coastguard Worker #endif
1008*a67afe4dSAndroid Build Coastguard Worker    {
1009*a67afe4dSAndroid Build Coastguard Worker       if (red >= 0 && green >= 0 && red + green <= PNG_FP_1)
1010*a67afe4dSAndroid Build Coastguard Worker       {
1011*a67afe4dSAndroid Build Coastguard Worker          png_uint_16 red_int, green_int;
1012*a67afe4dSAndroid Build Coastguard Worker 
1013*a67afe4dSAndroid Build Coastguard Worker          /* NOTE: this calculation does not round, but this behavior is retained
1014*a67afe4dSAndroid Build Coastguard Worker           * for consistency; the inaccuracy is very small.  The code here always
1015*a67afe4dSAndroid Build Coastguard Worker           * overwrites the coefficients, regardless of whether they have been
1016*a67afe4dSAndroid Build Coastguard Worker           * defaulted or set already.
1017*a67afe4dSAndroid Build Coastguard Worker           */
1018*a67afe4dSAndroid Build Coastguard Worker          red_int = (png_uint_16)(((png_uint_32)red*32768)/100000);
1019*a67afe4dSAndroid Build Coastguard Worker          green_int = (png_uint_16)(((png_uint_32)green*32768)/100000);
1020*a67afe4dSAndroid Build Coastguard Worker 
1021*a67afe4dSAndroid Build Coastguard Worker          png_ptr->rgb_to_gray_red_coeff   = red_int;
1022*a67afe4dSAndroid Build Coastguard Worker          png_ptr->rgb_to_gray_green_coeff = green_int;
1023*a67afe4dSAndroid Build Coastguard Worker          png_ptr->rgb_to_gray_coefficients_set = 1;
1024*a67afe4dSAndroid Build Coastguard Worker       }
1025*a67afe4dSAndroid Build Coastguard Worker 
1026*a67afe4dSAndroid Build Coastguard Worker       else
1027*a67afe4dSAndroid Build Coastguard Worker       {
1028*a67afe4dSAndroid Build Coastguard Worker          if (red >= 0 && green >= 0)
1029*a67afe4dSAndroid Build Coastguard Worker             png_app_warning(png_ptr,
1030*a67afe4dSAndroid Build Coastguard Worker                 "ignoring out of range rgb_to_gray coefficients");
1031*a67afe4dSAndroid Build Coastguard Worker 
1032*a67afe4dSAndroid Build Coastguard Worker          /* Use the defaults, from the cHRM chunk if set, else the historical
1033*a67afe4dSAndroid Build Coastguard Worker           * values which are close to the sRGB/HDTV/ITU-Rec 709 values.  See
1034*a67afe4dSAndroid Build Coastguard Worker           * png_do_rgb_to_gray for more discussion of the values.  In this case
1035*a67afe4dSAndroid Build Coastguard Worker           * the coefficients are not marked as 'set' and are not overwritten if
1036*a67afe4dSAndroid Build Coastguard Worker           * something has already provided a default.
1037*a67afe4dSAndroid Build Coastguard Worker           */
1038*a67afe4dSAndroid Build Coastguard Worker          if (png_ptr->rgb_to_gray_red_coeff == 0 &&
1039*a67afe4dSAndroid Build Coastguard Worker              png_ptr->rgb_to_gray_green_coeff == 0)
1040*a67afe4dSAndroid Build Coastguard Worker          {
1041*a67afe4dSAndroid Build Coastguard Worker             png_ptr->rgb_to_gray_red_coeff   = 6968;
1042*a67afe4dSAndroid Build Coastguard Worker             png_ptr->rgb_to_gray_green_coeff = 23434;
1043*a67afe4dSAndroid Build Coastguard Worker             /* png_ptr->rgb_to_gray_blue_coeff  = 2366; */
1044*a67afe4dSAndroid Build Coastguard Worker          }
1045*a67afe4dSAndroid Build Coastguard Worker       }
1046*a67afe4dSAndroid Build Coastguard Worker    }
1047*a67afe4dSAndroid Build Coastguard Worker }
1048*a67afe4dSAndroid Build Coastguard Worker 
1049*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_FLOATING_POINT_SUPPORTED
1050*a67afe4dSAndroid Build Coastguard Worker /* Convert a RGB image to a grayscale of the same width.  This allows us,
1051*a67afe4dSAndroid Build Coastguard Worker  * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.
1052*a67afe4dSAndroid Build Coastguard Worker  */
1053*a67afe4dSAndroid Build Coastguard Worker 
1054*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_set_rgb_to_gray(png_structrp png_ptr,int error_action,double red,double green)1055*a67afe4dSAndroid Build Coastguard Worker png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red,
1056*a67afe4dSAndroid Build Coastguard Worker     double green)
1057*a67afe4dSAndroid Build Coastguard Worker {
1058*a67afe4dSAndroid Build Coastguard Worker    png_set_rgb_to_gray_fixed(png_ptr, error_action,
1059*a67afe4dSAndroid Build Coastguard Worker        png_fixed(png_ptr, red, "rgb to gray red coefficient"),
1060*a67afe4dSAndroid Build Coastguard Worker       png_fixed(png_ptr, green, "rgb to gray green coefficient"));
1061*a67afe4dSAndroid Build Coastguard Worker }
1062*a67afe4dSAndroid Build Coastguard Worker #endif /* FLOATING POINT */
1063*a67afe4dSAndroid Build Coastguard Worker 
1064*a67afe4dSAndroid Build Coastguard Worker #endif /* RGB_TO_GRAY */
1065*a67afe4dSAndroid Build Coastguard Worker 
1066*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
1067*a67afe4dSAndroid Build Coastguard Worker     defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
1068*a67afe4dSAndroid Build Coastguard Worker void PNGAPI
png_set_read_user_transform_fn(png_structrp png_ptr,png_user_transform_ptr read_user_transform_fn)1069*a67afe4dSAndroid Build Coastguard Worker png_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr
1070*a67afe4dSAndroid Build Coastguard Worker     read_user_transform_fn)
1071*a67afe4dSAndroid Build Coastguard Worker {
1072*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_set_read_user_transform_fn");
1073*a67afe4dSAndroid Build Coastguard Worker 
1074*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
1075*a67afe4dSAndroid Build Coastguard Worker    png_ptr->transformations |= PNG_USER_TRANSFORM;
1076*a67afe4dSAndroid Build Coastguard Worker    png_ptr->read_user_transform_fn = read_user_transform_fn;
1077*a67afe4dSAndroid Build Coastguard Worker #endif
1078*a67afe4dSAndroid Build Coastguard Worker }
1079*a67afe4dSAndroid Build Coastguard Worker #endif
1080*a67afe4dSAndroid Build Coastguard Worker 
1081*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_TRANSFORMS_SUPPORTED
1082*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
1083*a67afe4dSAndroid Build Coastguard Worker /* In the case of gamma transformations only do transformations on images where
1084*a67afe4dSAndroid Build Coastguard Worker  * the [file] gamma and screen_gamma are not close reciprocals, otherwise it
1085*a67afe4dSAndroid Build Coastguard Worker  * slows things down slightly, and also needlessly introduces small errors.
1086*a67afe4dSAndroid Build Coastguard Worker  */
1087*a67afe4dSAndroid Build Coastguard Worker static int /* PRIVATE */
png_gamma_threshold(png_fixed_point screen_gamma,png_fixed_point file_gamma)1088*a67afe4dSAndroid Build Coastguard Worker png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma)
1089*a67afe4dSAndroid Build Coastguard Worker {
1090*a67afe4dSAndroid Build Coastguard Worker    /* PNG_GAMMA_THRESHOLD is the threshold for performing gamma
1091*a67afe4dSAndroid Build Coastguard Worker     * correction as a difference of the overall transform from 1.0
1092*a67afe4dSAndroid Build Coastguard Worker     *
1093*a67afe4dSAndroid Build Coastguard Worker     * We want to compare the threshold with s*f - 1, if we get
1094*a67afe4dSAndroid Build Coastguard Worker     * overflow here it is because of wacky gamma values so we
1095*a67afe4dSAndroid Build Coastguard Worker     * turn on processing anyway.
1096*a67afe4dSAndroid Build Coastguard Worker     */
1097*a67afe4dSAndroid Build Coastguard Worker    png_fixed_point gtest;
1098*a67afe4dSAndroid Build Coastguard Worker    return !png_muldiv(&gtest, screen_gamma, file_gamma, PNG_FP_1) ||
1099*a67afe4dSAndroid Build Coastguard Worker        png_gamma_significant(gtest);
1100*a67afe4dSAndroid Build Coastguard Worker }
1101*a67afe4dSAndroid Build Coastguard Worker #endif
1102*a67afe4dSAndroid Build Coastguard Worker 
1103*a67afe4dSAndroid Build Coastguard Worker /* Initialize everything needed for the read.  This includes modifying
1104*a67afe4dSAndroid Build Coastguard Worker  * the palette.
1105*a67afe4dSAndroid Build Coastguard Worker  */
1106*a67afe4dSAndroid Build Coastguard Worker 
1107*a67afe4dSAndroid Build Coastguard Worker /* For the moment 'png_init_palette_transformations' and
1108*a67afe4dSAndroid Build Coastguard Worker  * 'png_init_rgb_transformations' only do some flag canceling optimizations.
1109*a67afe4dSAndroid Build Coastguard Worker  * The intent is that these two routines should have palette or rgb operations
1110*a67afe4dSAndroid Build Coastguard Worker  * extracted from 'png_init_read_transformations'.
1111*a67afe4dSAndroid Build Coastguard Worker  */
1112*a67afe4dSAndroid Build Coastguard Worker static void /* PRIVATE */
png_init_palette_transformations(png_structrp png_ptr)1113*a67afe4dSAndroid Build Coastguard Worker png_init_palette_transformations(png_structrp png_ptr)
1114*a67afe4dSAndroid Build Coastguard Worker {
1115*a67afe4dSAndroid Build Coastguard Worker    /* Called to handle the (input) palette case.  In png_do_read_transformations
1116*a67afe4dSAndroid Build Coastguard Worker     * the first step is to expand the palette if requested, so this code must
1117*a67afe4dSAndroid Build Coastguard Worker     * take care to only make changes that are invariant with respect to the
1118*a67afe4dSAndroid Build Coastguard Worker     * palette expansion, or only do them if there is no expansion.
1119*a67afe4dSAndroid Build Coastguard Worker     *
1120*a67afe4dSAndroid Build Coastguard Worker     * STRIP_ALPHA has already been handled in the caller (by setting num_trans
1121*a67afe4dSAndroid Build Coastguard Worker     * to 0.)
1122*a67afe4dSAndroid Build Coastguard Worker     */
1123*a67afe4dSAndroid Build Coastguard Worker    int input_has_alpha = 0;
1124*a67afe4dSAndroid Build Coastguard Worker    int input_has_transparency = 0;
1125*a67afe4dSAndroid Build Coastguard Worker 
1126*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr->num_trans > 0)
1127*a67afe4dSAndroid Build Coastguard Worker    {
1128*a67afe4dSAndroid Build Coastguard Worker       int i;
1129*a67afe4dSAndroid Build Coastguard Worker 
1130*a67afe4dSAndroid Build Coastguard Worker       /* Ignore if all the entries are opaque (unlikely!) */
1131*a67afe4dSAndroid Build Coastguard Worker       for (i=0; i<png_ptr->num_trans; ++i)
1132*a67afe4dSAndroid Build Coastguard Worker       {
1133*a67afe4dSAndroid Build Coastguard Worker          if (png_ptr->trans_alpha[i] == 255)
1134*a67afe4dSAndroid Build Coastguard Worker             continue;
1135*a67afe4dSAndroid Build Coastguard Worker          else if (png_ptr->trans_alpha[i] == 0)
1136*a67afe4dSAndroid Build Coastguard Worker             input_has_transparency = 1;
1137*a67afe4dSAndroid Build Coastguard Worker          else
1138*a67afe4dSAndroid Build Coastguard Worker          {
1139*a67afe4dSAndroid Build Coastguard Worker             input_has_transparency = 1;
1140*a67afe4dSAndroid Build Coastguard Worker             input_has_alpha = 1;
1141*a67afe4dSAndroid Build Coastguard Worker             break;
1142*a67afe4dSAndroid Build Coastguard Worker          }
1143*a67afe4dSAndroid Build Coastguard Worker       }
1144*a67afe4dSAndroid Build Coastguard Worker    }
1145*a67afe4dSAndroid Build Coastguard Worker 
1146*a67afe4dSAndroid Build Coastguard Worker    /* If no alpha we can optimize. */
1147*a67afe4dSAndroid Build Coastguard Worker    if (input_has_alpha == 0)
1148*a67afe4dSAndroid Build Coastguard Worker    {
1149*a67afe4dSAndroid Build Coastguard Worker       /* Any alpha means background and associative alpha processing is
1150*a67afe4dSAndroid Build Coastguard Worker        * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA
1151*a67afe4dSAndroid Build Coastguard Worker        * and ENCODE_ALPHA are irrelevant.
1152*a67afe4dSAndroid Build Coastguard Worker        */
1153*a67afe4dSAndroid Build Coastguard Worker       png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
1154*a67afe4dSAndroid Build Coastguard Worker       png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
1155*a67afe4dSAndroid Build Coastguard Worker 
1156*a67afe4dSAndroid Build Coastguard Worker       if (input_has_transparency == 0)
1157*a67afe4dSAndroid Build Coastguard Worker          png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);
1158*a67afe4dSAndroid Build Coastguard Worker    }
1159*a67afe4dSAndroid Build Coastguard Worker 
1160*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
1161*a67afe4dSAndroid Build Coastguard Worker    /* png_set_background handling - deals with the complexity of whether the
1162*a67afe4dSAndroid Build Coastguard Worker     * background color is in the file format or the screen format in the case
1163*a67afe4dSAndroid Build Coastguard Worker     * where an 'expand' will happen.
1164*a67afe4dSAndroid Build Coastguard Worker     */
1165*a67afe4dSAndroid Build Coastguard Worker 
1166*a67afe4dSAndroid Build Coastguard Worker    /* The following code cannot be entered in the alpha pre-multiplication case
1167*a67afe4dSAndroid Build Coastguard Worker     * because PNG_BACKGROUND_EXPAND is cancelled below.
1168*a67afe4dSAndroid Build Coastguard Worker     */
1169*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 &&
1170*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->transformations & PNG_EXPAND) != 0)
1171*a67afe4dSAndroid Build Coastguard Worker    {
1172*a67afe4dSAndroid Build Coastguard Worker       {
1173*a67afe4dSAndroid Build Coastguard Worker          png_ptr->background.red   =
1174*a67afe4dSAndroid Build Coastguard Worker              png_ptr->palette[png_ptr->background.index].red;
1175*a67afe4dSAndroid Build Coastguard Worker          png_ptr->background.green =
1176*a67afe4dSAndroid Build Coastguard Worker              png_ptr->palette[png_ptr->background.index].green;
1177*a67afe4dSAndroid Build Coastguard Worker          png_ptr->background.blue  =
1178*a67afe4dSAndroid Build Coastguard Worker              png_ptr->palette[png_ptr->background.index].blue;
1179*a67afe4dSAndroid Build Coastguard Worker 
1180*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
1181*a67afe4dSAndroid Build Coastguard Worker          if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0)
1182*a67afe4dSAndroid Build Coastguard Worker          {
1183*a67afe4dSAndroid Build Coastguard Worker             if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0)
1184*a67afe4dSAndroid Build Coastguard Worker             {
1185*a67afe4dSAndroid Build Coastguard Worker                /* Invert the alpha channel (in tRNS) unless the pixels are
1186*a67afe4dSAndroid Build Coastguard Worker                 * going to be expanded, in which case leave it for later
1187*a67afe4dSAndroid Build Coastguard Worker                 */
1188*a67afe4dSAndroid Build Coastguard Worker                int i, istop = png_ptr->num_trans;
1189*a67afe4dSAndroid Build Coastguard Worker 
1190*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < istop; i++)
1191*a67afe4dSAndroid Build Coastguard Worker                   png_ptr->trans_alpha[i] =
1192*a67afe4dSAndroid Build Coastguard Worker                       (png_byte)(255 - png_ptr->trans_alpha[i]);
1193*a67afe4dSAndroid Build Coastguard Worker             }
1194*a67afe4dSAndroid Build Coastguard Worker          }
1195*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_INVERT_ALPHA */
1196*a67afe4dSAndroid Build Coastguard Worker       }
1197*a67afe4dSAndroid Build Coastguard Worker    } /* background expand and (therefore) no alpha association. */
1198*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_EXPAND && READ_BACKGROUND */
1199*a67afe4dSAndroid Build Coastguard Worker }
1200*a67afe4dSAndroid Build Coastguard Worker 
1201*a67afe4dSAndroid Build Coastguard Worker static void /* PRIVATE */
png_init_rgb_transformations(png_structrp png_ptr)1202*a67afe4dSAndroid Build Coastguard Worker png_init_rgb_transformations(png_structrp png_ptr)
1203*a67afe4dSAndroid Build Coastguard Worker {
1204*a67afe4dSAndroid Build Coastguard Worker    /* Added to libpng-1.5.4: check the color type to determine whether there
1205*a67afe4dSAndroid Build Coastguard Worker     * is any alpha or transparency in the image and simply cancel the
1206*a67afe4dSAndroid Build Coastguard Worker     * background and alpha mode stuff if there isn't.
1207*a67afe4dSAndroid Build Coastguard Worker     */
1208*a67afe4dSAndroid Build Coastguard Worker    int input_has_alpha = (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0;
1209*a67afe4dSAndroid Build Coastguard Worker    int input_has_transparency = png_ptr->num_trans > 0;
1210*a67afe4dSAndroid Build Coastguard Worker 
1211*a67afe4dSAndroid Build Coastguard Worker    /* If no alpha we can optimize. */
1212*a67afe4dSAndroid Build Coastguard Worker    if (input_has_alpha == 0)
1213*a67afe4dSAndroid Build Coastguard Worker    {
1214*a67afe4dSAndroid Build Coastguard Worker       /* Any alpha means background and associative alpha processing is
1215*a67afe4dSAndroid Build Coastguard Worker        * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA
1216*a67afe4dSAndroid Build Coastguard Worker        * and ENCODE_ALPHA are irrelevant.
1217*a67afe4dSAndroid Build Coastguard Worker        */
1218*a67afe4dSAndroid Build Coastguard Worker #     ifdef PNG_READ_ALPHA_MODE_SUPPORTED
1219*a67afe4dSAndroid Build Coastguard Worker          png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
1220*a67afe4dSAndroid Build Coastguard Worker          png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
1221*a67afe4dSAndroid Build Coastguard Worker #     endif
1222*a67afe4dSAndroid Build Coastguard Worker 
1223*a67afe4dSAndroid Build Coastguard Worker       if (input_has_transparency == 0)
1224*a67afe4dSAndroid Build Coastguard Worker          png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);
1225*a67afe4dSAndroid Build Coastguard Worker    }
1226*a67afe4dSAndroid Build Coastguard Worker 
1227*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
1228*a67afe4dSAndroid Build Coastguard Worker    /* png_set_background handling - deals with the complexity of whether the
1229*a67afe4dSAndroid Build Coastguard Worker     * background color is in the file format or the screen format in the case
1230*a67afe4dSAndroid Build Coastguard Worker     * where an 'expand' will happen.
1231*a67afe4dSAndroid Build Coastguard Worker     */
1232*a67afe4dSAndroid Build Coastguard Worker 
1233*a67afe4dSAndroid Build Coastguard Worker    /* The following code cannot be entered in the alpha pre-multiplication case
1234*a67afe4dSAndroid Build Coastguard Worker     * because PNG_BACKGROUND_EXPAND is cancelled below.
1235*a67afe4dSAndroid Build Coastguard Worker     */
1236*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 &&
1237*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->transformations & PNG_EXPAND) != 0 &&
1238*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)
1239*a67afe4dSAndroid Build Coastguard Worker        /* i.e., GRAY or GRAY_ALPHA */
1240*a67afe4dSAndroid Build Coastguard Worker    {
1241*a67afe4dSAndroid Build Coastguard Worker       {
1242*a67afe4dSAndroid Build Coastguard Worker          /* Expand background and tRNS chunks */
1243*a67afe4dSAndroid Build Coastguard Worker          int gray = png_ptr->background.gray;
1244*a67afe4dSAndroid Build Coastguard Worker          int trans_gray = png_ptr->trans_color.gray;
1245*a67afe4dSAndroid Build Coastguard Worker 
1246*a67afe4dSAndroid Build Coastguard Worker          switch (png_ptr->bit_depth)
1247*a67afe4dSAndroid Build Coastguard Worker          {
1248*a67afe4dSAndroid Build Coastguard Worker             case 1:
1249*a67afe4dSAndroid Build Coastguard Worker                gray *= 0xff;
1250*a67afe4dSAndroid Build Coastguard Worker                trans_gray *= 0xff;
1251*a67afe4dSAndroid Build Coastguard Worker                break;
1252*a67afe4dSAndroid Build Coastguard Worker 
1253*a67afe4dSAndroid Build Coastguard Worker             case 2:
1254*a67afe4dSAndroid Build Coastguard Worker                gray *= 0x55;
1255*a67afe4dSAndroid Build Coastguard Worker                trans_gray *= 0x55;
1256*a67afe4dSAndroid Build Coastguard Worker                break;
1257*a67afe4dSAndroid Build Coastguard Worker 
1258*a67afe4dSAndroid Build Coastguard Worker             case 4:
1259*a67afe4dSAndroid Build Coastguard Worker                gray *= 0x11;
1260*a67afe4dSAndroid Build Coastguard Worker                trans_gray *= 0x11;
1261*a67afe4dSAndroid Build Coastguard Worker                break;
1262*a67afe4dSAndroid Build Coastguard Worker 
1263*a67afe4dSAndroid Build Coastguard Worker             default:
1264*a67afe4dSAndroid Build Coastguard Worker 
1265*a67afe4dSAndroid Build Coastguard Worker             case 8:
1266*a67afe4dSAndroid Build Coastguard Worker                /* FALLTHROUGH */ /*  (Already 8 bits) */
1267*a67afe4dSAndroid Build Coastguard Worker 
1268*a67afe4dSAndroid Build Coastguard Worker             case 16:
1269*a67afe4dSAndroid Build Coastguard Worker                /* Already a full 16 bits */
1270*a67afe4dSAndroid Build Coastguard Worker                break;
1271*a67afe4dSAndroid Build Coastguard Worker          }
1272*a67afe4dSAndroid Build Coastguard Worker 
1273*a67afe4dSAndroid Build Coastguard Worker          png_ptr->background.red = png_ptr->background.green =
1274*a67afe4dSAndroid Build Coastguard Worker             png_ptr->background.blue = (png_uint_16)gray;
1275*a67afe4dSAndroid Build Coastguard Worker 
1276*a67afe4dSAndroid Build Coastguard Worker          if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0)
1277*a67afe4dSAndroid Build Coastguard Worker          {
1278*a67afe4dSAndroid Build Coastguard Worker             png_ptr->trans_color.red = png_ptr->trans_color.green =
1279*a67afe4dSAndroid Build Coastguard Worker                png_ptr->trans_color.blue = (png_uint_16)trans_gray;
1280*a67afe4dSAndroid Build Coastguard Worker          }
1281*a67afe4dSAndroid Build Coastguard Worker       }
1282*a67afe4dSAndroid Build Coastguard Worker    } /* background expand and (therefore) no alpha association. */
1283*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_EXPAND && READ_BACKGROUND */
1284*a67afe4dSAndroid Build Coastguard Worker }
1285*a67afe4dSAndroid Build Coastguard Worker 
1286*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_init_read_transformations(png_structrp png_ptr)1287*a67afe4dSAndroid Build Coastguard Worker png_init_read_transformations(png_structrp png_ptr)
1288*a67afe4dSAndroid Build Coastguard Worker {
1289*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_init_read_transformations");
1290*a67afe4dSAndroid Build Coastguard Worker 
1291*a67afe4dSAndroid Build Coastguard Worker    /* This internal function is called from png_read_start_row in pngrutil.c
1292*a67afe4dSAndroid Build Coastguard Worker     * and it is called before the 'rowbytes' calculation is done, so the code
1293*a67afe4dSAndroid Build Coastguard Worker     * in here can change or update the transformations flags.
1294*a67afe4dSAndroid Build Coastguard Worker     *
1295*a67afe4dSAndroid Build Coastguard Worker     * First do updates that do not depend on the details of the PNG image data
1296*a67afe4dSAndroid Build Coastguard Worker     * being processed.
1297*a67afe4dSAndroid Build Coastguard Worker     */
1298*a67afe4dSAndroid Build Coastguard Worker 
1299*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
1300*a67afe4dSAndroid Build Coastguard Worker    /* Prior to 1.5.4 these tests were performed from png_set_gamma, 1.5.4 adds
1301*a67afe4dSAndroid Build Coastguard Worker     * png_set_alpha_mode and this is another source for a default file gamma so
1302*a67afe4dSAndroid Build Coastguard Worker     * the test needs to be performed later - here.  In addition prior to 1.5.4
1303*a67afe4dSAndroid Build Coastguard Worker     * the tests were repeated for the PALETTE color type here - this is no
1304*a67afe4dSAndroid Build Coastguard Worker     * longer necessary (and doesn't seem to have been necessary before.)
1305*a67afe4dSAndroid Build Coastguard Worker     */
1306*a67afe4dSAndroid Build Coastguard Worker    {
1307*a67afe4dSAndroid Build Coastguard Worker       /* The following temporary indicates if overall gamma correction is
1308*a67afe4dSAndroid Build Coastguard Worker        * required.
1309*a67afe4dSAndroid Build Coastguard Worker        */
1310*a67afe4dSAndroid Build Coastguard Worker       int gamma_correction = 0;
1311*a67afe4dSAndroid Build Coastguard Worker 
1312*a67afe4dSAndroid Build Coastguard Worker       if (png_ptr->colorspace.gamma != 0) /* has been set */
1313*a67afe4dSAndroid Build Coastguard Worker       {
1314*a67afe4dSAndroid Build Coastguard Worker          if (png_ptr->screen_gamma != 0) /* screen set too */
1315*a67afe4dSAndroid Build Coastguard Worker             gamma_correction = png_gamma_threshold(png_ptr->colorspace.gamma,
1316*a67afe4dSAndroid Build Coastguard Worker                 png_ptr->screen_gamma);
1317*a67afe4dSAndroid Build Coastguard Worker 
1318*a67afe4dSAndroid Build Coastguard Worker          else
1319*a67afe4dSAndroid Build Coastguard Worker             /* Assume the output matches the input; a long time default behavior
1320*a67afe4dSAndroid Build Coastguard Worker              * of libpng, although the standard has nothing to say about this.
1321*a67afe4dSAndroid Build Coastguard Worker              */
1322*a67afe4dSAndroid Build Coastguard Worker             png_ptr->screen_gamma = png_reciprocal(png_ptr->colorspace.gamma);
1323*a67afe4dSAndroid Build Coastguard Worker       }
1324*a67afe4dSAndroid Build Coastguard Worker 
1325*a67afe4dSAndroid Build Coastguard Worker       else if (png_ptr->screen_gamma != 0)
1326*a67afe4dSAndroid Build Coastguard Worker          /* The converse - assume the file matches the screen, note that this
1327*a67afe4dSAndroid Build Coastguard Worker           * perhaps undesirable default can (from 1.5.4) be changed by calling
1328*a67afe4dSAndroid Build Coastguard Worker           * png_set_alpha_mode (even if the alpha handling mode isn't required
1329*a67afe4dSAndroid Build Coastguard Worker           * or isn't changed from the default.)
1330*a67afe4dSAndroid Build Coastguard Worker           */
1331*a67afe4dSAndroid Build Coastguard Worker          png_ptr->colorspace.gamma = png_reciprocal(png_ptr->screen_gamma);
1332*a67afe4dSAndroid Build Coastguard Worker 
1333*a67afe4dSAndroid Build Coastguard Worker       else /* neither are set */
1334*a67afe4dSAndroid Build Coastguard Worker          /* Just in case the following prevents any processing - file and screen
1335*a67afe4dSAndroid Build Coastguard Worker           * are both assumed to be linear and there is no way to introduce a
1336*a67afe4dSAndroid Build Coastguard Worker           * third gamma value other than png_set_background with 'UNIQUE', and,
1337*a67afe4dSAndroid Build Coastguard Worker           * prior to 1.5.4
1338*a67afe4dSAndroid Build Coastguard Worker           */
1339*a67afe4dSAndroid Build Coastguard Worker          png_ptr->screen_gamma = png_ptr->colorspace.gamma = PNG_FP_1;
1340*a67afe4dSAndroid Build Coastguard Worker 
1341*a67afe4dSAndroid Build Coastguard Worker       /* We have a gamma value now. */
1342*a67afe4dSAndroid Build Coastguard Worker       png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
1343*a67afe4dSAndroid Build Coastguard Worker 
1344*a67afe4dSAndroid Build Coastguard Worker       /* Now turn the gamma transformation on or off as appropriate.  Notice
1345*a67afe4dSAndroid Build Coastguard Worker        * that PNG_GAMMA just refers to the file->screen correction.  Alpha
1346*a67afe4dSAndroid Build Coastguard Worker        * composition may independently cause gamma correction because it needs
1347*a67afe4dSAndroid Build Coastguard Worker        * linear data (e.g. if the file has a gAMA chunk but the screen gamma
1348*a67afe4dSAndroid Build Coastguard Worker        * hasn't been specified.)  In any case this flag may get turned off in
1349*a67afe4dSAndroid Build Coastguard Worker        * the code immediately below if the transform can be handled outside the
1350*a67afe4dSAndroid Build Coastguard Worker        * row loop.
1351*a67afe4dSAndroid Build Coastguard Worker        */
1352*a67afe4dSAndroid Build Coastguard Worker       if (gamma_correction != 0)
1353*a67afe4dSAndroid Build Coastguard Worker          png_ptr->transformations |= PNG_GAMMA;
1354*a67afe4dSAndroid Build Coastguard Worker 
1355*a67afe4dSAndroid Build Coastguard Worker       else
1356*a67afe4dSAndroid Build Coastguard Worker          png_ptr->transformations &= ~PNG_GAMMA;
1357*a67afe4dSAndroid Build Coastguard Worker    }
1358*a67afe4dSAndroid Build Coastguard Worker #endif
1359*a67afe4dSAndroid Build Coastguard Worker 
1360*a67afe4dSAndroid Build Coastguard Worker    /* Certain transformations have the effect of preventing other
1361*a67afe4dSAndroid Build Coastguard Worker     * transformations that happen afterward in png_do_read_transformations;
1362*a67afe4dSAndroid Build Coastguard Worker     * resolve the interdependencies here.  From the code of
1363*a67afe4dSAndroid Build Coastguard Worker     * png_do_read_transformations the order is:
1364*a67afe4dSAndroid Build Coastguard Worker     *
1365*a67afe4dSAndroid Build Coastguard Worker     *  1) PNG_EXPAND (including PNG_EXPAND_tRNS)
1366*a67afe4dSAndroid Build Coastguard Worker     *  2) PNG_STRIP_ALPHA (if no compose)
1367*a67afe4dSAndroid Build Coastguard Worker     *  3) PNG_RGB_TO_GRAY
1368*a67afe4dSAndroid Build Coastguard Worker     *  4) PNG_GRAY_TO_RGB iff !PNG_BACKGROUND_IS_GRAY
1369*a67afe4dSAndroid Build Coastguard Worker     *  5) PNG_COMPOSE
1370*a67afe4dSAndroid Build Coastguard Worker     *  6) PNG_GAMMA
1371*a67afe4dSAndroid Build Coastguard Worker     *  7) PNG_STRIP_ALPHA (if compose)
1372*a67afe4dSAndroid Build Coastguard Worker     *  8) PNG_ENCODE_ALPHA
1373*a67afe4dSAndroid Build Coastguard Worker     *  9) PNG_SCALE_16_TO_8
1374*a67afe4dSAndroid Build Coastguard Worker     * 10) PNG_16_TO_8
1375*a67afe4dSAndroid Build Coastguard Worker     * 11) PNG_QUANTIZE (converts to palette)
1376*a67afe4dSAndroid Build Coastguard Worker     * 12) PNG_EXPAND_16
1377*a67afe4dSAndroid Build Coastguard Worker     * 13) PNG_GRAY_TO_RGB iff PNG_BACKGROUND_IS_GRAY
1378*a67afe4dSAndroid Build Coastguard Worker     * 14) PNG_INVERT_MONO
1379*a67afe4dSAndroid Build Coastguard Worker     * 15) PNG_INVERT_ALPHA
1380*a67afe4dSAndroid Build Coastguard Worker     * 16) PNG_SHIFT
1381*a67afe4dSAndroid Build Coastguard Worker     * 17) PNG_PACK
1382*a67afe4dSAndroid Build Coastguard Worker     * 18) PNG_BGR
1383*a67afe4dSAndroid Build Coastguard Worker     * 19) PNG_PACKSWAP
1384*a67afe4dSAndroid Build Coastguard Worker     * 20) PNG_FILLER (includes PNG_ADD_ALPHA)
1385*a67afe4dSAndroid Build Coastguard Worker     * 21) PNG_SWAP_ALPHA
1386*a67afe4dSAndroid Build Coastguard Worker     * 22) PNG_SWAP_BYTES
1387*a67afe4dSAndroid Build Coastguard Worker     * 23) PNG_USER_TRANSFORM [must be last]
1388*a67afe4dSAndroid Build Coastguard Worker     */
1389*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
1390*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 &&
1391*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->transformations & PNG_COMPOSE) == 0)
1392*a67afe4dSAndroid Build Coastguard Worker    {
1393*a67afe4dSAndroid Build Coastguard Worker       /* Stripping the alpha channel happens immediately after the 'expand'
1394*a67afe4dSAndroid Build Coastguard Worker        * transformations, before all other transformation, so it cancels out
1395*a67afe4dSAndroid Build Coastguard Worker        * the alpha handling.  It has the side effect negating the effect of
1396*a67afe4dSAndroid Build Coastguard Worker        * PNG_EXPAND_tRNS too:
1397*a67afe4dSAndroid Build Coastguard Worker        */
1398*a67afe4dSAndroid Build Coastguard Worker       png_ptr->transformations &= ~(PNG_BACKGROUND_EXPAND | PNG_ENCODE_ALPHA |
1399*a67afe4dSAndroid Build Coastguard Worker          PNG_EXPAND_tRNS);
1400*a67afe4dSAndroid Build Coastguard Worker       png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
1401*a67afe4dSAndroid Build Coastguard Worker 
1402*a67afe4dSAndroid Build Coastguard Worker       /* Kill the tRNS chunk itself too.  Prior to 1.5.4 this did not happen
1403*a67afe4dSAndroid Build Coastguard Worker        * so transparency information would remain just so long as it wasn't
1404*a67afe4dSAndroid Build Coastguard Worker        * expanded.  This produces unexpected API changes if the set of things
1405*a67afe4dSAndroid Build Coastguard Worker        * that do PNG_EXPAND_tRNS changes (perfectly possible given the
1406*a67afe4dSAndroid Build Coastguard Worker        * documentation - which says ask for what you want, accept what you
1407*a67afe4dSAndroid Build Coastguard Worker        * get.)  This makes the behavior consistent from 1.5.4:
1408*a67afe4dSAndroid Build Coastguard Worker        */
1409*a67afe4dSAndroid Build Coastguard Worker       png_ptr->num_trans = 0;
1410*a67afe4dSAndroid Build Coastguard Worker    }
1411*a67afe4dSAndroid Build Coastguard Worker #endif /* STRIP_ALPHA supported, no COMPOSE */
1412*a67afe4dSAndroid Build Coastguard Worker 
1413*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_ALPHA_MODE_SUPPORTED
1414*a67afe4dSAndroid Build Coastguard Worker    /* If the screen gamma is about 1.0 then the OPTIMIZE_ALPHA and ENCODE_ALPHA
1415*a67afe4dSAndroid Build Coastguard Worker     * settings will have no effect.
1416*a67afe4dSAndroid Build Coastguard Worker     */
1417*a67afe4dSAndroid Build Coastguard Worker    if (png_gamma_significant(png_ptr->screen_gamma) == 0)
1418*a67afe4dSAndroid Build Coastguard Worker    {
1419*a67afe4dSAndroid Build Coastguard Worker       png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
1420*a67afe4dSAndroid Build Coastguard Worker       png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
1421*a67afe4dSAndroid Build Coastguard Worker    }
1422*a67afe4dSAndroid Build Coastguard Worker #endif
1423*a67afe4dSAndroid Build Coastguard Worker 
1424*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
1425*a67afe4dSAndroid Build Coastguard Worker    /* Make sure the coefficients for the rgb to gray conversion are set
1426*a67afe4dSAndroid Build Coastguard Worker     * appropriately.
1427*a67afe4dSAndroid Build Coastguard Worker     */
1428*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)
1429*a67afe4dSAndroid Build Coastguard Worker       png_colorspace_set_rgb_coefficients(png_ptr);
1430*a67afe4dSAndroid Build Coastguard Worker #endif
1431*a67afe4dSAndroid Build Coastguard Worker 
1432*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
1433*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
1434*a67afe4dSAndroid Build Coastguard Worker    /* Detect gray background and attempt to enable optimization for
1435*a67afe4dSAndroid Build Coastguard Worker     * gray --> RGB case.
1436*a67afe4dSAndroid Build Coastguard Worker     *
1437*a67afe4dSAndroid Build Coastguard Worker     * Note:  if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or
1438*a67afe4dSAndroid Build Coastguard Worker     * RGB_ALPHA (in which case need_expand is superfluous anyway), the
1439*a67afe4dSAndroid Build Coastguard Worker     * background color might actually be gray yet not be flagged as such.
1440*a67afe4dSAndroid Build Coastguard Worker     * This is not a problem for the current code, which uses
1441*a67afe4dSAndroid Build Coastguard Worker     * PNG_BACKGROUND_IS_GRAY only to decide when to do the
1442*a67afe4dSAndroid Build Coastguard Worker     * png_do_gray_to_rgb() transformation.
1443*a67afe4dSAndroid Build Coastguard Worker     *
1444*a67afe4dSAndroid Build Coastguard Worker     * TODO: this code needs to be revised to avoid the complexity and
1445*a67afe4dSAndroid Build Coastguard Worker     * interdependencies.  The color type of the background should be recorded in
1446*a67afe4dSAndroid Build Coastguard Worker     * png_set_background, along with the bit depth, then the code has a record
1447*a67afe4dSAndroid Build Coastguard Worker     * of exactly what color space the background is currently in.
1448*a67afe4dSAndroid Build Coastguard Worker     */
1449*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0)
1450*a67afe4dSAndroid Build Coastguard Worker    {
1451*a67afe4dSAndroid Build Coastguard Worker       /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if
1452*a67afe4dSAndroid Build Coastguard Worker        * the file was grayscale the background value is gray.
1453*a67afe4dSAndroid Build Coastguard Worker        */
1454*a67afe4dSAndroid Build Coastguard Worker       if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)
1455*a67afe4dSAndroid Build Coastguard Worker          png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
1456*a67afe4dSAndroid Build Coastguard Worker    }
1457*a67afe4dSAndroid Build Coastguard Worker 
1458*a67afe4dSAndroid Build Coastguard Worker    else if ((png_ptr->transformations & PNG_COMPOSE) != 0)
1459*a67afe4dSAndroid Build Coastguard Worker    {
1460*a67afe4dSAndroid Build Coastguard Worker       /* PNG_COMPOSE: png_set_background was called with need_expand false,
1461*a67afe4dSAndroid Build Coastguard Worker        * so the color is in the color space of the output or png_set_alpha_mode
1462*a67afe4dSAndroid Build Coastguard Worker        * was called and the color is black.  Ignore RGB_TO_GRAY because that
1463*a67afe4dSAndroid Build Coastguard Worker        * happens before GRAY_TO_RGB.
1464*a67afe4dSAndroid Build Coastguard Worker        */
1465*a67afe4dSAndroid Build Coastguard Worker       if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0)
1466*a67afe4dSAndroid Build Coastguard Worker       {
1467*a67afe4dSAndroid Build Coastguard Worker          if (png_ptr->background.red == png_ptr->background.green &&
1468*a67afe4dSAndroid Build Coastguard Worker              png_ptr->background.red == png_ptr->background.blue)
1469*a67afe4dSAndroid Build Coastguard Worker          {
1470*a67afe4dSAndroid Build Coastguard Worker             png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
1471*a67afe4dSAndroid Build Coastguard Worker             png_ptr->background.gray = png_ptr->background.red;
1472*a67afe4dSAndroid Build Coastguard Worker          }
1473*a67afe4dSAndroid Build Coastguard Worker       }
1474*a67afe4dSAndroid Build Coastguard Worker    }
1475*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_EXPAND && READ_BACKGROUND */
1476*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_GRAY_TO_RGB */
1477*a67afe4dSAndroid Build Coastguard Worker 
1478*a67afe4dSAndroid Build Coastguard Worker    /* For indexed PNG data (PNG_COLOR_TYPE_PALETTE) many of the transformations
1479*a67afe4dSAndroid Build Coastguard Worker     * can be performed directly on the palette, and some (such as rgb to gray)
1480*a67afe4dSAndroid Build Coastguard Worker     * can be optimized inside the palette.  This is particularly true of the
1481*a67afe4dSAndroid Build Coastguard Worker     * composite (background and alpha) stuff, which can be pretty much all done
1482*a67afe4dSAndroid Build Coastguard Worker     * in the palette even if the result is expanded to RGB or gray afterward.
1483*a67afe4dSAndroid Build Coastguard Worker     *
1484*a67afe4dSAndroid Build Coastguard Worker     * NOTE: this is Not Yet Implemented, the code behaves as in 1.5.1 and
1485*a67afe4dSAndroid Build Coastguard Worker     * earlier and the palette stuff is actually handled on the first row.  This
1486*a67afe4dSAndroid Build Coastguard Worker     * leads to the reported bug that the palette returned by png_get_PLTE is not
1487*a67afe4dSAndroid Build Coastguard Worker     * updated.
1488*a67afe4dSAndroid Build Coastguard Worker     */
1489*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1490*a67afe4dSAndroid Build Coastguard Worker       png_init_palette_transformations(png_ptr);
1491*a67afe4dSAndroid Build Coastguard Worker 
1492*a67afe4dSAndroid Build Coastguard Worker    else
1493*a67afe4dSAndroid Build Coastguard Worker       png_init_rgb_transformations(png_ptr);
1494*a67afe4dSAndroid Build Coastguard Worker 
1495*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
1496*a67afe4dSAndroid Build Coastguard Worker    defined(PNG_READ_EXPAND_16_SUPPORTED)
1497*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_EXPAND_16) != 0 &&
1498*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->transformations & PNG_COMPOSE) != 0 &&
1499*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 &&
1500*a67afe4dSAndroid Build Coastguard Worker        png_ptr->bit_depth != 16)
1501*a67afe4dSAndroid Build Coastguard Worker    {
1502*a67afe4dSAndroid Build Coastguard Worker       /* TODO: fix this.  Because the expand_16 operation is after the compose
1503*a67afe4dSAndroid Build Coastguard Worker        * handling the background color must be 8, not 16, bits deep, but the
1504*a67afe4dSAndroid Build Coastguard Worker        * application will supply a 16-bit value so reduce it here.
1505*a67afe4dSAndroid Build Coastguard Worker        *
1506*a67afe4dSAndroid Build Coastguard Worker        * The PNG_BACKGROUND_EXPAND code above does not expand to 16 bits at
1507*a67afe4dSAndroid Build Coastguard Worker        * present, so that case is ok (until do_expand_16 is moved.)
1508*a67afe4dSAndroid Build Coastguard Worker        *
1509*a67afe4dSAndroid Build Coastguard Worker        * NOTE: this discards the low 16 bits of the user supplied background
1510*a67afe4dSAndroid Build Coastguard Worker        * color, but until expand_16 works properly there is no choice!
1511*a67afe4dSAndroid Build Coastguard Worker        */
1512*a67afe4dSAndroid Build Coastguard Worker #     define CHOP(x) (x)=((png_uint_16)PNG_DIV257(x))
1513*a67afe4dSAndroid Build Coastguard Worker       CHOP(png_ptr->background.red);
1514*a67afe4dSAndroid Build Coastguard Worker       CHOP(png_ptr->background.green);
1515*a67afe4dSAndroid Build Coastguard Worker       CHOP(png_ptr->background.blue);
1516*a67afe4dSAndroid Build Coastguard Worker       CHOP(png_ptr->background.gray);
1517*a67afe4dSAndroid Build Coastguard Worker #     undef CHOP
1518*a67afe4dSAndroid Build Coastguard Worker    }
1519*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_BACKGROUND && READ_EXPAND_16 */
1520*a67afe4dSAndroid Build Coastguard Worker 
1521*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
1522*a67afe4dSAndroid Build Coastguard Worker    (defined(PNG_READ_SCALE_16_TO_8_SUPPORTED) || \
1523*a67afe4dSAndroid Build Coastguard Worker    defined(PNG_READ_STRIP_16_TO_8_SUPPORTED))
1524*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & (PNG_16_TO_8|PNG_SCALE_16_TO_8)) != 0 &&
1525*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->transformations & PNG_COMPOSE) != 0 &&
1526*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 &&
1527*a67afe4dSAndroid Build Coastguard Worker        png_ptr->bit_depth == 16)
1528*a67afe4dSAndroid Build Coastguard Worker    {
1529*a67afe4dSAndroid Build Coastguard Worker       /* On the other hand, if a 16-bit file is to be reduced to 8-bits per
1530*a67afe4dSAndroid Build Coastguard Worker        * component this will also happen after PNG_COMPOSE and so the background
1531*a67afe4dSAndroid Build Coastguard Worker        * color must be pre-expanded here.
1532*a67afe4dSAndroid Build Coastguard Worker        *
1533*a67afe4dSAndroid Build Coastguard Worker        * TODO: fix this too.
1534*a67afe4dSAndroid Build Coastguard Worker        */
1535*a67afe4dSAndroid Build Coastguard Worker       png_ptr->background.red = (png_uint_16)(png_ptr->background.red * 257);
1536*a67afe4dSAndroid Build Coastguard Worker       png_ptr->background.green =
1537*a67afe4dSAndroid Build Coastguard Worker          (png_uint_16)(png_ptr->background.green * 257);
1538*a67afe4dSAndroid Build Coastguard Worker       png_ptr->background.blue = (png_uint_16)(png_ptr->background.blue * 257);
1539*a67afe4dSAndroid Build Coastguard Worker       png_ptr->background.gray = (png_uint_16)(png_ptr->background.gray * 257);
1540*a67afe4dSAndroid Build Coastguard Worker    }
1541*a67afe4dSAndroid Build Coastguard Worker #endif
1542*a67afe4dSAndroid Build Coastguard Worker 
1543*a67afe4dSAndroid Build Coastguard Worker    /* NOTE: below 'PNG_READ_ALPHA_MODE_SUPPORTED' is presumed to also enable the
1544*a67afe4dSAndroid Build Coastguard Worker     * background support (see the comments in scripts/pnglibconf.dfa), this
1545*a67afe4dSAndroid Build Coastguard Worker     * allows pre-multiplication of the alpha channel to be implemented as
1546*a67afe4dSAndroid Build Coastguard Worker     * compositing on black.  This is probably sub-optimal and has been done in
1547*a67afe4dSAndroid Build Coastguard Worker     * 1.5.4 betas simply to enable external critique and testing (i.e. to
1548*a67afe4dSAndroid Build Coastguard Worker     * implement the new API quickly, without lots of internal changes.)
1549*a67afe4dSAndroid Build Coastguard Worker     */
1550*a67afe4dSAndroid Build Coastguard Worker 
1551*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
1552*a67afe4dSAndroid Build Coastguard Worker #  ifdef PNG_READ_BACKGROUND_SUPPORTED
1553*a67afe4dSAndroid Build Coastguard Worker       /* Includes ALPHA_MODE */
1554*a67afe4dSAndroid Build Coastguard Worker       png_ptr->background_1 = png_ptr->background;
1555*a67afe4dSAndroid Build Coastguard Worker #  endif
1556*a67afe4dSAndroid Build Coastguard Worker 
1557*a67afe4dSAndroid Build Coastguard Worker    /* This needs to change - in the palette image case a whole set of tables are
1558*a67afe4dSAndroid Build Coastguard Worker     * built when it would be quicker to just calculate the correct value for
1559*a67afe4dSAndroid Build Coastguard Worker     * each palette entry directly.  Also, the test is too tricky - why check
1560*a67afe4dSAndroid Build Coastguard Worker     * PNG_RGB_TO_GRAY if PNG_GAMMA is not set?  The answer seems to be that
1561*a67afe4dSAndroid Build Coastguard Worker     * PNG_GAMMA is cancelled even if the gamma is known?  The test excludes the
1562*a67afe4dSAndroid Build Coastguard Worker     * PNG_COMPOSE case, so apparently if there is no *overall* gamma correction
1563*a67afe4dSAndroid Build Coastguard Worker     * the gamma tables will not be built even if composition is required on a
1564*a67afe4dSAndroid Build Coastguard Worker     * gamma encoded value.
1565*a67afe4dSAndroid Build Coastguard Worker     *
1566*a67afe4dSAndroid Build Coastguard Worker     * In 1.5.4 this is addressed below by an additional check on the individual
1567*a67afe4dSAndroid Build Coastguard Worker     * file gamma - if it is not 1.0 both RGB_TO_GRAY and COMPOSE need the
1568*a67afe4dSAndroid Build Coastguard Worker     * tables.
1569*a67afe4dSAndroid Build Coastguard Worker     */
1570*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_GAMMA) != 0 ||
1571*a67afe4dSAndroid Build Coastguard Worker        ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0 &&
1572*a67afe4dSAndroid Build Coastguard Worker         (png_gamma_significant(png_ptr->colorspace.gamma) != 0 ||
1573*a67afe4dSAndroid Build Coastguard Worker          png_gamma_significant(png_ptr->screen_gamma) != 0)) ||
1574*a67afe4dSAndroid Build Coastguard Worker         ((png_ptr->transformations & PNG_COMPOSE) != 0 &&
1575*a67afe4dSAndroid Build Coastguard Worker          (png_gamma_significant(png_ptr->colorspace.gamma) != 0 ||
1576*a67afe4dSAndroid Build Coastguard Worker           png_gamma_significant(png_ptr->screen_gamma) != 0
1577*a67afe4dSAndroid Build Coastguard Worker #  ifdef PNG_READ_BACKGROUND_SUPPORTED
1578*a67afe4dSAndroid Build Coastguard Worker          || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE &&
1579*a67afe4dSAndroid Build Coastguard Worker            png_gamma_significant(png_ptr->background_gamma) != 0)
1580*a67afe4dSAndroid Build Coastguard Worker #  endif
1581*a67afe4dSAndroid Build Coastguard Worker         )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 &&
1582*a67afe4dSAndroid Build Coastguard Worker        png_gamma_significant(png_ptr->screen_gamma) != 0))
1583*a67afe4dSAndroid Build Coastguard Worker    {
1584*a67afe4dSAndroid Build Coastguard Worker       png_build_gamma_table(png_ptr, png_ptr->bit_depth);
1585*a67afe4dSAndroid Build Coastguard Worker 
1586*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_BACKGROUND_SUPPORTED
1587*a67afe4dSAndroid Build Coastguard Worker       if ((png_ptr->transformations & PNG_COMPOSE) != 0)
1588*a67afe4dSAndroid Build Coastguard Worker       {
1589*a67afe4dSAndroid Build Coastguard Worker          /* Issue a warning about this combination: because RGB_TO_GRAY is
1590*a67afe4dSAndroid Build Coastguard Worker           * optimized to do the gamma transform if present yet do_background has
1591*a67afe4dSAndroid Build Coastguard Worker           * to do the same thing if both options are set a
1592*a67afe4dSAndroid Build Coastguard Worker           * double-gamma-correction happens.  This is true in all versions of
1593*a67afe4dSAndroid Build Coastguard Worker           * libpng to date.
1594*a67afe4dSAndroid Build Coastguard Worker           */
1595*a67afe4dSAndroid Build Coastguard Worker          if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)
1596*a67afe4dSAndroid Build Coastguard Worker             png_warning(png_ptr,
1597*a67afe4dSAndroid Build Coastguard Worker                 "libpng does not support gamma+background+rgb_to_gray");
1598*a67afe4dSAndroid Build Coastguard Worker 
1599*a67afe4dSAndroid Build Coastguard Worker          if ((png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) != 0)
1600*a67afe4dSAndroid Build Coastguard Worker          {
1601*a67afe4dSAndroid Build Coastguard Worker             /* We don't get to here unless there is a tRNS chunk with non-opaque
1602*a67afe4dSAndroid Build Coastguard Worker              * entries - see the checking code at the start of this function.
1603*a67afe4dSAndroid Build Coastguard Worker              */
1604*a67afe4dSAndroid Build Coastguard Worker             png_color back, back_1;
1605*a67afe4dSAndroid Build Coastguard Worker             png_colorp palette = png_ptr->palette;
1606*a67afe4dSAndroid Build Coastguard Worker             int num_palette = png_ptr->num_palette;
1607*a67afe4dSAndroid Build Coastguard Worker             int i;
1608*a67afe4dSAndroid Build Coastguard Worker             if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
1609*a67afe4dSAndroid Build Coastguard Worker             {
1610*a67afe4dSAndroid Build Coastguard Worker 
1611*a67afe4dSAndroid Build Coastguard Worker                back.red = png_ptr->gamma_table[png_ptr->background.red];
1612*a67afe4dSAndroid Build Coastguard Worker                back.green = png_ptr->gamma_table[png_ptr->background.green];
1613*a67afe4dSAndroid Build Coastguard Worker                back.blue = png_ptr->gamma_table[png_ptr->background.blue];
1614*a67afe4dSAndroid Build Coastguard Worker 
1615*a67afe4dSAndroid Build Coastguard Worker                back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
1616*a67afe4dSAndroid Build Coastguard Worker                back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
1617*a67afe4dSAndroid Build Coastguard Worker                back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
1618*a67afe4dSAndroid Build Coastguard Worker             }
1619*a67afe4dSAndroid Build Coastguard Worker             else
1620*a67afe4dSAndroid Build Coastguard Worker             {
1621*a67afe4dSAndroid Build Coastguard Worker                png_fixed_point g, gs;
1622*a67afe4dSAndroid Build Coastguard Worker 
1623*a67afe4dSAndroid Build Coastguard Worker                switch (png_ptr->background_gamma_type)
1624*a67afe4dSAndroid Build Coastguard Worker                {
1625*a67afe4dSAndroid Build Coastguard Worker                   case PNG_BACKGROUND_GAMMA_SCREEN:
1626*a67afe4dSAndroid Build Coastguard Worker                      g = (png_ptr->screen_gamma);
1627*a67afe4dSAndroid Build Coastguard Worker                      gs = PNG_FP_1;
1628*a67afe4dSAndroid Build Coastguard Worker                      break;
1629*a67afe4dSAndroid Build Coastguard Worker 
1630*a67afe4dSAndroid Build Coastguard Worker                   case PNG_BACKGROUND_GAMMA_FILE:
1631*a67afe4dSAndroid Build Coastguard Worker                      g = png_reciprocal(png_ptr->colorspace.gamma);
1632*a67afe4dSAndroid Build Coastguard Worker                      gs = png_reciprocal2(png_ptr->colorspace.gamma,
1633*a67afe4dSAndroid Build Coastguard Worker                          png_ptr->screen_gamma);
1634*a67afe4dSAndroid Build Coastguard Worker                      break;
1635*a67afe4dSAndroid Build Coastguard Worker 
1636*a67afe4dSAndroid Build Coastguard Worker                   case PNG_BACKGROUND_GAMMA_UNIQUE:
1637*a67afe4dSAndroid Build Coastguard Worker                      g = png_reciprocal(png_ptr->background_gamma);
1638*a67afe4dSAndroid Build Coastguard Worker                      gs = png_reciprocal2(png_ptr->background_gamma,
1639*a67afe4dSAndroid Build Coastguard Worker                          png_ptr->screen_gamma);
1640*a67afe4dSAndroid Build Coastguard Worker                      break;
1641*a67afe4dSAndroid Build Coastguard Worker                   default:
1642*a67afe4dSAndroid Build Coastguard Worker                      g = PNG_FP_1;    /* back_1 */
1643*a67afe4dSAndroid Build Coastguard Worker                      gs = PNG_FP_1;   /* back */
1644*a67afe4dSAndroid Build Coastguard Worker                      break;
1645*a67afe4dSAndroid Build Coastguard Worker                }
1646*a67afe4dSAndroid Build Coastguard Worker 
1647*a67afe4dSAndroid Build Coastguard Worker                if (png_gamma_significant(gs) != 0)
1648*a67afe4dSAndroid Build Coastguard Worker                {
1649*a67afe4dSAndroid Build Coastguard Worker                   back.red = png_gamma_8bit_correct(png_ptr->background.red,
1650*a67afe4dSAndroid Build Coastguard Worker                       gs);
1651*a67afe4dSAndroid Build Coastguard Worker                   back.green = png_gamma_8bit_correct(png_ptr->background.green,
1652*a67afe4dSAndroid Build Coastguard Worker                       gs);
1653*a67afe4dSAndroid Build Coastguard Worker                   back.blue = png_gamma_8bit_correct(png_ptr->background.blue,
1654*a67afe4dSAndroid Build Coastguard Worker                       gs);
1655*a67afe4dSAndroid Build Coastguard Worker                }
1656*a67afe4dSAndroid Build Coastguard Worker 
1657*a67afe4dSAndroid Build Coastguard Worker                else
1658*a67afe4dSAndroid Build Coastguard Worker                {
1659*a67afe4dSAndroid Build Coastguard Worker                   back.red   = (png_byte)png_ptr->background.red;
1660*a67afe4dSAndroid Build Coastguard Worker                   back.green = (png_byte)png_ptr->background.green;
1661*a67afe4dSAndroid Build Coastguard Worker                   back.blue  = (png_byte)png_ptr->background.blue;
1662*a67afe4dSAndroid Build Coastguard Worker                }
1663*a67afe4dSAndroid Build Coastguard Worker 
1664*a67afe4dSAndroid Build Coastguard Worker                if (png_gamma_significant(g) != 0)
1665*a67afe4dSAndroid Build Coastguard Worker                {
1666*a67afe4dSAndroid Build Coastguard Worker                   back_1.red = png_gamma_8bit_correct(png_ptr->background.red,
1667*a67afe4dSAndroid Build Coastguard Worker                       g);
1668*a67afe4dSAndroid Build Coastguard Worker                   back_1.green = png_gamma_8bit_correct(
1669*a67afe4dSAndroid Build Coastguard Worker                       png_ptr->background.green, g);
1670*a67afe4dSAndroid Build Coastguard Worker                   back_1.blue = png_gamma_8bit_correct(png_ptr->background.blue,
1671*a67afe4dSAndroid Build Coastguard Worker                       g);
1672*a67afe4dSAndroid Build Coastguard Worker                }
1673*a67afe4dSAndroid Build Coastguard Worker 
1674*a67afe4dSAndroid Build Coastguard Worker                else
1675*a67afe4dSAndroid Build Coastguard Worker                {
1676*a67afe4dSAndroid Build Coastguard Worker                   back_1.red   = (png_byte)png_ptr->background.red;
1677*a67afe4dSAndroid Build Coastguard Worker                   back_1.green = (png_byte)png_ptr->background.green;
1678*a67afe4dSAndroid Build Coastguard Worker                   back_1.blue  = (png_byte)png_ptr->background.blue;
1679*a67afe4dSAndroid Build Coastguard Worker                }
1680*a67afe4dSAndroid Build Coastguard Worker             }
1681*a67afe4dSAndroid Build Coastguard Worker 
1682*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < num_palette; i++)
1683*a67afe4dSAndroid Build Coastguard Worker             {
1684*a67afe4dSAndroid Build Coastguard Worker                if (i < (int)png_ptr->num_trans &&
1685*a67afe4dSAndroid Build Coastguard Worker                    png_ptr->trans_alpha[i] != 0xff)
1686*a67afe4dSAndroid Build Coastguard Worker                {
1687*a67afe4dSAndroid Build Coastguard Worker                   if (png_ptr->trans_alpha[i] == 0)
1688*a67afe4dSAndroid Build Coastguard Worker                   {
1689*a67afe4dSAndroid Build Coastguard Worker                      palette[i] = back;
1690*a67afe4dSAndroid Build Coastguard Worker                   }
1691*a67afe4dSAndroid Build Coastguard Worker                   else /* if (png_ptr->trans_alpha[i] != 0xff) */
1692*a67afe4dSAndroid Build Coastguard Worker                   {
1693*a67afe4dSAndroid Build Coastguard Worker                      png_byte v, w;
1694*a67afe4dSAndroid Build Coastguard Worker 
1695*a67afe4dSAndroid Build Coastguard Worker                      v = png_ptr->gamma_to_1[palette[i].red];
1696*a67afe4dSAndroid Build Coastguard Worker                      png_composite(w, v, png_ptr->trans_alpha[i], back_1.red);
1697*a67afe4dSAndroid Build Coastguard Worker                      palette[i].red = png_ptr->gamma_from_1[w];
1698*a67afe4dSAndroid Build Coastguard Worker 
1699*a67afe4dSAndroid Build Coastguard Worker                      v = png_ptr->gamma_to_1[palette[i].green];
1700*a67afe4dSAndroid Build Coastguard Worker                      png_composite(w, v, png_ptr->trans_alpha[i], back_1.green);
1701*a67afe4dSAndroid Build Coastguard Worker                      palette[i].green = png_ptr->gamma_from_1[w];
1702*a67afe4dSAndroid Build Coastguard Worker 
1703*a67afe4dSAndroid Build Coastguard Worker                      v = png_ptr->gamma_to_1[palette[i].blue];
1704*a67afe4dSAndroid Build Coastguard Worker                      png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue);
1705*a67afe4dSAndroid Build Coastguard Worker                      palette[i].blue = png_ptr->gamma_from_1[w];
1706*a67afe4dSAndroid Build Coastguard Worker                   }
1707*a67afe4dSAndroid Build Coastguard Worker                }
1708*a67afe4dSAndroid Build Coastguard Worker                else
1709*a67afe4dSAndroid Build Coastguard Worker                {
1710*a67afe4dSAndroid Build Coastguard Worker                   palette[i].red = png_ptr->gamma_table[palette[i].red];
1711*a67afe4dSAndroid Build Coastguard Worker                   palette[i].green = png_ptr->gamma_table[palette[i].green];
1712*a67afe4dSAndroid Build Coastguard Worker                   palette[i].blue = png_ptr->gamma_table[palette[i].blue];
1713*a67afe4dSAndroid Build Coastguard Worker                }
1714*a67afe4dSAndroid Build Coastguard Worker             }
1715*a67afe4dSAndroid Build Coastguard Worker 
1716*a67afe4dSAndroid Build Coastguard Worker             /* Prevent the transformations being done again.
1717*a67afe4dSAndroid Build Coastguard Worker              *
1718*a67afe4dSAndroid Build Coastguard Worker              * NOTE: this is highly dubious; it removes the transformations in
1719*a67afe4dSAndroid Build Coastguard Worker              * place.  This seems inconsistent with the general treatment of the
1720*a67afe4dSAndroid Build Coastguard Worker              * transformations elsewhere.
1721*a67afe4dSAndroid Build Coastguard Worker              */
1722*a67afe4dSAndroid Build Coastguard Worker             png_ptr->transformations &= ~(PNG_COMPOSE | PNG_GAMMA);
1723*a67afe4dSAndroid Build Coastguard Worker          } /* color_type == PNG_COLOR_TYPE_PALETTE */
1724*a67afe4dSAndroid Build Coastguard Worker 
1725*a67afe4dSAndroid Build Coastguard Worker          /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */
1726*a67afe4dSAndroid Build Coastguard Worker          else /* color_type != PNG_COLOR_TYPE_PALETTE */
1727*a67afe4dSAndroid Build Coastguard Worker          {
1728*a67afe4dSAndroid Build Coastguard Worker             int gs_sig, g_sig;
1729*a67afe4dSAndroid Build Coastguard Worker             png_fixed_point g = PNG_FP_1;  /* Correction to linear */
1730*a67afe4dSAndroid Build Coastguard Worker             png_fixed_point gs = PNG_FP_1; /* Correction to screen */
1731*a67afe4dSAndroid Build Coastguard Worker 
1732*a67afe4dSAndroid Build Coastguard Worker             switch (png_ptr->background_gamma_type)
1733*a67afe4dSAndroid Build Coastguard Worker             {
1734*a67afe4dSAndroid Build Coastguard Worker                case PNG_BACKGROUND_GAMMA_SCREEN:
1735*a67afe4dSAndroid Build Coastguard Worker                   g = png_ptr->screen_gamma;
1736*a67afe4dSAndroid Build Coastguard Worker                   /* gs = PNG_FP_1; */
1737*a67afe4dSAndroid Build Coastguard Worker                   break;
1738*a67afe4dSAndroid Build Coastguard Worker 
1739*a67afe4dSAndroid Build Coastguard Worker                case PNG_BACKGROUND_GAMMA_FILE:
1740*a67afe4dSAndroid Build Coastguard Worker                   g = png_reciprocal(png_ptr->colorspace.gamma);
1741*a67afe4dSAndroid Build Coastguard Worker                   gs = png_reciprocal2(png_ptr->colorspace.gamma,
1742*a67afe4dSAndroid Build Coastguard Worker                       png_ptr->screen_gamma);
1743*a67afe4dSAndroid Build Coastguard Worker                   break;
1744*a67afe4dSAndroid Build Coastguard Worker 
1745*a67afe4dSAndroid Build Coastguard Worker                case PNG_BACKGROUND_GAMMA_UNIQUE:
1746*a67afe4dSAndroid Build Coastguard Worker                   g = png_reciprocal(png_ptr->background_gamma);
1747*a67afe4dSAndroid Build Coastguard Worker                   gs = png_reciprocal2(png_ptr->background_gamma,
1748*a67afe4dSAndroid Build Coastguard Worker                       png_ptr->screen_gamma);
1749*a67afe4dSAndroid Build Coastguard Worker                   break;
1750*a67afe4dSAndroid Build Coastguard Worker 
1751*a67afe4dSAndroid Build Coastguard Worker                default:
1752*a67afe4dSAndroid Build Coastguard Worker                   png_error(png_ptr, "invalid background gamma type");
1753*a67afe4dSAndroid Build Coastguard Worker             }
1754*a67afe4dSAndroid Build Coastguard Worker 
1755*a67afe4dSAndroid Build Coastguard Worker             g_sig = png_gamma_significant(g);
1756*a67afe4dSAndroid Build Coastguard Worker             gs_sig = png_gamma_significant(gs);
1757*a67afe4dSAndroid Build Coastguard Worker 
1758*a67afe4dSAndroid Build Coastguard Worker             if (g_sig != 0)
1759*a67afe4dSAndroid Build Coastguard Worker                png_ptr->background_1.gray = png_gamma_correct(png_ptr,
1760*a67afe4dSAndroid Build Coastguard Worker                    png_ptr->background.gray, g);
1761*a67afe4dSAndroid Build Coastguard Worker 
1762*a67afe4dSAndroid Build Coastguard Worker             if (gs_sig != 0)
1763*a67afe4dSAndroid Build Coastguard Worker                png_ptr->background.gray = png_gamma_correct(png_ptr,
1764*a67afe4dSAndroid Build Coastguard Worker                    png_ptr->background.gray, gs);
1765*a67afe4dSAndroid Build Coastguard Worker 
1766*a67afe4dSAndroid Build Coastguard Worker             if ((png_ptr->background.red != png_ptr->background.green) ||
1767*a67afe4dSAndroid Build Coastguard Worker                 (png_ptr->background.red != png_ptr->background.blue) ||
1768*a67afe4dSAndroid Build Coastguard Worker                 (png_ptr->background.red != png_ptr->background.gray))
1769*a67afe4dSAndroid Build Coastguard Worker             {
1770*a67afe4dSAndroid Build Coastguard Worker                /* RGB or RGBA with color background */
1771*a67afe4dSAndroid Build Coastguard Worker                if (g_sig != 0)
1772*a67afe4dSAndroid Build Coastguard Worker                {
1773*a67afe4dSAndroid Build Coastguard Worker                   png_ptr->background_1.red = png_gamma_correct(png_ptr,
1774*a67afe4dSAndroid Build Coastguard Worker                       png_ptr->background.red, g);
1775*a67afe4dSAndroid Build Coastguard Worker 
1776*a67afe4dSAndroid Build Coastguard Worker                   png_ptr->background_1.green = png_gamma_correct(png_ptr,
1777*a67afe4dSAndroid Build Coastguard Worker                       png_ptr->background.green, g);
1778*a67afe4dSAndroid Build Coastguard Worker 
1779*a67afe4dSAndroid Build Coastguard Worker                   png_ptr->background_1.blue = png_gamma_correct(png_ptr,
1780*a67afe4dSAndroid Build Coastguard Worker                       png_ptr->background.blue, g);
1781*a67afe4dSAndroid Build Coastguard Worker                }
1782*a67afe4dSAndroid Build Coastguard Worker 
1783*a67afe4dSAndroid Build Coastguard Worker                if (gs_sig != 0)
1784*a67afe4dSAndroid Build Coastguard Worker                {
1785*a67afe4dSAndroid Build Coastguard Worker                   png_ptr->background.red = png_gamma_correct(png_ptr,
1786*a67afe4dSAndroid Build Coastguard Worker                       png_ptr->background.red, gs);
1787*a67afe4dSAndroid Build Coastguard Worker 
1788*a67afe4dSAndroid Build Coastguard Worker                   png_ptr->background.green = png_gamma_correct(png_ptr,
1789*a67afe4dSAndroid Build Coastguard Worker                       png_ptr->background.green, gs);
1790*a67afe4dSAndroid Build Coastguard Worker 
1791*a67afe4dSAndroid Build Coastguard Worker                   png_ptr->background.blue = png_gamma_correct(png_ptr,
1792*a67afe4dSAndroid Build Coastguard Worker                       png_ptr->background.blue, gs);
1793*a67afe4dSAndroid Build Coastguard Worker                }
1794*a67afe4dSAndroid Build Coastguard Worker             }
1795*a67afe4dSAndroid Build Coastguard Worker 
1796*a67afe4dSAndroid Build Coastguard Worker             else
1797*a67afe4dSAndroid Build Coastguard Worker             {
1798*a67afe4dSAndroid Build Coastguard Worker                /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */
1799*a67afe4dSAndroid Build Coastguard Worker                png_ptr->background_1.red = png_ptr->background_1.green
1800*a67afe4dSAndroid Build Coastguard Worker                    = png_ptr->background_1.blue = png_ptr->background_1.gray;
1801*a67afe4dSAndroid Build Coastguard Worker 
1802*a67afe4dSAndroid Build Coastguard Worker                png_ptr->background.red = png_ptr->background.green
1803*a67afe4dSAndroid Build Coastguard Worker                    = png_ptr->background.blue = png_ptr->background.gray;
1804*a67afe4dSAndroid Build Coastguard Worker             }
1805*a67afe4dSAndroid Build Coastguard Worker 
1806*a67afe4dSAndroid Build Coastguard Worker             /* The background is now in screen gamma: */
1807*a67afe4dSAndroid Build Coastguard Worker             png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_SCREEN;
1808*a67afe4dSAndroid Build Coastguard Worker          } /* color_type != PNG_COLOR_TYPE_PALETTE */
1809*a67afe4dSAndroid Build Coastguard Worker       }/* png_ptr->transformations & PNG_BACKGROUND */
1810*a67afe4dSAndroid Build Coastguard Worker 
1811*a67afe4dSAndroid Build Coastguard Worker       else
1812*a67afe4dSAndroid Build Coastguard Worker       /* Transformation does not include PNG_BACKGROUND */
1813*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_BACKGROUND */
1814*a67afe4dSAndroid Build Coastguard Worker       if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE
1815*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
1816*a67afe4dSAndroid Build Coastguard Worker          /* RGB_TO_GRAY needs to have non-gamma-corrected values! */
1817*a67afe4dSAndroid Build Coastguard Worker          && ((png_ptr->transformations & PNG_EXPAND) == 0 ||
1818*a67afe4dSAndroid Build Coastguard Worker          (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0)
1819*a67afe4dSAndroid Build Coastguard Worker #endif
1820*a67afe4dSAndroid Build Coastguard Worker          )
1821*a67afe4dSAndroid Build Coastguard Worker       {
1822*a67afe4dSAndroid Build Coastguard Worker          png_colorp palette = png_ptr->palette;
1823*a67afe4dSAndroid Build Coastguard Worker          int num_palette = png_ptr->num_palette;
1824*a67afe4dSAndroid Build Coastguard Worker          int i;
1825*a67afe4dSAndroid Build Coastguard Worker 
1826*a67afe4dSAndroid Build Coastguard Worker          /* NOTE: there are other transformations that should probably be in
1827*a67afe4dSAndroid Build Coastguard Worker           * here too.
1828*a67afe4dSAndroid Build Coastguard Worker           */
1829*a67afe4dSAndroid Build Coastguard Worker          for (i = 0; i < num_palette; i++)
1830*a67afe4dSAndroid Build Coastguard Worker          {
1831*a67afe4dSAndroid Build Coastguard Worker             palette[i].red = png_ptr->gamma_table[palette[i].red];
1832*a67afe4dSAndroid Build Coastguard Worker             palette[i].green = png_ptr->gamma_table[palette[i].green];
1833*a67afe4dSAndroid Build Coastguard Worker             palette[i].blue = png_ptr->gamma_table[palette[i].blue];
1834*a67afe4dSAndroid Build Coastguard Worker          }
1835*a67afe4dSAndroid Build Coastguard Worker 
1836*a67afe4dSAndroid Build Coastguard Worker          /* Done the gamma correction. */
1837*a67afe4dSAndroid Build Coastguard Worker          png_ptr->transformations &= ~PNG_GAMMA;
1838*a67afe4dSAndroid Build Coastguard Worker       } /* color_type == PALETTE && !PNG_BACKGROUND transformation */
1839*a67afe4dSAndroid Build Coastguard Worker    }
1840*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_BACKGROUND_SUPPORTED
1841*a67afe4dSAndroid Build Coastguard Worker    else
1842*a67afe4dSAndroid Build Coastguard Worker #endif
1843*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_GAMMA */
1844*a67afe4dSAndroid Build Coastguard Worker 
1845*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_BACKGROUND_SUPPORTED
1846*a67afe4dSAndroid Build Coastguard Worker    /* No GAMMA transformation (see the hanging else 4 lines above) */
1847*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_COMPOSE) != 0 &&
1848*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
1849*a67afe4dSAndroid Build Coastguard Worker    {
1850*a67afe4dSAndroid Build Coastguard Worker       int i;
1851*a67afe4dSAndroid Build Coastguard Worker       int istop = (int)png_ptr->num_trans;
1852*a67afe4dSAndroid Build Coastguard Worker       png_color back;
1853*a67afe4dSAndroid Build Coastguard Worker       png_colorp palette = png_ptr->palette;
1854*a67afe4dSAndroid Build Coastguard Worker 
1855*a67afe4dSAndroid Build Coastguard Worker       back.red   = (png_byte)png_ptr->background.red;
1856*a67afe4dSAndroid Build Coastguard Worker       back.green = (png_byte)png_ptr->background.green;
1857*a67afe4dSAndroid Build Coastguard Worker       back.blue  = (png_byte)png_ptr->background.blue;
1858*a67afe4dSAndroid Build Coastguard Worker 
1859*a67afe4dSAndroid Build Coastguard Worker       for (i = 0; i < istop; i++)
1860*a67afe4dSAndroid Build Coastguard Worker       {
1861*a67afe4dSAndroid Build Coastguard Worker          if (png_ptr->trans_alpha[i] == 0)
1862*a67afe4dSAndroid Build Coastguard Worker          {
1863*a67afe4dSAndroid Build Coastguard Worker             palette[i] = back;
1864*a67afe4dSAndroid Build Coastguard Worker          }
1865*a67afe4dSAndroid Build Coastguard Worker 
1866*a67afe4dSAndroid Build Coastguard Worker          else if (png_ptr->trans_alpha[i] != 0xff)
1867*a67afe4dSAndroid Build Coastguard Worker          {
1868*a67afe4dSAndroid Build Coastguard Worker             /* The png_composite() macro is defined in png.h */
1869*a67afe4dSAndroid Build Coastguard Worker             png_composite(palette[i].red, palette[i].red,
1870*a67afe4dSAndroid Build Coastguard Worker                 png_ptr->trans_alpha[i], back.red);
1871*a67afe4dSAndroid Build Coastguard Worker 
1872*a67afe4dSAndroid Build Coastguard Worker             png_composite(palette[i].green, palette[i].green,
1873*a67afe4dSAndroid Build Coastguard Worker                 png_ptr->trans_alpha[i], back.green);
1874*a67afe4dSAndroid Build Coastguard Worker 
1875*a67afe4dSAndroid Build Coastguard Worker             png_composite(palette[i].blue, palette[i].blue,
1876*a67afe4dSAndroid Build Coastguard Worker                 png_ptr->trans_alpha[i], back.blue);
1877*a67afe4dSAndroid Build Coastguard Worker          }
1878*a67afe4dSAndroid Build Coastguard Worker       }
1879*a67afe4dSAndroid Build Coastguard Worker 
1880*a67afe4dSAndroid Build Coastguard Worker       png_ptr->transformations &= ~PNG_COMPOSE;
1881*a67afe4dSAndroid Build Coastguard Worker    }
1882*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_BACKGROUND */
1883*a67afe4dSAndroid Build Coastguard Worker 
1884*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_SHIFT_SUPPORTED
1885*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_SHIFT) != 0 &&
1886*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->transformations & PNG_EXPAND) == 0 &&
1887*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
1888*a67afe4dSAndroid Build Coastguard Worker    {
1889*a67afe4dSAndroid Build Coastguard Worker       int i;
1890*a67afe4dSAndroid Build Coastguard Worker       int istop = png_ptr->num_palette;
1891*a67afe4dSAndroid Build Coastguard Worker       int shift = 8 - png_ptr->sig_bit.red;
1892*a67afe4dSAndroid Build Coastguard Worker 
1893*a67afe4dSAndroid Build Coastguard Worker       png_ptr->transformations &= ~PNG_SHIFT;
1894*a67afe4dSAndroid Build Coastguard Worker 
1895*a67afe4dSAndroid Build Coastguard Worker       /* significant bits can be in the range 1 to 7 for a meaningful result, if
1896*a67afe4dSAndroid Build Coastguard Worker        * the number of significant bits is 0 then no shift is done (this is an
1897*a67afe4dSAndroid Build Coastguard Worker        * error condition which is silently ignored.)
1898*a67afe4dSAndroid Build Coastguard Worker        */
1899*a67afe4dSAndroid Build Coastguard Worker       if (shift > 0 && shift < 8)
1900*a67afe4dSAndroid Build Coastguard Worker          for (i=0; i<istop; ++i)
1901*a67afe4dSAndroid Build Coastguard Worker          {
1902*a67afe4dSAndroid Build Coastguard Worker             int component = png_ptr->palette[i].red;
1903*a67afe4dSAndroid Build Coastguard Worker 
1904*a67afe4dSAndroid Build Coastguard Worker             component >>= shift;
1905*a67afe4dSAndroid Build Coastguard Worker             png_ptr->palette[i].red = (png_byte)component;
1906*a67afe4dSAndroid Build Coastguard Worker          }
1907*a67afe4dSAndroid Build Coastguard Worker 
1908*a67afe4dSAndroid Build Coastguard Worker       shift = 8 - png_ptr->sig_bit.green;
1909*a67afe4dSAndroid Build Coastguard Worker       if (shift > 0 && shift < 8)
1910*a67afe4dSAndroid Build Coastguard Worker          for (i=0; i<istop; ++i)
1911*a67afe4dSAndroid Build Coastguard Worker          {
1912*a67afe4dSAndroid Build Coastguard Worker             int component = png_ptr->palette[i].green;
1913*a67afe4dSAndroid Build Coastguard Worker 
1914*a67afe4dSAndroid Build Coastguard Worker             component >>= shift;
1915*a67afe4dSAndroid Build Coastguard Worker             png_ptr->palette[i].green = (png_byte)component;
1916*a67afe4dSAndroid Build Coastguard Worker          }
1917*a67afe4dSAndroid Build Coastguard Worker 
1918*a67afe4dSAndroid Build Coastguard Worker       shift = 8 - png_ptr->sig_bit.blue;
1919*a67afe4dSAndroid Build Coastguard Worker       if (shift > 0 && shift < 8)
1920*a67afe4dSAndroid Build Coastguard Worker          for (i=0; i<istop; ++i)
1921*a67afe4dSAndroid Build Coastguard Worker          {
1922*a67afe4dSAndroid Build Coastguard Worker             int component = png_ptr->palette[i].blue;
1923*a67afe4dSAndroid Build Coastguard Worker 
1924*a67afe4dSAndroid Build Coastguard Worker             component >>= shift;
1925*a67afe4dSAndroid Build Coastguard Worker             png_ptr->palette[i].blue = (png_byte)component;
1926*a67afe4dSAndroid Build Coastguard Worker          }
1927*a67afe4dSAndroid Build Coastguard Worker    }
1928*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_SHIFT */
1929*a67afe4dSAndroid Build Coastguard Worker }
1930*a67afe4dSAndroid Build Coastguard Worker 
1931*a67afe4dSAndroid Build Coastguard Worker /* Modify the info structure to reflect the transformations.  The
1932*a67afe4dSAndroid Build Coastguard Worker  * info should be updated so a PNG file could be written with it,
1933*a67afe4dSAndroid Build Coastguard Worker  * assuming the transformations result in valid PNG data.
1934*a67afe4dSAndroid Build Coastguard Worker  */
1935*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_read_transform_info(png_structrp png_ptr,png_inforp info_ptr)1936*a67afe4dSAndroid Build Coastguard Worker png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr)
1937*a67afe4dSAndroid Build Coastguard Worker {
1938*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_read_transform_info");
1939*a67afe4dSAndroid Build Coastguard Worker 
1940*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_EXPAND_SUPPORTED
1941*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_EXPAND) != 0)
1942*a67afe4dSAndroid Build Coastguard Worker    {
1943*a67afe4dSAndroid Build Coastguard Worker       if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1944*a67afe4dSAndroid Build Coastguard Worker       {
1945*a67afe4dSAndroid Build Coastguard Worker          /* This check must match what actually happens in
1946*a67afe4dSAndroid Build Coastguard Worker           * png_do_expand_palette; if it ever checks the tRNS chunk to see if
1947*a67afe4dSAndroid Build Coastguard Worker           * it is all opaque we must do the same (at present it does not.)
1948*a67afe4dSAndroid Build Coastguard Worker           */
1949*a67afe4dSAndroid Build Coastguard Worker          if (png_ptr->num_trans > 0)
1950*a67afe4dSAndroid Build Coastguard Worker             info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
1951*a67afe4dSAndroid Build Coastguard Worker 
1952*a67afe4dSAndroid Build Coastguard Worker          else
1953*a67afe4dSAndroid Build Coastguard Worker             info_ptr->color_type = PNG_COLOR_TYPE_RGB;
1954*a67afe4dSAndroid Build Coastguard Worker 
1955*a67afe4dSAndroid Build Coastguard Worker          info_ptr->bit_depth = 8;
1956*a67afe4dSAndroid Build Coastguard Worker          info_ptr->num_trans = 0;
1957*a67afe4dSAndroid Build Coastguard Worker 
1958*a67afe4dSAndroid Build Coastguard Worker          if (png_ptr->palette == NULL)
1959*a67afe4dSAndroid Build Coastguard Worker             png_error (png_ptr, "Palette is NULL in indexed image");
1960*a67afe4dSAndroid Build Coastguard Worker       }
1961*a67afe4dSAndroid Build Coastguard Worker       else
1962*a67afe4dSAndroid Build Coastguard Worker       {
1963*a67afe4dSAndroid Build Coastguard Worker          if (png_ptr->num_trans != 0)
1964*a67afe4dSAndroid Build Coastguard Worker          {
1965*a67afe4dSAndroid Build Coastguard Worker             if ((png_ptr->transformations & PNG_EXPAND_tRNS) != 0)
1966*a67afe4dSAndroid Build Coastguard Worker                info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
1967*a67afe4dSAndroid Build Coastguard Worker          }
1968*a67afe4dSAndroid Build Coastguard Worker          if (info_ptr->bit_depth < 8)
1969*a67afe4dSAndroid Build Coastguard Worker             info_ptr->bit_depth = 8;
1970*a67afe4dSAndroid Build Coastguard Worker 
1971*a67afe4dSAndroid Build Coastguard Worker          info_ptr->num_trans = 0;
1972*a67afe4dSAndroid Build Coastguard Worker       }
1973*a67afe4dSAndroid Build Coastguard Worker    }
1974*a67afe4dSAndroid Build Coastguard Worker #endif
1975*a67afe4dSAndroid Build Coastguard Worker 
1976*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
1977*a67afe4dSAndroid Build Coastguard Worker    defined(PNG_READ_ALPHA_MODE_SUPPORTED)
1978*a67afe4dSAndroid Build Coastguard Worker    /* The following is almost certainly wrong unless the background value is in
1979*a67afe4dSAndroid Build Coastguard Worker     * the screen space!
1980*a67afe4dSAndroid Build Coastguard Worker     */
1981*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_COMPOSE) != 0)
1982*a67afe4dSAndroid Build Coastguard Worker       info_ptr->background = png_ptr->background;
1983*a67afe4dSAndroid Build Coastguard Worker #endif
1984*a67afe4dSAndroid Build Coastguard Worker 
1985*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
1986*a67afe4dSAndroid Build Coastguard Worker    /* The following used to be conditional on PNG_GAMMA (prior to 1.5.4),
1987*a67afe4dSAndroid Build Coastguard Worker     * however it seems that the code in png_init_read_transformations, which has
1988*a67afe4dSAndroid Build Coastguard Worker     * been called before this from png_read_update_info->png_read_start_row
1989*a67afe4dSAndroid Build Coastguard Worker     * sometimes does the gamma transform and cancels the flag.
1990*a67afe4dSAndroid Build Coastguard Worker     *
1991*a67afe4dSAndroid Build Coastguard Worker     * TODO: this looks wrong; the info_ptr should end up with a gamma equal to
1992*a67afe4dSAndroid Build Coastguard Worker     * the screen_gamma value.  The following probably results in weirdness if
1993*a67afe4dSAndroid Build Coastguard Worker     * the info_ptr is used by the app after the rows have been read.
1994*a67afe4dSAndroid Build Coastguard Worker     */
1995*a67afe4dSAndroid Build Coastguard Worker    info_ptr->colorspace.gamma = png_ptr->colorspace.gamma;
1996*a67afe4dSAndroid Build Coastguard Worker #endif
1997*a67afe4dSAndroid Build Coastguard Worker 
1998*a67afe4dSAndroid Build Coastguard Worker    if (info_ptr->bit_depth == 16)
1999*a67afe4dSAndroid Build Coastguard Worker    {
2000*a67afe4dSAndroid Build Coastguard Worker #  ifdef PNG_READ_16BIT_SUPPORTED
2001*a67afe4dSAndroid Build Coastguard Worker #     ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
2002*a67afe4dSAndroid Build Coastguard Worker          if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0)
2003*a67afe4dSAndroid Build Coastguard Worker             info_ptr->bit_depth = 8;
2004*a67afe4dSAndroid Build Coastguard Worker #     endif
2005*a67afe4dSAndroid Build Coastguard Worker 
2006*a67afe4dSAndroid Build Coastguard Worker #     ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
2007*a67afe4dSAndroid Build Coastguard Worker          if ((png_ptr->transformations & PNG_16_TO_8) != 0)
2008*a67afe4dSAndroid Build Coastguard Worker             info_ptr->bit_depth = 8;
2009*a67afe4dSAndroid Build Coastguard Worker #     endif
2010*a67afe4dSAndroid Build Coastguard Worker 
2011*a67afe4dSAndroid Build Coastguard Worker #  else
2012*a67afe4dSAndroid Build Coastguard Worker       /* No 16-bit support: force chopping 16-bit input down to 8, in this case
2013*a67afe4dSAndroid Build Coastguard Worker        * the app program can chose if both APIs are available by setting the
2014*a67afe4dSAndroid Build Coastguard Worker        * correct scaling to use.
2015*a67afe4dSAndroid Build Coastguard Worker        */
2016*a67afe4dSAndroid Build Coastguard Worker #     ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
2017*a67afe4dSAndroid Build Coastguard Worker          /* For compatibility with previous versions use the strip method by
2018*a67afe4dSAndroid Build Coastguard Worker           * default.  This code works because if PNG_SCALE_16_TO_8 is already
2019*a67afe4dSAndroid Build Coastguard Worker           * set the code below will do that in preference to the chop.
2020*a67afe4dSAndroid Build Coastguard Worker           */
2021*a67afe4dSAndroid Build Coastguard Worker          png_ptr->transformations |= PNG_16_TO_8;
2022*a67afe4dSAndroid Build Coastguard Worker          info_ptr->bit_depth = 8;
2023*a67afe4dSAndroid Build Coastguard Worker #     else
2024*a67afe4dSAndroid Build Coastguard Worker 
2025*a67afe4dSAndroid Build Coastguard Worker #        ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
2026*a67afe4dSAndroid Build Coastguard Worker             png_ptr->transformations |= PNG_SCALE_16_TO_8;
2027*a67afe4dSAndroid Build Coastguard Worker             info_ptr->bit_depth = 8;
2028*a67afe4dSAndroid Build Coastguard Worker #        else
2029*a67afe4dSAndroid Build Coastguard Worker 
2030*a67afe4dSAndroid Build Coastguard Worker             CONFIGURATION ERROR: you must enable at least one 16 to 8 method
2031*a67afe4dSAndroid Build Coastguard Worker #        endif
2032*a67afe4dSAndroid Build Coastguard Worker #    endif
2033*a67afe4dSAndroid Build Coastguard Worker #endif /* !READ_16BIT */
2034*a67afe4dSAndroid Build Coastguard Worker    }
2035*a67afe4dSAndroid Build Coastguard Worker 
2036*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
2037*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0)
2038*a67afe4dSAndroid Build Coastguard Worker       info_ptr->color_type = (png_byte)(info_ptr->color_type |
2039*a67afe4dSAndroid Build Coastguard Worker          PNG_COLOR_MASK_COLOR);
2040*a67afe4dSAndroid Build Coastguard Worker #endif
2041*a67afe4dSAndroid Build Coastguard Worker 
2042*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
2043*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)
2044*a67afe4dSAndroid Build Coastguard Worker       info_ptr->color_type = (png_byte)(info_ptr->color_type &
2045*a67afe4dSAndroid Build Coastguard Worker          ~PNG_COLOR_MASK_COLOR);
2046*a67afe4dSAndroid Build Coastguard Worker #endif
2047*a67afe4dSAndroid Build Coastguard Worker 
2048*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_QUANTIZE_SUPPORTED
2049*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_QUANTIZE) != 0)
2050*a67afe4dSAndroid Build Coastguard Worker    {
2051*a67afe4dSAndroid Build Coastguard Worker       if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
2052*a67afe4dSAndroid Build Coastguard Worker           (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
2053*a67afe4dSAndroid Build Coastguard Worker           png_ptr->palette_lookup != 0 && info_ptr->bit_depth == 8)
2054*a67afe4dSAndroid Build Coastguard Worker       {
2055*a67afe4dSAndroid Build Coastguard Worker          info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
2056*a67afe4dSAndroid Build Coastguard Worker       }
2057*a67afe4dSAndroid Build Coastguard Worker    }
2058*a67afe4dSAndroid Build Coastguard Worker #endif
2059*a67afe4dSAndroid Build Coastguard Worker 
2060*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_EXPAND_16_SUPPORTED
2061*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_EXPAND_16) != 0 &&
2062*a67afe4dSAndroid Build Coastguard Worker        info_ptr->bit_depth == 8 &&
2063*a67afe4dSAndroid Build Coastguard Worker        info_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
2064*a67afe4dSAndroid Build Coastguard Worker    {
2065*a67afe4dSAndroid Build Coastguard Worker       info_ptr->bit_depth = 16;
2066*a67afe4dSAndroid Build Coastguard Worker    }
2067*a67afe4dSAndroid Build Coastguard Worker #endif
2068*a67afe4dSAndroid Build Coastguard Worker 
2069*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_PACK_SUPPORTED
2070*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_PACK) != 0 &&
2071*a67afe4dSAndroid Build Coastguard Worker        (info_ptr->bit_depth < 8))
2072*a67afe4dSAndroid Build Coastguard Worker       info_ptr->bit_depth = 8;
2073*a67afe4dSAndroid Build Coastguard Worker #endif
2074*a67afe4dSAndroid Build Coastguard Worker 
2075*a67afe4dSAndroid Build Coastguard Worker    if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2076*a67afe4dSAndroid Build Coastguard Worker       info_ptr->channels = 1;
2077*a67afe4dSAndroid Build Coastguard Worker 
2078*a67afe4dSAndroid Build Coastguard Worker    else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
2079*a67afe4dSAndroid Build Coastguard Worker       info_ptr->channels = 3;
2080*a67afe4dSAndroid Build Coastguard Worker 
2081*a67afe4dSAndroid Build Coastguard Worker    else
2082*a67afe4dSAndroid Build Coastguard Worker       info_ptr->channels = 1;
2083*a67afe4dSAndroid Build Coastguard Worker 
2084*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
2085*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0)
2086*a67afe4dSAndroid Build Coastguard Worker    {
2087*a67afe4dSAndroid Build Coastguard Worker       info_ptr->color_type = (png_byte)(info_ptr->color_type &
2088*a67afe4dSAndroid Build Coastguard Worker          ~PNG_COLOR_MASK_ALPHA);
2089*a67afe4dSAndroid Build Coastguard Worker       info_ptr->num_trans = 0;
2090*a67afe4dSAndroid Build Coastguard Worker    }
2091*a67afe4dSAndroid Build Coastguard Worker #endif
2092*a67afe4dSAndroid Build Coastguard Worker 
2093*a67afe4dSAndroid Build Coastguard Worker    if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)
2094*a67afe4dSAndroid Build Coastguard Worker       info_ptr->channels++;
2095*a67afe4dSAndroid Build Coastguard Worker 
2096*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_FILLER_SUPPORTED
2097*a67afe4dSAndroid Build Coastguard Worker    /* STRIP_ALPHA and FILLER allowed:  MASK_ALPHA bit stripped above */
2098*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_FILLER) != 0 &&
2099*a67afe4dSAndroid Build Coastguard Worker        (info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
2100*a67afe4dSAndroid Build Coastguard Worker        info_ptr->color_type == PNG_COLOR_TYPE_GRAY))
2101*a67afe4dSAndroid Build Coastguard Worker    {
2102*a67afe4dSAndroid Build Coastguard Worker       info_ptr->channels++;
2103*a67afe4dSAndroid Build Coastguard Worker       /* If adding a true alpha channel not just filler */
2104*a67afe4dSAndroid Build Coastguard Worker       if ((png_ptr->transformations & PNG_ADD_ALPHA) != 0)
2105*a67afe4dSAndroid Build Coastguard Worker          info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
2106*a67afe4dSAndroid Build Coastguard Worker    }
2107*a67afe4dSAndroid Build Coastguard Worker #endif
2108*a67afe4dSAndroid Build Coastguard Worker 
2109*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \
2110*a67afe4dSAndroid Build Coastguard Worker defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
2111*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0)
2112*a67afe4dSAndroid Build Coastguard Worker    {
2113*a67afe4dSAndroid Build Coastguard Worker       if (png_ptr->user_transform_depth != 0)
2114*a67afe4dSAndroid Build Coastguard Worker          info_ptr->bit_depth = png_ptr->user_transform_depth;
2115*a67afe4dSAndroid Build Coastguard Worker 
2116*a67afe4dSAndroid Build Coastguard Worker       if (png_ptr->user_transform_channels != 0)
2117*a67afe4dSAndroid Build Coastguard Worker          info_ptr->channels = png_ptr->user_transform_channels;
2118*a67afe4dSAndroid Build Coastguard Worker    }
2119*a67afe4dSAndroid Build Coastguard Worker #endif
2120*a67afe4dSAndroid Build Coastguard Worker 
2121*a67afe4dSAndroid Build Coastguard Worker    info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
2122*a67afe4dSAndroid Build Coastguard Worker        info_ptr->bit_depth);
2123*a67afe4dSAndroid Build Coastguard Worker 
2124*a67afe4dSAndroid Build Coastguard Worker    info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width);
2125*a67afe4dSAndroid Build Coastguard Worker 
2126*a67afe4dSAndroid Build Coastguard Worker    /* Adding in 1.5.4: cache the above value in png_struct so that we can later
2127*a67afe4dSAndroid Build Coastguard Worker     * check in png_rowbytes that the user buffer won't get overwritten.  Note
2128*a67afe4dSAndroid Build Coastguard Worker     * that the field is not always set - if png_read_update_info isn't called
2129*a67afe4dSAndroid Build Coastguard Worker     * the application has to either not do any transforms or get the calculation
2130*a67afe4dSAndroid Build Coastguard Worker     * right itself.
2131*a67afe4dSAndroid Build Coastguard Worker     */
2132*a67afe4dSAndroid Build Coastguard Worker    png_ptr->info_rowbytes = info_ptr->rowbytes;
2133*a67afe4dSAndroid Build Coastguard Worker 
2134*a67afe4dSAndroid Build Coastguard Worker #ifndef PNG_READ_EXPAND_SUPPORTED
2135*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr != NULL)
2136*a67afe4dSAndroid Build Coastguard Worker       return;
2137*a67afe4dSAndroid Build Coastguard Worker #endif
2138*a67afe4dSAndroid Build Coastguard Worker }
2139*a67afe4dSAndroid Build Coastguard Worker 
2140*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_PACK_SUPPORTED
2141*a67afe4dSAndroid Build Coastguard Worker /* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
2142*a67afe4dSAndroid Build Coastguard Worker  * without changing the actual values.  Thus, if you had a row with
2143*a67afe4dSAndroid Build Coastguard Worker  * a bit depth of 1, you would end up with bytes that only contained
2144*a67afe4dSAndroid Build Coastguard Worker  * the numbers 0 or 1.  If you would rather they contain 0 and 255, use
2145*a67afe4dSAndroid Build Coastguard Worker  * png_do_shift() after this.
2146*a67afe4dSAndroid Build Coastguard Worker  */
2147*a67afe4dSAndroid Build Coastguard Worker static void
png_do_unpack(png_row_infop row_info,png_bytep row)2148*a67afe4dSAndroid Build Coastguard Worker png_do_unpack(png_row_infop row_info, png_bytep row)
2149*a67afe4dSAndroid Build Coastguard Worker {
2150*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_do_unpack");
2151*a67afe4dSAndroid Build Coastguard Worker 
2152*a67afe4dSAndroid Build Coastguard Worker    if (row_info->bit_depth < 8)
2153*a67afe4dSAndroid Build Coastguard Worker    {
2154*a67afe4dSAndroid Build Coastguard Worker       png_uint_32 i;
2155*a67afe4dSAndroid Build Coastguard Worker       png_uint_32 row_width=row_info->width;
2156*a67afe4dSAndroid Build Coastguard Worker 
2157*a67afe4dSAndroid Build Coastguard Worker       switch (row_info->bit_depth)
2158*a67afe4dSAndroid Build Coastguard Worker       {
2159*a67afe4dSAndroid Build Coastguard Worker          case 1:
2160*a67afe4dSAndroid Build Coastguard Worker          {
2161*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row + (size_t)((row_width - 1) >> 3);
2162*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = row + (size_t)row_width - 1;
2163*a67afe4dSAndroid Build Coastguard Worker             png_uint_32 shift = 7U - ((row_width + 7U) & 0x07);
2164*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < row_width; i++)
2165*a67afe4dSAndroid Build Coastguard Worker             {
2166*a67afe4dSAndroid Build Coastguard Worker                *dp = (png_byte)((*sp >> shift) & 0x01);
2167*a67afe4dSAndroid Build Coastguard Worker 
2168*a67afe4dSAndroid Build Coastguard Worker                if (shift == 7)
2169*a67afe4dSAndroid Build Coastguard Worker                {
2170*a67afe4dSAndroid Build Coastguard Worker                   shift = 0;
2171*a67afe4dSAndroid Build Coastguard Worker                   sp--;
2172*a67afe4dSAndroid Build Coastguard Worker                }
2173*a67afe4dSAndroid Build Coastguard Worker 
2174*a67afe4dSAndroid Build Coastguard Worker                else
2175*a67afe4dSAndroid Build Coastguard Worker                   shift++;
2176*a67afe4dSAndroid Build Coastguard Worker 
2177*a67afe4dSAndroid Build Coastguard Worker                dp--;
2178*a67afe4dSAndroid Build Coastguard Worker             }
2179*a67afe4dSAndroid Build Coastguard Worker             break;
2180*a67afe4dSAndroid Build Coastguard Worker          }
2181*a67afe4dSAndroid Build Coastguard Worker 
2182*a67afe4dSAndroid Build Coastguard Worker          case 2:
2183*a67afe4dSAndroid Build Coastguard Worker          {
2184*a67afe4dSAndroid Build Coastguard Worker 
2185*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row + (size_t)((row_width - 1) >> 2);
2186*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = row + (size_t)row_width - 1;
2187*a67afe4dSAndroid Build Coastguard Worker             png_uint_32 shift = ((3U - ((row_width + 3U) & 0x03)) << 1);
2188*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < row_width; i++)
2189*a67afe4dSAndroid Build Coastguard Worker             {
2190*a67afe4dSAndroid Build Coastguard Worker                *dp = (png_byte)((*sp >> shift) & 0x03);
2191*a67afe4dSAndroid Build Coastguard Worker 
2192*a67afe4dSAndroid Build Coastguard Worker                if (shift == 6)
2193*a67afe4dSAndroid Build Coastguard Worker                {
2194*a67afe4dSAndroid Build Coastguard Worker                   shift = 0;
2195*a67afe4dSAndroid Build Coastguard Worker                   sp--;
2196*a67afe4dSAndroid Build Coastguard Worker                }
2197*a67afe4dSAndroid Build Coastguard Worker 
2198*a67afe4dSAndroid Build Coastguard Worker                else
2199*a67afe4dSAndroid Build Coastguard Worker                   shift += 2;
2200*a67afe4dSAndroid Build Coastguard Worker 
2201*a67afe4dSAndroid Build Coastguard Worker                dp--;
2202*a67afe4dSAndroid Build Coastguard Worker             }
2203*a67afe4dSAndroid Build Coastguard Worker             break;
2204*a67afe4dSAndroid Build Coastguard Worker          }
2205*a67afe4dSAndroid Build Coastguard Worker 
2206*a67afe4dSAndroid Build Coastguard Worker          case 4:
2207*a67afe4dSAndroid Build Coastguard Worker          {
2208*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row + (size_t)((row_width - 1) >> 1);
2209*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = row + (size_t)row_width - 1;
2210*a67afe4dSAndroid Build Coastguard Worker             png_uint_32 shift = ((1U - ((row_width + 1U) & 0x01)) << 2);
2211*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < row_width; i++)
2212*a67afe4dSAndroid Build Coastguard Worker             {
2213*a67afe4dSAndroid Build Coastguard Worker                *dp = (png_byte)((*sp >> shift) & 0x0f);
2214*a67afe4dSAndroid Build Coastguard Worker 
2215*a67afe4dSAndroid Build Coastguard Worker                if (shift == 4)
2216*a67afe4dSAndroid Build Coastguard Worker                {
2217*a67afe4dSAndroid Build Coastguard Worker                   shift = 0;
2218*a67afe4dSAndroid Build Coastguard Worker                   sp--;
2219*a67afe4dSAndroid Build Coastguard Worker                }
2220*a67afe4dSAndroid Build Coastguard Worker 
2221*a67afe4dSAndroid Build Coastguard Worker                else
2222*a67afe4dSAndroid Build Coastguard Worker                   shift = 4;
2223*a67afe4dSAndroid Build Coastguard Worker 
2224*a67afe4dSAndroid Build Coastguard Worker                dp--;
2225*a67afe4dSAndroid Build Coastguard Worker             }
2226*a67afe4dSAndroid Build Coastguard Worker             break;
2227*a67afe4dSAndroid Build Coastguard Worker          }
2228*a67afe4dSAndroid Build Coastguard Worker 
2229*a67afe4dSAndroid Build Coastguard Worker          default:
2230*a67afe4dSAndroid Build Coastguard Worker             break;
2231*a67afe4dSAndroid Build Coastguard Worker       }
2232*a67afe4dSAndroid Build Coastguard Worker       row_info->bit_depth = 8;
2233*a67afe4dSAndroid Build Coastguard Worker       row_info->pixel_depth = (png_byte)(8 * row_info->channels);
2234*a67afe4dSAndroid Build Coastguard Worker       row_info->rowbytes = row_width * row_info->channels;
2235*a67afe4dSAndroid Build Coastguard Worker    }
2236*a67afe4dSAndroid Build Coastguard Worker }
2237*a67afe4dSAndroid Build Coastguard Worker #endif
2238*a67afe4dSAndroid Build Coastguard Worker 
2239*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_SHIFT_SUPPORTED
2240*a67afe4dSAndroid Build Coastguard Worker /* Reverse the effects of png_do_shift.  This routine merely shifts the
2241*a67afe4dSAndroid Build Coastguard Worker  * pixels back to their significant bits values.  Thus, if you have
2242*a67afe4dSAndroid Build Coastguard Worker  * a row of bit depth 8, but only 5 are significant, this will shift
2243*a67afe4dSAndroid Build Coastguard Worker  * the values back to 0 through 31.
2244*a67afe4dSAndroid Build Coastguard Worker  */
2245*a67afe4dSAndroid Build Coastguard Worker static void
png_do_unshift(png_row_infop row_info,png_bytep row,png_const_color_8p sig_bits)2246*a67afe4dSAndroid Build Coastguard Worker png_do_unshift(png_row_infop row_info, png_bytep row,
2247*a67afe4dSAndroid Build Coastguard Worker     png_const_color_8p sig_bits)
2248*a67afe4dSAndroid Build Coastguard Worker {
2249*a67afe4dSAndroid Build Coastguard Worker    int color_type;
2250*a67afe4dSAndroid Build Coastguard Worker 
2251*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_do_unshift");
2252*a67afe4dSAndroid Build Coastguard Worker 
2253*a67afe4dSAndroid Build Coastguard Worker    /* The palette case has already been handled in the _init routine. */
2254*a67afe4dSAndroid Build Coastguard Worker    color_type = row_info->color_type;
2255*a67afe4dSAndroid Build Coastguard Worker 
2256*a67afe4dSAndroid Build Coastguard Worker    if (color_type != PNG_COLOR_TYPE_PALETTE)
2257*a67afe4dSAndroid Build Coastguard Worker    {
2258*a67afe4dSAndroid Build Coastguard Worker       int shift[4];
2259*a67afe4dSAndroid Build Coastguard Worker       int channels = 0;
2260*a67afe4dSAndroid Build Coastguard Worker       int bit_depth = row_info->bit_depth;
2261*a67afe4dSAndroid Build Coastguard Worker 
2262*a67afe4dSAndroid Build Coastguard Worker       if ((color_type & PNG_COLOR_MASK_COLOR) != 0)
2263*a67afe4dSAndroid Build Coastguard Worker       {
2264*a67afe4dSAndroid Build Coastguard Worker          shift[channels++] = bit_depth - sig_bits->red;
2265*a67afe4dSAndroid Build Coastguard Worker          shift[channels++] = bit_depth - sig_bits->green;
2266*a67afe4dSAndroid Build Coastguard Worker          shift[channels++] = bit_depth - sig_bits->blue;
2267*a67afe4dSAndroid Build Coastguard Worker       }
2268*a67afe4dSAndroid Build Coastguard Worker 
2269*a67afe4dSAndroid Build Coastguard Worker       else
2270*a67afe4dSAndroid Build Coastguard Worker       {
2271*a67afe4dSAndroid Build Coastguard Worker          shift[channels++] = bit_depth - sig_bits->gray;
2272*a67afe4dSAndroid Build Coastguard Worker       }
2273*a67afe4dSAndroid Build Coastguard Worker 
2274*a67afe4dSAndroid Build Coastguard Worker       if ((color_type & PNG_COLOR_MASK_ALPHA) != 0)
2275*a67afe4dSAndroid Build Coastguard Worker       {
2276*a67afe4dSAndroid Build Coastguard Worker          shift[channels++] = bit_depth - sig_bits->alpha;
2277*a67afe4dSAndroid Build Coastguard Worker       }
2278*a67afe4dSAndroid Build Coastguard Worker 
2279*a67afe4dSAndroid Build Coastguard Worker       {
2280*a67afe4dSAndroid Build Coastguard Worker          int c, have_shift;
2281*a67afe4dSAndroid Build Coastguard Worker 
2282*a67afe4dSAndroid Build Coastguard Worker          for (c = have_shift = 0; c < channels; ++c)
2283*a67afe4dSAndroid Build Coastguard Worker          {
2284*a67afe4dSAndroid Build Coastguard Worker             /* A shift of more than the bit depth is an error condition but it
2285*a67afe4dSAndroid Build Coastguard Worker              * gets ignored here.
2286*a67afe4dSAndroid Build Coastguard Worker              */
2287*a67afe4dSAndroid Build Coastguard Worker             if (shift[c] <= 0 || shift[c] >= bit_depth)
2288*a67afe4dSAndroid Build Coastguard Worker                shift[c] = 0;
2289*a67afe4dSAndroid Build Coastguard Worker 
2290*a67afe4dSAndroid Build Coastguard Worker             else
2291*a67afe4dSAndroid Build Coastguard Worker                have_shift = 1;
2292*a67afe4dSAndroid Build Coastguard Worker          }
2293*a67afe4dSAndroid Build Coastguard Worker 
2294*a67afe4dSAndroid Build Coastguard Worker          if (have_shift == 0)
2295*a67afe4dSAndroid Build Coastguard Worker             return;
2296*a67afe4dSAndroid Build Coastguard Worker       }
2297*a67afe4dSAndroid Build Coastguard Worker 
2298*a67afe4dSAndroid Build Coastguard Worker       switch (bit_depth)
2299*a67afe4dSAndroid Build Coastguard Worker       {
2300*a67afe4dSAndroid Build Coastguard Worker          default:
2301*a67afe4dSAndroid Build Coastguard Worker          /* Must be 1bpp gray: should not be here! */
2302*a67afe4dSAndroid Build Coastguard Worker             /* NOTREACHED */
2303*a67afe4dSAndroid Build Coastguard Worker             break;
2304*a67afe4dSAndroid Build Coastguard Worker 
2305*a67afe4dSAndroid Build Coastguard Worker          case 2:
2306*a67afe4dSAndroid Build Coastguard Worker          /* Must be 2bpp gray */
2307*a67afe4dSAndroid Build Coastguard Worker          /* assert(channels == 1 && shift[0] == 1) */
2308*a67afe4dSAndroid Build Coastguard Worker          {
2309*a67afe4dSAndroid Build Coastguard Worker             png_bytep bp = row;
2310*a67afe4dSAndroid Build Coastguard Worker             png_bytep bp_end = bp + row_info->rowbytes;
2311*a67afe4dSAndroid Build Coastguard Worker 
2312*a67afe4dSAndroid Build Coastguard Worker             while (bp < bp_end)
2313*a67afe4dSAndroid Build Coastguard Worker             {
2314*a67afe4dSAndroid Build Coastguard Worker                int b = (*bp >> 1) & 0x55;
2315*a67afe4dSAndroid Build Coastguard Worker                *bp++ = (png_byte)b;
2316*a67afe4dSAndroid Build Coastguard Worker             }
2317*a67afe4dSAndroid Build Coastguard Worker             break;
2318*a67afe4dSAndroid Build Coastguard Worker          }
2319*a67afe4dSAndroid Build Coastguard Worker 
2320*a67afe4dSAndroid Build Coastguard Worker          case 4:
2321*a67afe4dSAndroid Build Coastguard Worker          /* Must be 4bpp gray */
2322*a67afe4dSAndroid Build Coastguard Worker          /* assert(channels == 1) */
2323*a67afe4dSAndroid Build Coastguard Worker          {
2324*a67afe4dSAndroid Build Coastguard Worker             png_bytep bp = row;
2325*a67afe4dSAndroid Build Coastguard Worker             png_bytep bp_end = bp + row_info->rowbytes;
2326*a67afe4dSAndroid Build Coastguard Worker             int gray_shift = shift[0];
2327*a67afe4dSAndroid Build Coastguard Worker             int mask =  0xf >> gray_shift;
2328*a67afe4dSAndroid Build Coastguard Worker 
2329*a67afe4dSAndroid Build Coastguard Worker             mask |= mask << 4;
2330*a67afe4dSAndroid Build Coastguard Worker 
2331*a67afe4dSAndroid Build Coastguard Worker             while (bp < bp_end)
2332*a67afe4dSAndroid Build Coastguard Worker             {
2333*a67afe4dSAndroid Build Coastguard Worker                int b = (*bp >> gray_shift) & mask;
2334*a67afe4dSAndroid Build Coastguard Worker                *bp++ = (png_byte)b;
2335*a67afe4dSAndroid Build Coastguard Worker             }
2336*a67afe4dSAndroid Build Coastguard Worker             break;
2337*a67afe4dSAndroid Build Coastguard Worker          }
2338*a67afe4dSAndroid Build Coastguard Worker 
2339*a67afe4dSAndroid Build Coastguard Worker          case 8:
2340*a67afe4dSAndroid Build Coastguard Worker          /* Single byte components, G, GA, RGB, RGBA */
2341*a67afe4dSAndroid Build Coastguard Worker          {
2342*a67afe4dSAndroid Build Coastguard Worker             png_bytep bp = row;
2343*a67afe4dSAndroid Build Coastguard Worker             png_bytep bp_end = bp + row_info->rowbytes;
2344*a67afe4dSAndroid Build Coastguard Worker             int channel = 0;
2345*a67afe4dSAndroid Build Coastguard Worker 
2346*a67afe4dSAndroid Build Coastguard Worker             while (bp < bp_end)
2347*a67afe4dSAndroid Build Coastguard Worker             {
2348*a67afe4dSAndroid Build Coastguard Worker                int b = *bp >> shift[channel];
2349*a67afe4dSAndroid Build Coastguard Worker                if (++channel >= channels)
2350*a67afe4dSAndroid Build Coastguard Worker                   channel = 0;
2351*a67afe4dSAndroid Build Coastguard Worker                *bp++ = (png_byte)b;
2352*a67afe4dSAndroid Build Coastguard Worker             }
2353*a67afe4dSAndroid Build Coastguard Worker             break;
2354*a67afe4dSAndroid Build Coastguard Worker          }
2355*a67afe4dSAndroid Build Coastguard Worker 
2356*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_16BIT_SUPPORTED
2357*a67afe4dSAndroid Build Coastguard Worker          case 16:
2358*a67afe4dSAndroid Build Coastguard Worker          /* Double byte components, G, GA, RGB, RGBA */
2359*a67afe4dSAndroid Build Coastguard Worker          {
2360*a67afe4dSAndroid Build Coastguard Worker             png_bytep bp = row;
2361*a67afe4dSAndroid Build Coastguard Worker             png_bytep bp_end = bp + row_info->rowbytes;
2362*a67afe4dSAndroid Build Coastguard Worker             int channel = 0;
2363*a67afe4dSAndroid Build Coastguard Worker 
2364*a67afe4dSAndroid Build Coastguard Worker             while (bp < bp_end)
2365*a67afe4dSAndroid Build Coastguard Worker             {
2366*a67afe4dSAndroid Build Coastguard Worker                int value = (bp[0] << 8) + bp[1];
2367*a67afe4dSAndroid Build Coastguard Worker 
2368*a67afe4dSAndroid Build Coastguard Worker                value >>= shift[channel];
2369*a67afe4dSAndroid Build Coastguard Worker                if (++channel >= channels)
2370*a67afe4dSAndroid Build Coastguard Worker                   channel = 0;
2371*a67afe4dSAndroid Build Coastguard Worker                *bp++ = (png_byte)(value >> 8);
2372*a67afe4dSAndroid Build Coastguard Worker                *bp++ = (png_byte)value;
2373*a67afe4dSAndroid Build Coastguard Worker             }
2374*a67afe4dSAndroid Build Coastguard Worker             break;
2375*a67afe4dSAndroid Build Coastguard Worker          }
2376*a67afe4dSAndroid Build Coastguard Worker #endif
2377*a67afe4dSAndroid Build Coastguard Worker       }
2378*a67afe4dSAndroid Build Coastguard Worker    }
2379*a67afe4dSAndroid Build Coastguard Worker }
2380*a67afe4dSAndroid Build Coastguard Worker #endif
2381*a67afe4dSAndroid Build Coastguard Worker 
2382*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
2383*a67afe4dSAndroid Build Coastguard Worker /* Scale rows of bit depth 16 down to 8 accurately */
2384*a67afe4dSAndroid Build Coastguard Worker static void
png_do_scale_16_to_8(png_row_infop row_info,png_bytep row)2385*a67afe4dSAndroid Build Coastguard Worker png_do_scale_16_to_8(png_row_infop row_info, png_bytep row)
2386*a67afe4dSAndroid Build Coastguard Worker {
2387*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_do_scale_16_to_8");
2388*a67afe4dSAndroid Build Coastguard Worker 
2389*a67afe4dSAndroid Build Coastguard Worker    if (row_info->bit_depth == 16)
2390*a67afe4dSAndroid Build Coastguard Worker    {
2391*a67afe4dSAndroid Build Coastguard Worker       png_bytep sp = row; /* source */
2392*a67afe4dSAndroid Build Coastguard Worker       png_bytep dp = row; /* destination */
2393*a67afe4dSAndroid Build Coastguard Worker       png_bytep ep = sp + row_info->rowbytes; /* end+1 */
2394*a67afe4dSAndroid Build Coastguard Worker 
2395*a67afe4dSAndroid Build Coastguard Worker       while (sp < ep)
2396*a67afe4dSAndroid Build Coastguard Worker       {
2397*a67afe4dSAndroid Build Coastguard Worker          /* The input is an array of 16-bit components, these must be scaled to
2398*a67afe4dSAndroid Build Coastguard Worker           * 8 bits each.  For a 16-bit value V the required value (from the PNG
2399*a67afe4dSAndroid Build Coastguard Worker           * specification) is:
2400*a67afe4dSAndroid Build Coastguard Worker           *
2401*a67afe4dSAndroid Build Coastguard Worker           *    (V * 255) / 65535
2402*a67afe4dSAndroid Build Coastguard Worker           *
2403*a67afe4dSAndroid Build Coastguard Worker           * This reduces to round(V / 257), or floor((V + 128.5)/257)
2404*a67afe4dSAndroid Build Coastguard Worker           *
2405*a67afe4dSAndroid Build Coastguard Worker           * Represent V as the two byte value vhi.vlo.  Make a guess that the
2406*a67afe4dSAndroid Build Coastguard Worker           * result is the top byte of V, vhi, then the correction to this value
2407*a67afe4dSAndroid Build Coastguard Worker           * is:
2408*a67afe4dSAndroid Build Coastguard Worker           *
2409*a67afe4dSAndroid Build Coastguard Worker           *    error = floor(((V-vhi.vhi) + 128.5) / 257)
2410*a67afe4dSAndroid Build Coastguard Worker           *          = floor(((vlo-vhi) + 128.5) / 257)
2411*a67afe4dSAndroid Build Coastguard Worker           *
2412*a67afe4dSAndroid Build Coastguard Worker           * This can be approximated using integer arithmetic (and a signed
2413*a67afe4dSAndroid Build Coastguard Worker           * shift):
2414*a67afe4dSAndroid Build Coastguard Worker           *
2415*a67afe4dSAndroid Build Coastguard Worker           *    error = (vlo-vhi+128) >> 8;
2416*a67afe4dSAndroid Build Coastguard Worker           *
2417*a67afe4dSAndroid Build Coastguard Worker           * The approximate differs from the exact answer only when (vlo-vhi) is
2418*a67afe4dSAndroid Build Coastguard Worker           * 128; it then gives a correction of +1 when the exact correction is
2419*a67afe4dSAndroid Build Coastguard Worker           * 0.  This gives 128 errors.  The exact answer (correct for all 16-bit
2420*a67afe4dSAndroid Build Coastguard Worker           * input values) is:
2421*a67afe4dSAndroid Build Coastguard Worker           *
2422*a67afe4dSAndroid Build Coastguard Worker           *    error = (vlo-vhi+128)*65535 >> 24;
2423*a67afe4dSAndroid Build Coastguard Worker           *
2424*a67afe4dSAndroid Build Coastguard Worker           * An alternative arithmetic calculation which also gives no errors is:
2425*a67afe4dSAndroid Build Coastguard Worker           *
2426*a67afe4dSAndroid Build Coastguard Worker           *    (V * 255 + 32895) >> 16
2427*a67afe4dSAndroid Build Coastguard Worker           */
2428*a67afe4dSAndroid Build Coastguard Worker 
2429*a67afe4dSAndroid Build Coastguard Worker          png_int_32 tmp = *sp++; /* must be signed! */
2430*a67afe4dSAndroid Build Coastguard Worker          tmp += (((int)*sp++ - tmp + 128) * 65535) >> 24;
2431*a67afe4dSAndroid Build Coastguard Worker          *dp++ = (png_byte)tmp;
2432*a67afe4dSAndroid Build Coastguard Worker       }
2433*a67afe4dSAndroid Build Coastguard Worker 
2434*a67afe4dSAndroid Build Coastguard Worker       row_info->bit_depth = 8;
2435*a67afe4dSAndroid Build Coastguard Worker       row_info->pixel_depth = (png_byte)(8 * row_info->channels);
2436*a67afe4dSAndroid Build Coastguard Worker       row_info->rowbytes = row_info->width * row_info->channels;
2437*a67afe4dSAndroid Build Coastguard Worker    }
2438*a67afe4dSAndroid Build Coastguard Worker }
2439*a67afe4dSAndroid Build Coastguard Worker #endif
2440*a67afe4dSAndroid Build Coastguard Worker 
2441*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
2442*a67afe4dSAndroid Build Coastguard Worker static void
2443*a67afe4dSAndroid Build Coastguard Worker /* Simply discard the low byte.  This was the default behavior prior
2444*a67afe4dSAndroid Build Coastguard Worker  * to libpng-1.5.4.
2445*a67afe4dSAndroid Build Coastguard Worker  */
png_do_chop(png_row_infop row_info,png_bytep row)2446*a67afe4dSAndroid Build Coastguard Worker png_do_chop(png_row_infop row_info, png_bytep row)
2447*a67afe4dSAndroid Build Coastguard Worker {
2448*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_do_chop");
2449*a67afe4dSAndroid Build Coastguard Worker 
2450*a67afe4dSAndroid Build Coastguard Worker    if (row_info->bit_depth == 16)
2451*a67afe4dSAndroid Build Coastguard Worker    {
2452*a67afe4dSAndroid Build Coastguard Worker       png_bytep sp = row; /* source */
2453*a67afe4dSAndroid Build Coastguard Worker       png_bytep dp = row; /* destination */
2454*a67afe4dSAndroid Build Coastguard Worker       png_bytep ep = sp + row_info->rowbytes; /* end+1 */
2455*a67afe4dSAndroid Build Coastguard Worker 
2456*a67afe4dSAndroid Build Coastguard Worker       while (sp < ep)
2457*a67afe4dSAndroid Build Coastguard Worker       {
2458*a67afe4dSAndroid Build Coastguard Worker          *dp++ = *sp;
2459*a67afe4dSAndroid Build Coastguard Worker          sp += 2; /* skip low byte */
2460*a67afe4dSAndroid Build Coastguard Worker       }
2461*a67afe4dSAndroid Build Coastguard Worker 
2462*a67afe4dSAndroid Build Coastguard Worker       row_info->bit_depth = 8;
2463*a67afe4dSAndroid Build Coastguard Worker       row_info->pixel_depth = (png_byte)(8 * row_info->channels);
2464*a67afe4dSAndroid Build Coastguard Worker       row_info->rowbytes = row_info->width * row_info->channels;
2465*a67afe4dSAndroid Build Coastguard Worker    }
2466*a67afe4dSAndroid Build Coastguard Worker }
2467*a67afe4dSAndroid Build Coastguard Worker #endif
2468*a67afe4dSAndroid Build Coastguard Worker 
2469*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
2470*a67afe4dSAndroid Build Coastguard Worker static void
png_do_read_swap_alpha(png_row_infop row_info,png_bytep row)2471*a67afe4dSAndroid Build Coastguard Worker png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
2472*a67afe4dSAndroid Build Coastguard Worker {
2473*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 row_width = row_info->width;
2474*a67afe4dSAndroid Build Coastguard Worker 
2475*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_do_read_swap_alpha");
2476*a67afe4dSAndroid Build Coastguard Worker 
2477*a67afe4dSAndroid Build Coastguard Worker    if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2478*a67afe4dSAndroid Build Coastguard Worker    {
2479*a67afe4dSAndroid Build Coastguard Worker       /* This converts from RGBA to ARGB */
2480*a67afe4dSAndroid Build Coastguard Worker       if (row_info->bit_depth == 8)
2481*a67afe4dSAndroid Build Coastguard Worker       {
2482*a67afe4dSAndroid Build Coastguard Worker          png_bytep sp = row + row_info->rowbytes;
2483*a67afe4dSAndroid Build Coastguard Worker          png_bytep dp = sp;
2484*a67afe4dSAndroid Build Coastguard Worker          png_byte save;
2485*a67afe4dSAndroid Build Coastguard Worker          png_uint_32 i;
2486*a67afe4dSAndroid Build Coastguard Worker 
2487*a67afe4dSAndroid Build Coastguard Worker          for (i = 0; i < row_width; i++)
2488*a67afe4dSAndroid Build Coastguard Worker          {
2489*a67afe4dSAndroid Build Coastguard Worker             save = *(--sp);
2490*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2491*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2492*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2493*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = save;
2494*a67afe4dSAndroid Build Coastguard Worker          }
2495*a67afe4dSAndroid Build Coastguard Worker       }
2496*a67afe4dSAndroid Build Coastguard Worker 
2497*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_16BIT_SUPPORTED
2498*a67afe4dSAndroid Build Coastguard Worker       /* This converts from RRGGBBAA to AARRGGBB */
2499*a67afe4dSAndroid Build Coastguard Worker       else
2500*a67afe4dSAndroid Build Coastguard Worker       {
2501*a67afe4dSAndroid Build Coastguard Worker          png_bytep sp = row + row_info->rowbytes;
2502*a67afe4dSAndroid Build Coastguard Worker          png_bytep dp = sp;
2503*a67afe4dSAndroid Build Coastguard Worker          png_byte save[2];
2504*a67afe4dSAndroid Build Coastguard Worker          png_uint_32 i;
2505*a67afe4dSAndroid Build Coastguard Worker 
2506*a67afe4dSAndroid Build Coastguard Worker          for (i = 0; i < row_width; i++)
2507*a67afe4dSAndroid Build Coastguard Worker          {
2508*a67afe4dSAndroid Build Coastguard Worker             save[0] = *(--sp);
2509*a67afe4dSAndroid Build Coastguard Worker             save[1] = *(--sp);
2510*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2511*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2512*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2513*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2514*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2515*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2516*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = save[0];
2517*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = save[1];
2518*a67afe4dSAndroid Build Coastguard Worker          }
2519*a67afe4dSAndroid Build Coastguard Worker       }
2520*a67afe4dSAndroid Build Coastguard Worker #endif
2521*a67afe4dSAndroid Build Coastguard Worker    }
2522*a67afe4dSAndroid Build Coastguard Worker 
2523*a67afe4dSAndroid Build Coastguard Worker    else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2524*a67afe4dSAndroid Build Coastguard Worker    {
2525*a67afe4dSAndroid Build Coastguard Worker       /* This converts from GA to AG */
2526*a67afe4dSAndroid Build Coastguard Worker       if (row_info->bit_depth == 8)
2527*a67afe4dSAndroid Build Coastguard Worker       {
2528*a67afe4dSAndroid Build Coastguard Worker          png_bytep sp = row + row_info->rowbytes;
2529*a67afe4dSAndroid Build Coastguard Worker          png_bytep dp = sp;
2530*a67afe4dSAndroid Build Coastguard Worker          png_byte save;
2531*a67afe4dSAndroid Build Coastguard Worker          png_uint_32 i;
2532*a67afe4dSAndroid Build Coastguard Worker 
2533*a67afe4dSAndroid Build Coastguard Worker          for (i = 0; i < row_width; i++)
2534*a67afe4dSAndroid Build Coastguard Worker          {
2535*a67afe4dSAndroid Build Coastguard Worker             save = *(--sp);
2536*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2537*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = save;
2538*a67afe4dSAndroid Build Coastguard Worker          }
2539*a67afe4dSAndroid Build Coastguard Worker       }
2540*a67afe4dSAndroid Build Coastguard Worker 
2541*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_16BIT_SUPPORTED
2542*a67afe4dSAndroid Build Coastguard Worker       /* This converts from GGAA to AAGG */
2543*a67afe4dSAndroid Build Coastguard Worker       else
2544*a67afe4dSAndroid Build Coastguard Worker       {
2545*a67afe4dSAndroid Build Coastguard Worker          png_bytep sp = row + row_info->rowbytes;
2546*a67afe4dSAndroid Build Coastguard Worker          png_bytep dp = sp;
2547*a67afe4dSAndroid Build Coastguard Worker          png_byte save[2];
2548*a67afe4dSAndroid Build Coastguard Worker          png_uint_32 i;
2549*a67afe4dSAndroid Build Coastguard Worker 
2550*a67afe4dSAndroid Build Coastguard Worker          for (i = 0; i < row_width; i++)
2551*a67afe4dSAndroid Build Coastguard Worker          {
2552*a67afe4dSAndroid Build Coastguard Worker             save[0] = *(--sp);
2553*a67afe4dSAndroid Build Coastguard Worker             save[1] = *(--sp);
2554*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2555*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2556*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = save[0];
2557*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = save[1];
2558*a67afe4dSAndroid Build Coastguard Worker          }
2559*a67afe4dSAndroid Build Coastguard Worker       }
2560*a67afe4dSAndroid Build Coastguard Worker #endif
2561*a67afe4dSAndroid Build Coastguard Worker    }
2562*a67afe4dSAndroid Build Coastguard Worker }
2563*a67afe4dSAndroid Build Coastguard Worker #endif
2564*a67afe4dSAndroid Build Coastguard Worker 
2565*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
2566*a67afe4dSAndroid Build Coastguard Worker static void
png_do_read_invert_alpha(png_row_infop row_info,png_bytep row)2567*a67afe4dSAndroid Build Coastguard Worker png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
2568*a67afe4dSAndroid Build Coastguard Worker {
2569*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 row_width;
2570*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_do_read_invert_alpha");
2571*a67afe4dSAndroid Build Coastguard Worker 
2572*a67afe4dSAndroid Build Coastguard Worker    row_width = row_info->width;
2573*a67afe4dSAndroid Build Coastguard Worker    if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2574*a67afe4dSAndroid Build Coastguard Worker    {
2575*a67afe4dSAndroid Build Coastguard Worker       if (row_info->bit_depth == 8)
2576*a67afe4dSAndroid Build Coastguard Worker       {
2577*a67afe4dSAndroid Build Coastguard Worker          /* This inverts the alpha channel in RGBA */
2578*a67afe4dSAndroid Build Coastguard Worker          png_bytep sp = row + row_info->rowbytes;
2579*a67afe4dSAndroid Build Coastguard Worker          png_bytep dp = sp;
2580*a67afe4dSAndroid Build Coastguard Worker          png_uint_32 i;
2581*a67afe4dSAndroid Build Coastguard Worker 
2582*a67afe4dSAndroid Build Coastguard Worker          for (i = 0; i < row_width; i++)
2583*a67afe4dSAndroid Build Coastguard Worker          {
2584*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = (png_byte)(255 - *(--sp));
2585*a67afe4dSAndroid Build Coastguard Worker 
2586*a67afe4dSAndroid Build Coastguard Worker /*          This does nothing:
2587*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2588*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2589*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2590*a67afe4dSAndroid Build Coastguard Worker             We can replace it with:
2591*a67afe4dSAndroid Build Coastguard Worker */
2592*a67afe4dSAndroid Build Coastguard Worker             sp-=3;
2593*a67afe4dSAndroid Build Coastguard Worker             dp=sp;
2594*a67afe4dSAndroid Build Coastguard Worker          }
2595*a67afe4dSAndroid Build Coastguard Worker       }
2596*a67afe4dSAndroid Build Coastguard Worker 
2597*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_16BIT_SUPPORTED
2598*a67afe4dSAndroid Build Coastguard Worker       /* This inverts the alpha channel in RRGGBBAA */
2599*a67afe4dSAndroid Build Coastguard Worker       else
2600*a67afe4dSAndroid Build Coastguard Worker       {
2601*a67afe4dSAndroid Build Coastguard Worker          png_bytep sp = row + row_info->rowbytes;
2602*a67afe4dSAndroid Build Coastguard Worker          png_bytep dp = sp;
2603*a67afe4dSAndroid Build Coastguard Worker          png_uint_32 i;
2604*a67afe4dSAndroid Build Coastguard Worker 
2605*a67afe4dSAndroid Build Coastguard Worker          for (i = 0; i < row_width; i++)
2606*a67afe4dSAndroid Build Coastguard Worker          {
2607*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = (png_byte)(255 - *(--sp));
2608*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = (png_byte)(255 - *(--sp));
2609*a67afe4dSAndroid Build Coastguard Worker 
2610*a67afe4dSAndroid Build Coastguard Worker /*          This does nothing:
2611*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2612*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2613*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2614*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2615*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2616*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2617*a67afe4dSAndroid Build Coastguard Worker             We can replace it with:
2618*a67afe4dSAndroid Build Coastguard Worker */
2619*a67afe4dSAndroid Build Coastguard Worker             sp-=6;
2620*a67afe4dSAndroid Build Coastguard Worker             dp=sp;
2621*a67afe4dSAndroid Build Coastguard Worker          }
2622*a67afe4dSAndroid Build Coastguard Worker       }
2623*a67afe4dSAndroid Build Coastguard Worker #endif
2624*a67afe4dSAndroid Build Coastguard Worker    }
2625*a67afe4dSAndroid Build Coastguard Worker    else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2626*a67afe4dSAndroid Build Coastguard Worker    {
2627*a67afe4dSAndroid Build Coastguard Worker       if (row_info->bit_depth == 8)
2628*a67afe4dSAndroid Build Coastguard Worker       {
2629*a67afe4dSAndroid Build Coastguard Worker          /* This inverts the alpha channel in GA */
2630*a67afe4dSAndroid Build Coastguard Worker          png_bytep sp = row + row_info->rowbytes;
2631*a67afe4dSAndroid Build Coastguard Worker          png_bytep dp = sp;
2632*a67afe4dSAndroid Build Coastguard Worker          png_uint_32 i;
2633*a67afe4dSAndroid Build Coastguard Worker 
2634*a67afe4dSAndroid Build Coastguard Worker          for (i = 0; i < row_width; i++)
2635*a67afe4dSAndroid Build Coastguard Worker          {
2636*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = (png_byte)(255 - *(--sp));
2637*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2638*a67afe4dSAndroid Build Coastguard Worker          }
2639*a67afe4dSAndroid Build Coastguard Worker       }
2640*a67afe4dSAndroid Build Coastguard Worker 
2641*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_16BIT_SUPPORTED
2642*a67afe4dSAndroid Build Coastguard Worker       else
2643*a67afe4dSAndroid Build Coastguard Worker       {
2644*a67afe4dSAndroid Build Coastguard Worker          /* This inverts the alpha channel in GGAA */
2645*a67afe4dSAndroid Build Coastguard Worker          png_bytep sp  = row + row_info->rowbytes;
2646*a67afe4dSAndroid Build Coastguard Worker          png_bytep dp = sp;
2647*a67afe4dSAndroid Build Coastguard Worker          png_uint_32 i;
2648*a67afe4dSAndroid Build Coastguard Worker 
2649*a67afe4dSAndroid Build Coastguard Worker          for (i = 0; i < row_width; i++)
2650*a67afe4dSAndroid Build Coastguard Worker          {
2651*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = (png_byte)(255 - *(--sp));
2652*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = (png_byte)(255 - *(--sp));
2653*a67afe4dSAndroid Build Coastguard Worker /*
2654*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2655*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = *(--sp);
2656*a67afe4dSAndroid Build Coastguard Worker */
2657*a67afe4dSAndroid Build Coastguard Worker             sp-=2;
2658*a67afe4dSAndroid Build Coastguard Worker             dp=sp;
2659*a67afe4dSAndroid Build Coastguard Worker          }
2660*a67afe4dSAndroid Build Coastguard Worker       }
2661*a67afe4dSAndroid Build Coastguard Worker #endif
2662*a67afe4dSAndroid Build Coastguard Worker    }
2663*a67afe4dSAndroid Build Coastguard Worker }
2664*a67afe4dSAndroid Build Coastguard Worker #endif
2665*a67afe4dSAndroid Build Coastguard Worker 
2666*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_FILLER_SUPPORTED
2667*a67afe4dSAndroid Build Coastguard Worker /* Add filler channel if we have RGB color */
2668*a67afe4dSAndroid Build Coastguard Worker static void
png_do_read_filler(png_row_infop row_info,png_bytep row,png_uint_32 filler,png_uint_32 flags)2669*a67afe4dSAndroid Build Coastguard Worker png_do_read_filler(png_row_infop row_info, png_bytep row,
2670*a67afe4dSAndroid Build Coastguard Worker     png_uint_32 filler, png_uint_32 flags)
2671*a67afe4dSAndroid Build Coastguard Worker {
2672*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 i;
2673*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 row_width = row_info->width;
2674*a67afe4dSAndroid Build Coastguard Worker 
2675*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_16BIT_SUPPORTED
2676*a67afe4dSAndroid Build Coastguard Worker    png_byte hi_filler = (png_byte)(filler>>8);
2677*a67afe4dSAndroid Build Coastguard Worker #endif
2678*a67afe4dSAndroid Build Coastguard Worker    png_byte lo_filler = (png_byte)filler;
2679*a67afe4dSAndroid Build Coastguard Worker 
2680*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_do_read_filler");
2681*a67afe4dSAndroid Build Coastguard Worker 
2682*a67afe4dSAndroid Build Coastguard Worker    if (
2683*a67afe4dSAndroid Build Coastguard Worker        row_info->color_type == PNG_COLOR_TYPE_GRAY)
2684*a67afe4dSAndroid Build Coastguard Worker    {
2685*a67afe4dSAndroid Build Coastguard Worker       if (row_info->bit_depth == 8)
2686*a67afe4dSAndroid Build Coastguard Worker       {
2687*a67afe4dSAndroid Build Coastguard Worker          if ((flags & PNG_FLAG_FILLER_AFTER) != 0)
2688*a67afe4dSAndroid Build Coastguard Worker          {
2689*a67afe4dSAndroid Build Coastguard Worker             /* This changes the data from G to GX */
2690*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row + (size_t)row_width;
2691*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp =  sp + (size_t)row_width;
2692*a67afe4dSAndroid Build Coastguard Worker             for (i = 1; i < row_width; i++)
2693*a67afe4dSAndroid Build Coastguard Worker             {
2694*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = lo_filler;
2695*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2696*a67afe4dSAndroid Build Coastguard Worker             }
2697*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = lo_filler;
2698*a67afe4dSAndroid Build Coastguard Worker             row_info->channels = 2;
2699*a67afe4dSAndroid Build Coastguard Worker             row_info->pixel_depth = 16;
2700*a67afe4dSAndroid Build Coastguard Worker             row_info->rowbytes = row_width * 2;
2701*a67afe4dSAndroid Build Coastguard Worker          }
2702*a67afe4dSAndroid Build Coastguard Worker 
2703*a67afe4dSAndroid Build Coastguard Worker          else
2704*a67afe4dSAndroid Build Coastguard Worker          {
2705*a67afe4dSAndroid Build Coastguard Worker             /* This changes the data from G to XG */
2706*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row + (size_t)row_width;
2707*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = sp  + (size_t)row_width;
2708*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < row_width; i++)
2709*a67afe4dSAndroid Build Coastguard Worker             {
2710*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2711*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = lo_filler;
2712*a67afe4dSAndroid Build Coastguard Worker             }
2713*a67afe4dSAndroid Build Coastguard Worker             row_info->channels = 2;
2714*a67afe4dSAndroid Build Coastguard Worker             row_info->pixel_depth = 16;
2715*a67afe4dSAndroid Build Coastguard Worker             row_info->rowbytes = row_width * 2;
2716*a67afe4dSAndroid Build Coastguard Worker          }
2717*a67afe4dSAndroid Build Coastguard Worker       }
2718*a67afe4dSAndroid Build Coastguard Worker 
2719*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_16BIT_SUPPORTED
2720*a67afe4dSAndroid Build Coastguard Worker       else if (row_info->bit_depth == 16)
2721*a67afe4dSAndroid Build Coastguard Worker       {
2722*a67afe4dSAndroid Build Coastguard Worker          if ((flags & PNG_FLAG_FILLER_AFTER) != 0)
2723*a67afe4dSAndroid Build Coastguard Worker          {
2724*a67afe4dSAndroid Build Coastguard Worker             /* This changes the data from GG to GGXX */
2725*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row + (size_t)row_width * 2;
2726*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = sp  + (size_t)row_width * 2;
2727*a67afe4dSAndroid Build Coastguard Worker             for (i = 1; i < row_width; i++)
2728*a67afe4dSAndroid Build Coastguard Worker             {
2729*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = lo_filler;
2730*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = hi_filler;
2731*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2732*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2733*a67afe4dSAndroid Build Coastguard Worker             }
2734*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = lo_filler;
2735*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = hi_filler;
2736*a67afe4dSAndroid Build Coastguard Worker             row_info->channels = 2;
2737*a67afe4dSAndroid Build Coastguard Worker             row_info->pixel_depth = 32;
2738*a67afe4dSAndroid Build Coastguard Worker             row_info->rowbytes = row_width * 4;
2739*a67afe4dSAndroid Build Coastguard Worker          }
2740*a67afe4dSAndroid Build Coastguard Worker 
2741*a67afe4dSAndroid Build Coastguard Worker          else
2742*a67afe4dSAndroid Build Coastguard Worker          {
2743*a67afe4dSAndroid Build Coastguard Worker             /* This changes the data from GG to XXGG */
2744*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row + (size_t)row_width * 2;
2745*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = sp  + (size_t)row_width * 2;
2746*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < row_width; i++)
2747*a67afe4dSAndroid Build Coastguard Worker             {
2748*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2749*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2750*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = lo_filler;
2751*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = hi_filler;
2752*a67afe4dSAndroid Build Coastguard Worker             }
2753*a67afe4dSAndroid Build Coastguard Worker             row_info->channels = 2;
2754*a67afe4dSAndroid Build Coastguard Worker             row_info->pixel_depth = 32;
2755*a67afe4dSAndroid Build Coastguard Worker             row_info->rowbytes = row_width * 4;
2756*a67afe4dSAndroid Build Coastguard Worker          }
2757*a67afe4dSAndroid Build Coastguard Worker       }
2758*a67afe4dSAndroid Build Coastguard Worker #endif
2759*a67afe4dSAndroid Build Coastguard Worker    } /* COLOR_TYPE == GRAY */
2760*a67afe4dSAndroid Build Coastguard Worker    else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2761*a67afe4dSAndroid Build Coastguard Worker    {
2762*a67afe4dSAndroid Build Coastguard Worker       if (row_info->bit_depth == 8)
2763*a67afe4dSAndroid Build Coastguard Worker       {
2764*a67afe4dSAndroid Build Coastguard Worker          if ((flags & PNG_FLAG_FILLER_AFTER) != 0)
2765*a67afe4dSAndroid Build Coastguard Worker          {
2766*a67afe4dSAndroid Build Coastguard Worker             /* This changes the data from RGB to RGBX */
2767*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row + (size_t)row_width * 3;
2768*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = sp  + (size_t)row_width;
2769*a67afe4dSAndroid Build Coastguard Worker             for (i = 1; i < row_width; i++)
2770*a67afe4dSAndroid Build Coastguard Worker             {
2771*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = lo_filler;
2772*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2773*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2774*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2775*a67afe4dSAndroid Build Coastguard Worker             }
2776*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = lo_filler;
2777*a67afe4dSAndroid Build Coastguard Worker             row_info->channels = 4;
2778*a67afe4dSAndroid Build Coastguard Worker             row_info->pixel_depth = 32;
2779*a67afe4dSAndroid Build Coastguard Worker             row_info->rowbytes = row_width * 4;
2780*a67afe4dSAndroid Build Coastguard Worker          }
2781*a67afe4dSAndroid Build Coastguard Worker 
2782*a67afe4dSAndroid Build Coastguard Worker          else
2783*a67afe4dSAndroid Build Coastguard Worker          {
2784*a67afe4dSAndroid Build Coastguard Worker             /* This changes the data from RGB to XRGB */
2785*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row + (size_t)row_width * 3;
2786*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = sp + (size_t)row_width;
2787*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < row_width; i++)
2788*a67afe4dSAndroid Build Coastguard Worker             {
2789*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2790*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2791*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2792*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = lo_filler;
2793*a67afe4dSAndroid Build Coastguard Worker             }
2794*a67afe4dSAndroid Build Coastguard Worker             row_info->channels = 4;
2795*a67afe4dSAndroid Build Coastguard Worker             row_info->pixel_depth = 32;
2796*a67afe4dSAndroid Build Coastguard Worker             row_info->rowbytes = row_width * 4;
2797*a67afe4dSAndroid Build Coastguard Worker          }
2798*a67afe4dSAndroid Build Coastguard Worker       }
2799*a67afe4dSAndroid Build Coastguard Worker 
2800*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_16BIT_SUPPORTED
2801*a67afe4dSAndroid Build Coastguard Worker       else if (row_info->bit_depth == 16)
2802*a67afe4dSAndroid Build Coastguard Worker       {
2803*a67afe4dSAndroid Build Coastguard Worker          if ((flags & PNG_FLAG_FILLER_AFTER) != 0)
2804*a67afe4dSAndroid Build Coastguard Worker          {
2805*a67afe4dSAndroid Build Coastguard Worker             /* This changes the data from RRGGBB to RRGGBBXX */
2806*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row + (size_t)row_width * 6;
2807*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = sp  + (size_t)row_width * 2;
2808*a67afe4dSAndroid Build Coastguard Worker             for (i = 1; i < row_width; i++)
2809*a67afe4dSAndroid Build Coastguard Worker             {
2810*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = lo_filler;
2811*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = hi_filler;
2812*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2813*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2814*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2815*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2816*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2817*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2818*a67afe4dSAndroid Build Coastguard Worker             }
2819*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = lo_filler;
2820*a67afe4dSAndroid Build Coastguard Worker             *(--dp) = hi_filler;
2821*a67afe4dSAndroid Build Coastguard Worker             row_info->channels = 4;
2822*a67afe4dSAndroid Build Coastguard Worker             row_info->pixel_depth = 64;
2823*a67afe4dSAndroid Build Coastguard Worker             row_info->rowbytes = row_width * 8;
2824*a67afe4dSAndroid Build Coastguard Worker          }
2825*a67afe4dSAndroid Build Coastguard Worker 
2826*a67afe4dSAndroid Build Coastguard Worker          else
2827*a67afe4dSAndroid Build Coastguard Worker          {
2828*a67afe4dSAndroid Build Coastguard Worker             /* This changes the data from RRGGBB to XXRRGGBB */
2829*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row + (size_t)row_width * 6;
2830*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = sp  + (size_t)row_width * 2;
2831*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < row_width; i++)
2832*a67afe4dSAndroid Build Coastguard Worker             {
2833*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2834*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2835*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2836*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2837*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2838*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = *(--sp);
2839*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = lo_filler;
2840*a67afe4dSAndroid Build Coastguard Worker                *(--dp) = hi_filler;
2841*a67afe4dSAndroid Build Coastguard Worker             }
2842*a67afe4dSAndroid Build Coastguard Worker 
2843*a67afe4dSAndroid Build Coastguard Worker             row_info->channels = 4;
2844*a67afe4dSAndroid Build Coastguard Worker             row_info->pixel_depth = 64;
2845*a67afe4dSAndroid Build Coastguard Worker             row_info->rowbytes = row_width * 8;
2846*a67afe4dSAndroid Build Coastguard Worker          }
2847*a67afe4dSAndroid Build Coastguard Worker       }
2848*a67afe4dSAndroid Build Coastguard Worker #endif
2849*a67afe4dSAndroid Build Coastguard Worker    } /* COLOR_TYPE == RGB */
2850*a67afe4dSAndroid Build Coastguard Worker }
2851*a67afe4dSAndroid Build Coastguard Worker #endif
2852*a67afe4dSAndroid Build Coastguard Worker 
2853*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
2854*a67afe4dSAndroid Build Coastguard Worker /* Expand grayscale files to RGB, with or without alpha */
2855*a67afe4dSAndroid Build Coastguard Worker static void
png_do_gray_to_rgb(png_row_infop row_info,png_bytep row)2856*a67afe4dSAndroid Build Coastguard Worker png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
2857*a67afe4dSAndroid Build Coastguard Worker {
2858*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 i;
2859*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 row_width = row_info->width;
2860*a67afe4dSAndroid Build Coastguard Worker 
2861*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_do_gray_to_rgb");
2862*a67afe4dSAndroid Build Coastguard Worker 
2863*a67afe4dSAndroid Build Coastguard Worker    if (row_info->bit_depth >= 8 &&
2864*a67afe4dSAndroid Build Coastguard Worker        (row_info->color_type & PNG_COLOR_MASK_COLOR) == 0)
2865*a67afe4dSAndroid Build Coastguard Worker    {
2866*a67afe4dSAndroid Build Coastguard Worker       if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
2867*a67afe4dSAndroid Build Coastguard Worker       {
2868*a67afe4dSAndroid Build Coastguard Worker          if (row_info->bit_depth == 8)
2869*a67afe4dSAndroid Build Coastguard Worker          {
2870*a67afe4dSAndroid Build Coastguard Worker             /* This changes G to RGB */
2871*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row + (size_t)row_width - 1;
2872*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = sp  + (size_t)row_width * 2;
2873*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < row_width; i++)
2874*a67afe4dSAndroid Build Coastguard Worker             {
2875*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *sp;
2876*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *sp;
2877*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *(sp--);
2878*a67afe4dSAndroid Build Coastguard Worker             }
2879*a67afe4dSAndroid Build Coastguard Worker          }
2880*a67afe4dSAndroid Build Coastguard Worker 
2881*a67afe4dSAndroid Build Coastguard Worker          else
2882*a67afe4dSAndroid Build Coastguard Worker          {
2883*a67afe4dSAndroid Build Coastguard Worker             /* This changes GG to RRGGBB */
2884*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row + (size_t)row_width * 2 - 1;
2885*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = sp  + (size_t)row_width * 4;
2886*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < row_width; i++)
2887*a67afe4dSAndroid Build Coastguard Worker             {
2888*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *sp;
2889*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *(sp - 1);
2890*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *sp;
2891*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *(sp - 1);
2892*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *(sp--);
2893*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *(sp--);
2894*a67afe4dSAndroid Build Coastguard Worker             }
2895*a67afe4dSAndroid Build Coastguard Worker          }
2896*a67afe4dSAndroid Build Coastguard Worker       }
2897*a67afe4dSAndroid Build Coastguard Worker 
2898*a67afe4dSAndroid Build Coastguard Worker       else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2899*a67afe4dSAndroid Build Coastguard Worker       {
2900*a67afe4dSAndroid Build Coastguard Worker          if (row_info->bit_depth == 8)
2901*a67afe4dSAndroid Build Coastguard Worker          {
2902*a67afe4dSAndroid Build Coastguard Worker             /* This changes GA to RGBA */
2903*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row + (size_t)row_width * 2 - 1;
2904*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = sp  + (size_t)row_width * 2;
2905*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < row_width; i++)
2906*a67afe4dSAndroid Build Coastguard Worker             {
2907*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *(sp--);
2908*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *sp;
2909*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *sp;
2910*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *(sp--);
2911*a67afe4dSAndroid Build Coastguard Worker             }
2912*a67afe4dSAndroid Build Coastguard Worker          }
2913*a67afe4dSAndroid Build Coastguard Worker 
2914*a67afe4dSAndroid Build Coastguard Worker          else
2915*a67afe4dSAndroid Build Coastguard Worker          {
2916*a67afe4dSAndroid Build Coastguard Worker             /* This changes GGAA to RRGGBBAA */
2917*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row + (size_t)row_width * 4 - 1;
2918*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = sp  + (size_t)row_width * 4;
2919*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < row_width; i++)
2920*a67afe4dSAndroid Build Coastguard Worker             {
2921*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *(sp--);
2922*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *(sp--);
2923*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *sp;
2924*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *(sp - 1);
2925*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *sp;
2926*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *(sp - 1);
2927*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *(sp--);
2928*a67afe4dSAndroid Build Coastguard Worker                *(dp--) = *(sp--);
2929*a67afe4dSAndroid Build Coastguard Worker             }
2930*a67afe4dSAndroid Build Coastguard Worker          }
2931*a67afe4dSAndroid Build Coastguard Worker       }
2932*a67afe4dSAndroid Build Coastguard Worker       row_info->channels = (png_byte)(row_info->channels + 2);
2933*a67afe4dSAndroid Build Coastguard Worker       row_info->color_type |= PNG_COLOR_MASK_COLOR;
2934*a67afe4dSAndroid Build Coastguard Worker       row_info->pixel_depth = (png_byte)(row_info->channels *
2935*a67afe4dSAndroid Build Coastguard Worker           row_info->bit_depth);
2936*a67afe4dSAndroid Build Coastguard Worker       row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
2937*a67afe4dSAndroid Build Coastguard Worker    }
2938*a67afe4dSAndroid Build Coastguard Worker }
2939*a67afe4dSAndroid Build Coastguard Worker #endif
2940*a67afe4dSAndroid Build Coastguard Worker 
2941*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
2942*a67afe4dSAndroid Build Coastguard Worker /* Reduce RGB files to grayscale, with or without alpha
2943*a67afe4dSAndroid Build Coastguard Worker  * using the equation given in Poynton's ColorFAQ of 1998-01-04 at
2944*a67afe4dSAndroid Build Coastguard Worker  * <http://www.inforamp.net/~poynton/>  (THIS LINK IS DEAD June 2008 but
2945*a67afe4dSAndroid Build Coastguard Worker  * versions dated 1998 through November 2002 have been archived at
2946*a67afe4dSAndroid Build Coastguard Worker  * https://web.archive.org/web/20000816232553/www.inforamp.net/
2947*a67afe4dSAndroid Build Coastguard Worker  * ~poynton/notes/colour_and_gamma/ColorFAQ.txt )
2948*a67afe4dSAndroid Build Coastguard Worker  * Charles Poynton poynton at poynton.com
2949*a67afe4dSAndroid Build Coastguard Worker  *
2950*a67afe4dSAndroid Build Coastguard Worker  *     Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
2951*a67afe4dSAndroid Build Coastguard Worker  *
2952*a67afe4dSAndroid Build Coastguard Worker  *  which can be expressed with integers as
2953*a67afe4dSAndroid Build Coastguard Worker  *
2954*a67afe4dSAndroid Build Coastguard Worker  *     Y = (6969 * R + 23434 * G + 2365 * B)/32768
2955*a67afe4dSAndroid Build Coastguard Worker  *
2956*a67afe4dSAndroid Build Coastguard Worker  * Poynton's current link (as of January 2003 through July 2011):
2957*a67afe4dSAndroid Build Coastguard Worker  * <http://www.poynton.com/notes/colour_and_gamma/>
2958*a67afe4dSAndroid Build Coastguard Worker  * has changed the numbers slightly:
2959*a67afe4dSAndroid Build Coastguard Worker  *
2960*a67afe4dSAndroid Build Coastguard Worker  *     Y = 0.2126*R + 0.7152*G + 0.0722*B
2961*a67afe4dSAndroid Build Coastguard Worker  *
2962*a67afe4dSAndroid Build Coastguard Worker  *  which can be expressed with integers as
2963*a67afe4dSAndroid Build Coastguard Worker  *
2964*a67afe4dSAndroid Build Coastguard Worker  *     Y = (6966 * R + 23436 * G + 2366 * B)/32768
2965*a67afe4dSAndroid Build Coastguard Worker  *
2966*a67afe4dSAndroid Build Coastguard Worker  *  Historically, however, libpng uses numbers derived from the ITU-R Rec 709
2967*a67afe4dSAndroid Build Coastguard Worker  *  end point chromaticities and the D65 white point.  Depending on the
2968*a67afe4dSAndroid Build Coastguard Worker  *  precision used for the D65 white point this produces a variety of different
2969*a67afe4dSAndroid Build Coastguard Worker  *  numbers, however if the four decimal place value used in ITU-R Rec 709 is
2970*a67afe4dSAndroid Build Coastguard Worker  *  used (0.3127,0.3290) the Y calculation would be:
2971*a67afe4dSAndroid Build Coastguard Worker  *
2972*a67afe4dSAndroid Build Coastguard Worker  *     Y = (6968 * R + 23435 * G + 2366 * B)/32768
2973*a67afe4dSAndroid Build Coastguard Worker  *
2974*a67afe4dSAndroid Build Coastguard Worker  *  While this is correct the rounding results in an overflow for white, because
2975*a67afe4dSAndroid Build Coastguard Worker  *  the sum of the rounded coefficients is 32769, not 32768.  Consequently
2976*a67afe4dSAndroid Build Coastguard Worker  *  libpng uses, instead, the closest non-overflowing approximation:
2977*a67afe4dSAndroid Build Coastguard Worker  *
2978*a67afe4dSAndroid Build Coastguard Worker  *     Y = (6968 * R + 23434 * G + 2366 * B)/32768
2979*a67afe4dSAndroid Build Coastguard Worker  *
2980*a67afe4dSAndroid Build Coastguard Worker  *  Starting with libpng-1.5.5, if the image being converted has a cHRM chunk
2981*a67afe4dSAndroid Build Coastguard Worker  *  (including an sRGB chunk) then the chromaticities are used to calculate the
2982*a67afe4dSAndroid Build Coastguard Worker  *  coefficients.  See the chunk handling in pngrutil.c for more information.
2983*a67afe4dSAndroid Build Coastguard Worker  *
2984*a67afe4dSAndroid Build Coastguard Worker  *  In all cases the calculation is to be done in a linear colorspace.  If no
2985*a67afe4dSAndroid Build Coastguard Worker  *  gamma information is available to correct the encoding of the original RGB
2986*a67afe4dSAndroid Build Coastguard Worker  *  values this results in an implicit assumption that the original PNG RGB
2987*a67afe4dSAndroid Build Coastguard Worker  *  values were linear.
2988*a67afe4dSAndroid Build Coastguard Worker  *
2989*a67afe4dSAndroid Build Coastguard Worker  *  Other integer coefficients can be used via png_set_rgb_to_gray().  Because
2990*a67afe4dSAndroid Build Coastguard Worker  *  the API takes just red and green coefficients the blue coefficient is
2991*a67afe4dSAndroid Build Coastguard Worker  *  calculated to make the sum 32768.  This will result in different rounding
2992*a67afe4dSAndroid Build Coastguard Worker  *  to that used above.
2993*a67afe4dSAndroid Build Coastguard Worker  */
2994*a67afe4dSAndroid Build Coastguard Worker static int
png_do_rgb_to_gray(png_structrp png_ptr,png_row_infop row_info,png_bytep row)2995*a67afe4dSAndroid Build Coastguard Worker png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row)
2996*a67afe4dSAndroid Build Coastguard Worker {
2997*a67afe4dSAndroid Build Coastguard Worker    int rgb_error = 0;
2998*a67afe4dSAndroid Build Coastguard Worker 
2999*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_do_rgb_to_gray");
3000*a67afe4dSAndroid Build Coastguard Worker 
3001*a67afe4dSAndroid Build Coastguard Worker    if ((row_info->color_type & PNG_COLOR_MASK_PALETTE) == 0 &&
3002*a67afe4dSAndroid Build Coastguard Worker        (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)
3003*a67afe4dSAndroid Build Coastguard Worker    {
3004*a67afe4dSAndroid Build Coastguard Worker       png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
3005*a67afe4dSAndroid Build Coastguard Worker       png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
3006*a67afe4dSAndroid Build Coastguard Worker       png_uint_32 bc = 32768 - rc - gc;
3007*a67afe4dSAndroid Build Coastguard Worker       png_uint_32 row_width = row_info->width;
3008*a67afe4dSAndroid Build Coastguard Worker       int have_alpha = (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0;
3009*a67afe4dSAndroid Build Coastguard Worker 
3010*a67afe4dSAndroid Build Coastguard Worker       if (row_info->bit_depth == 8)
3011*a67afe4dSAndroid Build Coastguard Worker       {
3012*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
3013*a67afe4dSAndroid Build Coastguard Worker          /* Notice that gamma to/from 1 are not necessarily inverses (if
3014*a67afe4dSAndroid Build Coastguard Worker           * there is an overall gamma correction).  Prior to 1.5.5 this code
3015*a67afe4dSAndroid Build Coastguard Worker           * checked the linearized values for equality; this doesn't match
3016*a67afe4dSAndroid Build Coastguard Worker           * the documentation, the original values must be checked.
3017*a67afe4dSAndroid Build Coastguard Worker           */
3018*a67afe4dSAndroid Build Coastguard Worker          if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
3019*a67afe4dSAndroid Build Coastguard Worker          {
3020*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row;
3021*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = row;
3022*a67afe4dSAndroid Build Coastguard Worker             png_uint_32 i;
3023*a67afe4dSAndroid Build Coastguard Worker 
3024*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < row_width; i++)
3025*a67afe4dSAndroid Build Coastguard Worker             {
3026*a67afe4dSAndroid Build Coastguard Worker                png_byte red   = *(sp++);
3027*a67afe4dSAndroid Build Coastguard Worker                png_byte green = *(sp++);
3028*a67afe4dSAndroid Build Coastguard Worker                png_byte blue  = *(sp++);
3029*a67afe4dSAndroid Build Coastguard Worker 
3030*a67afe4dSAndroid Build Coastguard Worker                if (red != green || red != blue)
3031*a67afe4dSAndroid Build Coastguard Worker                {
3032*a67afe4dSAndroid Build Coastguard Worker                   red = png_ptr->gamma_to_1[red];
3033*a67afe4dSAndroid Build Coastguard Worker                   green = png_ptr->gamma_to_1[green];
3034*a67afe4dSAndroid Build Coastguard Worker                   blue = png_ptr->gamma_to_1[blue];
3035*a67afe4dSAndroid Build Coastguard Worker 
3036*a67afe4dSAndroid Build Coastguard Worker                   rgb_error |= 1;
3037*a67afe4dSAndroid Build Coastguard Worker                   *(dp++) = png_ptr->gamma_from_1[
3038*a67afe4dSAndroid Build Coastguard Worker                       (rc*red + gc*green + bc*blue + 16384)>>15];
3039*a67afe4dSAndroid Build Coastguard Worker                }
3040*a67afe4dSAndroid Build Coastguard Worker 
3041*a67afe4dSAndroid Build Coastguard Worker                else
3042*a67afe4dSAndroid Build Coastguard Worker                {
3043*a67afe4dSAndroid Build Coastguard Worker                   /* If there is no overall correction the table will not be
3044*a67afe4dSAndroid Build Coastguard Worker                    * set.
3045*a67afe4dSAndroid Build Coastguard Worker                    */
3046*a67afe4dSAndroid Build Coastguard Worker                   if (png_ptr->gamma_table != NULL)
3047*a67afe4dSAndroid Build Coastguard Worker                      red = png_ptr->gamma_table[red];
3048*a67afe4dSAndroid Build Coastguard Worker 
3049*a67afe4dSAndroid Build Coastguard Worker                   *(dp++) = red;
3050*a67afe4dSAndroid Build Coastguard Worker                }
3051*a67afe4dSAndroid Build Coastguard Worker 
3052*a67afe4dSAndroid Build Coastguard Worker                if (have_alpha != 0)
3053*a67afe4dSAndroid Build Coastguard Worker                   *(dp++) = *(sp++);
3054*a67afe4dSAndroid Build Coastguard Worker             }
3055*a67afe4dSAndroid Build Coastguard Worker          }
3056*a67afe4dSAndroid Build Coastguard Worker          else
3057*a67afe4dSAndroid Build Coastguard Worker #endif
3058*a67afe4dSAndroid Build Coastguard Worker          {
3059*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row;
3060*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = row;
3061*a67afe4dSAndroid Build Coastguard Worker             png_uint_32 i;
3062*a67afe4dSAndroid Build Coastguard Worker 
3063*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < row_width; i++)
3064*a67afe4dSAndroid Build Coastguard Worker             {
3065*a67afe4dSAndroid Build Coastguard Worker                png_byte red   = *(sp++);
3066*a67afe4dSAndroid Build Coastguard Worker                png_byte green = *(sp++);
3067*a67afe4dSAndroid Build Coastguard Worker                png_byte blue  = *(sp++);
3068*a67afe4dSAndroid Build Coastguard Worker 
3069*a67afe4dSAndroid Build Coastguard Worker                if (red != green || red != blue)
3070*a67afe4dSAndroid Build Coastguard Worker                {
3071*a67afe4dSAndroid Build Coastguard Worker                   rgb_error |= 1;
3072*a67afe4dSAndroid Build Coastguard Worker                   /* NOTE: this is the historical approach which simply
3073*a67afe4dSAndroid Build Coastguard Worker                    * truncates the results.
3074*a67afe4dSAndroid Build Coastguard Worker                    */
3075*a67afe4dSAndroid Build Coastguard Worker                   *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
3076*a67afe4dSAndroid Build Coastguard Worker                }
3077*a67afe4dSAndroid Build Coastguard Worker 
3078*a67afe4dSAndroid Build Coastguard Worker                else
3079*a67afe4dSAndroid Build Coastguard Worker                   *(dp++) = red;
3080*a67afe4dSAndroid Build Coastguard Worker 
3081*a67afe4dSAndroid Build Coastguard Worker                if (have_alpha != 0)
3082*a67afe4dSAndroid Build Coastguard Worker                   *(dp++) = *(sp++);
3083*a67afe4dSAndroid Build Coastguard Worker             }
3084*a67afe4dSAndroid Build Coastguard Worker          }
3085*a67afe4dSAndroid Build Coastguard Worker       }
3086*a67afe4dSAndroid Build Coastguard Worker 
3087*a67afe4dSAndroid Build Coastguard Worker       else /* RGB bit_depth == 16 */
3088*a67afe4dSAndroid Build Coastguard Worker       {
3089*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
3090*a67afe4dSAndroid Build Coastguard Worker          if (png_ptr->gamma_16_to_1 != NULL && png_ptr->gamma_16_from_1 != NULL)
3091*a67afe4dSAndroid Build Coastguard Worker          {
3092*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row;
3093*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = row;
3094*a67afe4dSAndroid Build Coastguard Worker             png_uint_32 i;
3095*a67afe4dSAndroid Build Coastguard Worker 
3096*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < row_width; i++)
3097*a67afe4dSAndroid Build Coastguard Worker             {
3098*a67afe4dSAndroid Build Coastguard Worker                png_uint_16 red, green, blue, w;
3099*a67afe4dSAndroid Build Coastguard Worker                png_byte hi,lo;
3100*a67afe4dSAndroid Build Coastguard Worker 
3101*a67afe4dSAndroid Build Coastguard Worker                hi=*(sp)++; lo=*(sp)++; red   = (png_uint_16)((hi << 8) | (lo));
3102*a67afe4dSAndroid Build Coastguard Worker                hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo));
3103*a67afe4dSAndroid Build Coastguard Worker                hi=*(sp)++; lo=*(sp)++; blue  = (png_uint_16)((hi << 8) | (lo));
3104*a67afe4dSAndroid Build Coastguard Worker 
3105*a67afe4dSAndroid Build Coastguard Worker                if (red == green && red == blue)
3106*a67afe4dSAndroid Build Coastguard Worker                {
3107*a67afe4dSAndroid Build Coastguard Worker                   if (png_ptr->gamma_16_table != NULL)
3108*a67afe4dSAndroid Build Coastguard Worker                      w = png_ptr->gamma_16_table[(red & 0xff)
3109*a67afe4dSAndroid Build Coastguard Worker                          >> png_ptr->gamma_shift][red >> 8];
3110*a67afe4dSAndroid Build Coastguard Worker 
3111*a67afe4dSAndroid Build Coastguard Worker                   else
3112*a67afe4dSAndroid Build Coastguard Worker                      w = red;
3113*a67afe4dSAndroid Build Coastguard Worker                }
3114*a67afe4dSAndroid Build Coastguard Worker 
3115*a67afe4dSAndroid Build Coastguard Worker                else
3116*a67afe4dSAndroid Build Coastguard Worker                {
3117*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 red_1   = png_ptr->gamma_16_to_1[(red & 0xff)
3118*a67afe4dSAndroid Build Coastguard Worker                       >> png_ptr->gamma_shift][red>>8];
3119*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 green_1 =
3120*a67afe4dSAndroid Build Coastguard Worker                       png_ptr->gamma_16_to_1[(green & 0xff) >>
3121*a67afe4dSAndroid Build Coastguard Worker                       png_ptr->gamma_shift][green>>8];
3122*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 blue_1  = png_ptr->gamma_16_to_1[(blue & 0xff)
3123*a67afe4dSAndroid Build Coastguard Worker                       >> png_ptr->gamma_shift][blue>>8];
3124*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 gray16  = (png_uint_16)((rc*red_1 + gc*green_1
3125*a67afe4dSAndroid Build Coastguard Worker                       + bc*blue_1 + 16384)>>15);
3126*a67afe4dSAndroid Build Coastguard Worker                   w = png_ptr->gamma_16_from_1[(gray16 & 0xff) >>
3127*a67afe4dSAndroid Build Coastguard Worker                       png_ptr->gamma_shift][gray16 >> 8];
3128*a67afe4dSAndroid Build Coastguard Worker                   rgb_error |= 1;
3129*a67afe4dSAndroid Build Coastguard Worker                }
3130*a67afe4dSAndroid Build Coastguard Worker 
3131*a67afe4dSAndroid Build Coastguard Worker                *(dp++) = (png_byte)((w>>8) & 0xff);
3132*a67afe4dSAndroid Build Coastguard Worker                *(dp++) = (png_byte)(w & 0xff);
3133*a67afe4dSAndroid Build Coastguard Worker 
3134*a67afe4dSAndroid Build Coastguard Worker                if (have_alpha != 0)
3135*a67afe4dSAndroid Build Coastguard Worker                {
3136*a67afe4dSAndroid Build Coastguard Worker                   *(dp++) = *(sp++);
3137*a67afe4dSAndroid Build Coastguard Worker                   *(dp++) = *(sp++);
3138*a67afe4dSAndroid Build Coastguard Worker                }
3139*a67afe4dSAndroid Build Coastguard Worker             }
3140*a67afe4dSAndroid Build Coastguard Worker          }
3141*a67afe4dSAndroid Build Coastguard Worker          else
3142*a67afe4dSAndroid Build Coastguard Worker #endif
3143*a67afe4dSAndroid Build Coastguard Worker          {
3144*a67afe4dSAndroid Build Coastguard Worker             png_bytep sp = row;
3145*a67afe4dSAndroid Build Coastguard Worker             png_bytep dp = row;
3146*a67afe4dSAndroid Build Coastguard Worker             png_uint_32 i;
3147*a67afe4dSAndroid Build Coastguard Worker 
3148*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < row_width; i++)
3149*a67afe4dSAndroid Build Coastguard Worker             {
3150*a67afe4dSAndroid Build Coastguard Worker                png_uint_16 red, green, blue, gray16;
3151*a67afe4dSAndroid Build Coastguard Worker                png_byte hi,lo;
3152*a67afe4dSAndroid Build Coastguard Worker 
3153*a67afe4dSAndroid Build Coastguard Worker                hi=*(sp)++; lo=*(sp)++; red   = (png_uint_16)((hi << 8) | (lo));
3154*a67afe4dSAndroid Build Coastguard Worker                hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo));
3155*a67afe4dSAndroid Build Coastguard Worker                hi=*(sp)++; lo=*(sp)++; blue  = (png_uint_16)((hi << 8) | (lo));
3156*a67afe4dSAndroid Build Coastguard Worker 
3157*a67afe4dSAndroid Build Coastguard Worker                if (red != green || red != blue)
3158*a67afe4dSAndroid Build Coastguard Worker                   rgb_error |= 1;
3159*a67afe4dSAndroid Build Coastguard Worker 
3160*a67afe4dSAndroid Build Coastguard Worker                /* From 1.5.5 in the 16-bit case do the accurate conversion even
3161*a67afe4dSAndroid Build Coastguard Worker                 * in the 'fast' case - this is because this is where the code
3162*a67afe4dSAndroid Build Coastguard Worker                 * ends up when handling linear 16-bit data.
3163*a67afe4dSAndroid Build Coastguard Worker                 */
3164*a67afe4dSAndroid Build Coastguard Worker                gray16  = (png_uint_16)((rc*red + gc*green + bc*blue + 16384) >>
3165*a67afe4dSAndroid Build Coastguard Worker                   15);
3166*a67afe4dSAndroid Build Coastguard Worker                *(dp++) = (png_byte)((gray16 >> 8) & 0xff);
3167*a67afe4dSAndroid Build Coastguard Worker                *(dp++) = (png_byte)(gray16 & 0xff);
3168*a67afe4dSAndroid Build Coastguard Worker 
3169*a67afe4dSAndroid Build Coastguard Worker                if (have_alpha != 0)
3170*a67afe4dSAndroid Build Coastguard Worker                {
3171*a67afe4dSAndroid Build Coastguard Worker                   *(dp++) = *(sp++);
3172*a67afe4dSAndroid Build Coastguard Worker                   *(dp++) = *(sp++);
3173*a67afe4dSAndroid Build Coastguard Worker                }
3174*a67afe4dSAndroid Build Coastguard Worker             }
3175*a67afe4dSAndroid Build Coastguard Worker          }
3176*a67afe4dSAndroid Build Coastguard Worker       }
3177*a67afe4dSAndroid Build Coastguard Worker 
3178*a67afe4dSAndroid Build Coastguard Worker       row_info->channels = (png_byte)(row_info->channels - 2);
3179*a67afe4dSAndroid Build Coastguard Worker       row_info->color_type = (png_byte)(row_info->color_type &
3180*a67afe4dSAndroid Build Coastguard Worker           ~PNG_COLOR_MASK_COLOR);
3181*a67afe4dSAndroid Build Coastguard Worker       row_info->pixel_depth = (png_byte)(row_info->channels *
3182*a67afe4dSAndroid Build Coastguard Worker           row_info->bit_depth);
3183*a67afe4dSAndroid Build Coastguard Worker       row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
3184*a67afe4dSAndroid Build Coastguard Worker    }
3185*a67afe4dSAndroid Build Coastguard Worker    return rgb_error;
3186*a67afe4dSAndroid Build Coastguard Worker }
3187*a67afe4dSAndroid Build Coastguard Worker #endif
3188*a67afe4dSAndroid Build Coastguard Worker 
3189*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
3190*a67afe4dSAndroid Build Coastguard Worker    defined(PNG_READ_ALPHA_MODE_SUPPORTED)
3191*a67afe4dSAndroid Build Coastguard Worker /* Replace any alpha or transparency with the supplied background color.
3192*a67afe4dSAndroid Build Coastguard Worker  * "background" is already in the screen gamma, while "background_1" is
3193*a67afe4dSAndroid Build Coastguard Worker  * at a gamma of 1.0.  Paletted files have already been taken care of.
3194*a67afe4dSAndroid Build Coastguard Worker  */
3195*a67afe4dSAndroid Build Coastguard Worker static void
png_do_compose(png_row_infop row_info,png_bytep row,png_structrp png_ptr)3196*a67afe4dSAndroid Build Coastguard Worker png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr)
3197*a67afe4dSAndroid Build Coastguard Worker {
3198*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
3199*a67afe4dSAndroid Build Coastguard Worker    png_const_bytep gamma_table = png_ptr->gamma_table;
3200*a67afe4dSAndroid Build Coastguard Worker    png_const_bytep gamma_from_1 = png_ptr->gamma_from_1;
3201*a67afe4dSAndroid Build Coastguard Worker    png_const_bytep gamma_to_1 = png_ptr->gamma_to_1;
3202*a67afe4dSAndroid Build Coastguard Worker    png_const_uint_16pp gamma_16 = png_ptr->gamma_16_table;
3203*a67afe4dSAndroid Build Coastguard Worker    png_const_uint_16pp gamma_16_from_1 = png_ptr->gamma_16_from_1;
3204*a67afe4dSAndroid Build Coastguard Worker    png_const_uint_16pp gamma_16_to_1 = png_ptr->gamma_16_to_1;
3205*a67afe4dSAndroid Build Coastguard Worker    int gamma_shift = png_ptr->gamma_shift;
3206*a67afe4dSAndroid Build Coastguard Worker    int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0;
3207*a67afe4dSAndroid Build Coastguard Worker #endif
3208*a67afe4dSAndroid Build Coastguard Worker 
3209*a67afe4dSAndroid Build Coastguard Worker    png_bytep sp;
3210*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 i;
3211*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 row_width = row_info->width;
3212*a67afe4dSAndroid Build Coastguard Worker    int shift;
3213*a67afe4dSAndroid Build Coastguard Worker 
3214*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_do_compose");
3215*a67afe4dSAndroid Build Coastguard Worker 
3216*a67afe4dSAndroid Build Coastguard Worker    switch (row_info->color_type)
3217*a67afe4dSAndroid Build Coastguard Worker    {
3218*a67afe4dSAndroid Build Coastguard Worker       case PNG_COLOR_TYPE_GRAY:
3219*a67afe4dSAndroid Build Coastguard Worker       {
3220*a67afe4dSAndroid Build Coastguard Worker          switch (row_info->bit_depth)
3221*a67afe4dSAndroid Build Coastguard Worker          {
3222*a67afe4dSAndroid Build Coastguard Worker             case 1:
3223*a67afe4dSAndroid Build Coastguard Worker             {
3224*a67afe4dSAndroid Build Coastguard Worker                sp = row;
3225*a67afe4dSAndroid Build Coastguard Worker                shift = 7;
3226*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++)
3227*a67afe4dSAndroid Build Coastguard Worker                {
3228*a67afe4dSAndroid Build Coastguard Worker                   if ((png_uint_16)((*sp >> shift) & 0x01)
3229*a67afe4dSAndroid Build Coastguard Worker                      == png_ptr->trans_color.gray)
3230*a67afe4dSAndroid Build Coastguard Worker                   {
3231*a67afe4dSAndroid Build Coastguard Worker                      unsigned int tmp = *sp & (0x7f7f >> (7 - shift));
3232*a67afe4dSAndroid Build Coastguard Worker                      tmp |=
3233*a67afe4dSAndroid Build Coastguard Worker                          (unsigned int)(png_ptr->background.gray << shift);
3234*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)(tmp & 0xff);
3235*a67afe4dSAndroid Build Coastguard Worker                   }
3236*a67afe4dSAndroid Build Coastguard Worker 
3237*a67afe4dSAndroid Build Coastguard Worker                   if (shift == 0)
3238*a67afe4dSAndroid Build Coastguard Worker                   {
3239*a67afe4dSAndroid Build Coastguard Worker                      shift = 7;
3240*a67afe4dSAndroid Build Coastguard Worker                      sp++;
3241*a67afe4dSAndroid Build Coastguard Worker                   }
3242*a67afe4dSAndroid Build Coastguard Worker 
3243*a67afe4dSAndroid Build Coastguard Worker                   else
3244*a67afe4dSAndroid Build Coastguard Worker                      shift--;
3245*a67afe4dSAndroid Build Coastguard Worker                }
3246*a67afe4dSAndroid Build Coastguard Worker                break;
3247*a67afe4dSAndroid Build Coastguard Worker             }
3248*a67afe4dSAndroid Build Coastguard Worker 
3249*a67afe4dSAndroid Build Coastguard Worker             case 2:
3250*a67afe4dSAndroid Build Coastguard Worker             {
3251*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
3252*a67afe4dSAndroid Build Coastguard Worker                if (gamma_table != NULL)
3253*a67afe4dSAndroid Build Coastguard Worker                {
3254*a67afe4dSAndroid Build Coastguard Worker                   sp = row;
3255*a67afe4dSAndroid Build Coastguard Worker                   shift = 6;
3256*a67afe4dSAndroid Build Coastguard Worker                   for (i = 0; i < row_width; i++)
3257*a67afe4dSAndroid Build Coastguard Worker                   {
3258*a67afe4dSAndroid Build Coastguard Worker                      if ((png_uint_16)((*sp >> shift) & 0x03)
3259*a67afe4dSAndroid Build Coastguard Worker                          == png_ptr->trans_color.gray)
3260*a67afe4dSAndroid Build Coastguard Worker                      {
3261*a67afe4dSAndroid Build Coastguard Worker                         unsigned int tmp = *sp & (0x3f3f >> (6 - shift));
3262*a67afe4dSAndroid Build Coastguard Worker                         tmp |=
3263*a67afe4dSAndroid Build Coastguard Worker                            (unsigned int)png_ptr->background.gray << shift;
3264*a67afe4dSAndroid Build Coastguard Worker                         *sp = (png_byte)(tmp & 0xff);
3265*a67afe4dSAndroid Build Coastguard Worker                      }
3266*a67afe4dSAndroid Build Coastguard Worker 
3267*a67afe4dSAndroid Build Coastguard Worker                      else
3268*a67afe4dSAndroid Build Coastguard Worker                      {
3269*a67afe4dSAndroid Build Coastguard Worker                         unsigned int p = (*sp >> shift) & 0x03;
3270*a67afe4dSAndroid Build Coastguard Worker                         unsigned int g = (gamma_table [p | (p << 2) |
3271*a67afe4dSAndroid Build Coastguard Worker                             (p << 4) | (p << 6)] >> 6) & 0x03;
3272*a67afe4dSAndroid Build Coastguard Worker                         unsigned int tmp = *sp & (0x3f3f >> (6 - shift));
3273*a67afe4dSAndroid Build Coastguard Worker                         tmp |= (unsigned int)(g << shift);
3274*a67afe4dSAndroid Build Coastguard Worker                         *sp = (png_byte)(tmp & 0xff);
3275*a67afe4dSAndroid Build Coastguard Worker                      }
3276*a67afe4dSAndroid Build Coastguard Worker 
3277*a67afe4dSAndroid Build Coastguard Worker                      if (shift == 0)
3278*a67afe4dSAndroid Build Coastguard Worker                      {
3279*a67afe4dSAndroid Build Coastguard Worker                         shift = 6;
3280*a67afe4dSAndroid Build Coastguard Worker                         sp++;
3281*a67afe4dSAndroid Build Coastguard Worker                      }
3282*a67afe4dSAndroid Build Coastguard Worker 
3283*a67afe4dSAndroid Build Coastguard Worker                      else
3284*a67afe4dSAndroid Build Coastguard Worker                         shift -= 2;
3285*a67afe4dSAndroid Build Coastguard Worker                   }
3286*a67afe4dSAndroid Build Coastguard Worker                }
3287*a67afe4dSAndroid Build Coastguard Worker 
3288*a67afe4dSAndroid Build Coastguard Worker                else
3289*a67afe4dSAndroid Build Coastguard Worker #endif
3290*a67afe4dSAndroid Build Coastguard Worker                {
3291*a67afe4dSAndroid Build Coastguard Worker                   sp = row;
3292*a67afe4dSAndroid Build Coastguard Worker                   shift = 6;
3293*a67afe4dSAndroid Build Coastguard Worker                   for (i = 0; i < row_width; i++)
3294*a67afe4dSAndroid Build Coastguard Worker                   {
3295*a67afe4dSAndroid Build Coastguard Worker                      if ((png_uint_16)((*sp >> shift) & 0x03)
3296*a67afe4dSAndroid Build Coastguard Worker                          == png_ptr->trans_color.gray)
3297*a67afe4dSAndroid Build Coastguard Worker                      {
3298*a67afe4dSAndroid Build Coastguard Worker                         unsigned int tmp = *sp & (0x3f3f >> (6 - shift));
3299*a67afe4dSAndroid Build Coastguard Worker                         tmp |=
3300*a67afe4dSAndroid Build Coastguard Worker                             (unsigned int)png_ptr->background.gray << shift;
3301*a67afe4dSAndroid Build Coastguard Worker                         *sp = (png_byte)(tmp & 0xff);
3302*a67afe4dSAndroid Build Coastguard Worker                      }
3303*a67afe4dSAndroid Build Coastguard Worker 
3304*a67afe4dSAndroid Build Coastguard Worker                      if (shift == 0)
3305*a67afe4dSAndroid Build Coastguard Worker                      {
3306*a67afe4dSAndroid Build Coastguard Worker                         shift = 6;
3307*a67afe4dSAndroid Build Coastguard Worker                         sp++;
3308*a67afe4dSAndroid Build Coastguard Worker                      }
3309*a67afe4dSAndroid Build Coastguard Worker 
3310*a67afe4dSAndroid Build Coastguard Worker                      else
3311*a67afe4dSAndroid Build Coastguard Worker                         shift -= 2;
3312*a67afe4dSAndroid Build Coastguard Worker                   }
3313*a67afe4dSAndroid Build Coastguard Worker                }
3314*a67afe4dSAndroid Build Coastguard Worker                break;
3315*a67afe4dSAndroid Build Coastguard Worker             }
3316*a67afe4dSAndroid Build Coastguard Worker 
3317*a67afe4dSAndroid Build Coastguard Worker             case 4:
3318*a67afe4dSAndroid Build Coastguard Worker             {
3319*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
3320*a67afe4dSAndroid Build Coastguard Worker                if (gamma_table != NULL)
3321*a67afe4dSAndroid Build Coastguard Worker                {
3322*a67afe4dSAndroid Build Coastguard Worker                   sp = row;
3323*a67afe4dSAndroid Build Coastguard Worker                   shift = 4;
3324*a67afe4dSAndroid Build Coastguard Worker                   for (i = 0; i < row_width; i++)
3325*a67afe4dSAndroid Build Coastguard Worker                   {
3326*a67afe4dSAndroid Build Coastguard Worker                      if ((png_uint_16)((*sp >> shift) & 0x0f)
3327*a67afe4dSAndroid Build Coastguard Worker                          == png_ptr->trans_color.gray)
3328*a67afe4dSAndroid Build Coastguard Worker                      {
3329*a67afe4dSAndroid Build Coastguard Worker                         unsigned int tmp = *sp & (0x0f0f >> (4 - shift));
3330*a67afe4dSAndroid Build Coastguard Worker                         tmp |=
3331*a67afe4dSAndroid Build Coastguard Worker                            (unsigned int)(png_ptr->background.gray << shift);
3332*a67afe4dSAndroid Build Coastguard Worker                         *sp = (png_byte)(tmp & 0xff);
3333*a67afe4dSAndroid Build Coastguard Worker                      }
3334*a67afe4dSAndroid Build Coastguard Worker 
3335*a67afe4dSAndroid Build Coastguard Worker                      else
3336*a67afe4dSAndroid Build Coastguard Worker                      {
3337*a67afe4dSAndroid Build Coastguard Worker                         unsigned int p = (*sp >> shift) & 0x0f;
3338*a67afe4dSAndroid Build Coastguard Worker                         unsigned int g = (gamma_table[p | (p << 4)] >> 4) &
3339*a67afe4dSAndroid Build Coastguard Worker                            0x0f;
3340*a67afe4dSAndroid Build Coastguard Worker                         unsigned int tmp = *sp & (0x0f0f >> (4 - shift));
3341*a67afe4dSAndroid Build Coastguard Worker                         tmp |= (unsigned int)(g << shift);
3342*a67afe4dSAndroid Build Coastguard Worker                         *sp = (png_byte)(tmp & 0xff);
3343*a67afe4dSAndroid Build Coastguard Worker                      }
3344*a67afe4dSAndroid Build Coastguard Worker 
3345*a67afe4dSAndroid Build Coastguard Worker                      if (shift == 0)
3346*a67afe4dSAndroid Build Coastguard Worker                      {
3347*a67afe4dSAndroid Build Coastguard Worker                         shift = 4;
3348*a67afe4dSAndroid Build Coastguard Worker                         sp++;
3349*a67afe4dSAndroid Build Coastguard Worker                      }
3350*a67afe4dSAndroid Build Coastguard Worker 
3351*a67afe4dSAndroid Build Coastguard Worker                      else
3352*a67afe4dSAndroid Build Coastguard Worker                         shift -= 4;
3353*a67afe4dSAndroid Build Coastguard Worker                   }
3354*a67afe4dSAndroid Build Coastguard Worker                }
3355*a67afe4dSAndroid Build Coastguard Worker 
3356*a67afe4dSAndroid Build Coastguard Worker                else
3357*a67afe4dSAndroid Build Coastguard Worker #endif
3358*a67afe4dSAndroid Build Coastguard Worker                {
3359*a67afe4dSAndroid Build Coastguard Worker                   sp = row;
3360*a67afe4dSAndroid Build Coastguard Worker                   shift = 4;
3361*a67afe4dSAndroid Build Coastguard Worker                   for (i = 0; i < row_width; i++)
3362*a67afe4dSAndroid Build Coastguard Worker                   {
3363*a67afe4dSAndroid Build Coastguard Worker                      if ((png_uint_16)((*sp >> shift) & 0x0f)
3364*a67afe4dSAndroid Build Coastguard Worker                          == png_ptr->trans_color.gray)
3365*a67afe4dSAndroid Build Coastguard Worker                      {
3366*a67afe4dSAndroid Build Coastguard Worker                         unsigned int tmp = *sp & (0x0f0f >> (4 - shift));
3367*a67afe4dSAndroid Build Coastguard Worker                         tmp |=
3368*a67afe4dSAndroid Build Coastguard Worker                            (unsigned int)(png_ptr->background.gray << shift);
3369*a67afe4dSAndroid Build Coastguard Worker                         *sp = (png_byte)(tmp & 0xff);
3370*a67afe4dSAndroid Build Coastguard Worker                      }
3371*a67afe4dSAndroid Build Coastguard Worker 
3372*a67afe4dSAndroid Build Coastguard Worker                      if (shift == 0)
3373*a67afe4dSAndroid Build Coastguard Worker                      {
3374*a67afe4dSAndroid Build Coastguard Worker                         shift = 4;
3375*a67afe4dSAndroid Build Coastguard Worker                         sp++;
3376*a67afe4dSAndroid Build Coastguard Worker                      }
3377*a67afe4dSAndroid Build Coastguard Worker 
3378*a67afe4dSAndroid Build Coastguard Worker                      else
3379*a67afe4dSAndroid Build Coastguard Worker                         shift -= 4;
3380*a67afe4dSAndroid Build Coastguard Worker                   }
3381*a67afe4dSAndroid Build Coastguard Worker                }
3382*a67afe4dSAndroid Build Coastguard Worker                break;
3383*a67afe4dSAndroid Build Coastguard Worker             }
3384*a67afe4dSAndroid Build Coastguard Worker 
3385*a67afe4dSAndroid Build Coastguard Worker             case 8:
3386*a67afe4dSAndroid Build Coastguard Worker             {
3387*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
3388*a67afe4dSAndroid Build Coastguard Worker                if (gamma_table != NULL)
3389*a67afe4dSAndroid Build Coastguard Worker                {
3390*a67afe4dSAndroid Build Coastguard Worker                   sp = row;
3391*a67afe4dSAndroid Build Coastguard Worker                   for (i = 0; i < row_width; i++, sp++)
3392*a67afe4dSAndroid Build Coastguard Worker                   {
3393*a67afe4dSAndroid Build Coastguard Worker                      if (*sp == png_ptr->trans_color.gray)
3394*a67afe4dSAndroid Build Coastguard Worker                         *sp = (png_byte)png_ptr->background.gray;
3395*a67afe4dSAndroid Build Coastguard Worker 
3396*a67afe4dSAndroid Build Coastguard Worker                      else
3397*a67afe4dSAndroid Build Coastguard Worker                         *sp = gamma_table[*sp];
3398*a67afe4dSAndroid Build Coastguard Worker                   }
3399*a67afe4dSAndroid Build Coastguard Worker                }
3400*a67afe4dSAndroid Build Coastguard Worker                else
3401*a67afe4dSAndroid Build Coastguard Worker #endif
3402*a67afe4dSAndroid Build Coastguard Worker                {
3403*a67afe4dSAndroid Build Coastguard Worker                   sp = row;
3404*a67afe4dSAndroid Build Coastguard Worker                   for (i = 0; i < row_width; i++, sp++)
3405*a67afe4dSAndroid Build Coastguard Worker                   {
3406*a67afe4dSAndroid Build Coastguard Worker                      if (*sp == png_ptr->trans_color.gray)
3407*a67afe4dSAndroid Build Coastguard Worker                         *sp = (png_byte)png_ptr->background.gray;
3408*a67afe4dSAndroid Build Coastguard Worker                   }
3409*a67afe4dSAndroid Build Coastguard Worker                }
3410*a67afe4dSAndroid Build Coastguard Worker                break;
3411*a67afe4dSAndroid Build Coastguard Worker             }
3412*a67afe4dSAndroid Build Coastguard Worker 
3413*a67afe4dSAndroid Build Coastguard Worker             case 16:
3414*a67afe4dSAndroid Build Coastguard Worker             {
3415*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
3416*a67afe4dSAndroid Build Coastguard Worker                if (gamma_16 != NULL)
3417*a67afe4dSAndroid Build Coastguard Worker                {
3418*a67afe4dSAndroid Build Coastguard Worker                   sp = row;
3419*a67afe4dSAndroid Build Coastguard Worker                   for (i = 0; i < row_width; i++, sp += 2)
3420*a67afe4dSAndroid Build Coastguard Worker                   {
3421*a67afe4dSAndroid Build Coastguard Worker                      png_uint_16 v;
3422*a67afe4dSAndroid Build Coastguard Worker 
3423*a67afe4dSAndroid Build Coastguard Worker                      v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3424*a67afe4dSAndroid Build Coastguard Worker 
3425*a67afe4dSAndroid Build Coastguard Worker                      if (v == png_ptr->trans_color.gray)
3426*a67afe4dSAndroid Build Coastguard Worker                      {
3427*a67afe4dSAndroid Build Coastguard Worker                         /* Background is already in screen gamma */
3428*a67afe4dSAndroid Build Coastguard Worker                         *sp = (png_byte)((png_ptr->background.gray >> 8)
3429*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3430*a67afe4dSAndroid Build Coastguard Worker                         *(sp + 1) = (png_byte)(png_ptr->background.gray
3431*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3432*a67afe4dSAndroid Build Coastguard Worker                      }
3433*a67afe4dSAndroid Build Coastguard Worker 
3434*a67afe4dSAndroid Build Coastguard Worker                      else
3435*a67afe4dSAndroid Build Coastguard Worker                      {
3436*a67afe4dSAndroid Build Coastguard Worker                         v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
3437*a67afe4dSAndroid Build Coastguard Worker                         *sp = (png_byte)((v >> 8) & 0xff);
3438*a67afe4dSAndroid Build Coastguard Worker                         *(sp + 1) = (png_byte)(v & 0xff);
3439*a67afe4dSAndroid Build Coastguard Worker                      }
3440*a67afe4dSAndroid Build Coastguard Worker                   }
3441*a67afe4dSAndroid Build Coastguard Worker                }
3442*a67afe4dSAndroid Build Coastguard Worker                else
3443*a67afe4dSAndroid Build Coastguard Worker #endif
3444*a67afe4dSAndroid Build Coastguard Worker                {
3445*a67afe4dSAndroid Build Coastguard Worker                   sp = row;
3446*a67afe4dSAndroid Build Coastguard Worker                   for (i = 0; i < row_width; i++, sp += 2)
3447*a67afe4dSAndroid Build Coastguard Worker                   {
3448*a67afe4dSAndroid Build Coastguard Worker                      png_uint_16 v;
3449*a67afe4dSAndroid Build Coastguard Worker 
3450*a67afe4dSAndroid Build Coastguard Worker                      v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3451*a67afe4dSAndroid Build Coastguard Worker 
3452*a67afe4dSAndroid Build Coastguard Worker                      if (v == png_ptr->trans_color.gray)
3453*a67afe4dSAndroid Build Coastguard Worker                      {
3454*a67afe4dSAndroid Build Coastguard Worker                         *sp = (png_byte)((png_ptr->background.gray >> 8)
3455*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3456*a67afe4dSAndroid Build Coastguard Worker                         *(sp + 1) = (png_byte)(png_ptr->background.gray
3457*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3458*a67afe4dSAndroid Build Coastguard Worker                      }
3459*a67afe4dSAndroid Build Coastguard Worker                   }
3460*a67afe4dSAndroid Build Coastguard Worker                }
3461*a67afe4dSAndroid Build Coastguard Worker                break;
3462*a67afe4dSAndroid Build Coastguard Worker             }
3463*a67afe4dSAndroid Build Coastguard Worker 
3464*a67afe4dSAndroid Build Coastguard Worker             default:
3465*a67afe4dSAndroid Build Coastguard Worker                break;
3466*a67afe4dSAndroid Build Coastguard Worker          }
3467*a67afe4dSAndroid Build Coastguard Worker          break;
3468*a67afe4dSAndroid Build Coastguard Worker       }
3469*a67afe4dSAndroid Build Coastguard Worker 
3470*a67afe4dSAndroid Build Coastguard Worker       case PNG_COLOR_TYPE_RGB:
3471*a67afe4dSAndroid Build Coastguard Worker       {
3472*a67afe4dSAndroid Build Coastguard Worker          if (row_info->bit_depth == 8)
3473*a67afe4dSAndroid Build Coastguard Worker          {
3474*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
3475*a67afe4dSAndroid Build Coastguard Worker             if (gamma_table != NULL)
3476*a67afe4dSAndroid Build Coastguard Worker             {
3477*a67afe4dSAndroid Build Coastguard Worker                sp = row;
3478*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++, sp += 3)
3479*a67afe4dSAndroid Build Coastguard Worker                {
3480*a67afe4dSAndroid Build Coastguard Worker                   if (*sp == png_ptr->trans_color.red &&
3481*a67afe4dSAndroid Build Coastguard Worker                       *(sp + 1) == png_ptr->trans_color.green &&
3482*a67afe4dSAndroid Build Coastguard Worker                       *(sp + 2) == png_ptr->trans_color.blue)
3483*a67afe4dSAndroid Build Coastguard Worker                   {
3484*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)png_ptr->background.red;
3485*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = (png_byte)png_ptr->background.green;
3486*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 2) = (png_byte)png_ptr->background.blue;
3487*a67afe4dSAndroid Build Coastguard Worker                   }
3488*a67afe4dSAndroid Build Coastguard Worker 
3489*a67afe4dSAndroid Build Coastguard Worker                   else
3490*a67afe4dSAndroid Build Coastguard Worker                   {
3491*a67afe4dSAndroid Build Coastguard Worker                      *sp = gamma_table[*sp];
3492*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = gamma_table[*(sp + 1)];
3493*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 2) = gamma_table[*(sp + 2)];
3494*a67afe4dSAndroid Build Coastguard Worker                   }
3495*a67afe4dSAndroid Build Coastguard Worker                }
3496*a67afe4dSAndroid Build Coastguard Worker             }
3497*a67afe4dSAndroid Build Coastguard Worker             else
3498*a67afe4dSAndroid Build Coastguard Worker #endif
3499*a67afe4dSAndroid Build Coastguard Worker             {
3500*a67afe4dSAndroid Build Coastguard Worker                sp = row;
3501*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++, sp += 3)
3502*a67afe4dSAndroid Build Coastguard Worker                {
3503*a67afe4dSAndroid Build Coastguard Worker                   if (*sp == png_ptr->trans_color.red &&
3504*a67afe4dSAndroid Build Coastguard Worker                       *(sp + 1) == png_ptr->trans_color.green &&
3505*a67afe4dSAndroid Build Coastguard Worker                       *(sp + 2) == png_ptr->trans_color.blue)
3506*a67afe4dSAndroid Build Coastguard Worker                   {
3507*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)png_ptr->background.red;
3508*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = (png_byte)png_ptr->background.green;
3509*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 2) = (png_byte)png_ptr->background.blue;
3510*a67afe4dSAndroid Build Coastguard Worker                   }
3511*a67afe4dSAndroid Build Coastguard Worker                }
3512*a67afe4dSAndroid Build Coastguard Worker             }
3513*a67afe4dSAndroid Build Coastguard Worker          }
3514*a67afe4dSAndroid Build Coastguard Worker          else /* if (row_info->bit_depth == 16) */
3515*a67afe4dSAndroid Build Coastguard Worker          {
3516*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
3517*a67afe4dSAndroid Build Coastguard Worker             if (gamma_16 != NULL)
3518*a67afe4dSAndroid Build Coastguard Worker             {
3519*a67afe4dSAndroid Build Coastguard Worker                sp = row;
3520*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++, sp += 6)
3521*a67afe4dSAndroid Build Coastguard Worker                {
3522*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3523*a67afe4dSAndroid Build Coastguard Worker 
3524*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
3525*a67afe4dSAndroid Build Coastguard Worker                       + *(sp + 3));
3526*a67afe4dSAndroid Build Coastguard Worker 
3527*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
3528*a67afe4dSAndroid Build Coastguard Worker                       + *(sp + 5));
3529*a67afe4dSAndroid Build Coastguard Worker 
3530*a67afe4dSAndroid Build Coastguard Worker                   if (r == png_ptr->trans_color.red &&
3531*a67afe4dSAndroid Build Coastguard Worker                       g == png_ptr->trans_color.green &&
3532*a67afe4dSAndroid Build Coastguard Worker                       b == png_ptr->trans_color.blue)
3533*a67afe4dSAndroid Build Coastguard Worker                   {
3534*a67afe4dSAndroid Build Coastguard Worker                      /* Background is already in screen gamma */
3535*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
3536*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
3537*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
3538*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3539*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 3) = (png_byte)(png_ptr->background.green
3540*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3541*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
3542*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3543*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
3544*a67afe4dSAndroid Build Coastguard Worker                   }
3545*a67afe4dSAndroid Build Coastguard Worker 
3546*a67afe4dSAndroid Build Coastguard Worker                   else
3547*a67afe4dSAndroid Build Coastguard Worker                   {
3548*a67afe4dSAndroid Build Coastguard Worker                      png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
3549*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)((v >> 8) & 0xff);
3550*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = (png_byte)(v & 0xff);
3551*a67afe4dSAndroid Build Coastguard Worker 
3552*a67afe4dSAndroid Build Coastguard Worker                      v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
3553*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 2) = (png_byte)((v >> 8) & 0xff);
3554*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 3) = (png_byte)(v & 0xff);
3555*a67afe4dSAndroid Build Coastguard Worker 
3556*a67afe4dSAndroid Build Coastguard Worker                      v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
3557*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 4) = (png_byte)((v >> 8) & 0xff);
3558*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 5) = (png_byte)(v & 0xff);
3559*a67afe4dSAndroid Build Coastguard Worker                   }
3560*a67afe4dSAndroid Build Coastguard Worker                }
3561*a67afe4dSAndroid Build Coastguard Worker             }
3562*a67afe4dSAndroid Build Coastguard Worker 
3563*a67afe4dSAndroid Build Coastguard Worker             else
3564*a67afe4dSAndroid Build Coastguard Worker #endif
3565*a67afe4dSAndroid Build Coastguard Worker             {
3566*a67afe4dSAndroid Build Coastguard Worker                sp = row;
3567*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++, sp += 6)
3568*a67afe4dSAndroid Build Coastguard Worker                {
3569*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3570*a67afe4dSAndroid Build Coastguard Worker 
3571*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
3572*a67afe4dSAndroid Build Coastguard Worker                       + *(sp + 3));
3573*a67afe4dSAndroid Build Coastguard Worker 
3574*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
3575*a67afe4dSAndroid Build Coastguard Worker                       + *(sp + 5));
3576*a67afe4dSAndroid Build Coastguard Worker 
3577*a67afe4dSAndroid Build Coastguard Worker                   if (r == png_ptr->trans_color.red &&
3578*a67afe4dSAndroid Build Coastguard Worker                       g == png_ptr->trans_color.green &&
3579*a67afe4dSAndroid Build Coastguard Worker                       b == png_ptr->trans_color.blue)
3580*a67afe4dSAndroid Build Coastguard Worker                   {
3581*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
3582*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
3583*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
3584*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3585*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 3) = (png_byte)(png_ptr->background.green
3586*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3587*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
3588*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3589*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
3590*a67afe4dSAndroid Build Coastguard Worker                   }
3591*a67afe4dSAndroid Build Coastguard Worker                }
3592*a67afe4dSAndroid Build Coastguard Worker             }
3593*a67afe4dSAndroid Build Coastguard Worker          }
3594*a67afe4dSAndroid Build Coastguard Worker          break;
3595*a67afe4dSAndroid Build Coastguard Worker       }
3596*a67afe4dSAndroid Build Coastguard Worker 
3597*a67afe4dSAndroid Build Coastguard Worker       case PNG_COLOR_TYPE_GRAY_ALPHA:
3598*a67afe4dSAndroid Build Coastguard Worker       {
3599*a67afe4dSAndroid Build Coastguard Worker          if (row_info->bit_depth == 8)
3600*a67afe4dSAndroid Build Coastguard Worker          {
3601*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
3602*a67afe4dSAndroid Build Coastguard Worker             if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
3603*a67afe4dSAndroid Build Coastguard Worker                 gamma_table != NULL)
3604*a67afe4dSAndroid Build Coastguard Worker             {
3605*a67afe4dSAndroid Build Coastguard Worker                sp = row;
3606*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++, sp += 2)
3607*a67afe4dSAndroid Build Coastguard Worker                {
3608*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 a = *(sp + 1);
3609*a67afe4dSAndroid Build Coastguard Worker 
3610*a67afe4dSAndroid Build Coastguard Worker                   if (a == 0xff)
3611*a67afe4dSAndroid Build Coastguard Worker                      *sp = gamma_table[*sp];
3612*a67afe4dSAndroid Build Coastguard Worker 
3613*a67afe4dSAndroid Build Coastguard Worker                   else if (a == 0)
3614*a67afe4dSAndroid Build Coastguard Worker                   {
3615*a67afe4dSAndroid Build Coastguard Worker                      /* Background is already in screen gamma */
3616*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)png_ptr->background.gray;
3617*a67afe4dSAndroid Build Coastguard Worker                   }
3618*a67afe4dSAndroid Build Coastguard Worker 
3619*a67afe4dSAndroid Build Coastguard Worker                   else
3620*a67afe4dSAndroid Build Coastguard Worker                   {
3621*a67afe4dSAndroid Build Coastguard Worker                      png_byte v, w;
3622*a67afe4dSAndroid Build Coastguard Worker 
3623*a67afe4dSAndroid Build Coastguard Worker                      v = gamma_to_1[*sp];
3624*a67afe4dSAndroid Build Coastguard Worker                      png_composite(w, v, a, png_ptr->background_1.gray);
3625*a67afe4dSAndroid Build Coastguard Worker                      if (optimize == 0)
3626*a67afe4dSAndroid Build Coastguard Worker                         w = gamma_from_1[w];
3627*a67afe4dSAndroid Build Coastguard Worker                      *sp = w;
3628*a67afe4dSAndroid Build Coastguard Worker                   }
3629*a67afe4dSAndroid Build Coastguard Worker                }
3630*a67afe4dSAndroid Build Coastguard Worker             }
3631*a67afe4dSAndroid Build Coastguard Worker             else
3632*a67afe4dSAndroid Build Coastguard Worker #endif
3633*a67afe4dSAndroid Build Coastguard Worker             {
3634*a67afe4dSAndroid Build Coastguard Worker                sp = row;
3635*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++, sp += 2)
3636*a67afe4dSAndroid Build Coastguard Worker                {
3637*a67afe4dSAndroid Build Coastguard Worker                   png_byte a = *(sp + 1);
3638*a67afe4dSAndroid Build Coastguard Worker 
3639*a67afe4dSAndroid Build Coastguard Worker                   if (a == 0)
3640*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)png_ptr->background.gray;
3641*a67afe4dSAndroid Build Coastguard Worker 
3642*a67afe4dSAndroid Build Coastguard Worker                   else if (a < 0xff)
3643*a67afe4dSAndroid Build Coastguard Worker                      png_composite(*sp, *sp, a, png_ptr->background.gray);
3644*a67afe4dSAndroid Build Coastguard Worker                }
3645*a67afe4dSAndroid Build Coastguard Worker             }
3646*a67afe4dSAndroid Build Coastguard Worker          }
3647*a67afe4dSAndroid Build Coastguard Worker          else /* if (png_ptr->bit_depth == 16) */
3648*a67afe4dSAndroid Build Coastguard Worker          {
3649*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
3650*a67afe4dSAndroid Build Coastguard Worker             if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3651*a67afe4dSAndroid Build Coastguard Worker                 gamma_16_to_1 != NULL)
3652*a67afe4dSAndroid Build Coastguard Worker             {
3653*a67afe4dSAndroid Build Coastguard Worker                sp = row;
3654*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++, sp += 4)
3655*a67afe4dSAndroid Build Coastguard Worker                {
3656*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8)
3657*a67afe4dSAndroid Build Coastguard Worker                       + *(sp + 3));
3658*a67afe4dSAndroid Build Coastguard Worker 
3659*a67afe4dSAndroid Build Coastguard Worker                   if (a == (png_uint_16)0xffff)
3660*a67afe4dSAndroid Build Coastguard Worker                   {
3661*a67afe4dSAndroid Build Coastguard Worker                      png_uint_16 v;
3662*a67afe4dSAndroid Build Coastguard Worker 
3663*a67afe4dSAndroid Build Coastguard Worker                      v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
3664*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)((v >> 8) & 0xff);
3665*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = (png_byte)(v & 0xff);
3666*a67afe4dSAndroid Build Coastguard Worker                   }
3667*a67afe4dSAndroid Build Coastguard Worker 
3668*a67afe4dSAndroid Build Coastguard Worker                   else if (a == 0)
3669*a67afe4dSAndroid Build Coastguard Worker                   {
3670*a67afe4dSAndroid Build Coastguard Worker                      /* Background is already in screen gamma */
3671*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)((png_ptr->background.gray >> 8)
3672*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3673*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
3674*a67afe4dSAndroid Build Coastguard Worker                   }
3675*a67afe4dSAndroid Build Coastguard Worker 
3676*a67afe4dSAndroid Build Coastguard Worker                   else
3677*a67afe4dSAndroid Build Coastguard Worker                   {
3678*a67afe4dSAndroid Build Coastguard Worker                      png_uint_16 g, v, w;
3679*a67afe4dSAndroid Build Coastguard Worker 
3680*a67afe4dSAndroid Build Coastguard Worker                      g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
3681*a67afe4dSAndroid Build Coastguard Worker                      png_composite_16(v, g, a, png_ptr->background_1.gray);
3682*a67afe4dSAndroid Build Coastguard Worker                      if (optimize != 0)
3683*a67afe4dSAndroid Build Coastguard Worker                         w = v;
3684*a67afe4dSAndroid Build Coastguard Worker                      else
3685*a67afe4dSAndroid Build Coastguard Worker                         w = gamma_16_from_1[(v & 0xff) >>
3686*a67afe4dSAndroid Build Coastguard Worker                             gamma_shift][v >> 8];
3687*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)((w >> 8) & 0xff);
3688*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = (png_byte)(w & 0xff);
3689*a67afe4dSAndroid Build Coastguard Worker                   }
3690*a67afe4dSAndroid Build Coastguard Worker                }
3691*a67afe4dSAndroid Build Coastguard Worker             }
3692*a67afe4dSAndroid Build Coastguard Worker             else
3693*a67afe4dSAndroid Build Coastguard Worker #endif
3694*a67afe4dSAndroid Build Coastguard Worker             {
3695*a67afe4dSAndroid Build Coastguard Worker                sp = row;
3696*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++, sp += 4)
3697*a67afe4dSAndroid Build Coastguard Worker                {
3698*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8)
3699*a67afe4dSAndroid Build Coastguard Worker                       + *(sp + 3));
3700*a67afe4dSAndroid Build Coastguard Worker 
3701*a67afe4dSAndroid Build Coastguard Worker                   if (a == 0)
3702*a67afe4dSAndroid Build Coastguard Worker                   {
3703*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)((png_ptr->background.gray >> 8)
3704*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3705*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
3706*a67afe4dSAndroid Build Coastguard Worker                   }
3707*a67afe4dSAndroid Build Coastguard Worker 
3708*a67afe4dSAndroid Build Coastguard Worker                   else if (a < 0xffff)
3709*a67afe4dSAndroid Build Coastguard Worker                   {
3710*a67afe4dSAndroid Build Coastguard Worker                      png_uint_16 g, v;
3711*a67afe4dSAndroid Build Coastguard Worker 
3712*a67afe4dSAndroid Build Coastguard Worker                      g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3713*a67afe4dSAndroid Build Coastguard Worker                      png_composite_16(v, g, a, png_ptr->background.gray);
3714*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)((v >> 8) & 0xff);
3715*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = (png_byte)(v & 0xff);
3716*a67afe4dSAndroid Build Coastguard Worker                   }
3717*a67afe4dSAndroid Build Coastguard Worker                }
3718*a67afe4dSAndroid Build Coastguard Worker             }
3719*a67afe4dSAndroid Build Coastguard Worker          }
3720*a67afe4dSAndroid Build Coastguard Worker          break;
3721*a67afe4dSAndroid Build Coastguard Worker       }
3722*a67afe4dSAndroid Build Coastguard Worker 
3723*a67afe4dSAndroid Build Coastguard Worker       case PNG_COLOR_TYPE_RGB_ALPHA:
3724*a67afe4dSAndroid Build Coastguard Worker       {
3725*a67afe4dSAndroid Build Coastguard Worker          if (row_info->bit_depth == 8)
3726*a67afe4dSAndroid Build Coastguard Worker          {
3727*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
3728*a67afe4dSAndroid Build Coastguard Worker             if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
3729*a67afe4dSAndroid Build Coastguard Worker                 gamma_table != NULL)
3730*a67afe4dSAndroid Build Coastguard Worker             {
3731*a67afe4dSAndroid Build Coastguard Worker                sp = row;
3732*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++, sp += 4)
3733*a67afe4dSAndroid Build Coastguard Worker                {
3734*a67afe4dSAndroid Build Coastguard Worker                   png_byte a = *(sp + 3);
3735*a67afe4dSAndroid Build Coastguard Worker 
3736*a67afe4dSAndroid Build Coastguard Worker                   if (a == 0xff)
3737*a67afe4dSAndroid Build Coastguard Worker                   {
3738*a67afe4dSAndroid Build Coastguard Worker                      *sp = gamma_table[*sp];
3739*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = gamma_table[*(sp + 1)];
3740*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 2) = gamma_table[*(sp + 2)];
3741*a67afe4dSAndroid Build Coastguard Worker                   }
3742*a67afe4dSAndroid Build Coastguard Worker 
3743*a67afe4dSAndroid Build Coastguard Worker                   else if (a == 0)
3744*a67afe4dSAndroid Build Coastguard Worker                   {
3745*a67afe4dSAndroid Build Coastguard Worker                      /* Background is already in screen gamma */
3746*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)png_ptr->background.red;
3747*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = (png_byte)png_ptr->background.green;
3748*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 2) = (png_byte)png_ptr->background.blue;
3749*a67afe4dSAndroid Build Coastguard Worker                   }
3750*a67afe4dSAndroid Build Coastguard Worker 
3751*a67afe4dSAndroid Build Coastguard Worker                   else
3752*a67afe4dSAndroid Build Coastguard Worker                   {
3753*a67afe4dSAndroid Build Coastguard Worker                      png_byte v, w;
3754*a67afe4dSAndroid Build Coastguard Worker 
3755*a67afe4dSAndroid Build Coastguard Worker                      v = gamma_to_1[*sp];
3756*a67afe4dSAndroid Build Coastguard Worker                      png_composite(w, v, a, png_ptr->background_1.red);
3757*a67afe4dSAndroid Build Coastguard Worker                      if (optimize == 0) w = gamma_from_1[w];
3758*a67afe4dSAndroid Build Coastguard Worker                      *sp = w;
3759*a67afe4dSAndroid Build Coastguard Worker 
3760*a67afe4dSAndroid Build Coastguard Worker                      v = gamma_to_1[*(sp + 1)];
3761*a67afe4dSAndroid Build Coastguard Worker                      png_composite(w, v, a, png_ptr->background_1.green);
3762*a67afe4dSAndroid Build Coastguard Worker                      if (optimize == 0) w = gamma_from_1[w];
3763*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = w;
3764*a67afe4dSAndroid Build Coastguard Worker 
3765*a67afe4dSAndroid Build Coastguard Worker                      v = gamma_to_1[*(sp + 2)];
3766*a67afe4dSAndroid Build Coastguard Worker                      png_composite(w, v, a, png_ptr->background_1.blue);
3767*a67afe4dSAndroid Build Coastguard Worker                      if (optimize == 0) w = gamma_from_1[w];
3768*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 2) = w;
3769*a67afe4dSAndroid Build Coastguard Worker                   }
3770*a67afe4dSAndroid Build Coastguard Worker                }
3771*a67afe4dSAndroid Build Coastguard Worker             }
3772*a67afe4dSAndroid Build Coastguard Worker             else
3773*a67afe4dSAndroid Build Coastguard Worker #endif
3774*a67afe4dSAndroid Build Coastguard Worker             {
3775*a67afe4dSAndroid Build Coastguard Worker                sp = row;
3776*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++, sp += 4)
3777*a67afe4dSAndroid Build Coastguard Worker                {
3778*a67afe4dSAndroid Build Coastguard Worker                   png_byte a = *(sp + 3);
3779*a67afe4dSAndroid Build Coastguard Worker 
3780*a67afe4dSAndroid Build Coastguard Worker                   if (a == 0)
3781*a67afe4dSAndroid Build Coastguard Worker                   {
3782*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)png_ptr->background.red;
3783*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = (png_byte)png_ptr->background.green;
3784*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 2) = (png_byte)png_ptr->background.blue;
3785*a67afe4dSAndroid Build Coastguard Worker                   }
3786*a67afe4dSAndroid Build Coastguard Worker 
3787*a67afe4dSAndroid Build Coastguard Worker                   else if (a < 0xff)
3788*a67afe4dSAndroid Build Coastguard Worker                   {
3789*a67afe4dSAndroid Build Coastguard Worker                      png_composite(*sp, *sp, a, png_ptr->background.red);
3790*a67afe4dSAndroid Build Coastguard Worker 
3791*a67afe4dSAndroid Build Coastguard Worker                      png_composite(*(sp + 1), *(sp + 1), a,
3792*a67afe4dSAndroid Build Coastguard Worker                          png_ptr->background.green);
3793*a67afe4dSAndroid Build Coastguard Worker 
3794*a67afe4dSAndroid Build Coastguard Worker                      png_composite(*(sp + 2), *(sp + 2), a,
3795*a67afe4dSAndroid Build Coastguard Worker                          png_ptr->background.blue);
3796*a67afe4dSAndroid Build Coastguard Worker                   }
3797*a67afe4dSAndroid Build Coastguard Worker                }
3798*a67afe4dSAndroid Build Coastguard Worker             }
3799*a67afe4dSAndroid Build Coastguard Worker          }
3800*a67afe4dSAndroid Build Coastguard Worker          else /* if (row_info->bit_depth == 16) */
3801*a67afe4dSAndroid Build Coastguard Worker          {
3802*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
3803*a67afe4dSAndroid Build Coastguard Worker             if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3804*a67afe4dSAndroid Build Coastguard Worker                 gamma_16_to_1 != NULL)
3805*a67afe4dSAndroid Build Coastguard Worker             {
3806*a67afe4dSAndroid Build Coastguard Worker                sp = row;
3807*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++, sp += 8)
3808*a67afe4dSAndroid Build Coastguard Worker                {
3809*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3810*a67afe4dSAndroid Build Coastguard Worker                       << 8) + (png_uint_16)(*(sp + 7)));
3811*a67afe4dSAndroid Build Coastguard Worker 
3812*a67afe4dSAndroid Build Coastguard Worker                   if (a == (png_uint_16)0xffff)
3813*a67afe4dSAndroid Build Coastguard Worker                   {
3814*a67afe4dSAndroid Build Coastguard Worker                      png_uint_16 v;
3815*a67afe4dSAndroid Build Coastguard Worker 
3816*a67afe4dSAndroid Build Coastguard Worker                      v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
3817*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)((v >> 8) & 0xff);
3818*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = (png_byte)(v & 0xff);
3819*a67afe4dSAndroid Build Coastguard Worker 
3820*a67afe4dSAndroid Build Coastguard Worker                      v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
3821*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 2) = (png_byte)((v >> 8) & 0xff);
3822*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 3) = (png_byte)(v & 0xff);
3823*a67afe4dSAndroid Build Coastguard Worker 
3824*a67afe4dSAndroid Build Coastguard Worker                      v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
3825*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 4) = (png_byte)((v >> 8) & 0xff);
3826*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 5) = (png_byte)(v & 0xff);
3827*a67afe4dSAndroid Build Coastguard Worker                   }
3828*a67afe4dSAndroid Build Coastguard Worker 
3829*a67afe4dSAndroid Build Coastguard Worker                   else if (a == 0)
3830*a67afe4dSAndroid Build Coastguard Worker                   {
3831*a67afe4dSAndroid Build Coastguard Worker                      /* Background is already in screen gamma */
3832*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
3833*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
3834*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
3835*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3836*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 3) = (png_byte)(png_ptr->background.green
3837*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3838*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
3839*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3840*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
3841*a67afe4dSAndroid Build Coastguard Worker                   }
3842*a67afe4dSAndroid Build Coastguard Worker 
3843*a67afe4dSAndroid Build Coastguard Worker                   else
3844*a67afe4dSAndroid Build Coastguard Worker                   {
3845*a67afe4dSAndroid Build Coastguard Worker                      png_uint_16 v, w;
3846*a67afe4dSAndroid Build Coastguard Worker 
3847*a67afe4dSAndroid Build Coastguard Worker                      v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
3848*a67afe4dSAndroid Build Coastguard Worker                      png_composite_16(w, v, a, png_ptr->background_1.red);
3849*a67afe4dSAndroid Build Coastguard Worker                      if (optimize == 0)
3850*a67afe4dSAndroid Build Coastguard Worker                         w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >>
3851*a67afe4dSAndroid Build Coastguard Worker                              8];
3852*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)((w >> 8) & 0xff);
3853*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = (png_byte)(w & 0xff);
3854*a67afe4dSAndroid Build Coastguard Worker 
3855*a67afe4dSAndroid Build Coastguard Worker                      v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
3856*a67afe4dSAndroid Build Coastguard Worker                      png_composite_16(w, v, a, png_ptr->background_1.green);
3857*a67afe4dSAndroid Build Coastguard Worker                      if (optimize == 0)
3858*a67afe4dSAndroid Build Coastguard Worker                         w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >>
3859*a67afe4dSAndroid Build Coastguard Worker                              8];
3860*a67afe4dSAndroid Build Coastguard Worker 
3861*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 2) = (png_byte)((w >> 8) & 0xff);
3862*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 3) = (png_byte)(w & 0xff);
3863*a67afe4dSAndroid Build Coastguard Worker 
3864*a67afe4dSAndroid Build Coastguard Worker                      v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
3865*a67afe4dSAndroid Build Coastguard Worker                      png_composite_16(w, v, a, png_ptr->background_1.blue);
3866*a67afe4dSAndroid Build Coastguard Worker                      if (optimize == 0)
3867*a67afe4dSAndroid Build Coastguard Worker                         w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >>
3868*a67afe4dSAndroid Build Coastguard Worker                              8];
3869*a67afe4dSAndroid Build Coastguard Worker 
3870*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 4) = (png_byte)((w >> 8) & 0xff);
3871*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 5) = (png_byte)(w & 0xff);
3872*a67afe4dSAndroid Build Coastguard Worker                   }
3873*a67afe4dSAndroid Build Coastguard Worker                }
3874*a67afe4dSAndroid Build Coastguard Worker             }
3875*a67afe4dSAndroid Build Coastguard Worker 
3876*a67afe4dSAndroid Build Coastguard Worker             else
3877*a67afe4dSAndroid Build Coastguard Worker #endif
3878*a67afe4dSAndroid Build Coastguard Worker             {
3879*a67afe4dSAndroid Build Coastguard Worker                sp = row;
3880*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++, sp += 8)
3881*a67afe4dSAndroid Build Coastguard Worker                {
3882*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3883*a67afe4dSAndroid Build Coastguard Worker                       << 8) + (png_uint_16)(*(sp + 7)));
3884*a67afe4dSAndroid Build Coastguard Worker 
3885*a67afe4dSAndroid Build Coastguard Worker                   if (a == 0)
3886*a67afe4dSAndroid Build Coastguard Worker                   {
3887*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
3888*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
3889*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
3890*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3891*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 3) = (png_byte)(png_ptr->background.green
3892*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3893*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
3894*a67afe4dSAndroid Build Coastguard Worker                              & 0xff);
3895*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
3896*a67afe4dSAndroid Build Coastguard Worker                   }
3897*a67afe4dSAndroid Build Coastguard Worker 
3898*a67afe4dSAndroid Build Coastguard Worker                   else if (a < 0xffff)
3899*a67afe4dSAndroid Build Coastguard Worker                   {
3900*a67afe4dSAndroid Build Coastguard Worker                      png_uint_16 v;
3901*a67afe4dSAndroid Build Coastguard Worker 
3902*a67afe4dSAndroid Build Coastguard Worker                      png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3903*a67afe4dSAndroid Build Coastguard Worker                      png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
3904*a67afe4dSAndroid Build Coastguard Worker                          + *(sp + 3));
3905*a67afe4dSAndroid Build Coastguard Worker                      png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
3906*a67afe4dSAndroid Build Coastguard Worker                          + *(sp + 5));
3907*a67afe4dSAndroid Build Coastguard Worker 
3908*a67afe4dSAndroid Build Coastguard Worker                      png_composite_16(v, r, a, png_ptr->background.red);
3909*a67afe4dSAndroid Build Coastguard Worker                      *sp = (png_byte)((v >> 8) & 0xff);
3910*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 1) = (png_byte)(v & 0xff);
3911*a67afe4dSAndroid Build Coastguard Worker 
3912*a67afe4dSAndroid Build Coastguard Worker                      png_composite_16(v, g, a, png_ptr->background.green);
3913*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 2) = (png_byte)((v >> 8) & 0xff);
3914*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 3) = (png_byte)(v & 0xff);
3915*a67afe4dSAndroid Build Coastguard Worker 
3916*a67afe4dSAndroid Build Coastguard Worker                      png_composite_16(v, b, a, png_ptr->background.blue);
3917*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 4) = (png_byte)((v >> 8) & 0xff);
3918*a67afe4dSAndroid Build Coastguard Worker                      *(sp + 5) = (png_byte)(v & 0xff);
3919*a67afe4dSAndroid Build Coastguard Worker                   }
3920*a67afe4dSAndroid Build Coastguard Worker                }
3921*a67afe4dSAndroid Build Coastguard Worker             }
3922*a67afe4dSAndroid Build Coastguard Worker          }
3923*a67afe4dSAndroid Build Coastguard Worker          break;
3924*a67afe4dSAndroid Build Coastguard Worker       }
3925*a67afe4dSAndroid Build Coastguard Worker 
3926*a67afe4dSAndroid Build Coastguard Worker       default:
3927*a67afe4dSAndroid Build Coastguard Worker          break;
3928*a67afe4dSAndroid Build Coastguard Worker    }
3929*a67afe4dSAndroid Build Coastguard Worker }
3930*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_BACKGROUND || READ_ALPHA_MODE */
3931*a67afe4dSAndroid Build Coastguard Worker 
3932*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
3933*a67afe4dSAndroid Build Coastguard Worker /* Gamma correct the image, avoiding the alpha channel.  Make sure
3934*a67afe4dSAndroid Build Coastguard Worker  * you do this after you deal with the transparency issue on grayscale
3935*a67afe4dSAndroid Build Coastguard Worker  * or RGB images. If your bit depth is 8, use gamma_table, if it
3936*a67afe4dSAndroid Build Coastguard Worker  * is 16, use gamma_16_table and gamma_shift.  Build these with
3937*a67afe4dSAndroid Build Coastguard Worker  * build_gamma_table().
3938*a67afe4dSAndroid Build Coastguard Worker  */
3939*a67afe4dSAndroid Build Coastguard Worker static void
png_do_gamma(png_row_infop row_info,png_bytep row,png_structrp png_ptr)3940*a67afe4dSAndroid Build Coastguard Worker png_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr)
3941*a67afe4dSAndroid Build Coastguard Worker {
3942*a67afe4dSAndroid Build Coastguard Worker    png_const_bytep gamma_table = png_ptr->gamma_table;
3943*a67afe4dSAndroid Build Coastguard Worker    png_const_uint_16pp gamma_16_table = png_ptr->gamma_16_table;
3944*a67afe4dSAndroid Build Coastguard Worker    int gamma_shift = png_ptr->gamma_shift;
3945*a67afe4dSAndroid Build Coastguard Worker 
3946*a67afe4dSAndroid Build Coastguard Worker    png_bytep sp;
3947*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 i;
3948*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 row_width=row_info->width;
3949*a67afe4dSAndroid Build Coastguard Worker 
3950*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_do_gamma");
3951*a67afe4dSAndroid Build Coastguard Worker 
3952*a67afe4dSAndroid Build Coastguard Worker    if (((row_info->bit_depth <= 8 && gamma_table != NULL) ||
3953*a67afe4dSAndroid Build Coastguard Worker        (row_info->bit_depth == 16 && gamma_16_table != NULL)))
3954*a67afe4dSAndroid Build Coastguard Worker    {
3955*a67afe4dSAndroid Build Coastguard Worker       switch (row_info->color_type)
3956*a67afe4dSAndroid Build Coastguard Worker       {
3957*a67afe4dSAndroid Build Coastguard Worker          case PNG_COLOR_TYPE_RGB:
3958*a67afe4dSAndroid Build Coastguard Worker          {
3959*a67afe4dSAndroid Build Coastguard Worker             if (row_info->bit_depth == 8)
3960*a67afe4dSAndroid Build Coastguard Worker             {
3961*a67afe4dSAndroid Build Coastguard Worker                sp = row;
3962*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++)
3963*a67afe4dSAndroid Build Coastguard Worker                {
3964*a67afe4dSAndroid Build Coastguard Worker                   *sp = gamma_table[*sp];
3965*a67afe4dSAndroid Build Coastguard Worker                   sp++;
3966*a67afe4dSAndroid Build Coastguard Worker                   *sp = gamma_table[*sp];
3967*a67afe4dSAndroid Build Coastguard Worker                   sp++;
3968*a67afe4dSAndroid Build Coastguard Worker                   *sp = gamma_table[*sp];
3969*a67afe4dSAndroid Build Coastguard Worker                   sp++;
3970*a67afe4dSAndroid Build Coastguard Worker                }
3971*a67afe4dSAndroid Build Coastguard Worker             }
3972*a67afe4dSAndroid Build Coastguard Worker 
3973*a67afe4dSAndroid Build Coastguard Worker             else /* if (row_info->bit_depth == 16) */
3974*a67afe4dSAndroid Build Coastguard Worker             {
3975*a67afe4dSAndroid Build Coastguard Worker                sp = row;
3976*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++)
3977*a67afe4dSAndroid Build Coastguard Worker                {
3978*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 v;
3979*a67afe4dSAndroid Build Coastguard Worker 
3980*a67afe4dSAndroid Build Coastguard Worker                   v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3981*a67afe4dSAndroid Build Coastguard Worker                   *sp = (png_byte)((v >> 8) & 0xff);
3982*a67afe4dSAndroid Build Coastguard Worker                   *(sp + 1) = (png_byte)(v & 0xff);
3983*a67afe4dSAndroid Build Coastguard Worker                   sp += 2;
3984*a67afe4dSAndroid Build Coastguard Worker 
3985*a67afe4dSAndroid Build Coastguard Worker                   v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3986*a67afe4dSAndroid Build Coastguard Worker                   *sp = (png_byte)((v >> 8) & 0xff);
3987*a67afe4dSAndroid Build Coastguard Worker                   *(sp + 1) = (png_byte)(v & 0xff);
3988*a67afe4dSAndroid Build Coastguard Worker                   sp += 2;
3989*a67afe4dSAndroid Build Coastguard Worker 
3990*a67afe4dSAndroid Build Coastguard Worker                   v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3991*a67afe4dSAndroid Build Coastguard Worker                   *sp = (png_byte)((v >> 8) & 0xff);
3992*a67afe4dSAndroid Build Coastguard Worker                   *(sp + 1) = (png_byte)(v & 0xff);
3993*a67afe4dSAndroid Build Coastguard Worker                   sp += 2;
3994*a67afe4dSAndroid Build Coastguard Worker                }
3995*a67afe4dSAndroid Build Coastguard Worker             }
3996*a67afe4dSAndroid Build Coastguard Worker             break;
3997*a67afe4dSAndroid Build Coastguard Worker          }
3998*a67afe4dSAndroid Build Coastguard Worker 
3999*a67afe4dSAndroid Build Coastguard Worker          case PNG_COLOR_TYPE_RGB_ALPHA:
4000*a67afe4dSAndroid Build Coastguard Worker          {
4001*a67afe4dSAndroid Build Coastguard Worker             if (row_info->bit_depth == 8)
4002*a67afe4dSAndroid Build Coastguard Worker             {
4003*a67afe4dSAndroid Build Coastguard Worker                sp = row;
4004*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++)
4005*a67afe4dSAndroid Build Coastguard Worker                {
4006*a67afe4dSAndroid Build Coastguard Worker                   *sp = gamma_table[*sp];
4007*a67afe4dSAndroid Build Coastguard Worker                   sp++;
4008*a67afe4dSAndroid Build Coastguard Worker 
4009*a67afe4dSAndroid Build Coastguard Worker                   *sp = gamma_table[*sp];
4010*a67afe4dSAndroid Build Coastguard Worker                   sp++;
4011*a67afe4dSAndroid Build Coastguard Worker 
4012*a67afe4dSAndroid Build Coastguard Worker                   *sp = gamma_table[*sp];
4013*a67afe4dSAndroid Build Coastguard Worker                   sp++;
4014*a67afe4dSAndroid Build Coastguard Worker 
4015*a67afe4dSAndroid Build Coastguard Worker                   sp++;
4016*a67afe4dSAndroid Build Coastguard Worker                }
4017*a67afe4dSAndroid Build Coastguard Worker             }
4018*a67afe4dSAndroid Build Coastguard Worker 
4019*a67afe4dSAndroid Build Coastguard Worker             else /* if (row_info->bit_depth == 16) */
4020*a67afe4dSAndroid Build Coastguard Worker             {
4021*a67afe4dSAndroid Build Coastguard Worker                sp = row;
4022*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++)
4023*a67afe4dSAndroid Build Coastguard Worker                {
4024*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
4025*a67afe4dSAndroid Build Coastguard Worker                   *sp = (png_byte)((v >> 8) & 0xff);
4026*a67afe4dSAndroid Build Coastguard Worker                   *(sp + 1) = (png_byte)(v & 0xff);
4027*a67afe4dSAndroid Build Coastguard Worker                   sp += 2;
4028*a67afe4dSAndroid Build Coastguard Worker 
4029*a67afe4dSAndroid Build Coastguard Worker                   v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
4030*a67afe4dSAndroid Build Coastguard Worker                   *sp = (png_byte)((v >> 8) & 0xff);
4031*a67afe4dSAndroid Build Coastguard Worker                   *(sp + 1) = (png_byte)(v & 0xff);
4032*a67afe4dSAndroid Build Coastguard Worker                   sp += 2;
4033*a67afe4dSAndroid Build Coastguard Worker 
4034*a67afe4dSAndroid Build Coastguard Worker                   v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
4035*a67afe4dSAndroid Build Coastguard Worker                   *sp = (png_byte)((v >> 8) & 0xff);
4036*a67afe4dSAndroid Build Coastguard Worker                   *(sp + 1) = (png_byte)(v & 0xff);
4037*a67afe4dSAndroid Build Coastguard Worker                   sp += 4;
4038*a67afe4dSAndroid Build Coastguard Worker                }
4039*a67afe4dSAndroid Build Coastguard Worker             }
4040*a67afe4dSAndroid Build Coastguard Worker             break;
4041*a67afe4dSAndroid Build Coastguard Worker          }
4042*a67afe4dSAndroid Build Coastguard Worker 
4043*a67afe4dSAndroid Build Coastguard Worker          case PNG_COLOR_TYPE_GRAY_ALPHA:
4044*a67afe4dSAndroid Build Coastguard Worker          {
4045*a67afe4dSAndroid Build Coastguard Worker             if (row_info->bit_depth == 8)
4046*a67afe4dSAndroid Build Coastguard Worker             {
4047*a67afe4dSAndroid Build Coastguard Worker                sp = row;
4048*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++)
4049*a67afe4dSAndroid Build Coastguard Worker                {
4050*a67afe4dSAndroid Build Coastguard Worker                   *sp = gamma_table[*sp];
4051*a67afe4dSAndroid Build Coastguard Worker                   sp += 2;
4052*a67afe4dSAndroid Build Coastguard Worker                }
4053*a67afe4dSAndroid Build Coastguard Worker             }
4054*a67afe4dSAndroid Build Coastguard Worker 
4055*a67afe4dSAndroid Build Coastguard Worker             else /* if (row_info->bit_depth == 16) */
4056*a67afe4dSAndroid Build Coastguard Worker             {
4057*a67afe4dSAndroid Build Coastguard Worker                sp = row;
4058*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++)
4059*a67afe4dSAndroid Build Coastguard Worker                {
4060*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
4061*a67afe4dSAndroid Build Coastguard Worker                   *sp = (png_byte)((v >> 8) & 0xff);
4062*a67afe4dSAndroid Build Coastguard Worker                   *(sp + 1) = (png_byte)(v & 0xff);
4063*a67afe4dSAndroid Build Coastguard Worker                   sp += 4;
4064*a67afe4dSAndroid Build Coastguard Worker                }
4065*a67afe4dSAndroid Build Coastguard Worker             }
4066*a67afe4dSAndroid Build Coastguard Worker             break;
4067*a67afe4dSAndroid Build Coastguard Worker          }
4068*a67afe4dSAndroid Build Coastguard Worker 
4069*a67afe4dSAndroid Build Coastguard Worker          case PNG_COLOR_TYPE_GRAY:
4070*a67afe4dSAndroid Build Coastguard Worker          {
4071*a67afe4dSAndroid Build Coastguard Worker             if (row_info->bit_depth == 2)
4072*a67afe4dSAndroid Build Coastguard Worker             {
4073*a67afe4dSAndroid Build Coastguard Worker                sp = row;
4074*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i += 4)
4075*a67afe4dSAndroid Build Coastguard Worker                {
4076*a67afe4dSAndroid Build Coastguard Worker                   int a = *sp & 0xc0;
4077*a67afe4dSAndroid Build Coastguard Worker                   int b = *sp & 0x30;
4078*a67afe4dSAndroid Build Coastguard Worker                   int c = *sp & 0x0c;
4079*a67afe4dSAndroid Build Coastguard Worker                   int d = *sp & 0x03;
4080*a67afe4dSAndroid Build Coastguard Worker 
4081*a67afe4dSAndroid Build Coastguard Worker                   *sp = (png_byte)(
4082*a67afe4dSAndroid Build Coastguard Worker                       ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)])   ) & 0xc0)|
4083*a67afe4dSAndroid Build Coastguard Worker                       ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
4084*a67afe4dSAndroid Build Coastguard Worker                       ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
4085*a67afe4dSAndroid Build Coastguard Worker                       ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
4086*a67afe4dSAndroid Build Coastguard Worker                   sp++;
4087*a67afe4dSAndroid Build Coastguard Worker                }
4088*a67afe4dSAndroid Build Coastguard Worker             }
4089*a67afe4dSAndroid Build Coastguard Worker 
4090*a67afe4dSAndroid Build Coastguard Worker             if (row_info->bit_depth == 4)
4091*a67afe4dSAndroid Build Coastguard Worker             {
4092*a67afe4dSAndroid Build Coastguard Worker                sp = row;
4093*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i += 2)
4094*a67afe4dSAndroid Build Coastguard Worker                {
4095*a67afe4dSAndroid Build Coastguard Worker                   int msb = *sp & 0xf0;
4096*a67afe4dSAndroid Build Coastguard Worker                   int lsb = *sp & 0x0f;
4097*a67afe4dSAndroid Build Coastguard Worker 
4098*a67afe4dSAndroid Build Coastguard Worker                   *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)
4099*a67afe4dSAndroid Build Coastguard Worker                       | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
4100*a67afe4dSAndroid Build Coastguard Worker                   sp++;
4101*a67afe4dSAndroid Build Coastguard Worker                }
4102*a67afe4dSAndroid Build Coastguard Worker             }
4103*a67afe4dSAndroid Build Coastguard Worker 
4104*a67afe4dSAndroid Build Coastguard Worker             else if (row_info->bit_depth == 8)
4105*a67afe4dSAndroid Build Coastguard Worker             {
4106*a67afe4dSAndroid Build Coastguard Worker                sp = row;
4107*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++)
4108*a67afe4dSAndroid Build Coastguard Worker                {
4109*a67afe4dSAndroid Build Coastguard Worker                   *sp = gamma_table[*sp];
4110*a67afe4dSAndroid Build Coastguard Worker                   sp++;
4111*a67afe4dSAndroid Build Coastguard Worker                }
4112*a67afe4dSAndroid Build Coastguard Worker             }
4113*a67afe4dSAndroid Build Coastguard Worker 
4114*a67afe4dSAndroid Build Coastguard Worker             else if (row_info->bit_depth == 16)
4115*a67afe4dSAndroid Build Coastguard Worker             {
4116*a67afe4dSAndroid Build Coastguard Worker                sp = row;
4117*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++)
4118*a67afe4dSAndroid Build Coastguard Worker                {
4119*a67afe4dSAndroid Build Coastguard Worker                   png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
4120*a67afe4dSAndroid Build Coastguard Worker                   *sp = (png_byte)((v >> 8) & 0xff);
4121*a67afe4dSAndroid Build Coastguard Worker                   *(sp + 1) = (png_byte)(v & 0xff);
4122*a67afe4dSAndroid Build Coastguard Worker                   sp += 2;
4123*a67afe4dSAndroid Build Coastguard Worker                }
4124*a67afe4dSAndroid Build Coastguard Worker             }
4125*a67afe4dSAndroid Build Coastguard Worker             break;
4126*a67afe4dSAndroid Build Coastguard Worker          }
4127*a67afe4dSAndroid Build Coastguard Worker 
4128*a67afe4dSAndroid Build Coastguard Worker          default:
4129*a67afe4dSAndroid Build Coastguard Worker             break;
4130*a67afe4dSAndroid Build Coastguard Worker       }
4131*a67afe4dSAndroid Build Coastguard Worker    }
4132*a67afe4dSAndroid Build Coastguard Worker }
4133*a67afe4dSAndroid Build Coastguard Worker #endif
4134*a67afe4dSAndroid Build Coastguard Worker 
4135*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_ALPHA_MODE_SUPPORTED
4136*a67afe4dSAndroid Build Coastguard Worker /* Encode the alpha channel to the output gamma (the input channel is always
4137*a67afe4dSAndroid Build Coastguard Worker  * linear.)  Called only with color types that have an alpha channel.  Needs the
4138*a67afe4dSAndroid Build Coastguard Worker  * from_1 tables.
4139*a67afe4dSAndroid Build Coastguard Worker  */
4140*a67afe4dSAndroid Build Coastguard Worker static void
png_do_encode_alpha(png_row_infop row_info,png_bytep row,png_structrp png_ptr)4141*a67afe4dSAndroid Build Coastguard Worker png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr)
4142*a67afe4dSAndroid Build Coastguard Worker {
4143*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 row_width = row_info->width;
4144*a67afe4dSAndroid Build Coastguard Worker 
4145*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_do_encode_alpha");
4146*a67afe4dSAndroid Build Coastguard Worker 
4147*a67afe4dSAndroid Build Coastguard Worker    if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0)
4148*a67afe4dSAndroid Build Coastguard Worker    {
4149*a67afe4dSAndroid Build Coastguard Worker       if (row_info->bit_depth == 8)
4150*a67afe4dSAndroid Build Coastguard Worker       {
4151*a67afe4dSAndroid Build Coastguard Worker          png_bytep table = png_ptr->gamma_from_1;
4152*a67afe4dSAndroid Build Coastguard Worker 
4153*a67afe4dSAndroid Build Coastguard Worker          if (table != NULL)
4154*a67afe4dSAndroid Build Coastguard Worker          {
4155*a67afe4dSAndroid Build Coastguard Worker             int step = (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 4 : 2;
4156*a67afe4dSAndroid Build Coastguard Worker 
4157*a67afe4dSAndroid Build Coastguard Worker             /* The alpha channel is the last component: */
4158*a67afe4dSAndroid Build Coastguard Worker             row += step - 1;
4159*a67afe4dSAndroid Build Coastguard Worker 
4160*a67afe4dSAndroid Build Coastguard Worker             for (; row_width > 0; --row_width, row += step)
4161*a67afe4dSAndroid Build Coastguard Worker                *row = table[*row];
4162*a67afe4dSAndroid Build Coastguard Worker 
4163*a67afe4dSAndroid Build Coastguard Worker             return;
4164*a67afe4dSAndroid Build Coastguard Worker          }
4165*a67afe4dSAndroid Build Coastguard Worker       }
4166*a67afe4dSAndroid Build Coastguard Worker 
4167*a67afe4dSAndroid Build Coastguard Worker       else if (row_info->bit_depth == 16)
4168*a67afe4dSAndroid Build Coastguard Worker       {
4169*a67afe4dSAndroid Build Coastguard Worker          png_uint_16pp table = png_ptr->gamma_16_from_1;
4170*a67afe4dSAndroid Build Coastguard Worker          int gamma_shift = png_ptr->gamma_shift;
4171*a67afe4dSAndroid Build Coastguard Worker 
4172*a67afe4dSAndroid Build Coastguard Worker          if (table != NULL)
4173*a67afe4dSAndroid Build Coastguard Worker          {
4174*a67afe4dSAndroid Build Coastguard Worker             int step = (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 8 : 4;
4175*a67afe4dSAndroid Build Coastguard Worker 
4176*a67afe4dSAndroid Build Coastguard Worker             /* The alpha channel is the last component: */
4177*a67afe4dSAndroid Build Coastguard Worker             row += step - 2;
4178*a67afe4dSAndroid Build Coastguard Worker 
4179*a67afe4dSAndroid Build Coastguard Worker             for (; row_width > 0; --row_width, row += step)
4180*a67afe4dSAndroid Build Coastguard Worker             {
4181*a67afe4dSAndroid Build Coastguard Worker                png_uint_16 v;
4182*a67afe4dSAndroid Build Coastguard Worker 
4183*a67afe4dSAndroid Build Coastguard Worker                v = table[*(row + 1) >> gamma_shift][*row];
4184*a67afe4dSAndroid Build Coastguard Worker                *row = (png_byte)((v >> 8) & 0xff);
4185*a67afe4dSAndroid Build Coastguard Worker                *(row + 1) = (png_byte)(v & 0xff);
4186*a67afe4dSAndroid Build Coastguard Worker             }
4187*a67afe4dSAndroid Build Coastguard Worker 
4188*a67afe4dSAndroid Build Coastguard Worker             return;
4189*a67afe4dSAndroid Build Coastguard Worker          }
4190*a67afe4dSAndroid Build Coastguard Worker       }
4191*a67afe4dSAndroid Build Coastguard Worker    }
4192*a67afe4dSAndroid Build Coastguard Worker 
4193*a67afe4dSAndroid Build Coastguard Worker    /* Only get to here if called with a weird row_info; no harm has been done,
4194*a67afe4dSAndroid Build Coastguard Worker     * so just issue a warning.
4195*a67afe4dSAndroid Build Coastguard Worker     */
4196*a67afe4dSAndroid Build Coastguard Worker    png_warning(png_ptr, "png_do_encode_alpha: unexpected call");
4197*a67afe4dSAndroid Build Coastguard Worker }
4198*a67afe4dSAndroid Build Coastguard Worker #endif
4199*a67afe4dSAndroid Build Coastguard Worker 
4200*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_EXPAND_SUPPORTED
4201*a67afe4dSAndroid Build Coastguard Worker /* Expands a palette row to an RGB or RGBA row depending
4202*a67afe4dSAndroid Build Coastguard Worker  * upon whether you supply trans and num_trans.
4203*a67afe4dSAndroid Build Coastguard Worker  */
4204*a67afe4dSAndroid Build Coastguard Worker static void
png_do_expand_palette(png_structrp png_ptr,png_row_infop row_info,png_bytep row,png_const_colorp palette,png_const_bytep trans_alpha,int num_trans)4205*a67afe4dSAndroid Build Coastguard Worker png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info,
4206*a67afe4dSAndroid Build Coastguard Worker     png_bytep row, png_const_colorp palette, png_const_bytep trans_alpha,
4207*a67afe4dSAndroid Build Coastguard Worker     int num_trans)
4208*a67afe4dSAndroid Build Coastguard Worker {
4209*a67afe4dSAndroid Build Coastguard Worker    int shift, value;
4210*a67afe4dSAndroid Build Coastguard Worker    png_bytep sp, dp;
4211*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 i;
4212*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 row_width=row_info->width;
4213*a67afe4dSAndroid Build Coastguard Worker 
4214*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_do_expand_palette");
4215*a67afe4dSAndroid Build Coastguard Worker 
4216*a67afe4dSAndroid Build Coastguard Worker    if (row_info->color_type == PNG_COLOR_TYPE_PALETTE)
4217*a67afe4dSAndroid Build Coastguard Worker    {
4218*a67afe4dSAndroid Build Coastguard Worker       if (row_info->bit_depth < 8)
4219*a67afe4dSAndroid Build Coastguard Worker       {
4220*a67afe4dSAndroid Build Coastguard Worker          switch (row_info->bit_depth)
4221*a67afe4dSAndroid Build Coastguard Worker          {
4222*a67afe4dSAndroid Build Coastguard Worker             case 1:
4223*a67afe4dSAndroid Build Coastguard Worker             {
4224*a67afe4dSAndroid Build Coastguard Worker                sp = row + (size_t)((row_width - 1) >> 3);
4225*a67afe4dSAndroid Build Coastguard Worker                dp = row + (size_t)row_width - 1;
4226*a67afe4dSAndroid Build Coastguard Worker                shift = 7 - (int)((row_width + 7) & 0x07);
4227*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++)
4228*a67afe4dSAndroid Build Coastguard Worker                {
4229*a67afe4dSAndroid Build Coastguard Worker                   if ((*sp >> shift) & 0x01)
4230*a67afe4dSAndroid Build Coastguard Worker                      *dp = 1;
4231*a67afe4dSAndroid Build Coastguard Worker 
4232*a67afe4dSAndroid Build Coastguard Worker                   else
4233*a67afe4dSAndroid Build Coastguard Worker                      *dp = 0;
4234*a67afe4dSAndroid Build Coastguard Worker 
4235*a67afe4dSAndroid Build Coastguard Worker                   if (shift == 7)
4236*a67afe4dSAndroid Build Coastguard Worker                   {
4237*a67afe4dSAndroid Build Coastguard Worker                      shift = 0;
4238*a67afe4dSAndroid Build Coastguard Worker                      sp--;
4239*a67afe4dSAndroid Build Coastguard Worker                   }
4240*a67afe4dSAndroid Build Coastguard Worker 
4241*a67afe4dSAndroid Build Coastguard Worker                   else
4242*a67afe4dSAndroid Build Coastguard Worker                      shift++;
4243*a67afe4dSAndroid Build Coastguard Worker 
4244*a67afe4dSAndroid Build Coastguard Worker                   dp--;
4245*a67afe4dSAndroid Build Coastguard Worker                }
4246*a67afe4dSAndroid Build Coastguard Worker                break;
4247*a67afe4dSAndroid Build Coastguard Worker             }
4248*a67afe4dSAndroid Build Coastguard Worker 
4249*a67afe4dSAndroid Build Coastguard Worker             case 2:
4250*a67afe4dSAndroid Build Coastguard Worker             {
4251*a67afe4dSAndroid Build Coastguard Worker                sp = row + (size_t)((row_width - 1) >> 2);
4252*a67afe4dSAndroid Build Coastguard Worker                dp = row + (size_t)row_width - 1;
4253*a67afe4dSAndroid Build Coastguard Worker                shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
4254*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++)
4255*a67afe4dSAndroid Build Coastguard Worker                {
4256*a67afe4dSAndroid Build Coastguard Worker                   value = (*sp >> shift) & 0x03;
4257*a67afe4dSAndroid Build Coastguard Worker                   *dp = (png_byte)value;
4258*a67afe4dSAndroid Build Coastguard Worker                   if (shift == 6)
4259*a67afe4dSAndroid Build Coastguard Worker                   {
4260*a67afe4dSAndroid Build Coastguard Worker                      shift = 0;
4261*a67afe4dSAndroid Build Coastguard Worker                      sp--;
4262*a67afe4dSAndroid Build Coastguard Worker                   }
4263*a67afe4dSAndroid Build Coastguard Worker 
4264*a67afe4dSAndroid Build Coastguard Worker                   else
4265*a67afe4dSAndroid Build Coastguard Worker                      shift += 2;
4266*a67afe4dSAndroid Build Coastguard Worker 
4267*a67afe4dSAndroid Build Coastguard Worker                   dp--;
4268*a67afe4dSAndroid Build Coastguard Worker                }
4269*a67afe4dSAndroid Build Coastguard Worker                break;
4270*a67afe4dSAndroid Build Coastguard Worker             }
4271*a67afe4dSAndroid Build Coastguard Worker 
4272*a67afe4dSAndroid Build Coastguard Worker             case 4:
4273*a67afe4dSAndroid Build Coastguard Worker             {
4274*a67afe4dSAndroid Build Coastguard Worker                sp = row + (size_t)((row_width - 1) >> 1);
4275*a67afe4dSAndroid Build Coastguard Worker                dp = row + (size_t)row_width - 1;
4276*a67afe4dSAndroid Build Coastguard Worker                shift = (int)((row_width & 0x01) << 2);
4277*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++)
4278*a67afe4dSAndroid Build Coastguard Worker                {
4279*a67afe4dSAndroid Build Coastguard Worker                   value = (*sp >> shift) & 0x0f;
4280*a67afe4dSAndroid Build Coastguard Worker                   *dp = (png_byte)value;
4281*a67afe4dSAndroid Build Coastguard Worker                   if (shift == 4)
4282*a67afe4dSAndroid Build Coastguard Worker                   {
4283*a67afe4dSAndroid Build Coastguard Worker                      shift = 0;
4284*a67afe4dSAndroid Build Coastguard Worker                      sp--;
4285*a67afe4dSAndroid Build Coastguard Worker                   }
4286*a67afe4dSAndroid Build Coastguard Worker 
4287*a67afe4dSAndroid Build Coastguard Worker                   else
4288*a67afe4dSAndroid Build Coastguard Worker                      shift += 4;
4289*a67afe4dSAndroid Build Coastguard Worker 
4290*a67afe4dSAndroid Build Coastguard Worker                   dp--;
4291*a67afe4dSAndroid Build Coastguard Worker                }
4292*a67afe4dSAndroid Build Coastguard Worker                break;
4293*a67afe4dSAndroid Build Coastguard Worker             }
4294*a67afe4dSAndroid Build Coastguard Worker 
4295*a67afe4dSAndroid Build Coastguard Worker             default:
4296*a67afe4dSAndroid Build Coastguard Worker                break;
4297*a67afe4dSAndroid Build Coastguard Worker          }
4298*a67afe4dSAndroid Build Coastguard Worker          row_info->bit_depth = 8;
4299*a67afe4dSAndroid Build Coastguard Worker          row_info->pixel_depth = 8;
4300*a67afe4dSAndroid Build Coastguard Worker          row_info->rowbytes = row_width;
4301*a67afe4dSAndroid Build Coastguard Worker       }
4302*a67afe4dSAndroid Build Coastguard Worker 
4303*a67afe4dSAndroid Build Coastguard Worker       if (row_info->bit_depth == 8)
4304*a67afe4dSAndroid Build Coastguard Worker       {
4305*a67afe4dSAndroid Build Coastguard Worker          {
4306*a67afe4dSAndroid Build Coastguard Worker             if (num_trans > 0)
4307*a67afe4dSAndroid Build Coastguard Worker             {
4308*a67afe4dSAndroid Build Coastguard Worker                sp = row + (size_t)row_width - 1;
4309*a67afe4dSAndroid Build Coastguard Worker                dp = row + ((size_t)row_width << 2) - 1;
4310*a67afe4dSAndroid Build Coastguard Worker 
4311*a67afe4dSAndroid Build Coastguard Worker                i = 0;
4312*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE
4313*a67afe4dSAndroid Build Coastguard Worker                if (png_ptr->riffled_palette != NULL)
4314*a67afe4dSAndroid Build Coastguard Worker                {
4315*a67afe4dSAndroid Build Coastguard Worker                   /* The RGBA optimization works with png_ptr->bit_depth == 8
4316*a67afe4dSAndroid Build Coastguard Worker                    * but sometimes row_info->bit_depth has been changed to 8.
4317*a67afe4dSAndroid Build Coastguard Worker                    * In these cases, the palette hasn't been riffled.
4318*a67afe4dSAndroid Build Coastguard Worker                    */
4319*a67afe4dSAndroid Build Coastguard Worker                   i = png_do_expand_palette_rgba8_neon(png_ptr, row_info, row,
4320*a67afe4dSAndroid Build Coastguard Worker                       &sp, &dp);
4321*a67afe4dSAndroid Build Coastguard Worker                }
4322*a67afe4dSAndroid Build Coastguard Worker #else
4323*a67afe4dSAndroid Build Coastguard Worker                PNG_UNUSED(png_ptr)
4324*a67afe4dSAndroid Build Coastguard Worker #endif
4325*a67afe4dSAndroid Build Coastguard Worker 
4326*a67afe4dSAndroid Build Coastguard Worker                for (; i < row_width; i++)
4327*a67afe4dSAndroid Build Coastguard Worker                {
4328*a67afe4dSAndroid Build Coastguard Worker                   if ((int)(*sp) >= num_trans)
4329*a67afe4dSAndroid Build Coastguard Worker                      *dp-- = 0xff;
4330*a67afe4dSAndroid Build Coastguard Worker                   else
4331*a67afe4dSAndroid Build Coastguard Worker                      *dp-- = trans_alpha[*sp];
4332*a67afe4dSAndroid Build Coastguard Worker                   *dp-- = palette[*sp].blue;
4333*a67afe4dSAndroid Build Coastguard Worker                   *dp-- = palette[*sp].green;
4334*a67afe4dSAndroid Build Coastguard Worker                   *dp-- = palette[*sp].red;
4335*a67afe4dSAndroid Build Coastguard Worker                   sp--;
4336*a67afe4dSAndroid Build Coastguard Worker                }
4337*a67afe4dSAndroid Build Coastguard Worker                row_info->bit_depth = 8;
4338*a67afe4dSAndroid Build Coastguard Worker                row_info->pixel_depth = 32;
4339*a67afe4dSAndroid Build Coastguard Worker                row_info->rowbytes = row_width * 4;
4340*a67afe4dSAndroid Build Coastguard Worker                row_info->color_type = 6;
4341*a67afe4dSAndroid Build Coastguard Worker                row_info->channels = 4;
4342*a67afe4dSAndroid Build Coastguard Worker             }
4343*a67afe4dSAndroid Build Coastguard Worker 
4344*a67afe4dSAndroid Build Coastguard Worker             else
4345*a67afe4dSAndroid Build Coastguard Worker             {
4346*a67afe4dSAndroid Build Coastguard Worker                sp = row + (size_t)row_width - 1;
4347*a67afe4dSAndroid Build Coastguard Worker                dp = row + (size_t)(row_width * 3) - 1;
4348*a67afe4dSAndroid Build Coastguard Worker                i = 0;
4349*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE
4350*a67afe4dSAndroid Build Coastguard Worker                i = png_do_expand_palette_rgb8_neon(png_ptr, row_info, row,
4351*a67afe4dSAndroid Build Coastguard Worker                    &sp, &dp);
4352*a67afe4dSAndroid Build Coastguard Worker #else
4353*a67afe4dSAndroid Build Coastguard Worker                PNG_UNUSED(png_ptr)
4354*a67afe4dSAndroid Build Coastguard Worker #endif
4355*a67afe4dSAndroid Build Coastguard Worker 
4356*a67afe4dSAndroid Build Coastguard Worker                for (; i < row_width; i++)
4357*a67afe4dSAndroid Build Coastguard Worker                {
4358*a67afe4dSAndroid Build Coastguard Worker                   *dp-- = palette[*sp].blue;
4359*a67afe4dSAndroid Build Coastguard Worker                   *dp-- = palette[*sp].green;
4360*a67afe4dSAndroid Build Coastguard Worker                   *dp-- = palette[*sp].red;
4361*a67afe4dSAndroid Build Coastguard Worker                   sp--;
4362*a67afe4dSAndroid Build Coastguard Worker                }
4363*a67afe4dSAndroid Build Coastguard Worker 
4364*a67afe4dSAndroid Build Coastguard Worker                row_info->bit_depth = 8;
4365*a67afe4dSAndroid Build Coastguard Worker                row_info->pixel_depth = 24;
4366*a67afe4dSAndroid Build Coastguard Worker                row_info->rowbytes = row_width * 3;
4367*a67afe4dSAndroid Build Coastguard Worker                row_info->color_type = 2;
4368*a67afe4dSAndroid Build Coastguard Worker                row_info->channels = 3;
4369*a67afe4dSAndroid Build Coastguard Worker             }
4370*a67afe4dSAndroid Build Coastguard Worker          }
4371*a67afe4dSAndroid Build Coastguard Worker       }
4372*a67afe4dSAndroid Build Coastguard Worker    }
4373*a67afe4dSAndroid Build Coastguard Worker }
4374*a67afe4dSAndroid Build Coastguard Worker 
4375*a67afe4dSAndroid Build Coastguard Worker /* If the bit depth < 8, it is expanded to 8.  Also, if the already
4376*a67afe4dSAndroid Build Coastguard Worker  * expanded transparency value is supplied, an alpha channel is built.
4377*a67afe4dSAndroid Build Coastguard Worker  */
4378*a67afe4dSAndroid Build Coastguard Worker static void
png_do_expand(png_row_infop row_info,png_bytep row,png_const_color_16p trans_color)4379*a67afe4dSAndroid Build Coastguard Worker png_do_expand(png_row_infop row_info, png_bytep row,
4380*a67afe4dSAndroid Build Coastguard Worker     png_const_color_16p trans_color)
4381*a67afe4dSAndroid Build Coastguard Worker {
4382*a67afe4dSAndroid Build Coastguard Worker    int shift, value;
4383*a67afe4dSAndroid Build Coastguard Worker    png_bytep sp, dp;
4384*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 i;
4385*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 row_width=row_info->width;
4386*a67afe4dSAndroid Build Coastguard Worker 
4387*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_do_expand");
4388*a67afe4dSAndroid Build Coastguard Worker 
4389*a67afe4dSAndroid Build Coastguard Worker    if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
4390*a67afe4dSAndroid Build Coastguard Worker    {
4391*a67afe4dSAndroid Build Coastguard Worker       unsigned int gray = trans_color != NULL ? trans_color->gray : 0;
4392*a67afe4dSAndroid Build Coastguard Worker 
4393*a67afe4dSAndroid Build Coastguard Worker       if (row_info->bit_depth < 8)
4394*a67afe4dSAndroid Build Coastguard Worker       {
4395*a67afe4dSAndroid Build Coastguard Worker          switch (row_info->bit_depth)
4396*a67afe4dSAndroid Build Coastguard Worker          {
4397*a67afe4dSAndroid Build Coastguard Worker             case 1:
4398*a67afe4dSAndroid Build Coastguard Worker             {
4399*a67afe4dSAndroid Build Coastguard Worker                gray = (gray & 0x01) * 0xff;
4400*a67afe4dSAndroid Build Coastguard Worker                sp = row + (size_t)((row_width - 1) >> 3);
4401*a67afe4dSAndroid Build Coastguard Worker                dp = row + (size_t)row_width - 1;
4402*a67afe4dSAndroid Build Coastguard Worker                shift = 7 - (int)((row_width + 7) & 0x07);
4403*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++)
4404*a67afe4dSAndroid Build Coastguard Worker                {
4405*a67afe4dSAndroid Build Coastguard Worker                   if ((*sp >> shift) & 0x01)
4406*a67afe4dSAndroid Build Coastguard Worker                      *dp = 0xff;
4407*a67afe4dSAndroid Build Coastguard Worker 
4408*a67afe4dSAndroid Build Coastguard Worker                   else
4409*a67afe4dSAndroid Build Coastguard Worker                      *dp = 0;
4410*a67afe4dSAndroid Build Coastguard Worker 
4411*a67afe4dSAndroid Build Coastguard Worker                   if (shift == 7)
4412*a67afe4dSAndroid Build Coastguard Worker                   {
4413*a67afe4dSAndroid Build Coastguard Worker                      shift = 0;
4414*a67afe4dSAndroid Build Coastguard Worker                      sp--;
4415*a67afe4dSAndroid Build Coastguard Worker                   }
4416*a67afe4dSAndroid Build Coastguard Worker 
4417*a67afe4dSAndroid Build Coastguard Worker                   else
4418*a67afe4dSAndroid Build Coastguard Worker                      shift++;
4419*a67afe4dSAndroid Build Coastguard Worker 
4420*a67afe4dSAndroid Build Coastguard Worker                   dp--;
4421*a67afe4dSAndroid Build Coastguard Worker                }
4422*a67afe4dSAndroid Build Coastguard Worker                break;
4423*a67afe4dSAndroid Build Coastguard Worker             }
4424*a67afe4dSAndroid Build Coastguard Worker 
4425*a67afe4dSAndroid Build Coastguard Worker             case 2:
4426*a67afe4dSAndroid Build Coastguard Worker             {
4427*a67afe4dSAndroid Build Coastguard Worker                gray = (gray & 0x03) * 0x55;
4428*a67afe4dSAndroid Build Coastguard Worker                sp = row + (size_t)((row_width - 1) >> 2);
4429*a67afe4dSAndroid Build Coastguard Worker                dp = row + (size_t)row_width - 1;
4430*a67afe4dSAndroid Build Coastguard Worker                shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
4431*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++)
4432*a67afe4dSAndroid Build Coastguard Worker                {
4433*a67afe4dSAndroid Build Coastguard Worker                   value = (*sp >> shift) & 0x03;
4434*a67afe4dSAndroid Build Coastguard Worker                   *dp = (png_byte)(value | (value << 2) | (value << 4) |
4435*a67afe4dSAndroid Build Coastguard Worker                      (value << 6));
4436*a67afe4dSAndroid Build Coastguard Worker                   if (shift == 6)
4437*a67afe4dSAndroid Build Coastguard Worker                   {
4438*a67afe4dSAndroid Build Coastguard Worker                      shift = 0;
4439*a67afe4dSAndroid Build Coastguard Worker                      sp--;
4440*a67afe4dSAndroid Build Coastguard Worker                   }
4441*a67afe4dSAndroid Build Coastguard Worker 
4442*a67afe4dSAndroid Build Coastguard Worker                   else
4443*a67afe4dSAndroid Build Coastguard Worker                      shift += 2;
4444*a67afe4dSAndroid Build Coastguard Worker 
4445*a67afe4dSAndroid Build Coastguard Worker                   dp--;
4446*a67afe4dSAndroid Build Coastguard Worker                }
4447*a67afe4dSAndroid Build Coastguard Worker                break;
4448*a67afe4dSAndroid Build Coastguard Worker             }
4449*a67afe4dSAndroid Build Coastguard Worker 
4450*a67afe4dSAndroid Build Coastguard Worker             case 4:
4451*a67afe4dSAndroid Build Coastguard Worker             {
4452*a67afe4dSAndroid Build Coastguard Worker                gray = (gray & 0x0f) * 0x11;
4453*a67afe4dSAndroid Build Coastguard Worker                sp = row + (size_t)((row_width - 1) >> 1);
4454*a67afe4dSAndroid Build Coastguard Worker                dp = row + (size_t)row_width - 1;
4455*a67afe4dSAndroid Build Coastguard Worker                shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
4456*a67afe4dSAndroid Build Coastguard Worker                for (i = 0; i < row_width; i++)
4457*a67afe4dSAndroid Build Coastguard Worker                {
4458*a67afe4dSAndroid Build Coastguard Worker                   value = (*sp >> shift) & 0x0f;
4459*a67afe4dSAndroid Build Coastguard Worker                   *dp = (png_byte)(value | (value << 4));
4460*a67afe4dSAndroid Build Coastguard Worker                   if (shift == 4)
4461*a67afe4dSAndroid Build Coastguard Worker                   {
4462*a67afe4dSAndroid Build Coastguard Worker                      shift = 0;
4463*a67afe4dSAndroid Build Coastguard Worker                      sp--;
4464*a67afe4dSAndroid Build Coastguard Worker                   }
4465*a67afe4dSAndroid Build Coastguard Worker 
4466*a67afe4dSAndroid Build Coastguard Worker                   else
4467*a67afe4dSAndroid Build Coastguard Worker                      shift = 4;
4468*a67afe4dSAndroid Build Coastguard Worker 
4469*a67afe4dSAndroid Build Coastguard Worker                   dp--;
4470*a67afe4dSAndroid Build Coastguard Worker                }
4471*a67afe4dSAndroid Build Coastguard Worker                break;
4472*a67afe4dSAndroid Build Coastguard Worker             }
4473*a67afe4dSAndroid Build Coastguard Worker 
4474*a67afe4dSAndroid Build Coastguard Worker             default:
4475*a67afe4dSAndroid Build Coastguard Worker                break;
4476*a67afe4dSAndroid Build Coastguard Worker          }
4477*a67afe4dSAndroid Build Coastguard Worker 
4478*a67afe4dSAndroid Build Coastguard Worker          row_info->bit_depth = 8;
4479*a67afe4dSAndroid Build Coastguard Worker          row_info->pixel_depth = 8;
4480*a67afe4dSAndroid Build Coastguard Worker          row_info->rowbytes = row_width;
4481*a67afe4dSAndroid Build Coastguard Worker       }
4482*a67afe4dSAndroid Build Coastguard Worker 
4483*a67afe4dSAndroid Build Coastguard Worker       if (trans_color != NULL)
4484*a67afe4dSAndroid Build Coastguard Worker       {
4485*a67afe4dSAndroid Build Coastguard Worker          if (row_info->bit_depth == 8)
4486*a67afe4dSAndroid Build Coastguard Worker          {
4487*a67afe4dSAndroid Build Coastguard Worker             gray = gray & 0xff;
4488*a67afe4dSAndroid Build Coastguard Worker             sp = row + (size_t)row_width - 1;
4489*a67afe4dSAndroid Build Coastguard Worker             dp = row + ((size_t)row_width << 1) - 1;
4490*a67afe4dSAndroid Build Coastguard Worker 
4491*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < row_width; i++)
4492*a67afe4dSAndroid Build Coastguard Worker             {
4493*a67afe4dSAndroid Build Coastguard Worker                if ((*sp & 0xffU) == gray)
4494*a67afe4dSAndroid Build Coastguard Worker                   *dp-- = 0;
4495*a67afe4dSAndroid Build Coastguard Worker 
4496*a67afe4dSAndroid Build Coastguard Worker                else
4497*a67afe4dSAndroid Build Coastguard Worker                   *dp-- = 0xff;
4498*a67afe4dSAndroid Build Coastguard Worker 
4499*a67afe4dSAndroid Build Coastguard Worker                *dp-- = *sp--;
4500*a67afe4dSAndroid Build Coastguard Worker             }
4501*a67afe4dSAndroid Build Coastguard Worker          }
4502*a67afe4dSAndroid Build Coastguard Worker 
4503*a67afe4dSAndroid Build Coastguard Worker          else if (row_info->bit_depth == 16)
4504*a67afe4dSAndroid Build Coastguard Worker          {
4505*a67afe4dSAndroid Build Coastguard Worker             unsigned int gray_high = (gray >> 8) & 0xff;
4506*a67afe4dSAndroid Build Coastguard Worker             unsigned int gray_low = gray & 0xff;
4507*a67afe4dSAndroid Build Coastguard Worker             sp = row + row_info->rowbytes - 1;
4508*a67afe4dSAndroid Build Coastguard Worker             dp = row + (row_info->rowbytes << 1) - 1;
4509*a67afe4dSAndroid Build Coastguard Worker             for (i = 0; i < row_width; i++)
4510*a67afe4dSAndroid Build Coastguard Worker             {
4511*a67afe4dSAndroid Build Coastguard Worker                if ((*(sp - 1) & 0xffU) == gray_high &&
4512*a67afe4dSAndroid Build Coastguard Worker                    (*(sp) & 0xffU) == gray_low)
4513*a67afe4dSAndroid Build Coastguard Worker                {
4514*a67afe4dSAndroid Build Coastguard Worker                   *dp-- = 0;
4515*a67afe4dSAndroid Build Coastguard Worker                   *dp-- = 0;
4516*a67afe4dSAndroid Build Coastguard Worker                }
4517*a67afe4dSAndroid Build Coastguard Worker 
4518*a67afe4dSAndroid Build Coastguard Worker                else
4519*a67afe4dSAndroid Build Coastguard Worker                {
4520*a67afe4dSAndroid Build Coastguard Worker                   *dp-- = 0xff;
4521*a67afe4dSAndroid Build Coastguard Worker                   *dp-- = 0xff;
4522*a67afe4dSAndroid Build Coastguard Worker                }
4523*a67afe4dSAndroid Build Coastguard Worker 
4524*a67afe4dSAndroid Build Coastguard Worker                *dp-- = *sp--;
4525*a67afe4dSAndroid Build Coastguard Worker                *dp-- = *sp--;
4526*a67afe4dSAndroid Build Coastguard Worker             }
4527*a67afe4dSAndroid Build Coastguard Worker          }
4528*a67afe4dSAndroid Build Coastguard Worker 
4529*a67afe4dSAndroid Build Coastguard Worker          row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
4530*a67afe4dSAndroid Build Coastguard Worker          row_info->channels = 2;
4531*a67afe4dSAndroid Build Coastguard Worker          row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
4532*a67afe4dSAndroid Build Coastguard Worker          row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
4533*a67afe4dSAndroid Build Coastguard Worker              row_width);
4534*a67afe4dSAndroid Build Coastguard Worker       }
4535*a67afe4dSAndroid Build Coastguard Worker    }
4536*a67afe4dSAndroid Build Coastguard Worker    else if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
4537*a67afe4dSAndroid Build Coastguard Worker        trans_color != NULL)
4538*a67afe4dSAndroid Build Coastguard Worker    {
4539*a67afe4dSAndroid Build Coastguard Worker       if (row_info->bit_depth == 8)
4540*a67afe4dSAndroid Build Coastguard Worker       {
4541*a67afe4dSAndroid Build Coastguard Worker          png_byte red = (png_byte)(trans_color->red & 0xff);
4542*a67afe4dSAndroid Build Coastguard Worker          png_byte green = (png_byte)(trans_color->green & 0xff);
4543*a67afe4dSAndroid Build Coastguard Worker          png_byte blue = (png_byte)(trans_color->blue & 0xff);
4544*a67afe4dSAndroid Build Coastguard Worker          sp = row + (size_t)row_info->rowbytes - 1;
4545*a67afe4dSAndroid Build Coastguard Worker          dp = row + ((size_t)row_width << 2) - 1;
4546*a67afe4dSAndroid Build Coastguard Worker          for (i = 0; i < row_width; i++)
4547*a67afe4dSAndroid Build Coastguard Worker          {
4548*a67afe4dSAndroid Build Coastguard Worker             if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue)
4549*a67afe4dSAndroid Build Coastguard Worker                *dp-- = 0;
4550*a67afe4dSAndroid Build Coastguard Worker 
4551*a67afe4dSAndroid Build Coastguard Worker             else
4552*a67afe4dSAndroid Build Coastguard Worker                *dp-- = 0xff;
4553*a67afe4dSAndroid Build Coastguard Worker 
4554*a67afe4dSAndroid Build Coastguard Worker             *dp-- = *sp--;
4555*a67afe4dSAndroid Build Coastguard Worker             *dp-- = *sp--;
4556*a67afe4dSAndroid Build Coastguard Worker             *dp-- = *sp--;
4557*a67afe4dSAndroid Build Coastguard Worker          }
4558*a67afe4dSAndroid Build Coastguard Worker       }
4559*a67afe4dSAndroid Build Coastguard Worker       else if (row_info->bit_depth == 16)
4560*a67afe4dSAndroid Build Coastguard Worker       {
4561*a67afe4dSAndroid Build Coastguard Worker          png_byte red_high = (png_byte)((trans_color->red >> 8) & 0xff);
4562*a67afe4dSAndroid Build Coastguard Worker          png_byte green_high = (png_byte)((trans_color->green >> 8) & 0xff);
4563*a67afe4dSAndroid Build Coastguard Worker          png_byte blue_high = (png_byte)((trans_color->blue >> 8) & 0xff);
4564*a67afe4dSAndroid Build Coastguard Worker          png_byte red_low = (png_byte)(trans_color->red & 0xff);
4565*a67afe4dSAndroid Build Coastguard Worker          png_byte green_low = (png_byte)(trans_color->green & 0xff);
4566*a67afe4dSAndroid Build Coastguard Worker          png_byte blue_low = (png_byte)(trans_color->blue & 0xff);
4567*a67afe4dSAndroid Build Coastguard Worker          sp = row + row_info->rowbytes - 1;
4568*a67afe4dSAndroid Build Coastguard Worker          dp = row + ((size_t)row_width << 3) - 1;
4569*a67afe4dSAndroid Build Coastguard Worker          for (i = 0; i < row_width; i++)
4570*a67afe4dSAndroid Build Coastguard Worker          {
4571*a67afe4dSAndroid Build Coastguard Worker             if (*(sp - 5) == red_high &&
4572*a67afe4dSAndroid Build Coastguard Worker                 *(sp - 4) == red_low &&
4573*a67afe4dSAndroid Build Coastguard Worker                 *(sp - 3) == green_high &&
4574*a67afe4dSAndroid Build Coastguard Worker                 *(sp - 2) == green_low &&
4575*a67afe4dSAndroid Build Coastguard Worker                 *(sp - 1) == blue_high &&
4576*a67afe4dSAndroid Build Coastguard Worker                 *(sp    ) == blue_low)
4577*a67afe4dSAndroid Build Coastguard Worker             {
4578*a67afe4dSAndroid Build Coastguard Worker                *dp-- = 0;
4579*a67afe4dSAndroid Build Coastguard Worker                *dp-- = 0;
4580*a67afe4dSAndroid Build Coastguard Worker             }
4581*a67afe4dSAndroid Build Coastguard Worker 
4582*a67afe4dSAndroid Build Coastguard Worker             else
4583*a67afe4dSAndroid Build Coastguard Worker             {
4584*a67afe4dSAndroid Build Coastguard Worker                *dp-- = 0xff;
4585*a67afe4dSAndroid Build Coastguard Worker                *dp-- = 0xff;
4586*a67afe4dSAndroid Build Coastguard Worker             }
4587*a67afe4dSAndroid Build Coastguard Worker 
4588*a67afe4dSAndroid Build Coastguard Worker             *dp-- = *sp--;
4589*a67afe4dSAndroid Build Coastguard Worker             *dp-- = *sp--;
4590*a67afe4dSAndroid Build Coastguard Worker             *dp-- = *sp--;
4591*a67afe4dSAndroid Build Coastguard Worker             *dp-- = *sp--;
4592*a67afe4dSAndroid Build Coastguard Worker             *dp-- = *sp--;
4593*a67afe4dSAndroid Build Coastguard Worker             *dp-- = *sp--;
4594*a67afe4dSAndroid Build Coastguard Worker          }
4595*a67afe4dSAndroid Build Coastguard Worker       }
4596*a67afe4dSAndroid Build Coastguard Worker       row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
4597*a67afe4dSAndroid Build Coastguard Worker       row_info->channels = 4;
4598*a67afe4dSAndroid Build Coastguard Worker       row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
4599*a67afe4dSAndroid Build Coastguard Worker       row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
4600*a67afe4dSAndroid Build Coastguard Worker    }
4601*a67afe4dSAndroid Build Coastguard Worker }
4602*a67afe4dSAndroid Build Coastguard Worker #endif
4603*a67afe4dSAndroid Build Coastguard Worker 
4604*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_EXPAND_16_SUPPORTED
4605*a67afe4dSAndroid Build Coastguard Worker /* If the bit depth is 8 and the color type is not a palette type expand the
4606*a67afe4dSAndroid Build Coastguard Worker  * whole row to 16 bits.  Has no effect otherwise.
4607*a67afe4dSAndroid Build Coastguard Worker  */
4608*a67afe4dSAndroid Build Coastguard Worker static void
png_do_expand_16(png_row_infop row_info,png_bytep row)4609*a67afe4dSAndroid Build Coastguard Worker png_do_expand_16(png_row_infop row_info, png_bytep row)
4610*a67afe4dSAndroid Build Coastguard Worker {
4611*a67afe4dSAndroid Build Coastguard Worker    if (row_info->bit_depth == 8 &&
4612*a67afe4dSAndroid Build Coastguard Worker       row_info->color_type != PNG_COLOR_TYPE_PALETTE)
4613*a67afe4dSAndroid Build Coastguard Worker    {
4614*a67afe4dSAndroid Build Coastguard Worker       /* The row have a sequence of bytes containing [0..255] and we need
4615*a67afe4dSAndroid Build Coastguard Worker        * to turn it into another row containing [0..65535], to do this we
4616*a67afe4dSAndroid Build Coastguard Worker        * calculate:
4617*a67afe4dSAndroid Build Coastguard Worker        *
4618*a67afe4dSAndroid Build Coastguard Worker        *  (input / 255) * 65535
4619*a67afe4dSAndroid Build Coastguard Worker        *
4620*a67afe4dSAndroid Build Coastguard Worker        *  Which happens to be exactly input * 257 and this can be achieved
4621*a67afe4dSAndroid Build Coastguard Worker        *  simply by byte replication in place (copying backwards).
4622*a67afe4dSAndroid Build Coastguard Worker        */
4623*a67afe4dSAndroid Build Coastguard Worker       png_byte *sp = row + row_info->rowbytes; /* source, last byte + 1 */
4624*a67afe4dSAndroid Build Coastguard Worker       png_byte *dp = sp + row_info->rowbytes;  /* destination, end + 1 */
4625*a67afe4dSAndroid Build Coastguard Worker       while (dp > sp)
4626*a67afe4dSAndroid Build Coastguard Worker       {
4627*a67afe4dSAndroid Build Coastguard Worker          dp[-2] = dp[-1] = *--sp; dp -= 2;
4628*a67afe4dSAndroid Build Coastguard Worker       }
4629*a67afe4dSAndroid Build Coastguard Worker 
4630*a67afe4dSAndroid Build Coastguard Worker       row_info->rowbytes *= 2;
4631*a67afe4dSAndroid Build Coastguard Worker       row_info->bit_depth = 16;
4632*a67afe4dSAndroid Build Coastguard Worker       row_info->pixel_depth = (png_byte)(row_info->channels * 16);
4633*a67afe4dSAndroid Build Coastguard Worker    }
4634*a67afe4dSAndroid Build Coastguard Worker }
4635*a67afe4dSAndroid Build Coastguard Worker #endif
4636*a67afe4dSAndroid Build Coastguard Worker 
4637*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_QUANTIZE_SUPPORTED
4638*a67afe4dSAndroid Build Coastguard Worker static void
png_do_quantize(png_row_infop row_info,png_bytep row,png_const_bytep palette_lookup,png_const_bytep quantize_lookup)4639*a67afe4dSAndroid Build Coastguard Worker png_do_quantize(png_row_infop row_info, png_bytep row,
4640*a67afe4dSAndroid Build Coastguard Worker     png_const_bytep palette_lookup, png_const_bytep quantize_lookup)
4641*a67afe4dSAndroid Build Coastguard Worker {
4642*a67afe4dSAndroid Build Coastguard Worker    png_bytep sp, dp;
4643*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 i;
4644*a67afe4dSAndroid Build Coastguard Worker    png_uint_32 row_width=row_info->width;
4645*a67afe4dSAndroid Build Coastguard Worker 
4646*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_do_quantize");
4647*a67afe4dSAndroid Build Coastguard Worker 
4648*a67afe4dSAndroid Build Coastguard Worker    if (row_info->bit_depth == 8)
4649*a67afe4dSAndroid Build Coastguard Worker    {
4650*a67afe4dSAndroid Build Coastguard Worker       if (row_info->color_type == PNG_COLOR_TYPE_RGB && palette_lookup)
4651*a67afe4dSAndroid Build Coastguard Worker       {
4652*a67afe4dSAndroid Build Coastguard Worker          int r, g, b, p;
4653*a67afe4dSAndroid Build Coastguard Worker          sp = row;
4654*a67afe4dSAndroid Build Coastguard Worker          dp = row;
4655*a67afe4dSAndroid Build Coastguard Worker          for (i = 0; i < row_width; i++)
4656*a67afe4dSAndroid Build Coastguard Worker          {
4657*a67afe4dSAndroid Build Coastguard Worker             r = *sp++;
4658*a67afe4dSAndroid Build Coastguard Worker             g = *sp++;
4659*a67afe4dSAndroid Build Coastguard Worker             b = *sp++;
4660*a67afe4dSAndroid Build Coastguard Worker 
4661*a67afe4dSAndroid Build Coastguard Worker             /* This looks real messy, but the compiler will reduce
4662*a67afe4dSAndroid Build Coastguard Worker              * it down to a reasonable formula.  For example, with
4663*a67afe4dSAndroid Build Coastguard Worker              * 5 bits per color, we get:
4664*a67afe4dSAndroid Build Coastguard Worker              * p = (((r >> 3) & 0x1f) << 10) |
4665*a67afe4dSAndroid Build Coastguard Worker              *    (((g >> 3) & 0x1f) << 5) |
4666*a67afe4dSAndroid Build Coastguard Worker              *    ((b >> 3) & 0x1f);
4667*a67afe4dSAndroid Build Coastguard Worker              */
4668*a67afe4dSAndroid Build Coastguard Worker             p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) &
4669*a67afe4dSAndroid Build Coastguard Worker                 ((1 << PNG_QUANTIZE_RED_BITS) - 1)) <<
4670*a67afe4dSAndroid Build Coastguard Worker                 (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) |
4671*a67afe4dSAndroid Build Coastguard Worker                 (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) &
4672*a67afe4dSAndroid Build Coastguard Worker                 ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) <<
4673*a67afe4dSAndroid Build Coastguard Worker                 (PNG_QUANTIZE_BLUE_BITS)) |
4674*a67afe4dSAndroid Build Coastguard Worker                 ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) &
4675*a67afe4dSAndroid Build Coastguard Worker                 ((1 << PNG_QUANTIZE_BLUE_BITS) - 1));
4676*a67afe4dSAndroid Build Coastguard Worker 
4677*a67afe4dSAndroid Build Coastguard Worker             *dp++ = palette_lookup[p];
4678*a67afe4dSAndroid Build Coastguard Worker          }
4679*a67afe4dSAndroid Build Coastguard Worker 
4680*a67afe4dSAndroid Build Coastguard Worker          row_info->color_type = PNG_COLOR_TYPE_PALETTE;
4681*a67afe4dSAndroid Build Coastguard Worker          row_info->channels = 1;
4682*a67afe4dSAndroid Build Coastguard Worker          row_info->pixel_depth = row_info->bit_depth;
4683*a67afe4dSAndroid Build Coastguard Worker          row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
4684*a67afe4dSAndroid Build Coastguard Worker       }
4685*a67afe4dSAndroid Build Coastguard Worker 
4686*a67afe4dSAndroid Build Coastguard Worker       else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
4687*a67afe4dSAndroid Build Coastguard Worker          palette_lookup != NULL)
4688*a67afe4dSAndroid Build Coastguard Worker       {
4689*a67afe4dSAndroid Build Coastguard Worker          int r, g, b, p;
4690*a67afe4dSAndroid Build Coastguard Worker          sp = row;
4691*a67afe4dSAndroid Build Coastguard Worker          dp = row;
4692*a67afe4dSAndroid Build Coastguard Worker          for (i = 0; i < row_width; i++)
4693*a67afe4dSAndroid Build Coastguard Worker          {
4694*a67afe4dSAndroid Build Coastguard Worker             r = *sp++;
4695*a67afe4dSAndroid Build Coastguard Worker             g = *sp++;
4696*a67afe4dSAndroid Build Coastguard Worker             b = *sp++;
4697*a67afe4dSAndroid Build Coastguard Worker             sp++;
4698*a67afe4dSAndroid Build Coastguard Worker 
4699*a67afe4dSAndroid Build Coastguard Worker             p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) &
4700*a67afe4dSAndroid Build Coastguard Worker                 ((1 << PNG_QUANTIZE_RED_BITS) - 1)) <<
4701*a67afe4dSAndroid Build Coastguard Worker                 (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) |
4702*a67afe4dSAndroid Build Coastguard Worker                 (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) &
4703*a67afe4dSAndroid Build Coastguard Worker                 ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) <<
4704*a67afe4dSAndroid Build Coastguard Worker                 (PNG_QUANTIZE_BLUE_BITS)) |
4705*a67afe4dSAndroid Build Coastguard Worker                 ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) &
4706*a67afe4dSAndroid Build Coastguard Worker                 ((1 << PNG_QUANTIZE_BLUE_BITS) - 1));
4707*a67afe4dSAndroid Build Coastguard Worker 
4708*a67afe4dSAndroid Build Coastguard Worker             *dp++ = palette_lookup[p];
4709*a67afe4dSAndroid Build Coastguard Worker          }
4710*a67afe4dSAndroid Build Coastguard Worker 
4711*a67afe4dSAndroid Build Coastguard Worker          row_info->color_type = PNG_COLOR_TYPE_PALETTE;
4712*a67afe4dSAndroid Build Coastguard Worker          row_info->channels = 1;
4713*a67afe4dSAndroid Build Coastguard Worker          row_info->pixel_depth = row_info->bit_depth;
4714*a67afe4dSAndroid Build Coastguard Worker          row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
4715*a67afe4dSAndroid Build Coastguard Worker       }
4716*a67afe4dSAndroid Build Coastguard Worker 
4717*a67afe4dSAndroid Build Coastguard Worker       else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
4718*a67afe4dSAndroid Build Coastguard Worker          quantize_lookup)
4719*a67afe4dSAndroid Build Coastguard Worker       {
4720*a67afe4dSAndroid Build Coastguard Worker          sp = row;
4721*a67afe4dSAndroid Build Coastguard Worker 
4722*a67afe4dSAndroid Build Coastguard Worker          for (i = 0; i < row_width; i++, sp++)
4723*a67afe4dSAndroid Build Coastguard Worker          {
4724*a67afe4dSAndroid Build Coastguard Worker             *sp = quantize_lookup[*sp];
4725*a67afe4dSAndroid Build Coastguard Worker          }
4726*a67afe4dSAndroid Build Coastguard Worker       }
4727*a67afe4dSAndroid Build Coastguard Worker    }
4728*a67afe4dSAndroid Build Coastguard Worker }
4729*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_QUANTIZE */
4730*a67afe4dSAndroid Build Coastguard Worker 
4731*a67afe4dSAndroid Build Coastguard Worker /* Transform the row.  The order of transformations is significant,
4732*a67afe4dSAndroid Build Coastguard Worker  * and is very touchy.  If you add a transformation, take care to
4733*a67afe4dSAndroid Build Coastguard Worker  * decide how it fits in with the other transformations here.
4734*a67afe4dSAndroid Build Coastguard Worker  */
4735*a67afe4dSAndroid Build Coastguard Worker void /* PRIVATE */
png_do_read_transformations(png_structrp png_ptr,png_row_infop row_info)4736*a67afe4dSAndroid Build Coastguard Worker png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info)
4737*a67afe4dSAndroid Build Coastguard Worker {
4738*a67afe4dSAndroid Build Coastguard Worker    png_debug(1, "in png_do_read_transformations");
4739*a67afe4dSAndroid Build Coastguard Worker 
4740*a67afe4dSAndroid Build Coastguard Worker    if (png_ptr->row_buf == NULL)
4741*a67afe4dSAndroid Build Coastguard Worker    {
4742*a67afe4dSAndroid Build Coastguard Worker       /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this
4743*a67afe4dSAndroid Build Coastguard Worker        * error is incredibly rare and incredibly easy to debug without this
4744*a67afe4dSAndroid Build Coastguard Worker        * information.
4745*a67afe4dSAndroid Build Coastguard Worker        */
4746*a67afe4dSAndroid Build Coastguard Worker       png_error(png_ptr, "NULL row buffer");
4747*a67afe4dSAndroid Build Coastguard Worker    }
4748*a67afe4dSAndroid Build Coastguard Worker 
4749*a67afe4dSAndroid Build Coastguard Worker    /* The following is debugging; prior to 1.5.4 the code was never compiled in;
4750*a67afe4dSAndroid Build Coastguard Worker     * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro
4751*a67afe4dSAndroid Build Coastguard Worker     * PNG_WARN_UNINITIALIZED_ROW removed.  In 1.6 the new flag is set only for
4752*a67afe4dSAndroid Build Coastguard Worker     * all transformations, however in practice the ROW_INIT always gets done on
4753*a67afe4dSAndroid Build Coastguard Worker     * demand, if necessary.
4754*a67afe4dSAndroid Build Coastguard Worker     */
4755*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 &&
4756*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)
4757*a67afe4dSAndroid Build Coastguard Worker    {
4758*a67afe4dSAndroid Build Coastguard Worker       /* Application has failed to call either png_read_start_image() or
4759*a67afe4dSAndroid Build Coastguard Worker        * png_read_update_info() after setting transforms that expand pixels.
4760*a67afe4dSAndroid Build Coastguard Worker        * This check added to libpng-1.2.19 (but not enabled until 1.5.4).
4761*a67afe4dSAndroid Build Coastguard Worker        */
4762*a67afe4dSAndroid Build Coastguard Worker       png_error(png_ptr, "Uninitialized row");
4763*a67afe4dSAndroid Build Coastguard Worker    }
4764*a67afe4dSAndroid Build Coastguard Worker 
4765*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_EXPAND_SUPPORTED
4766*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_EXPAND) != 0)
4767*a67afe4dSAndroid Build Coastguard Worker    {
4768*a67afe4dSAndroid Build Coastguard Worker       if (row_info->color_type == PNG_COLOR_TYPE_PALETTE)
4769*a67afe4dSAndroid Build Coastguard Worker       {
4770*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE
4771*a67afe4dSAndroid Build Coastguard Worker          if ((png_ptr->num_trans > 0) && (png_ptr->bit_depth == 8))
4772*a67afe4dSAndroid Build Coastguard Worker          {
4773*a67afe4dSAndroid Build Coastguard Worker             if (png_ptr->riffled_palette == NULL)
4774*a67afe4dSAndroid Build Coastguard Worker             {
4775*a67afe4dSAndroid Build Coastguard Worker                /* Initialize the accelerated palette expansion. */
4776*a67afe4dSAndroid Build Coastguard Worker                png_ptr->riffled_palette =
4777*a67afe4dSAndroid Build Coastguard Worker                    (png_bytep)png_malloc(png_ptr, 256 * 4);
4778*a67afe4dSAndroid Build Coastguard Worker                png_riffle_palette_neon(png_ptr);
4779*a67afe4dSAndroid Build Coastguard Worker             }
4780*a67afe4dSAndroid Build Coastguard Worker          }
4781*a67afe4dSAndroid Build Coastguard Worker #endif
4782*a67afe4dSAndroid Build Coastguard Worker          png_do_expand_palette(png_ptr, row_info, png_ptr->row_buf + 1,
4783*a67afe4dSAndroid Build Coastguard Worker              png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans);
4784*a67afe4dSAndroid Build Coastguard Worker       }
4785*a67afe4dSAndroid Build Coastguard Worker 
4786*a67afe4dSAndroid Build Coastguard Worker       else
4787*a67afe4dSAndroid Build Coastguard Worker       {
4788*a67afe4dSAndroid Build Coastguard Worker          if (png_ptr->num_trans != 0 &&
4789*a67afe4dSAndroid Build Coastguard Worker              (png_ptr->transformations & PNG_EXPAND_tRNS) != 0)
4790*a67afe4dSAndroid Build Coastguard Worker             png_do_expand(row_info, png_ptr->row_buf + 1,
4791*a67afe4dSAndroid Build Coastguard Worker                 &(png_ptr->trans_color));
4792*a67afe4dSAndroid Build Coastguard Worker 
4793*a67afe4dSAndroid Build Coastguard Worker          else
4794*a67afe4dSAndroid Build Coastguard Worker             png_do_expand(row_info, png_ptr->row_buf + 1, NULL);
4795*a67afe4dSAndroid Build Coastguard Worker       }
4796*a67afe4dSAndroid Build Coastguard Worker    }
4797*a67afe4dSAndroid Build Coastguard Worker #endif
4798*a67afe4dSAndroid Build Coastguard Worker 
4799*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
4800*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 &&
4801*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->transformations & PNG_COMPOSE) == 0 &&
4802*a67afe4dSAndroid Build Coastguard Worker        (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
4803*a67afe4dSAndroid Build Coastguard Worker        row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
4804*a67afe4dSAndroid Build Coastguard Worker       png_do_strip_channel(row_info, png_ptr->row_buf + 1,
4805*a67afe4dSAndroid Build Coastguard Worker           0 /* at_start == false, because SWAP_ALPHA happens later */);
4806*a67afe4dSAndroid Build Coastguard Worker #endif
4807*a67afe4dSAndroid Build Coastguard Worker 
4808*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
4809*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)
4810*a67afe4dSAndroid Build Coastguard Worker    {
4811*a67afe4dSAndroid Build Coastguard Worker       int rgb_error =
4812*a67afe4dSAndroid Build Coastguard Worker           png_do_rgb_to_gray(png_ptr, row_info,
4813*a67afe4dSAndroid Build Coastguard Worker               png_ptr->row_buf + 1);
4814*a67afe4dSAndroid Build Coastguard Worker 
4815*a67afe4dSAndroid Build Coastguard Worker       if (rgb_error != 0)
4816*a67afe4dSAndroid Build Coastguard Worker       {
4817*a67afe4dSAndroid Build Coastguard Worker          png_ptr->rgb_to_gray_status=1;
4818*a67afe4dSAndroid Build Coastguard Worker          if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
4819*a67afe4dSAndroid Build Coastguard Worker              PNG_RGB_TO_GRAY_WARN)
4820*a67afe4dSAndroid Build Coastguard Worker             png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
4821*a67afe4dSAndroid Build Coastguard Worker 
4822*a67afe4dSAndroid Build Coastguard Worker          if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
4823*a67afe4dSAndroid Build Coastguard Worker              PNG_RGB_TO_GRAY_ERR)
4824*a67afe4dSAndroid Build Coastguard Worker             png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
4825*a67afe4dSAndroid Build Coastguard Worker       }
4826*a67afe4dSAndroid Build Coastguard Worker    }
4827*a67afe4dSAndroid Build Coastguard Worker #endif
4828*a67afe4dSAndroid Build Coastguard Worker 
4829*a67afe4dSAndroid Build Coastguard Worker /* From Andreas Dilger e-mail to png-implement, 26 March 1998:
4830*a67afe4dSAndroid Build Coastguard Worker  *
4831*a67afe4dSAndroid Build Coastguard Worker  *   In most cases, the "simple transparency" should be done prior to doing
4832*a67afe4dSAndroid Build Coastguard Worker  *   gray-to-RGB, or you will have to test 3x as many bytes to check if a
4833*a67afe4dSAndroid Build Coastguard Worker  *   pixel is transparent.  You would also need to make sure that the
4834*a67afe4dSAndroid Build Coastguard Worker  *   transparency information is upgraded to RGB.
4835*a67afe4dSAndroid Build Coastguard Worker  *
4836*a67afe4dSAndroid Build Coastguard Worker  *   To summarize, the current flow is:
4837*a67afe4dSAndroid Build Coastguard Worker  *   - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
4838*a67afe4dSAndroid Build Coastguard Worker  *                                   with background "in place" if transparent,
4839*a67afe4dSAndroid Build Coastguard Worker  *                                   convert to RGB if necessary
4840*a67afe4dSAndroid Build Coastguard Worker  *   - Gray + alpha -> composite with gray background and remove alpha bytes,
4841*a67afe4dSAndroid Build Coastguard Worker  *                                   convert to RGB if necessary
4842*a67afe4dSAndroid Build Coastguard Worker  *
4843*a67afe4dSAndroid Build Coastguard Worker  *   To support RGB backgrounds for gray images we need:
4844*a67afe4dSAndroid Build Coastguard Worker  *   - Gray + simple transparency -> convert to RGB + simple transparency,
4845*a67afe4dSAndroid Build Coastguard Worker  *                                   compare 3 or 6 bytes and composite with
4846*a67afe4dSAndroid Build Coastguard Worker  *                                   background "in place" if transparent
4847*a67afe4dSAndroid Build Coastguard Worker  *                                   (3x compare/pixel compared to doing
4848*a67afe4dSAndroid Build Coastguard Worker  *                                   composite with gray bkgrnd)
4849*a67afe4dSAndroid Build Coastguard Worker  *   - Gray + alpha -> convert to RGB + alpha, composite with background and
4850*a67afe4dSAndroid Build Coastguard Worker  *                                   remove alpha bytes (3x float
4851*a67afe4dSAndroid Build Coastguard Worker  *                                   operations/pixel compared with composite
4852*a67afe4dSAndroid Build Coastguard Worker  *                                   on gray background)
4853*a67afe4dSAndroid Build Coastguard Worker  *
4854*a67afe4dSAndroid Build Coastguard Worker  *  Greg's change will do this.  The reason it wasn't done before is for
4855*a67afe4dSAndroid Build Coastguard Worker  *  performance, as this increases the per-pixel operations.  If we would check
4856*a67afe4dSAndroid Build Coastguard Worker  *  in advance if the background was gray or RGB, and position the gray-to-RGB
4857*a67afe4dSAndroid Build Coastguard Worker  *  transform appropriately, then it would save a lot of work/time.
4858*a67afe4dSAndroid Build Coastguard Worker  */
4859*a67afe4dSAndroid Build Coastguard Worker 
4860*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
4861*a67afe4dSAndroid Build Coastguard Worker    /* If gray -> RGB, do so now only if background is non-gray; else do later
4862*a67afe4dSAndroid Build Coastguard Worker     * for performance reasons
4863*a67afe4dSAndroid Build Coastguard Worker     */
4864*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 &&
4865*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) == 0)
4866*a67afe4dSAndroid Build Coastguard Worker       png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1);
4867*a67afe4dSAndroid Build Coastguard Worker #endif
4868*a67afe4dSAndroid Build Coastguard Worker 
4869*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
4870*a67afe4dSAndroid Build Coastguard Worker    defined(PNG_READ_ALPHA_MODE_SUPPORTED)
4871*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_COMPOSE) != 0)
4872*a67afe4dSAndroid Build Coastguard Worker       png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr);
4873*a67afe4dSAndroid Build Coastguard Worker #endif
4874*a67afe4dSAndroid Build Coastguard Worker 
4875*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GAMMA_SUPPORTED
4876*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_GAMMA) != 0 &&
4877*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
4878*a67afe4dSAndroid Build Coastguard Worker       /* Because RGB_TO_GRAY does the gamma transform. */
4879*a67afe4dSAndroid Build Coastguard Worker       (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0 &&
4880*a67afe4dSAndroid Build Coastguard Worker #endif
4881*a67afe4dSAndroid Build Coastguard Worker #if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
4882*a67afe4dSAndroid Build Coastguard Worker    defined(PNG_READ_ALPHA_MODE_SUPPORTED)
4883*a67afe4dSAndroid Build Coastguard Worker       /* Because PNG_COMPOSE does the gamma transform if there is something to
4884*a67afe4dSAndroid Build Coastguard Worker        * do (if there is an alpha channel or transparency.)
4885*a67afe4dSAndroid Build Coastguard Worker        */
4886*a67afe4dSAndroid Build Coastguard Worker        !((png_ptr->transformations & PNG_COMPOSE) != 0 &&
4887*a67afe4dSAndroid Build Coastguard Worker        ((png_ptr->num_trans != 0) ||
4888*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)) &&
4889*a67afe4dSAndroid Build Coastguard Worker #endif
4890*a67afe4dSAndroid Build Coastguard Worker       /* Because png_init_read_transformations transforms the palette, unless
4891*a67afe4dSAndroid Build Coastguard Worker        * RGB_TO_GRAY will do the transform.
4892*a67afe4dSAndroid Build Coastguard Worker        */
4893*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
4894*a67afe4dSAndroid Build Coastguard Worker       png_do_gamma(row_info, png_ptr->row_buf + 1, png_ptr);
4895*a67afe4dSAndroid Build Coastguard Worker #endif
4896*a67afe4dSAndroid Build Coastguard Worker 
4897*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
4898*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 &&
4899*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->transformations & PNG_COMPOSE) != 0 &&
4900*a67afe4dSAndroid Build Coastguard Worker        (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
4901*a67afe4dSAndroid Build Coastguard Worker        row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
4902*a67afe4dSAndroid Build Coastguard Worker       png_do_strip_channel(row_info, png_ptr->row_buf + 1,
4903*a67afe4dSAndroid Build Coastguard Worker           0 /* at_start == false, because SWAP_ALPHA happens later */);
4904*a67afe4dSAndroid Build Coastguard Worker #endif
4905*a67afe4dSAndroid Build Coastguard Worker 
4906*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_ALPHA_MODE_SUPPORTED
4907*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 &&
4908*a67afe4dSAndroid Build Coastguard Worker        (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0)
4909*a67afe4dSAndroid Build Coastguard Worker       png_do_encode_alpha(row_info, png_ptr->row_buf + 1, png_ptr);
4910*a67afe4dSAndroid Build Coastguard Worker #endif
4911*a67afe4dSAndroid Build Coastguard Worker 
4912*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
4913*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0)
4914*a67afe4dSAndroid Build Coastguard Worker       png_do_scale_16_to_8(row_info, png_ptr->row_buf + 1);
4915*a67afe4dSAndroid Build Coastguard Worker #endif
4916*a67afe4dSAndroid Build Coastguard Worker 
4917*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
4918*a67afe4dSAndroid Build Coastguard Worker    /* There is no harm in doing both of these because only one has any effect,
4919*a67afe4dSAndroid Build Coastguard Worker     * by putting the 'scale' option first if the app asks for scale (either by
4920*a67afe4dSAndroid Build Coastguard Worker     * calling the API or in a TRANSFORM flag) this is what happens.
4921*a67afe4dSAndroid Build Coastguard Worker     */
4922*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_16_TO_8) != 0)
4923*a67afe4dSAndroid Build Coastguard Worker       png_do_chop(row_info, png_ptr->row_buf + 1);
4924*a67afe4dSAndroid Build Coastguard Worker #endif
4925*a67afe4dSAndroid Build Coastguard Worker 
4926*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_QUANTIZE_SUPPORTED
4927*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_QUANTIZE) != 0)
4928*a67afe4dSAndroid Build Coastguard Worker    {
4929*a67afe4dSAndroid Build Coastguard Worker       png_do_quantize(row_info, png_ptr->row_buf + 1,
4930*a67afe4dSAndroid Build Coastguard Worker           png_ptr->palette_lookup, png_ptr->quantize_index);
4931*a67afe4dSAndroid Build Coastguard Worker 
4932*a67afe4dSAndroid Build Coastguard Worker       if (row_info->rowbytes == 0)
4933*a67afe4dSAndroid Build Coastguard Worker          png_error(png_ptr, "png_do_quantize returned rowbytes=0");
4934*a67afe4dSAndroid Build Coastguard Worker    }
4935*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_QUANTIZE */
4936*a67afe4dSAndroid Build Coastguard Worker 
4937*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_EXPAND_16_SUPPORTED
4938*a67afe4dSAndroid Build Coastguard Worker    /* Do the expansion now, after all the arithmetic has been done.  Notice
4939*a67afe4dSAndroid Build Coastguard Worker     * that previous transformations can handle the PNG_EXPAND_16 flag if this
4940*a67afe4dSAndroid Build Coastguard Worker     * is efficient (particularly true in the case of gamma correction, where
4941*a67afe4dSAndroid Build Coastguard Worker     * better accuracy results faster!)
4942*a67afe4dSAndroid Build Coastguard Worker     */
4943*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_EXPAND_16) != 0)
4944*a67afe4dSAndroid Build Coastguard Worker       png_do_expand_16(row_info, png_ptr->row_buf + 1);
4945*a67afe4dSAndroid Build Coastguard Worker #endif
4946*a67afe4dSAndroid Build Coastguard Worker 
4947*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
4948*a67afe4dSAndroid Build Coastguard Worker    /* NOTE: moved here in 1.5.4 (from much later in this list.) */
4949*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 &&
4950*a67afe4dSAndroid Build Coastguard Worker        (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) != 0)
4951*a67afe4dSAndroid Build Coastguard Worker       png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1);
4952*a67afe4dSAndroid Build Coastguard Worker #endif
4953*a67afe4dSAndroid Build Coastguard Worker 
4954*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_INVERT_SUPPORTED
4955*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)
4956*a67afe4dSAndroid Build Coastguard Worker       png_do_invert(row_info, png_ptr->row_buf + 1);
4957*a67afe4dSAndroid Build Coastguard Worker #endif
4958*a67afe4dSAndroid Build Coastguard Worker 
4959*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
4960*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0)
4961*a67afe4dSAndroid Build Coastguard Worker       png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1);
4962*a67afe4dSAndroid Build Coastguard Worker #endif
4963*a67afe4dSAndroid Build Coastguard Worker 
4964*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_SHIFT_SUPPORTED
4965*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_SHIFT) != 0)
4966*a67afe4dSAndroid Build Coastguard Worker       png_do_unshift(row_info, png_ptr->row_buf + 1,
4967*a67afe4dSAndroid Build Coastguard Worker           &(png_ptr->shift));
4968*a67afe4dSAndroid Build Coastguard Worker #endif
4969*a67afe4dSAndroid Build Coastguard Worker 
4970*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_PACK_SUPPORTED
4971*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_PACK) != 0)
4972*a67afe4dSAndroid Build Coastguard Worker       png_do_unpack(row_info, png_ptr->row_buf + 1);
4973*a67afe4dSAndroid Build Coastguard Worker #endif
4974*a67afe4dSAndroid Build Coastguard Worker 
4975*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
4976*a67afe4dSAndroid Build Coastguard Worker    /* Added at libpng-1.5.10 */
4977*a67afe4dSAndroid Build Coastguard Worker    if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
4978*a67afe4dSAndroid Build Coastguard Worker        png_ptr->num_palette_max >= 0)
4979*a67afe4dSAndroid Build Coastguard Worker       png_do_check_palette_indexes(png_ptr, row_info);
4980*a67afe4dSAndroid Build Coastguard Worker #endif
4981*a67afe4dSAndroid Build Coastguard Worker 
4982*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_BGR_SUPPORTED
4983*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_BGR) != 0)
4984*a67afe4dSAndroid Build Coastguard Worker       png_do_bgr(row_info, png_ptr->row_buf + 1);
4985*a67afe4dSAndroid Build Coastguard Worker #endif
4986*a67afe4dSAndroid Build Coastguard Worker 
4987*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_PACKSWAP_SUPPORTED
4988*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
4989*a67afe4dSAndroid Build Coastguard Worker       png_do_packswap(row_info, png_ptr->row_buf + 1);
4990*a67afe4dSAndroid Build Coastguard Worker #endif
4991*a67afe4dSAndroid Build Coastguard Worker 
4992*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_FILLER_SUPPORTED
4993*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_FILLER) != 0)
4994*a67afe4dSAndroid Build Coastguard Worker       png_do_read_filler(row_info, png_ptr->row_buf + 1,
4995*a67afe4dSAndroid Build Coastguard Worker           (png_uint_32)png_ptr->filler, png_ptr->flags);
4996*a67afe4dSAndroid Build Coastguard Worker #endif
4997*a67afe4dSAndroid Build Coastguard Worker 
4998*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
4999*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0)
5000*a67afe4dSAndroid Build Coastguard Worker       png_do_read_swap_alpha(row_info, png_ptr->row_buf + 1);
5001*a67afe4dSAndroid Build Coastguard Worker #endif
5002*a67afe4dSAndroid Build Coastguard Worker 
5003*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_16BIT_SUPPORTED
5004*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_SWAP_SUPPORTED
5005*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)
5006*a67afe4dSAndroid Build Coastguard Worker       png_do_swap(row_info, png_ptr->row_buf + 1);
5007*a67afe4dSAndroid Build Coastguard Worker #endif
5008*a67afe4dSAndroid Build Coastguard Worker #endif
5009*a67afe4dSAndroid Build Coastguard Worker 
5010*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
5011*a67afe4dSAndroid Build Coastguard Worker    if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0)
5012*a67afe4dSAndroid Build Coastguard Worker    {
5013*a67afe4dSAndroid Build Coastguard Worker       if (png_ptr->read_user_transform_fn != NULL)
5014*a67afe4dSAndroid Build Coastguard Worker          (*(png_ptr->read_user_transform_fn)) /* User read transform function */
5015*a67afe4dSAndroid Build Coastguard Worker              (png_ptr,     /* png_ptr */
5016*a67afe4dSAndroid Build Coastguard Worker              row_info,     /* row_info: */
5017*a67afe4dSAndroid Build Coastguard Worker                 /*  png_uint_32 width;       width of row */
5018*a67afe4dSAndroid Build Coastguard Worker                 /*  size_t rowbytes;         number of bytes in row */
5019*a67afe4dSAndroid Build Coastguard Worker                 /*  png_byte color_type;     color type of pixels */
5020*a67afe4dSAndroid Build Coastguard Worker                 /*  png_byte bit_depth;      bit depth of samples */
5021*a67afe4dSAndroid Build Coastguard Worker                 /*  png_byte channels;       number of channels (1-4) */
5022*a67afe4dSAndroid Build Coastguard Worker                 /*  png_byte pixel_depth;    bits per pixel (depth*channels) */
5023*a67afe4dSAndroid Build Coastguard Worker              png_ptr->row_buf + 1);    /* start of pixel data for row */
5024*a67afe4dSAndroid Build Coastguard Worker #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
5025*a67afe4dSAndroid Build Coastguard Worker       if (png_ptr->user_transform_depth != 0)
5026*a67afe4dSAndroid Build Coastguard Worker          row_info->bit_depth = png_ptr->user_transform_depth;
5027*a67afe4dSAndroid Build Coastguard Worker 
5028*a67afe4dSAndroid Build Coastguard Worker       if (png_ptr->user_transform_channels != 0)
5029*a67afe4dSAndroid Build Coastguard Worker          row_info->channels = png_ptr->user_transform_channels;
5030*a67afe4dSAndroid Build Coastguard Worker #endif
5031*a67afe4dSAndroid Build Coastguard Worker       row_info->pixel_depth = (png_byte)(row_info->bit_depth *
5032*a67afe4dSAndroid Build Coastguard Worker           row_info->channels);
5033*a67afe4dSAndroid Build Coastguard Worker 
5034*a67afe4dSAndroid Build Coastguard Worker       row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width);
5035*a67afe4dSAndroid Build Coastguard Worker    }
5036*a67afe4dSAndroid Build Coastguard Worker #endif
5037*a67afe4dSAndroid Build Coastguard Worker }
5038*a67afe4dSAndroid Build Coastguard Worker 
5039*a67afe4dSAndroid Build Coastguard Worker #endif /* READ_TRANSFORMS */
5040*a67afe4dSAndroid Build Coastguard Worker #endif /* READ */
5041