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