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