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