blob: 608adef414865a3fc3b0bab1d708fb751d0c65f6 [file] [log] [blame]
The Android Open Source Project893912b2009-03-03 19:30:05 -08001
2/* pngrtran.c - transforms the data in a row for PNG readers
3 *
Matt Sarett9ea75692016-01-08 13:00:42 -05004 * Last changed in libpng 1.6.19 [November 12, 2015]
5 * Copyright (c) 1998-2015 Glenn Randers-Pehrson
The Android Open Source Project893912b2009-03-03 19:30:05 -08006 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
7 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
8 *
Patrick Scotta0bb96c2009-07-22 11:50:02 -04009 * This code is released under the libpng license.
10 * For conditions of distribution and use, see the disclaimer
11 * and license in png.h
12 *
The Android Open Source Project893912b2009-03-03 19:30:05 -080013 * This file contains functions optionally called by an application
14 * in order to tell libpng how to handle data when reading a PNG.
15 * Transformations that are used in both reading and writing are
16 * in pngtrans.c.
17 */
18
Chris Craikb50c2172013-07-29 15:28:30 -070019#include "pngpriv.h"
20
Patrick Scott5f6bd842010-06-28 16:55:16 -040021#ifdef PNG_READ_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -080022
23/* Set the action on getting a CRC error for an ancillary or critical chunk. */
24void PNGAPI
Chris Craikb50c2172013-07-29 15:28:30 -070025png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action)
The Android Open Source Project893912b2009-03-03 19:30:05 -080026{
The Android Open Source Project4215dd12009-03-09 11:52:12 -070027 png_debug(1, "in png_set_crc_action");
Chris Craikb50c2172013-07-29 15:28:30 -070028
Patrick Scotta0bb96c2009-07-22 11:50:02 -040029 if (png_ptr == NULL)
30 return;
Patrick Scott5f6bd842010-06-28 16:55:16 -040031
32 /* Tell libpng how we react to CRC errors in critical chunks */
The Android Open Source Project893912b2009-03-03 19:30:05 -080033 switch (crit_action)
34 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -040035 case PNG_CRC_NO_CHANGE: /* Leave setting as is */
The Android Open Source Project893912b2009-03-03 19:30:05 -080036 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -040037
38 case PNG_CRC_WARN_USE: /* Warn/use data */
The Android Open Source Project893912b2009-03-03 19:30:05 -080039 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
40 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;
41 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -040042
43 case PNG_CRC_QUIET_USE: /* Quiet/use data */
The Android Open Source Project893912b2009-03-03 19:30:05 -080044 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
45 png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |
46 PNG_FLAG_CRC_CRITICAL_IGNORE;
47 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -040048
49 case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */
The Android Open Source Project4215dd12009-03-09 11:52:12 -070050 png_warning(png_ptr,
Chris Craikb50c2172013-07-29 15:28:30 -070051 "Can't discard critical data on CRC error");
Patrick Scotta0bb96c2009-07-22 11:50:02 -040052 case PNG_CRC_ERROR_QUIT: /* Error/quit */
53
The Android Open Source Project893912b2009-03-03 19:30:05 -080054 case PNG_CRC_DEFAULT:
55 default:
56 png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
57 break;
58 }
59
Patrick Scott5f6bd842010-06-28 16:55:16 -040060 /* Tell libpng how we react to CRC errors in ancillary chunks */
The Android Open Source Project893912b2009-03-03 19:30:05 -080061 switch (ancil_action)
62 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -040063 case PNG_CRC_NO_CHANGE: /* Leave setting as is */
The Android Open Source Project893912b2009-03-03 19:30:05 -080064 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -040065
66 case PNG_CRC_WARN_USE: /* Warn/use data */
The Android Open Source Project893912b2009-03-03 19:30:05 -080067 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
68 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
69 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -040070
71 case PNG_CRC_QUIET_USE: /* Quiet/use data */
The Android Open Source Project893912b2009-03-03 19:30:05 -080072 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
73 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |
74 PNG_FLAG_CRC_ANCILLARY_NOWARN;
75 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -040076
77 case PNG_CRC_ERROR_QUIT: /* Error/quit */
The Android Open Source Project893912b2009-03-03 19:30:05 -080078 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
79 png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;
80 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -040081
82 case PNG_CRC_WARN_DISCARD: /* Warn/discard data */
83
The Android Open Source Project893912b2009-03-03 19:30:05 -080084 case PNG_CRC_DEFAULT:
85 default:
86 png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
87 break;
88 }
89}
90
Chris Craikb50c2172013-07-29 15:28:30 -070091#ifdef PNG_READ_TRANSFORMS_SUPPORTED
92/* Is it OK to set a transformation now? Only if png_start_read_image or
93 * png_read_update_info have not been called. It is not necessary for the IHDR
Matt Sarett9ea75692016-01-08 13:00:42 -050094 * to have been read in all cases; the need_IHDR parameter allows for this
95 * check too.
Chris Craikb50c2172013-07-29 15:28:30 -070096 */
97static int
98png_rtran_ok(png_structrp png_ptr, int need_IHDR)
The Android Open Source Project893912b2009-03-03 19:30:05 -080099{
Chris Craikb50c2172013-07-29 15:28:30 -0700100 if (png_ptr != NULL)
101 {
Matt Sarett9ea75692016-01-08 13:00:42 -0500102#ifndef PNG_INDEX_SUPPORTED
103 if ((png_ptr->flags & PNG_FLAG_ROW_INIT) != 0)
Chris Craikb50c2172013-07-29 15:28:30 -0700104 png_app_error(png_ptr,
105 "invalid after png_start_read_image or png_read_update_info");
106
107 else if (need_IHDR && (png_ptr->mode & PNG_HAVE_IHDR) == 0)
108 png_app_error(png_ptr, "invalid before the PNG header has been read");
109
110 else
111 {
112 /* Turn on failure to initialize correctly for all transforms. */
113 png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED;
114
115 return 1; /* Ok */
116 }
Matt Sarett9ea75692016-01-08 13:00:42 -0500117#else
118 return 1;
119#endif
Chris Craikb50c2172013-07-29 15:28:30 -0700120 }
121
122 return 0; /* no png_error possible! */
123}
124#endif
125
126#ifdef PNG_READ_BACKGROUND_SUPPORTED
127/* Handle alpha and tRNS via a background color */
128void PNGFAPI
129png_set_background_fixed(png_structrp png_ptr,
130 png_const_color_16p background_color, int background_gamma_code,
131 int need_expand, png_fixed_point background_gamma)
132{
133 png_debug(1, "in png_set_background_fixed");
134
Matt Sarett9ea75692016-01-08 13:00:42 -0500135 if (png_rtran_ok(png_ptr, 0) == 0 || background_color == NULL)
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400136 return;
Chris Craikb50c2172013-07-29 15:28:30 -0700137
The Android Open Source Project893912b2009-03-03 19:30:05 -0800138 if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
139 {
140 png_warning(png_ptr, "Application must supply a known background gamma");
141 return;
142 }
143
Chris Craikb50c2172013-07-29 15:28:30 -0700144 png_ptr->transformations |= PNG_COMPOSE | PNG_STRIP_ALPHA;
145 png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
146 png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
147
148 png_ptr->background = *background_color;
149 png_ptr->background_gamma = background_gamma;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800150 png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
Matt Sarett9ea75692016-01-08 13:00:42 -0500151 if (need_expand != 0)
Chris Craikb50c2172013-07-29 15:28:30 -0700152 png_ptr->transformations |= PNG_BACKGROUND_EXPAND;
153 else
154 png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;
155}
156
157# ifdef PNG_FLOATING_POINT_SUPPORTED
158void PNGAPI
159png_set_background(png_structrp png_ptr,
160 png_const_color_16p background_color, int background_gamma_code,
161 int need_expand, double background_gamma)
162{
163 png_set_background_fixed(png_ptr, background_color, background_gamma_code,
164 need_expand, png_fixed(png_ptr, background_gamma, "png_set_background"));
165}
166# endif /* FLOATING_POINT */
167#endif /* READ_BACKGROUND */
168
169/* Scale 16-bit depth files to 8-bit depth. If both of these are set then the
170 * one that pngrtran does first (scale) happens. This is necessary to allow the
171 * TRANSFORM and API behavior to be somewhat consistent, and it's simpler.
172 */
173#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
174void PNGAPI
175png_set_scale_16(png_structrp png_ptr)
176{
177 png_debug(1, "in png_set_scale_16");
178
Matt Sarett9ea75692016-01-08 13:00:42 -0500179 if (png_rtran_ok(png_ptr, 0) == 0)
Chris Craikb50c2172013-07-29 15:28:30 -0700180 return;
181
182 png_ptr->transformations |= PNG_SCALE_16_TO_8;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800183}
184#endif
185
Chris Craikb50c2172013-07-29 15:28:30 -0700186#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
187/* Chop 16-bit depth files to 8-bit depth */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800188void PNGAPI
Chris Craikb50c2172013-07-29 15:28:30 -0700189png_set_strip_16(png_structrp png_ptr)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800190{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700191 png_debug(1, "in png_set_strip_16");
Patrick Scott5f6bd842010-06-28 16:55:16 -0400192
Matt Sarett9ea75692016-01-08 13:00:42 -0500193 if (png_rtran_ok(png_ptr, 0) == 0)
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400194 return;
Chris Craikb50c2172013-07-29 15:28:30 -0700195
The Android Open Source Project893912b2009-03-03 19:30:05 -0800196 png_ptr->transformations |= PNG_16_TO_8;
197}
198#endif
199
Patrick Scott5f6bd842010-06-28 16:55:16 -0400200#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800201void PNGAPI
Chris Craikb50c2172013-07-29 15:28:30 -0700202png_set_strip_alpha(png_structrp png_ptr)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800203{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700204 png_debug(1, "in png_set_strip_alpha");
Patrick Scott5f6bd842010-06-28 16:55:16 -0400205
Matt Sarett9ea75692016-01-08 13:00:42 -0500206 if (png_rtran_ok(png_ptr, 0) == 0)
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400207 return;
Chris Craikb50c2172013-07-29 15:28:30 -0700208
209 png_ptr->transformations |= PNG_STRIP_ALPHA;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800210}
211#endif
212
Chris Craikb50c2172013-07-29 15:28:30 -0700213#if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED)
214static png_fixed_point
215translate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma,
216 int is_screen)
217{
218 /* Check for flag values. The main reason for having the old Mac value as a
219 * flag is that it is pretty near impossible to work out what the correct
220 * value is from Apple documentation - a working Mac system is needed to
221 * discover the value!
222 */
223 if (output_gamma == PNG_DEFAULT_sRGB ||
224 output_gamma == PNG_FP_1 / PNG_DEFAULT_sRGB)
225 {
226 /* If there is no sRGB support this just sets the gamma to the standard
227 * sRGB value. (This is a side effect of using this function!)
228 */
229# ifdef PNG_READ_sRGB_SUPPORTED
230 png_ptr->flags |= PNG_FLAG_ASSUME_sRGB;
231# else
232 PNG_UNUSED(png_ptr)
233# endif
Matt Sarett9ea75692016-01-08 13:00:42 -0500234 if (is_screen != 0)
Chris Craikb50c2172013-07-29 15:28:30 -0700235 output_gamma = PNG_GAMMA_sRGB;
236 else
237 output_gamma = PNG_GAMMA_sRGB_INVERSE;
238 }
239
240 else if (output_gamma == PNG_GAMMA_MAC_18 ||
241 output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18)
242 {
Matt Sarett9ea75692016-01-08 13:00:42 -0500243 if (is_screen != 0)
Chris Craikb50c2172013-07-29 15:28:30 -0700244 output_gamma = PNG_GAMMA_MAC_OLD;
245 else
246 output_gamma = PNG_GAMMA_MAC_INVERSE;
247 }
248
249 return output_gamma;
250}
251
252# ifdef PNG_FLOATING_POINT_SUPPORTED
253static png_fixed_point
254convert_gamma_value(png_structrp png_ptr, double output_gamma)
255{
256 /* The following silently ignores cases where fixed point (times 100,000)
257 * gamma values are passed to the floating point API. This is safe and it
258 * means the fixed point constants work just fine with the floating point
259 * API. The alternative would just lead to undetected errors and spurious
260 * bug reports. Negative values fail inside the _fixed API unless they
261 * correspond to the flag values.
262 */
263 if (output_gamma > 0 && output_gamma < 128)
264 output_gamma *= PNG_FP_1;
265
266 /* This preserves -1 and -2 exactly: */
267 output_gamma = floor(output_gamma + .5);
268
269 if (output_gamma > PNG_FP_MAX || output_gamma < PNG_FP_MIN)
270 png_fixed_error(png_ptr, "gamma value");
271
272 return (png_fixed_point)output_gamma;
273}
274# endif
275#endif /* READ_ALPHA_MODE || READ_GAMMA */
276
277#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
278void PNGFAPI
279png_set_alpha_mode_fixed(png_structrp png_ptr, int mode,
280 png_fixed_point output_gamma)
281{
282 int compose = 0;
283 png_fixed_point file_gamma;
284
285 png_debug(1, "in png_set_alpha_mode");
286
Matt Sarett9ea75692016-01-08 13:00:42 -0500287 if (png_rtran_ok(png_ptr, 0) == 0)
Chris Craikb50c2172013-07-29 15:28:30 -0700288 return;
289
290 output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/);
291
292 /* Validate the value to ensure it is in a reasonable range. The value
293 * is expected to be 1 or greater, but this range test allows for some
294 * viewing correction values. The intent is to weed out users of this API
295 * who use the inverse of the gamma value accidentally! Since some of these
296 * values are reasonable this may have to be changed.
297 */
298 if (output_gamma < 70000 || output_gamma > 300000)
299 png_error(png_ptr, "output gamma out of expected range");
300
301 /* The default file gamma is the inverse of the output gamma; the output
302 * gamma may be changed below so get the file value first:
303 */
304 file_gamma = png_reciprocal(output_gamma);
305
306 /* There are really 8 possibilities here, composed of any combination
307 * of:
308 *
309 * premultiply the color channels
310 * do not encode non-opaque pixels
311 * encode the alpha as well as the color channels
312 *
313 * The differences disappear if the input/output ('screen') gamma is 1.0,
314 * because then the encoding is a no-op and there is only the choice of
315 * premultiplying the color channels or not.
316 *
317 * png_set_alpha_mode and png_set_background interact because both use
318 * png_compose to do the work. Calling both is only useful when
319 * png_set_alpha_mode is used to set the default mode - PNG_ALPHA_PNG - along
320 * with a default gamma value. Otherwise PNG_COMPOSE must not be set.
321 */
322 switch (mode)
323 {
324 case PNG_ALPHA_PNG: /* default: png standard */
325 /* No compose, but it may be set by png_set_background! */
326 png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
327 png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
328 break;
329
330 case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */
331 compose = 1;
332 png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
333 png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
334 /* The output is linear: */
335 output_gamma = PNG_FP_1;
336 break;
337
338 case PNG_ALPHA_OPTIMIZED: /* associated, non-opaque pixels linear */
339 compose = 1;
340 png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
341 png_ptr->flags |= PNG_FLAG_OPTIMIZE_ALPHA;
342 /* output_gamma records the encoding of opaque pixels! */
343 break;
344
345 case PNG_ALPHA_BROKEN: /* associated, non-linear, alpha encoded */
346 compose = 1;
347 png_ptr->transformations |= PNG_ENCODE_ALPHA;
348 png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
349 break;
350
351 default:
352 png_error(png_ptr, "invalid alpha mode");
353 }
354
355 /* Only set the default gamma if the file gamma has not been set (this has
356 * the side effect that the gamma in a second call to png_set_alpha_mode will
357 * be ignored.)
358 */
359 if (png_ptr->colorspace.gamma == 0)
360 {
361 png_ptr->colorspace.gamma = file_gamma;
362 png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
363 }
364
365 /* But always set the output gamma: */
366 png_ptr->screen_gamma = output_gamma;
367
368 /* Finally, if pre-multiplying, set the background fields to achieve the
369 * desired result.
370 */
Matt Sarett9ea75692016-01-08 13:00:42 -0500371 if (compose != 0)
Chris Craikb50c2172013-07-29 15:28:30 -0700372 {
373 /* And obtain alpha pre-multiplication by composing on black: */
374 memset(&png_ptr->background, 0, (sizeof png_ptr->background));
375 png_ptr->background_gamma = png_ptr->colorspace.gamma; /* just in case */
376 png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_FILE;
377 png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;
378
Matt Sarett9ea75692016-01-08 13:00:42 -0500379 if ((png_ptr->transformations & PNG_COMPOSE) != 0)
Chris Craikb50c2172013-07-29 15:28:30 -0700380 png_error(png_ptr,
381 "conflicting calls to set alpha mode and background");
382
383 png_ptr->transformations |= PNG_COMPOSE;
384 }
385}
386
387# ifdef PNG_FLOATING_POINT_SUPPORTED
388void PNGAPI
389png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma)
390{
391 png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr,
392 output_gamma));
393}
394# endif
395#endif
396
397#ifdef PNG_READ_QUANTIZE_SUPPORTED
398/* Dither file to 8-bit. Supply a palette, the current number
The Android Open Source Project893912b2009-03-03 19:30:05 -0800399 * of elements in the palette, the maximum number of elements
400 * allowed, and a histogram if possible. If the current number
Matt Sarett9ea75692016-01-08 13:00:42 -0500401 * of colors is greater than the maximum number, the palette will be
Chris Craikb50c2172013-07-29 15:28:30 -0700402 * modified to fit in the maximum number. "full_quantize" indicates
403 * whether we need a quantizing cube set up for RGB images, or if we
The Android Open Source Project893912b2009-03-03 19:30:05 -0800404 * simply are reducing the number of colors in a paletted image.
405 */
406
407typedef struct png_dsort_struct
408{
Chris Craikb50c2172013-07-29 15:28:30 -0700409 struct png_dsort_struct * next;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800410 png_byte left;
411 png_byte right;
412} png_dsort;
Chris Craikb50c2172013-07-29 15:28:30 -0700413typedef png_dsort * png_dsortp;
414typedef png_dsort * * png_dsortpp;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800415
416void PNGAPI
Chris Craikb50c2172013-07-29 15:28:30 -0700417png_set_quantize(png_structrp png_ptr, png_colorp palette,
418 int num_palette, int maximum_colors, png_const_uint_16p histogram,
419 int full_quantize)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800420{
Chris Craikb50c2172013-07-29 15:28:30 -0700421 png_debug(1, "in png_set_quantize");
Patrick Scott5f6bd842010-06-28 16:55:16 -0400422
Matt Sarett9ea75692016-01-08 13:00:42 -0500423 if (png_rtran_ok(png_ptr, 0) == 0)
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400424 return;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800425
Chris Craikb50c2172013-07-29 15:28:30 -0700426 png_ptr->transformations |= PNG_QUANTIZE;
427
Matt Sarett9ea75692016-01-08 13:00:42 -0500428 if (full_quantize == 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800429 {
430 int i;
431
Chris Craikb50c2172013-07-29 15:28:30 -0700432 png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr,
433 (png_uint_32)(num_palette * (sizeof (png_byte))));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800434 for (i = 0; i < num_palette; i++)
Chris Craikb50c2172013-07-29 15:28:30 -0700435 png_ptr->quantize_index[i] = (png_byte)i;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800436 }
437
438 if (num_palette > maximum_colors)
439 {
440 if (histogram != NULL)
441 {
442 /* This is easy enough, just throw out the least used colors.
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400443 * Perhaps not the best solution, but good enough.
444 */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800445
446 int i;
447
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400448 /* Initialize an array to sort colors */
Chris Craikb50c2172013-07-29 15:28:30 -0700449 png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr,
450 (png_uint_32)(num_palette * (sizeof (png_byte))));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800451
Chris Craikb50c2172013-07-29 15:28:30 -0700452 /* Initialize the quantize_sort array */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800453 for (i = 0; i < num_palette; i++)
Chris Craikb50c2172013-07-29 15:28:30 -0700454 png_ptr->quantize_sort[i] = (png_byte)i;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800455
456 /* Find the least used palette entries by starting a
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400457 * bubble sort, and running it until we have sorted
458 * out enough colors. Note that we don't care about
459 * sorting all the colors, just finding which are
460 * least used.
461 */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800462
463 for (i = num_palette - 1; i >= maximum_colors; i--)
464 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400465 int done; /* To stop early if the list is pre-sorted */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800466 int j;
467
468 done = 1;
469 for (j = 0; j < i; j++)
470 {
Chris Craikb50c2172013-07-29 15:28:30 -0700471 if (histogram[png_ptr->quantize_sort[j]]
472 < histogram[png_ptr->quantize_sort[j + 1]])
The Android Open Source Project893912b2009-03-03 19:30:05 -0800473 {
474 png_byte t;
475
Chris Craikb50c2172013-07-29 15:28:30 -0700476 t = png_ptr->quantize_sort[j];
477 png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1];
478 png_ptr->quantize_sort[j + 1] = t;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800479 done = 0;
480 }
481 }
Chris Craikb50c2172013-07-29 15:28:30 -0700482
Matt Sarett9ea75692016-01-08 13:00:42 -0500483 if (done != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800484 break;
485 }
486
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400487 /* Swap the palette around, and set up a table, if necessary */
Matt Sarett9ea75692016-01-08 13:00:42 -0500488 if (full_quantize != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800489 {
490 int j = num_palette;
491
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400492 /* Put all the useful colors within the max, but don't
493 * move the others.
494 */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800495 for (i = 0; i < maximum_colors; i++)
496 {
Chris Craikb50c2172013-07-29 15:28:30 -0700497 if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800498 {
499 do
500 j--;
Chris Craikb50c2172013-07-29 15:28:30 -0700501 while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
502
The Android Open Source Project893912b2009-03-03 19:30:05 -0800503 palette[i] = palette[j];
504 }
505 }
506 }
507 else
508 {
509 int j = num_palette;
510
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400511 /* Move all the used colors inside the max limit, and
512 * develop a translation table.
513 */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800514 for (i = 0; i < maximum_colors; i++)
515 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400516 /* Only move the colors we need to */
Chris Craikb50c2172013-07-29 15:28:30 -0700517 if ((int)png_ptr->quantize_sort[i] >= maximum_colors)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800518 {
519 png_color tmp_color;
520
521 do
522 j--;
Chris Craikb50c2172013-07-29 15:28:30 -0700523 while ((int)png_ptr->quantize_sort[j] >= maximum_colors);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800524
525 tmp_color = palette[j];
526 palette[j] = palette[i];
527 palette[i] = tmp_color;
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400528 /* Indicate where the color went */
Chris Craikb50c2172013-07-29 15:28:30 -0700529 png_ptr->quantize_index[j] = (png_byte)i;
530 png_ptr->quantize_index[i] = (png_byte)j;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800531 }
532 }
533
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400534 /* Find closest color for those colors we are not using */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800535 for (i = 0; i < num_palette; i++)
536 {
Chris Craikb50c2172013-07-29 15:28:30 -0700537 if ((int)png_ptr->quantize_index[i] >= maximum_colors)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800538 {
539 int min_d, k, min_k, d_index;
540
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400541 /* Find the closest color to one we threw out */
Chris Craikb50c2172013-07-29 15:28:30 -0700542 d_index = png_ptr->quantize_index[i];
The Android Open Source Project893912b2009-03-03 19:30:05 -0800543 min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
544 for (k = 1, min_k = 0; k < maximum_colors; k++)
545 {
546 int d;
547
548 d = PNG_COLOR_DIST(palette[d_index], palette[k]);
549
550 if (d < min_d)
551 {
552 min_d = d;
553 min_k = k;
554 }
555 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400556 /* Point to closest color */
Chris Craikb50c2172013-07-29 15:28:30 -0700557 png_ptr->quantize_index[i] = (png_byte)min_k;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800558 }
559 }
560 }
Chris Craikb50c2172013-07-29 15:28:30 -0700561 png_free(png_ptr, png_ptr->quantize_sort);
562 png_ptr->quantize_sort = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800563 }
564 else
565 {
566 /* This is much harder to do simply (and quickly). Perhaps
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400567 * we need to go through a median cut routine, but those
568 * don't always behave themselves with only a few colors
569 * as input. So we will just find the closest two colors,
570 * and throw out one of them (chosen somewhat randomly).
571 * [We don't understand this at all, so if someone wants to
572 * work on improving it, be our guest - AED, GRP]
573 */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800574 int i;
575 int max_d;
576 int num_new_palette;
577 png_dsortp t;
578 png_dsortpp hash;
579
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700580 t = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800581
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400582 /* Initialize palette index arrays */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800583 png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
Chris Craikb50c2172013-07-29 15:28:30 -0700584 (png_uint_32)(num_palette * (sizeof (png_byte))));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800585 png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
Chris Craikb50c2172013-07-29 15:28:30 -0700586 (png_uint_32)(num_palette * (sizeof (png_byte))));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800587
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400588 /* Initialize the sort array */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800589 for (i = 0; i < num_palette; i++)
590 {
591 png_ptr->index_to_palette[i] = (png_byte)i;
592 png_ptr->palette_to_index[i] = (png_byte)i;
593 }
594
Patrick Scott5f6bd842010-06-28 16:55:16 -0400595 hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 *
Chris Craikb50c2172013-07-29 15:28:30 -0700596 (sizeof (png_dsortp))));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800597
598 num_new_palette = num_palette;
599
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400600 /* Initial wild guess at how far apart the farthest pixel
601 * pair we will be eliminating will be. Larger
602 * numbers mean more areas will be allocated, Smaller
603 * numbers run the risk of not saving enough data, and
604 * having to do this all over again.
605 *
606 * I have not done extensive checking on this number.
607 */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800608 max_d = 96;
609
610 while (num_new_palette > maximum_colors)
611 {
612 for (i = 0; i < num_new_palette - 1; i++)
613 {
614 int j;
615
616 for (j = i + 1; j < num_new_palette; j++)
617 {
618 int d;
619
620 d = PNG_COLOR_DIST(palette[i], palette[j]);
621
622 if (d <= max_d)
623 {
624
625 t = (png_dsortp)png_malloc_warn(png_ptr,
Chris Craikb50c2172013-07-29 15:28:30 -0700626 (png_uint_32)(sizeof (png_dsort)));
627
The Android Open Source Project893912b2009-03-03 19:30:05 -0800628 if (t == NULL)
629 break;
Chris Craikb50c2172013-07-29 15:28:30 -0700630
The Android Open Source Project893912b2009-03-03 19:30:05 -0800631 t->next = hash[d];
632 t->left = (png_byte)i;
633 t->right = (png_byte)j;
634 hash[d] = t;
635 }
636 }
637 if (t == NULL)
638 break;
639 }
640
641 if (t != NULL)
642 for (i = 0; i <= max_d; i++)
643 {
644 if (hash[i] != NULL)
645 {
646 png_dsortp p;
647
648 for (p = hash[i]; p; p = p->next)
649 {
650 if ((int)png_ptr->index_to_palette[p->left]
Chris Craikb50c2172013-07-29 15:28:30 -0700651 < num_new_palette &&
652 (int)png_ptr->index_to_palette[p->right]
653 < num_new_palette)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800654 {
655 int j, next_j;
656
657 if (num_new_palette & 0x01)
658 {
659 j = p->left;
660 next_j = p->right;
661 }
662 else
663 {
664 j = p->right;
665 next_j = p->left;
666 }
667
668 num_new_palette--;
669 palette[png_ptr->index_to_palette[j]]
Chris Craikb50c2172013-07-29 15:28:30 -0700670 = palette[num_new_palette];
Matt Sarett9ea75692016-01-08 13:00:42 -0500671 if (full_quantize == 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800672 {
673 int k;
674
675 for (k = 0; k < num_palette; k++)
676 {
Chris Craikb50c2172013-07-29 15:28:30 -0700677 if (png_ptr->quantize_index[k] ==
678 png_ptr->index_to_palette[j])
679 png_ptr->quantize_index[k] =
680 png_ptr->index_to_palette[next_j];
681
682 if ((int)png_ptr->quantize_index[k] ==
683 num_new_palette)
684 png_ptr->quantize_index[k] =
685 png_ptr->index_to_palette[j];
The Android Open Source Project893912b2009-03-03 19:30:05 -0800686 }
687 }
688
689 png_ptr->index_to_palette[png_ptr->palette_to_index
Chris Craikb50c2172013-07-29 15:28:30 -0700690 [num_new_palette]] = png_ptr->index_to_palette[j];
691
The Android Open Source Project893912b2009-03-03 19:30:05 -0800692 png_ptr->palette_to_index[png_ptr->index_to_palette[j]]
Chris Craikb50c2172013-07-29 15:28:30 -0700693 = png_ptr->palette_to_index[num_new_palette];
The Android Open Source Project893912b2009-03-03 19:30:05 -0800694
Patrick Scott5f6bd842010-06-28 16:55:16 -0400695 png_ptr->index_to_palette[j] =
696 (png_byte)num_new_palette;
Chris Craikb50c2172013-07-29 15:28:30 -0700697
Patrick Scott5f6bd842010-06-28 16:55:16 -0400698 png_ptr->palette_to_index[num_new_palette] =
699 (png_byte)j;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800700 }
701 if (num_new_palette <= maximum_colors)
702 break;
703 }
704 if (num_new_palette <= maximum_colors)
705 break;
706 }
707 }
708
709 for (i = 0; i < 769; i++)
710 {
711 if (hash[i] != NULL)
712 {
713 png_dsortp p = hash[i];
714 while (p)
715 {
716 t = p->next;
717 png_free(png_ptr, p);
718 p = t;
719 }
720 }
721 hash[i] = 0;
722 }
723 max_d += 96;
724 }
725 png_free(png_ptr, hash);
726 png_free(png_ptr, png_ptr->palette_to_index);
727 png_free(png_ptr, png_ptr->index_to_palette);
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700728 png_ptr->palette_to_index = NULL;
729 png_ptr->index_to_palette = NULL;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800730 }
731 num_palette = maximum_colors;
732 }
733 if (png_ptr->palette == NULL)
734 {
735 png_ptr->palette = palette;
736 }
737 png_ptr->num_palette = (png_uint_16)num_palette;
738
Matt Sarett9ea75692016-01-08 13:00:42 -0500739 if (full_quantize != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800740 {
741 int i;
742 png_bytep distance;
Chris Craikb50c2172013-07-29 15:28:30 -0700743 int total_bits = PNG_QUANTIZE_RED_BITS + PNG_QUANTIZE_GREEN_BITS +
744 PNG_QUANTIZE_BLUE_BITS;
745 int num_red = (1 << PNG_QUANTIZE_RED_BITS);
746 int num_green = (1 << PNG_QUANTIZE_GREEN_BITS);
747 int num_blue = (1 << PNG_QUANTIZE_BLUE_BITS);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800748 png_size_t num_entries = ((png_size_t)1 << total_bits);
Patrick Scott5f6bd842010-06-28 16:55:16 -0400749
Chris Craikb50c2172013-07-29 15:28:30 -0700750 png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr,
751 (png_uint_32)(num_entries * (sizeof (png_byte))));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800752
753 distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *
Chris Craikb50c2172013-07-29 15:28:30 -0700754 (sizeof (png_byte))));
755
756 memset(distance, 0xff, num_entries * (sizeof (png_byte)));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800757
758 for (i = 0; i < num_palette; i++)
759 {
760 int ir, ig, ib;
Chris Craikb50c2172013-07-29 15:28:30 -0700761 int r = (palette[i].red >> (8 - PNG_QUANTIZE_RED_BITS));
762 int g = (palette[i].green >> (8 - PNG_QUANTIZE_GREEN_BITS));
763 int b = (palette[i].blue >> (8 - PNG_QUANTIZE_BLUE_BITS));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800764
765 for (ir = 0; ir < num_red; ir++)
766 {
767 /* int dr = abs(ir - r); */
768 int dr = ((ir > r) ? ir - r : r - ir);
Chris Craikb50c2172013-07-29 15:28:30 -0700769 int index_r = (ir << (PNG_QUANTIZE_BLUE_BITS +
770 PNG_QUANTIZE_GREEN_BITS));
The Android Open Source Project893912b2009-03-03 19:30:05 -0800771
772 for (ig = 0; ig < num_green; ig++)
773 {
774 /* int dg = abs(ig - g); */
775 int dg = ((ig > g) ? ig - g : g - ig);
776 int dt = dr + dg;
777 int dm = ((dr > dg) ? dr : dg);
Chris Craikb50c2172013-07-29 15:28:30 -0700778 int index_g = index_r | (ig << PNG_QUANTIZE_BLUE_BITS);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800779
780 for (ib = 0; ib < num_blue; ib++)
781 {
782 int d_index = index_g | ib;
783 /* int db = abs(ib - b); */
784 int db = ((ib > b) ? ib - b : b - ib);
785 int dmax = ((dm > db) ? dm : db);
786 int d = dmax + dt + db;
787
788 if (d < (int)distance[d_index])
789 {
790 distance[d_index] = (png_byte)d;
791 png_ptr->palette_lookup[d_index] = (png_byte)i;
792 }
793 }
794 }
795 }
796 }
797
798 png_free(png_ptr, distance);
799 }
800}
Matt Sarett9ea75692016-01-08 13:00:42 -0500801#endif /* READ_QUANTIZE */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800802
Chris Craikb50c2172013-07-29 15:28:30 -0700803#ifdef PNG_READ_GAMMA_SUPPORTED
804void PNGFAPI
805png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma,
806 png_fixed_point file_gamma)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800807{
Chris Craikb50c2172013-07-29 15:28:30 -0700808 png_debug(1, "in png_set_gamma_fixed");
Patrick Scott5f6bd842010-06-28 16:55:16 -0400809
Matt Sarett9ea75692016-01-08 13:00:42 -0500810 if (png_rtran_ok(png_ptr, 0) == 0)
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400811 return;
Patrick Scott5f6bd842010-06-28 16:55:16 -0400812
Chris Craikb50c2172013-07-29 15:28:30 -0700813 /* New in libpng-1.5.4 - reserve particular negative values as flags. */
814 scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/);
815 file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/);
816
817 /* Checking the gamma values for being >0 was added in 1.5.4 along with the
818 * premultiplied alpha support; this actually hides an undocumented feature
819 * of the previous implementation which allowed gamma processing to be
820 * disabled in background handling. There is no evidence (so far) that this
821 * was being used; however, png_set_background itself accepted and must still
822 * accept '0' for the gamma value it takes, because it isn't always used.
823 *
824 * Since this is an API change (albeit a very minor one that removes an
825 * undocumented API feature) the following checks were only enabled in
826 * libpng-1.6.0.
827 */
828 if (file_gamma <= 0)
829 png_error(png_ptr, "invalid file gamma in png_set_gamma");
830
831 if (scrn_gamma <= 0)
832 png_error(png_ptr, "invalid screen gamma in png_set_gamma");
833
834 /* Set the gamma values unconditionally - this overrides the value in the PNG
835 * file if a gAMA chunk was present. png_set_alpha_mode provides a
836 * different, easier, way to default the file gamma.
837 */
838 png_ptr->colorspace.gamma = file_gamma;
839 png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
840 png_ptr->screen_gamma = scrn_gamma;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800841}
Chris Craikb50c2172013-07-29 15:28:30 -0700842
843# ifdef PNG_FLOATING_POINT_SUPPORTED
844void PNGAPI
845png_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma)
846{
847 png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma),
848 convert_gamma_value(png_ptr, file_gamma));
849}
Matt Sarett9ea75692016-01-08 13:00:42 -0500850# endif /* FLOATING_POINT */
Chris Craikb50c2172013-07-29 15:28:30 -0700851#endif /* READ_GAMMA */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800852
Patrick Scott5f6bd842010-06-28 16:55:16 -0400853#ifdef PNG_READ_EXPAND_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800854/* Expand paletted images to RGB, expand grayscale images of
855 * less than 8-bit depth to 8-bit depth, and expand tRNS chunks
856 * to alpha channels.
857 */
858void PNGAPI
Chris Craikb50c2172013-07-29 15:28:30 -0700859png_set_expand(png_structrp png_ptr)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800860{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700861 png_debug(1, "in png_set_expand");
Patrick Scott5f6bd842010-06-28 16:55:16 -0400862
Matt Sarett9ea75692016-01-08 13:00:42 -0500863 if (png_rtran_ok(png_ptr, 0) == 0)
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400864 return;
Patrick Scott5f6bd842010-06-28 16:55:16 -0400865
The Android Open Source Project893912b2009-03-03 19:30:05 -0800866 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800867}
868
869/* GRR 19990627: the following three functions currently are identical
870 * to png_set_expand(). However, it is entirely reasonable that someone
871 * might wish to expand an indexed image to RGB but *not* expand a single,
872 * fully transparent palette entry to a full alpha channel--perhaps instead
873 * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace
874 * the transparent color with a particular RGB value, or drop tRNS entirely.
875 * IOW, a future version of the library may make the transformations flag
876 * a bit more fine-grained, with separate bits for each of these three
877 * functions.
878 *
879 * More to the point, these functions make it obvious what libpng will be
880 * doing, whereas "expand" can (and does) mean any number of things.
881 *
Patrick Scott5f6bd842010-06-28 16:55:16 -0400882 * GRP 20060307: In libpng-1.2.9, png_set_gray_1_2_4_to_8() was modified
883 * to expand only the sample depth but not to expand the tRNS to alpha
884 * and its name was changed to png_set_expand_gray_1_2_4_to_8().
The Android Open Source Project893912b2009-03-03 19:30:05 -0800885 */
886
887/* Expand paletted images to RGB. */
888void PNGAPI
Chris Craikb50c2172013-07-29 15:28:30 -0700889png_set_palette_to_rgb(png_structrp png_ptr)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800890{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700891 png_debug(1, "in png_set_palette_to_rgb");
Patrick Scott5f6bd842010-06-28 16:55:16 -0400892
Matt Sarett9ea75692016-01-08 13:00:42 -0500893 if (png_rtran_ok(png_ptr, 0) == 0)
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400894 return;
Patrick Scott5f6bd842010-06-28 16:55:16 -0400895
The Android Open Source Project893912b2009-03-03 19:30:05 -0800896 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800897}
898
The Android Open Source Project893912b2009-03-03 19:30:05 -0800899/* Expand grayscale images of less than 8-bit depth to 8 bits. */
900void PNGAPI
Chris Craikb50c2172013-07-29 15:28:30 -0700901png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800902{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700903 png_debug(1, "in png_set_expand_gray_1_2_4_to_8");
Patrick Scott5f6bd842010-06-28 16:55:16 -0400904
Matt Sarett9ea75692016-01-08 13:00:42 -0500905 if (png_rtran_ok(png_ptr, 0) == 0)
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400906 return;
Patrick Scott5f6bd842010-06-28 16:55:16 -0400907
The Android Open Source Project893912b2009-03-03 19:30:05 -0800908 png_ptr->transformations |= PNG_EXPAND;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800909}
The Android Open Source Project893912b2009-03-03 19:30:05 -0800910
Chris Craikb50c2172013-07-29 15:28:30 -0700911/* Expand tRNS chunks to alpha channels. */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800912void PNGAPI
Chris Craikb50c2172013-07-29 15:28:30 -0700913png_set_tRNS_to_alpha(png_structrp png_ptr)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800914{
Chris Craikb50c2172013-07-29 15:28:30 -0700915 png_debug(1, "in png_set_tRNS_to_alpha");
Patrick Scott5f6bd842010-06-28 16:55:16 -0400916
Matt Sarett9ea75692016-01-08 13:00:42 -0500917 if (png_rtran_ok(png_ptr, 0) == 0)
Patrick Scotta0bb96c2009-07-22 11:50:02 -0400918 return;
Patrick Scott5f6bd842010-06-28 16:55:16 -0400919
The Android Open Source Project893912b2009-03-03 19:30:05 -0800920 png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
921}
Matt Sarett9ea75692016-01-08 13:00:42 -0500922#endif /* READ_EXPAND */
The Android Open Source Project893912b2009-03-03 19:30:05 -0800923
Chris Craikb50c2172013-07-29 15:28:30 -0700924#ifdef PNG_READ_EXPAND_16_SUPPORTED
925/* Expand to 16-bit channels, expand the tRNS chunk too (because otherwise
926 * it may not work correctly.)
927 */
928void PNGAPI
929png_set_expand_16(png_structrp png_ptr)
930{
931 png_debug(1, "in png_set_expand_16");
932
Matt Sarett9ea75692016-01-08 13:00:42 -0500933 if (png_rtran_ok(png_ptr, 0) == 0)
Chris Craikb50c2172013-07-29 15:28:30 -0700934 return;
935
936 png_ptr->transformations |= (PNG_EXPAND_16 | PNG_EXPAND | PNG_EXPAND_tRNS);
937}
938#endif
939
Patrick Scott5f6bd842010-06-28 16:55:16 -0400940#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -0800941void PNGAPI
Chris Craikb50c2172013-07-29 15:28:30 -0700942png_set_gray_to_rgb(png_structrp png_ptr)
The Android Open Source Project893912b2009-03-03 19:30:05 -0800943{
The Android Open Source Project4215dd12009-03-09 11:52:12 -0700944 png_debug(1, "in png_set_gray_to_rgb");
Patrick Scott5f6bd842010-06-28 16:55:16 -0400945
Matt Sarett9ea75692016-01-08 13:00:42 -0500946 if (png_rtran_ok(png_ptr, 0) == 0)
Chris Craikb50c2172013-07-29 15:28:30 -0700947 return;
948
949 /* Because rgb must be 8 bits or more: */
950 png_set_expand_gray_1_2_4_to_8(png_ptr);
The Android Open Source Project893912b2009-03-03 19:30:05 -0800951 png_ptr->transformations |= PNG_GRAY_TO_RGB;
The Android Open Source Project893912b2009-03-03 19:30:05 -0800952}
953#endif
954
Patrick Scott5f6bd842010-06-28 16:55:16 -0400955#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
Chris Craikb50c2172013-07-29 15:28:30 -0700956void PNGFAPI
957png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action,
958 png_fixed_point red, png_fixed_point green)
959{
960 png_debug(1, "in png_set_rgb_to_gray");
961
962 /* Need the IHDR here because of the check on color_type below. */
963 /* TODO: fix this */
Matt Sarett9ea75692016-01-08 13:00:42 -0500964 if (png_rtran_ok(png_ptr, 1) == 0)
Chris Craikb50c2172013-07-29 15:28:30 -0700965 return;
966
Matt Sarett9ea75692016-01-08 13:00:42 -0500967 switch (error_action)
Chris Craikb50c2172013-07-29 15:28:30 -0700968 {
969 case PNG_ERROR_ACTION_NONE:
970 png_ptr->transformations |= PNG_RGB_TO_GRAY;
971 break;
972
973 case PNG_ERROR_ACTION_WARN:
974 png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;
975 break;
976
977 case PNG_ERROR_ACTION_ERROR:
978 png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;
979 break;
980
981 default:
982 png_error(png_ptr, "invalid error action to rgb_to_gray");
Chris Craikb50c2172013-07-29 15:28:30 -0700983 }
984
985 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
986#ifdef PNG_READ_EXPAND_SUPPORTED
987 png_ptr->transformations |= PNG_EXPAND;
988#else
989 {
990 /* Make this an error in 1.6 because otherwise the application may assume
991 * that it just worked and get a memory overwrite.
992 */
993 png_error(png_ptr,
994 "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED");
995
996 /* png_ptr->transformations &= ~PNG_RGB_TO_GRAY; */
997 }
998#endif
999 {
1000 if (red >= 0 && green >= 0 && red + green <= PNG_FP_1)
1001 {
1002 png_uint_16 red_int, green_int;
1003
1004 /* NOTE: this calculation does not round, but this behavior is retained
Matt Sarett9ea75692016-01-08 13:00:42 -05001005 * for consistency; the inaccuracy is very small. The code here always
Chris Craikb50c2172013-07-29 15:28:30 -07001006 * overwrites the coefficients, regardless of whether they have been
1007 * defaulted or set already.
1008 */
1009 red_int = (png_uint_16)(((png_uint_32)red*32768)/100000);
1010 green_int = (png_uint_16)(((png_uint_32)green*32768)/100000);
1011
1012 png_ptr->rgb_to_gray_red_coeff = red_int;
1013 png_ptr->rgb_to_gray_green_coeff = green_int;
1014 png_ptr->rgb_to_gray_coefficients_set = 1;
1015 }
1016
1017 else
1018 {
1019 if (red >= 0 && green >= 0)
1020 png_app_warning(png_ptr,
1021 "ignoring out of range rgb_to_gray coefficients");
1022
1023 /* Use the defaults, from the cHRM chunk if set, else the historical
1024 * values which are close to the sRGB/HDTV/ITU-Rec 709 values. See
1025 * png_do_rgb_to_gray for more discussion of the values. In this case
1026 * the coefficients are not marked as 'set' and are not overwritten if
1027 * something has already provided a default.
1028 */
1029 if (png_ptr->rgb_to_gray_red_coeff == 0 &&
1030 png_ptr->rgb_to_gray_green_coeff == 0)
1031 {
1032 png_ptr->rgb_to_gray_red_coeff = 6968;
1033 png_ptr->rgb_to_gray_green_coeff = 23434;
1034 /* png_ptr->rgb_to_gray_blue_coeff = 2366; */
1035 }
1036 }
1037 }
1038}
1039
Patrick Scott5f6bd842010-06-28 16:55:16 -04001040#ifdef PNG_FLOATING_POINT_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08001041/* Convert a RGB image to a grayscale of the same width. This allows us,
1042 * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.
1043 */
1044
1045void PNGAPI
Chris Craikb50c2172013-07-29 15:28:30 -07001046png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red,
The Android Open Source Project893912b2009-03-03 19:30:05 -08001047 double green)
1048{
Chris Craikb50c2172013-07-29 15:28:30 -07001049 png_set_rgb_to_gray_fixed(png_ptr, error_action,
1050 png_fixed(png_ptr, red, "rgb to gray red coefficient"),
1051 png_fixed(png_ptr, green, "rgb to gray green coefficient"));
The Android Open Source Project893912b2009-03-03 19:30:05 -08001052}
Chris Craikb50c2172013-07-29 15:28:30 -07001053#endif /* FLOATING POINT */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001054
Chris Craikb50c2172013-07-29 15:28:30 -07001055#endif /* RGB_TO_GRAY */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001056
1057#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001058 defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001059void PNGAPI
Chris Craikb50c2172013-07-29 15:28:30 -07001060png_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr
1061 read_user_transform_fn)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001062{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001063 png_debug(1, "in png_set_read_user_transform_fn");
Patrick Scott5f6bd842010-06-28 16:55:16 -04001064
Patrick Scott5f6bd842010-06-28 16:55:16 -04001065#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08001066 png_ptr->transformations |= PNG_USER_TRANSFORM;
1067 png_ptr->read_user_transform_fn = read_user_transform_fn;
1068#endif
Chris Craikb50c2172013-07-29 15:28:30 -07001069}
The Android Open Source Project893912b2009-03-03 19:30:05 -08001070#endif
Chris Craikb50c2172013-07-29 15:28:30 -07001071
1072#ifdef PNG_READ_TRANSFORMS_SUPPORTED
1073#ifdef PNG_READ_GAMMA_SUPPORTED
1074/* In the case of gamma transformations only do transformations on images where
1075 * the [file] gamma and screen_gamma are not close reciprocals, otherwise it
1076 * slows things down slightly, and also needlessly introduces small errors.
1077 */
1078static int /* PRIVATE */
1079png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma)
1080{
1081 /* PNG_GAMMA_THRESHOLD is the threshold for performing gamma
1082 * correction as a difference of the overall transform from 1.0
1083 *
1084 * We want to compare the threshold with s*f - 1, if we get
1085 * overflow here it is because of wacky gamma values so we
1086 * turn on processing anyway.
1087 */
1088 png_fixed_point gtest;
1089 return !png_muldiv(&gtest, screen_gamma, file_gamma, PNG_FP_1) ||
1090 png_gamma_significant(gtest);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001091}
1092#endif
1093
1094/* Initialize everything needed for the read. This includes modifying
1095 * the palette.
1096 */
Chris Craikb50c2172013-07-29 15:28:30 -07001097
Matt Sarett9ea75692016-01-08 13:00:42 -05001098/* For the moment 'png_init_palette_transformations' and
Chris Craikb50c2172013-07-29 15:28:30 -07001099 * 'png_init_rgb_transformations' only do some flag canceling optimizations.
1100 * The intent is that these two routines should have palette or rgb operations
1101 * extracted from 'png_init_read_transformations'.
1102 */
1103static void /* PRIVATE */
1104png_init_palette_transformations(png_structrp png_ptr)
1105{
1106 /* Called to handle the (input) palette case. In png_do_read_transformations
1107 * the first step is to expand the palette if requested, so this code must
1108 * take care to only make changes that are invariant with respect to the
1109 * palette expansion, or only do them if there is no expansion.
1110 *
1111 * STRIP_ALPHA has already been handled in the caller (by setting num_trans
1112 * to 0.)
1113 */
1114 int input_has_alpha = 0;
1115 int input_has_transparency = 0;
1116
1117 if (png_ptr->num_trans > 0)
1118 {
1119 int i;
1120
1121 /* Ignore if all the entries are opaque (unlikely!) */
1122 for (i=0; i<png_ptr->num_trans; ++i)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05301123 {
Chris Craikb50c2172013-07-29 15:28:30 -07001124 if (png_ptr->trans_alpha[i] == 255)
1125 continue;
1126 else if (png_ptr->trans_alpha[i] == 0)
1127 input_has_transparency = 1;
1128 else
Sireesh Tripurarib478e662014-05-09 15:15:10 +05301129 {
1130 input_has_transparency = 1;
Chris Craikb50c2172013-07-29 15:28:30 -07001131 input_has_alpha = 1;
Sireesh Tripurarib478e662014-05-09 15:15:10 +05301132 break;
1133 }
1134 }
Chris Craikb50c2172013-07-29 15:28:30 -07001135 }
1136
1137 /* If no alpha we can optimize. */
Matt Sarett9ea75692016-01-08 13:00:42 -05001138 if (input_has_alpha == 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001139 {
1140 /* Any alpha means background and associative alpha processing is
Sireesh Tripurarib478e662014-05-09 15:15:10 +05301141 * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA
Chris Craikb50c2172013-07-29 15:28:30 -07001142 * and ENCODE_ALPHA are irrelevant.
1143 */
1144 png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
1145 png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
1146
Matt Sarett9ea75692016-01-08 13:00:42 -05001147 if (input_has_transparency == 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001148 png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);
1149 }
1150
1151#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
1152 /* png_set_background handling - deals with the complexity of whether the
1153 * background color is in the file format or the screen format in the case
1154 * where an 'expand' will happen.
1155 */
1156
1157 /* The following code cannot be entered in the alpha pre-multiplication case
1158 * because PNG_BACKGROUND_EXPAND is cancelled below.
1159 */
Matt Sarett9ea75692016-01-08 13:00:42 -05001160 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 &&
1161 (png_ptr->transformations & PNG_EXPAND) != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001162 {
1163 {
1164 png_ptr->background.red =
1165 png_ptr->palette[png_ptr->background.index].red;
1166 png_ptr->background.green =
1167 png_ptr->palette[png_ptr->background.index].green;
1168 png_ptr->background.blue =
1169 png_ptr->palette[png_ptr->background.index].blue;
1170
1171#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05001172 if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001173 {
Matt Sarett9ea75692016-01-08 13:00:42 -05001174 if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001175 {
1176 /* Invert the alpha channel (in tRNS) unless the pixels are
1177 * going to be expanded, in which case leave it for later
1178 */
1179 int i, istop = png_ptr->num_trans;
1180
1181 for (i=0; i<istop; i++)
1182 png_ptr->trans_alpha[i] = (png_byte)(255 -
1183 png_ptr->trans_alpha[i]);
1184 }
1185 }
Matt Sarett9ea75692016-01-08 13:00:42 -05001186#endif /* READ_INVERT_ALPHA */
Chris Craikb50c2172013-07-29 15:28:30 -07001187 }
1188 } /* background expand and (therefore) no alpha association. */
Matt Sarett9ea75692016-01-08 13:00:42 -05001189#endif /* READ_EXPAND && READ_BACKGROUND */
Chris Craikb50c2172013-07-29 15:28:30 -07001190}
1191
1192static void /* PRIVATE */
1193png_init_rgb_transformations(png_structrp png_ptr)
1194{
1195 /* Added to libpng-1.5.4: check the color type to determine whether there
1196 * is any alpha or transparency in the image and simply cancel the
1197 * background and alpha mode stuff if there isn't.
1198 */
1199 int input_has_alpha = (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0;
1200 int input_has_transparency = png_ptr->num_trans > 0;
1201
1202 /* If no alpha we can optimize. */
Matt Sarett9ea75692016-01-08 13:00:42 -05001203 if (input_has_alpha == 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001204 {
1205 /* Any alpha means background and associative alpha processing is
Sireesh Tripurarib478e662014-05-09 15:15:10 +05301206 * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA
Chris Craikb50c2172013-07-29 15:28:30 -07001207 * and ENCODE_ALPHA are irrelevant.
1208 */
1209# ifdef PNG_READ_ALPHA_MODE_SUPPORTED
1210 png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
1211 png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
1212# endif
1213
Matt Sarett9ea75692016-01-08 13:00:42 -05001214 if (input_has_transparency == 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001215 png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);
1216 }
1217
1218#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
1219 /* png_set_background handling - deals with the complexity of whether the
1220 * background color is in the file format or the screen format in the case
1221 * where an 'expand' will happen.
1222 */
1223
1224 /* The following code cannot be entered in the alpha pre-multiplication case
1225 * because PNG_BACKGROUND_EXPAND is cancelled below.
1226 */
Matt Sarett9ea75692016-01-08 13:00:42 -05001227 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 &&
1228 (png_ptr->transformations & PNG_EXPAND) != 0 &&
1229 (png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001230 /* i.e., GRAY or GRAY_ALPHA */
1231 {
1232 {
1233 /* Expand background and tRNS chunks */
1234 int gray = png_ptr->background.gray;
1235 int trans_gray = png_ptr->trans_color.gray;
1236
1237 switch (png_ptr->bit_depth)
1238 {
1239 case 1:
1240 gray *= 0xff;
1241 trans_gray *= 0xff;
1242 break;
1243
1244 case 2:
1245 gray *= 0x55;
1246 trans_gray *= 0x55;
1247 break;
1248
1249 case 4:
1250 gray *= 0x11;
1251 trans_gray *= 0x11;
1252 break;
1253
1254 default:
1255
1256 case 8:
1257 /* FALL THROUGH (Already 8 bits) */
1258
1259 case 16:
1260 /* Already a full 16 bits */
1261 break;
1262 }
1263
1264 png_ptr->background.red = png_ptr->background.green =
1265 png_ptr->background.blue = (png_uint_16)gray;
1266
Matt Sarett9ea75692016-01-08 13:00:42 -05001267 if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001268 {
1269 png_ptr->trans_color.red = png_ptr->trans_color.green =
1270 png_ptr->trans_color.blue = (png_uint_16)trans_gray;
1271 }
1272 }
1273 } /* background expand and (therefore) no alpha association. */
Matt Sarett9ea75692016-01-08 13:00:42 -05001274#endif /* READ_EXPAND && READ_BACKGROUND */
Chris Craikb50c2172013-07-29 15:28:30 -07001275}
1276
The Android Open Source Project893912b2009-03-03 19:30:05 -08001277void /* PRIVATE */
Chris Craikb50c2172013-07-29 15:28:30 -07001278png_init_read_transformations(png_structrp png_ptr)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001279{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001280 png_debug(1, "in png_init_read_transformations");
Patrick Scott5f6bd842010-06-28 16:55:16 -04001281
Chris Craikb50c2172013-07-29 15:28:30 -07001282 /* This internal function is called from png_read_start_row in pngrutil.c
1283 * and it is called before the 'rowbytes' calculation is done, so the code
1284 * in here can change or update the transformations flags.
1285 *
1286 * First do updates that do not depend on the details of the PNG image data
1287 * being processed.
1288 */
1289
1290#ifdef PNG_READ_GAMMA_SUPPORTED
1291 /* Prior to 1.5.4 these tests were performed from png_set_gamma, 1.5.4 adds
1292 * png_set_alpha_mode and this is another source for a default file gamma so
1293 * the test needs to be performed later - here. In addition prior to 1.5.4
1294 * the tests were repeated for the PALETTE color type here - this is no
1295 * longer necessary (and doesn't seem to have been necessary before.)
1296 */
1297 {
1298 /* The following temporary indicates if overall gamma correction is
1299 * required.
1300 */
1301 int gamma_correction = 0;
1302
1303 if (png_ptr->colorspace.gamma != 0) /* has been set */
1304 {
1305 if (png_ptr->screen_gamma != 0) /* screen set too */
1306 gamma_correction = png_gamma_threshold(png_ptr->colorspace.gamma,
1307 png_ptr->screen_gamma);
1308
1309 else
1310 /* Assume the output matches the input; a long time default behavior
1311 * of libpng, although the standard has nothing to say about this.
1312 */
1313 png_ptr->screen_gamma = png_reciprocal(png_ptr->colorspace.gamma);
1314 }
1315
1316 else if (png_ptr->screen_gamma != 0)
1317 /* The converse - assume the file matches the screen, note that this
1318 * perhaps undesireable default can (from 1.5.4) be changed by calling
1319 * png_set_alpha_mode (even if the alpha handling mode isn't required
1320 * or isn't changed from the default.)
1321 */
1322 png_ptr->colorspace.gamma = png_reciprocal(png_ptr->screen_gamma);
1323
1324 else /* neither are set */
1325 /* Just in case the following prevents any processing - file and screen
1326 * are both assumed to be linear and there is no way to introduce a
1327 * third gamma value other than png_set_background with 'UNIQUE', and,
1328 * prior to 1.5.4
1329 */
1330 png_ptr->screen_gamma = png_ptr->colorspace.gamma = PNG_FP_1;
1331
1332 /* We have a gamma value now. */
1333 png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA;
1334
1335 /* Now turn the gamma transformation on or off as appropriate. Notice
1336 * that PNG_GAMMA just refers to the file->screen correction. Alpha
1337 * composition may independently cause gamma correction because it needs
1338 * linear data (e.g. if the file has a gAMA chunk but the screen gamma
1339 * hasn't been specified.) In any case this flag may get turned off in
1340 * the code immediately below if the transform can be handled outside the
1341 * row loop.
1342 */
Matt Sarett9ea75692016-01-08 13:00:42 -05001343 if (gamma_correction != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001344 png_ptr->transformations |= PNG_GAMMA;
1345
1346 else
1347 png_ptr->transformations &= ~PNG_GAMMA;
1348 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08001349#endif
1350
Chris Craikb50c2172013-07-29 15:28:30 -07001351 /* Certain transformations have the effect of preventing other
Matt Sarett9ea75692016-01-08 13:00:42 -05001352 * transformations that happen afterward in png_do_read_transformations;
Chris Craikb50c2172013-07-29 15:28:30 -07001353 * resolve the interdependencies here. From the code of
1354 * png_do_read_transformations the order is:
1355 *
1356 * 1) PNG_EXPAND (including PNG_EXPAND_tRNS)
1357 * 2) PNG_STRIP_ALPHA (if no compose)
1358 * 3) PNG_RGB_TO_GRAY
1359 * 4) PNG_GRAY_TO_RGB iff !PNG_BACKGROUND_IS_GRAY
1360 * 5) PNG_COMPOSE
1361 * 6) PNG_GAMMA
1362 * 7) PNG_STRIP_ALPHA (if compose)
1363 * 8) PNG_ENCODE_ALPHA
1364 * 9) PNG_SCALE_16_TO_8
1365 * 10) PNG_16_TO_8
1366 * 11) PNG_QUANTIZE (converts to palette)
1367 * 12) PNG_EXPAND_16
1368 * 13) PNG_GRAY_TO_RGB iff PNG_BACKGROUND_IS_GRAY
1369 * 14) PNG_INVERT_MONO
Sireesh Tripurarib478e662014-05-09 15:15:10 +05301370 * 15) PNG_INVERT_ALPHA
1371 * 16) PNG_SHIFT
1372 * 17) PNG_PACK
1373 * 18) PNG_BGR
1374 * 19) PNG_PACKSWAP
1375 * 20) PNG_FILLER (includes PNG_ADD_ALPHA)
Chris Craikb50c2172013-07-29 15:28:30 -07001376 * 21) PNG_SWAP_ALPHA
1377 * 22) PNG_SWAP_BYTES
1378 * 23) PNG_USER_TRANSFORM [must be last]
1379 */
1380#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05001381 if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 &&
1382 (png_ptr->transformations & PNG_COMPOSE) == 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001383 {
1384 /* Stripping the alpha channel happens immediately after the 'expand'
1385 * transformations, before all other transformation, so it cancels out
1386 * the alpha handling. It has the side effect negating the effect of
1387 * PNG_EXPAND_tRNS too:
1388 */
1389 png_ptr->transformations &= ~(PNG_BACKGROUND_EXPAND | PNG_ENCODE_ALPHA |
1390 PNG_EXPAND_tRNS);
1391 png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
1392
1393 /* Kill the tRNS chunk itself too. Prior to 1.5.4 this did not happen
1394 * so transparency information would remain just so long as it wasn't
1395 * expanded. This produces unexpected API changes if the set of things
1396 * that do PNG_EXPAND_tRNS changes (perfectly possible given the
1397 * documentation - which says ask for what you want, accept what you
1398 * get.) This makes the behavior consistent from 1.5.4:
1399 */
1400 png_ptr->num_trans = 0;
1401 }
1402#endif /* STRIP_ALPHA supported, no COMPOSE */
1403
1404#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
1405 /* If the screen gamma is about 1.0 then the OPTIMIZE_ALPHA and ENCODE_ALPHA
1406 * settings will have no effect.
1407 */
Matt Sarett9ea75692016-01-08 13:00:42 -05001408 if (png_gamma_significant(png_ptr->screen_gamma) == 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001409 {
1410 png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
1411 png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
1412 }
1413#endif
1414
1415#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
1416 /* Make sure the coefficients for the rgb to gray conversion are set
1417 * appropriately.
1418 */
Matt Sarett9ea75692016-01-08 13:00:42 -05001419 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001420 png_colorspace_set_rgb_coefficients(png_ptr);
1421#endif
The Android Open Source Project893912b2009-03-03 19:30:05 -08001422
Patrick Scott5f6bd842010-06-28 16:55:16 -04001423#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
Chris Craikb50c2172013-07-29 15:28:30 -07001424#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
1425 /* Detect gray background and attempt to enable optimization for
1426 * gray --> RGB case.
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001427 *
1428 * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or
The Android Open Source Project893912b2009-03-03 19:30:05 -08001429 * RGB_ALPHA (in which case need_expand is superfluous anyway), the
1430 * background color might actually be gray yet not be flagged as such.
1431 * This is not a problem for the current code, which uses
1432 * PNG_BACKGROUND_IS_GRAY only to decide when to do the
1433 * png_do_gray_to_rgb() transformation.
Chris Craikb50c2172013-07-29 15:28:30 -07001434 *
1435 * TODO: this code needs to be revised to avoid the complexity and
1436 * interdependencies. The color type of the background should be recorded in
1437 * png_set_background, along with the bit depth, then the code has a record
1438 * of exactly what color space the background is currently in.
The Android Open Source Project893912b2009-03-03 19:30:05 -08001439 */
Matt Sarett9ea75692016-01-08 13:00:42 -05001440 if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001441 {
Chris Craikb50c2172013-07-29 15:28:30 -07001442 /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if
1443 * the file was grayscale the background value is gray.
1444 */
Matt Sarett9ea75692016-01-08 13:00:42 -05001445 if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001446 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001447 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08001448
Matt Sarett9ea75692016-01-08 13:00:42 -05001449 else if ((png_ptr->transformations & PNG_COMPOSE) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001450 {
Chris Craikb50c2172013-07-29 15:28:30 -07001451 /* PNG_COMPOSE: png_set_background was called with need_expand false,
1452 * so the color is in the color space of the output or png_set_alpha_mode
1453 * was called and the color is black. Ignore RGB_TO_GRAY because that
1454 * happens before GRAY_TO_RGB.
1455 */
Matt Sarett9ea75692016-01-08 13:00:42 -05001456 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001457 {
Chris Craikb50c2172013-07-29 15:28:30 -07001458 if (png_ptr->background.red == png_ptr->background.green &&
1459 png_ptr->background.red == png_ptr->background.blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001460 {
Chris Craikb50c2172013-07-29 15:28:30 -07001461 png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
1462 png_ptr->background.gray = png_ptr->background.red;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001463 }
1464 }
Chris Craikb50c2172013-07-29 15:28:30 -07001465 }
Matt Sarett9ea75692016-01-08 13:00:42 -05001466#endif /* READ_EXPAND && READ_BACKGROUND */
1467#endif /* READ_GRAY_TO_RGB */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001468
Chris Craikb50c2172013-07-29 15:28:30 -07001469 /* For indexed PNG data (PNG_COLOR_TYPE_PALETTE) many of the transformations
1470 * can be performed directly on the palette, and some (such as rgb to gray)
1471 * can be optimized inside the palette. This is particularly true of the
1472 * composite (background and alpha) stuff, which can be pretty much all done
1473 * in the palette even if the result is expanded to RGB or gray afterward.
1474 *
1475 * NOTE: this is Not Yet Implemented, the code behaves as in 1.5.1 and
1476 * earlier and the palette stuff is actually handled on the first row. This
1477 * leads to the reported bug that the palette returned by png_get_PLTE is not
1478 * updated.
1479 */
1480 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1481 png_init_palette_transformations(png_ptr);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001482
Chris Craikb50c2172013-07-29 15:28:30 -07001483 else
1484 png_init_rgb_transformations(png_ptr);
1485
1486#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
1487 defined(PNG_READ_EXPAND_16_SUPPORTED)
Matt Sarett9ea75692016-01-08 13:00:42 -05001488 if ((png_ptr->transformations & PNG_EXPAND_16) != 0 &&
1489 (png_ptr->transformations & PNG_COMPOSE) != 0 &&
1490 (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 &&
1491 png_ptr->bit_depth != 16)
Chris Craikb50c2172013-07-29 15:28:30 -07001492 {
1493 /* TODO: fix this. Because the expand_16 operation is after the compose
1494 * handling the background color must be 8, not 16, bits deep, but the
1495 * application will supply a 16-bit value so reduce it here.
1496 *
1497 * The PNG_BACKGROUND_EXPAND code above does not expand to 16 bits at
1498 * present, so that case is ok (until do_expand_16 is moved.)
1499 *
1500 * NOTE: this discards the low 16 bits of the user supplied background
1501 * color, but until expand_16 works properly there is no choice!
1502 */
1503# define CHOP(x) (x)=((png_uint_16)PNG_DIV257(x))
1504 CHOP(png_ptr->background.red);
1505 CHOP(png_ptr->background.green);
1506 CHOP(png_ptr->background.blue);
1507 CHOP(png_ptr->background.gray);
1508# undef CHOP
1509 }
Matt Sarett9ea75692016-01-08 13:00:42 -05001510#endif /* READ_BACKGROUND && READ_EXPAND_16 */
Chris Craikb50c2172013-07-29 15:28:30 -07001511
1512#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
1513 (defined(PNG_READ_SCALE_16_TO_8_SUPPORTED) || \
1514 defined(PNG_READ_STRIP_16_TO_8_SUPPORTED))
Matt Sarett9ea75692016-01-08 13:00:42 -05001515 if ((png_ptr->transformations & (PNG_16_TO_8|PNG_SCALE_16_TO_8)) != 0 &&
1516 (png_ptr->transformations & PNG_COMPOSE) != 0 &&
1517 (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 &&
1518 png_ptr->bit_depth == 16)
Chris Craikb50c2172013-07-29 15:28:30 -07001519 {
1520 /* On the other hand, if a 16-bit file is to be reduced to 8-bits per
1521 * component this will also happen after PNG_COMPOSE and so the background
1522 * color must be pre-expanded here.
1523 *
1524 * TODO: fix this too.
1525 */
1526 png_ptr->background.red = (png_uint_16)(png_ptr->background.red * 257);
1527 png_ptr->background.green =
1528 (png_uint_16)(png_ptr->background.green * 257);
1529 png_ptr->background.blue = (png_uint_16)(png_ptr->background.blue * 257);
1530 png_ptr->background.gray = (png_uint_16)(png_ptr->background.gray * 257);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001531 }
1532#endif
1533
Chris Craikb50c2172013-07-29 15:28:30 -07001534 /* NOTE: below 'PNG_READ_ALPHA_MODE_SUPPORTED' is presumed to also enable the
1535 * background support (see the comments in scripts/pnglibconf.dfa), this
1536 * allows pre-multiplication of the alpha channel to be implemented as
1537 * compositing on black. This is probably sub-optimal and has been done in
1538 * 1.5.4 betas simply to enable external critique and testing (i.e. to
1539 * implement the new API quickly, without lots of internal changes.)
1540 */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001541
Chris Craikb50c2172013-07-29 15:28:30 -07001542#ifdef PNG_READ_GAMMA_SUPPORTED
1543# ifdef PNG_READ_BACKGROUND_SUPPORTED
1544 /* Includes ALPHA_MODE */
1545 png_ptr->background_1 = png_ptr->background;
1546# endif
The Android Open Source Project893912b2009-03-03 19:30:05 -08001547
Chris Craikb50c2172013-07-29 15:28:30 -07001548 /* This needs to change - in the palette image case a whole set of tables are
1549 * built when it would be quicker to just calculate the correct value for
1550 * each palette entry directly. Also, the test is too tricky - why check
1551 * PNG_RGB_TO_GRAY if PNG_GAMMA is not set? The answer seems to be that
1552 * PNG_GAMMA is cancelled even if the gamma is known? The test excludes the
1553 * PNG_COMPOSE case, so apparently if there is no *overall* gamma correction
1554 * the gamma tables will not be built even if composition is required on a
1555 * gamma encoded value.
1556 *
1557 * In 1.5.4 this is addressed below by an additional check on the individual
1558 * file gamma - if it is not 1.0 both RGB_TO_GRAY and COMPOSE need the
1559 * tables.
1560 */
Matt Sarett9ea75692016-01-08 13:00:42 -05001561 if ((png_ptr->transformations & PNG_GAMMA) != 0 ||
1562 ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0 &&
1563 (png_gamma_significant(png_ptr->colorspace.gamma) != 0 ||
1564 png_gamma_significant(png_ptr->screen_gamma) != 0)) ||
1565 ((png_ptr->transformations & PNG_COMPOSE) != 0 &&
1566 (png_gamma_significant(png_ptr->colorspace.gamma) != 0 ||
1567 png_gamma_significant(png_ptr->screen_gamma) != 0
Chris Craikb50c2172013-07-29 15:28:30 -07001568# ifdef PNG_READ_BACKGROUND_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05001569 || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE &&
1570 png_gamma_significant(png_ptr->background_gamma) != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001571# endif
Matt Sarett9ea75692016-01-08 13:00:42 -05001572 )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 &&
1573 png_gamma_significant(png_ptr->screen_gamma) != 0))
The Android Open Source Project893912b2009-03-03 19:30:05 -08001574 {
Chris Craikb50c2172013-07-29 15:28:30 -07001575 png_build_gamma_table(png_ptr, png_ptr->bit_depth);
Patrick Scott5f6bd842010-06-28 16:55:16 -04001576
1577#ifdef PNG_READ_BACKGROUND_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05001578 if ((png_ptr->transformations & PNG_COMPOSE) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001579 {
Chris Craikb50c2172013-07-29 15:28:30 -07001580 /* Issue a warning about this combination: because RGB_TO_GRAY is
1581 * optimized to do the gamma transform if present yet do_background has
1582 * to do the same thing if both options are set a
1583 * double-gamma-correction happens. This is true in all versions of
1584 * libpng to date.
1585 */
Matt Sarett9ea75692016-01-08 13:00:42 -05001586 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001587 png_warning(png_ptr,
1588 "libpng does not support gamma+background+rgb_to_gray");
1589
Matt Sarett9ea75692016-01-08 13:00:42 -05001590 if ((png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001591 {
Chris Craikb50c2172013-07-29 15:28:30 -07001592 /* We don't get to here unless there is a tRNS chunk with non-opaque
1593 * entries - see the checking code at the start of this function.
1594 */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001595 png_color back, back_1;
1596 png_colorp palette = png_ptr->palette;
1597 int num_palette = png_ptr->num_palette;
1598 int i;
1599 if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
1600 {
Chris Craikb50c2172013-07-29 15:28:30 -07001601
The Android Open Source Project893912b2009-03-03 19:30:05 -08001602 back.red = png_ptr->gamma_table[png_ptr->background.red];
1603 back.green = png_ptr->gamma_table[png_ptr->background.green];
1604 back.blue = png_ptr->gamma_table[png_ptr->background.blue];
1605
1606 back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
1607 back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
1608 back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
1609 }
1610 else
1611 {
Chris Craikb50c2172013-07-29 15:28:30 -07001612 png_fixed_point g, gs;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001613
1614 switch (png_ptr->background_gamma_type)
1615 {
1616 case PNG_BACKGROUND_GAMMA_SCREEN:
1617 g = (png_ptr->screen_gamma);
Chris Craikb50c2172013-07-29 15:28:30 -07001618 gs = PNG_FP_1;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001619 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001620
The Android Open Source Project893912b2009-03-03 19:30:05 -08001621 case PNG_BACKGROUND_GAMMA_FILE:
Chris Craikb50c2172013-07-29 15:28:30 -07001622 g = png_reciprocal(png_ptr->colorspace.gamma);
1623 gs = png_reciprocal2(png_ptr->colorspace.gamma,
1624 png_ptr->screen_gamma);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001625 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001626
The Android Open Source Project893912b2009-03-03 19:30:05 -08001627 case PNG_BACKGROUND_GAMMA_UNIQUE:
Chris Craikb50c2172013-07-29 15:28:30 -07001628 g = png_reciprocal(png_ptr->background_gamma);
1629 gs = png_reciprocal2(png_ptr->background_gamma,
1630 png_ptr->screen_gamma);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001631 break;
1632 default:
Chris Craikb50c2172013-07-29 15:28:30 -07001633 g = PNG_FP_1; /* back_1 */
1634 gs = PNG_FP_1; /* back */
1635 break;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001636 }
1637
Matt Sarett9ea75692016-01-08 13:00:42 -05001638 if (png_gamma_significant(gs) != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001639 {
1640 back.red = png_gamma_8bit_correct(png_ptr->background.red,
1641 gs);
1642 back.green = png_gamma_8bit_correct(png_ptr->background.green,
1643 gs);
1644 back.blue = png_gamma_8bit_correct(png_ptr->background.blue,
1645 gs);
1646 }
1647
1648 else
The Android Open Source Project893912b2009-03-03 19:30:05 -08001649 {
1650 back.red = (png_byte)png_ptr->background.red;
1651 back.green = (png_byte)png_ptr->background.green;
1652 back.blue = (png_byte)png_ptr->background.blue;
1653 }
Chris Craikb50c2172013-07-29 15:28:30 -07001654
Matt Sarett9ea75692016-01-08 13:00:42 -05001655 if (png_gamma_significant(g) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001656 {
Chris Craikb50c2172013-07-29 15:28:30 -07001657 back_1.red = png_gamma_8bit_correct(png_ptr->background.red,
1658 g);
1659 back_1.green = png_gamma_8bit_correct(
1660 png_ptr->background.green, g);
1661 back_1.blue = png_gamma_8bit_correct(png_ptr->background.blue,
1662 g);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001663 }
1664
Chris Craikb50c2172013-07-29 15:28:30 -07001665 else
1666 {
1667 back_1.red = (png_byte)png_ptr->background.red;
1668 back_1.green = (png_byte)png_ptr->background.green;
1669 back_1.blue = (png_byte)png_ptr->background.blue;
1670 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08001671 }
Chris Craikb50c2172013-07-29 15:28:30 -07001672
The Android Open Source Project893912b2009-03-03 19:30:05 -08001673 for (i = 0; i < num_palette; i++)
1674 {
Chris Craikb50c2172013-07-29 15:28:30 -07001675 if (i < (int)png_ptr->num_trans &&
1676 png_ptr->trans_alpha[i] != 0xff)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001677 {
Chris Craikb50c2172013-07-29 15:28:30 -07001678 if (png_ptr->trans_alpha[i] == 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001679 {
1680 palette[i] = back;
1681 }
Chris Craikb50c2172013-07-29 15:28:30 -07001682 else /* if (png_ptr->trans_alpha[i] != 0xff) */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001683 {
1684 png_byte v, w;
1685
1686 v = png_ptr->gamma_to_1[palette[i].red];
Chris Craikb50c2172013-07-29 15:28:30 -07001687 png_composite(w, v, png_ptr->trans_alpha[i], back_1.red);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001688 palette[i].red = png_ptr->gamma_from_1[w];
1689
1690 v = png_ptr->gamma_to_1[palette[i].green];
Chris Craikb50c2172013-07-29 15:28:30 -07001691 png_composite(w, v, png_ptr->trans_alpha[i], back_1.green);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001692 palette[i].green = png_ptr->gamma_from_1[w];
1693
1694 v = png_ptr->gamma_to_1[palette[i].blue];
Chris Craikb50c2172013-07-29 15:28:30 -07001695 png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001696 palette[i].blue = png_ptr->gamma_from_1[w];
1697 }
1698 }
1699 else
1700 {
1701 palette[i].red = png_ptr->gamma_table[palette[i].red];
1702 palette[i].green = png_ptr->gamma_table[palette[i].green];
1703 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
1704 }
1705 }
Chris Craikb50c2172013-07-29 15:28:30 -07001706
1707 /* Prevent the transformations being done again.
1708 *
1709 * NOTE: this is highly dubious; it removes the transformations in
1710 * place. This seems inconsistent with the general treatment of the
1711 * transformations elsewhere.
Patrick Scott5f6bd842010-06-28 16:55:16 -04001712 */
Chris Craikb50c2172013-07-29 15:28:30 -07001713 png_ptr->transformations &= ~(PNG_COMPOSE | PNG_GAMMA);
1714 } /* color_type == PNG_COLOR_TYPE_PALETTE */
1715
The Android Open Source Project893912b2009-03-03 19:30:05 -08001716 /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */
Chris Craikb50c2172013-07-29 15:28:30 -07001717 else /* color_type != PNG_COLOR_TYPE_PALETTE */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001718 {
Chris Craikb50c2172013-07-29 15:28:30 -07001719 int gs_sig, g_sig;
1720 png_fixed_point g = PNG_FP_1; /* Correction to linear */
1721 png_fixed_point gs = PNG_FP_1; /* Correction to screen */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001722
1723 switch (png_ptr->background_gamma_type)
1724 {
1725 case PNG_BACKGROUND_GAMMA_SCREEN:
Chris Craikb50c2172013-07-29 15:28:30 -07001726 g = png_ptr->screen_gamma;
1727 /* gs = PNG_FP_1; */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001728 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001729
The Android Open Source Project893912b2009-03-03 19:30:05 -08001730 case PNG_BACKGROUND_GAMMA_FILE:
Chris Craikb50c2172013-07-29 15:28:30 -07001731 g = png_reciprocal(png_ptr->colorspace.gamma);
1732 gs = png_reciprocal2(png_ptr->colorspace.gamma,
1733 png_ptr->screen_gamma);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001734 break;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001735
The Android Open Source Project893912b2009-03-03 19:30:05 -08001736 case PNG_BACKGROUND_GAMMA_UNIQUE:
Chris Craikb50c2172013-07-29 15:28:30 -07001737 g = png_reciprocal(png_ptr->background_gamma);
1738 gs = png_reciprocal2(png_ptr->background_gamma,
1739 png_ptr->screen_gamma);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001740 break;
Chris Craikb50c2172013-07-29 15:28:30 -07001741
1742 default:
1743 png_error(png_ptr, "invalid background gamma type");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001744 }
1745
Chris Craikb50c2172013-07-29 15:28:30 -07001746 g_sig = png_gamma_significant(g);
1747 gs_sig = png_gamma_significant(gs);
1748
Matt Sarett9ea75692016-01-08 13:00:42 -05001749 if (g_sig != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001750 png_ptr->background_1.gray = png_gamma_correct(png_ptr,
1751 png_ptr->background.gray, g);
1752
Matt Sarett9ea75692016-01-08 13:00:42 -05001753 if (gs_sig != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001754 png_ptr->background.gray = png_gamma_correct(png_ptr,
1755 png_ptr->background.gray, gs);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001756
1757 if ((png_ptr->background.red != png_ptr->background.green) ||
1758 (png_ptr->background.red != png_ptr->background.blue) ||
1759 (png_ptr->background.red != png_ptr->background.gray))
1760 {
1761 /* RGB or RGBA with color background */
Matt Sarett9ea75692016-01-08 13:00:42 -05001762 if (g_sig != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001763 {
1764 png_ptr->background_1.red = png_gamma_correct(png_ptr,
1765 png_ptr->background.red, g);
1766
1767 png_ptr->background_1.green = png_gamma_correct(png_ptr,
1768 png_ptr->background.green, g);
1769
1770 png_ptr->background_1.blue = png_gamma_correct(png_ptr,
1771 png_ptr->background.blue, g);
1772 }
1773
Matt Sarett9ea75692016-01-08 13:00:42 -05001774 if (gs_sig != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001775 {
1776 png_ptr->background.red = png_gamma_correct(png_ptr,
1777 png_ptr->background.red, gs);
1778
1779 png_ptr->background.green = png_gamma_correct(png_ptr,
1780 png_ptr->background.green, gs);
1781
1782 png_ptr->background.blue = png_gamma_correct(png_ptr,
1783 png_ptr->background.blue, gs);
1784 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08001785 }
Chris Craikb50c2172013-07-29 15:28:30 -07001786
The Android Open Source Project893912b2009-03-03 19:30:05 -08001787 else
1788 {
1789 /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */
1790 png_ptr->background_1.red = png_ptr->background_1.green
Chris Craikb50c2172013-07-29 15:28:30 -07001791 = png_ptr->background_1.blue = png_ptr->background_1.gray;
1792
The Android Open Source Project893912b2009-03-03 19:30:05 -08001793 png_ptr->background.red = png_ptr->background.green
Chris Craikb50c2172013-07-29 15:28:30 -07001794 = png_ptr->background.blue = png_ptr->background.gray;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001795 }
Chris Craikb50c2172013-07-29 15:28:30 -07001796
1797 /* The background is now in screen gamma: */
1798 png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_SCREEN;
1799 } /* color_type != PNG_COLOR_TYPE_PALETTE */
1800 }/* png_ptr->transformations & PNG_BACKGROUND */
1801
The Android Open Source Project893912b2009-03-03 19:30:05 -08001802 else
Patrick Scotta0bb96c2009-07-22 11:50:02 -04001803 /* Transformation does not include PNG_BACKGROUND */
Matt Sarett9ea75692016-01-08 13:00:42 -05001804#endif /* READ_BACKGROUND */
Chris Craikb50c2172013-07-29 15:28:30 -07001805 if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE
1806#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
1807 /* RGB_TO_GRAY needs to have non-gamma-corrected values! */
1808 && ((png_ptr->transformations & PNG_EXPAND) == 0 ||
1809 (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0)
1810#endif
1811 )
The Android Open Source Project893912b2009-03-03 19:30:05 -08001812 {
1813 png_colorp palette = png_ptr->palette;
1814 int num_palette = png_ptr->num_palette;
1815 int i;
1816
Chris Craikb50c2172013-07-29 15:28:30 -07001817 /* NOTE: there are other transformations that should probably be in
1818 * here too.
1819 */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001820 for (i = 0; i < num_palette; i++)
1821 {
1822 palette[i].red = png_ptr->gamma_table[palette[i].red];
1823 palette[i].green = png_ptr->gamma_table[palette[i].green];
1824 palette[i].blue = png_ptr->gamma_table[palette[i].blue];
1825 }
1826
Patrick Scott5f6bd842010-06-28 16:55:16 -04001827 /* Done the gamma correction. */
1828 png_ptr->transformations &= ~PNG_GAMMA;
Chris Craikb50c2172013-07-29 15:28:30 -07001829 } /* color_type == PALETTE && !PNG_BACKGROUND transformation */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001830 }
Patrick Scott5f6bd842010-06-28 16:55:16 -04001831#ifdef PNG_READ_BACKGROUND_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08001832 else
1833#endif
Matt Sarett9ea75692016-01-08 13:00:42 -05001834#endif /* READ_GAMMA */
Chris Craikb50c2172013-07-29 15:28:30 -07001835
Patrick Scott5f6bd842010-06-28 16:55:16 -04001836#ifdef PNG_READ_BACKGROUND_SUPPORTED
Chris Craikb50c2172013-07-29 15:28:30 -07001837 /* No GAMMA transformation (see the hanging else 4 lines above) */
Matt Sarett9ea75692016-01-08 13:00:42 -05001838 if ((png_ptr->transformations & PNG_COMPOSE) != 0 &&
Chris Craikb50c2172013-07-29 15:28:30 -07001839 (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
The Android Open Source Project893912b2009-03-03 19:30:05 -08001840 {
1841 int i;
1842 int istop = (int)png_ptr->num_trans;
1843 png_color back;
1844 png_colorp palette = png_ptr->palette;
1845
1846 back.red = (png_byte)png_ptr->background.red;
1847 back.green = (png_byte)png_ptr->background.green;
1848 back.blue = (png_byte)png_ptr->background.blue;
1849
1850 for (i = 0; i < istop; i++)
1851 {
Chris Craikb50c2172013-07-29 15:28:30 -07001852 if (png_ptr->trans_alpha[i] == 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001853 {
1854 palette[i] = back;
1855 }
Chris Craikb50c2172013-07-29 15:28:30 -07001856
1857 else if (png_ptr->trans_alpha[i] != 0xff)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001858 {
1859 /* The png_composite() macro is defined in png.h */
1860 png_composite(palette[i].red, palette[i].red,
Chris Craikb50c2172013-07-29 15:28:30 -07001861 png_ptr->trans_alpha[i], back.red);
1862
The Android Open Source Project893912b2009-03-03 19:30:05 -08001863 png_composite(palette[i].green, palette[i].green,
Chris Craikb50c2172013-07-29 15:28:30 -07001864 png_ptr->trans_alpha[i], back.green);
1865
The Android Open Source Project893912b2009-03-03 19:30:05 -08001866 png_composite(palette[i].blue, palette[i].blue,
Chris Craikb50c2172013-07-29 15:28:30 -07001867 png_ptr->trans_alpha[i], back.blue);
The Android Open Source Project893912b2009-03-03 19:30:05 -08001868 }
1869 }
1870
Chris Craikb50c2172013-07-29 15:28:30 -07001871 png_ptr->transformations &= ~PNG_COMPOSE;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001872 }
Matt Sarett9ea75692016-01-08 13:00:42 -05001873#endif /* READ_BACKGROUND */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001874
Patrick Scott5f6bd842010-06-28 16:55:16 -04001875#ifdef PNG_READ_SHIFT_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05001876 if ((png_ptr->transformations & PNG_SHIFT) != 0 &&
1877 (png_ptr->transformations & PNG_EXPAND) == 0 &&
Chris Craikb50c2172013-07-29 15:28:30 -07001878 (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
The Android Open Source Project893912b2009-03-03 19:30:05 -08001879 {
Chris Craikb50c2172013-07-29 15:28:30 -07001880 int i;
1881 int istop = png_ptr->num_palette;
1882 int shift = 8 - png_ptr->sig_bit.red;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001883
Chris Craikb50c2172013-07-29 15:28:30 -07001884 png_ptr->transformations &= ~PNG_SHIFT;
1885
1886 /* significant bits can be in the range 1 to 7 for a meaninful result, if
1887 * the number of significant bits is 0 then no shift is done (this is an
1888 * error condition which is silently ignored.)
1889 */
Sireesh Tripurarib478e662014-05-09 15:15:10 +05301890 if (shift > 0 && shift < 8)
1891 for (i=0; i<istop; ++i)
1892 {
1893 int component = png_ptr->palette[i].red;
Chris Craikb50c2172013-07-29 15:28:30 -07001894
Sireesh Tripurarib478e662014-05-09 15:15:10 +05301895 component >>= shift;
1896 png_ptr->palette[i].red = (png_byte)component;
1897 }
Chris Craikb50c2172013-07-29 15:28:30 -07001898
1899 shift = 8 - png_ptr->sig_bit.green;
Sireesh Tripurarib478e662014-05-09 15:15:10 +05301900 if (shift > 0 && shift < 8)
1901 for (i=0; i<istop; ++i)
1902 {
1903 int component = png_ptr->palette[i].green;
Chris Craikb50c2172013-07-29 15:28:30 -07001904
Sireesh Tripurarib478e662014-05-09 15:15:10 +05301905 component >>= shift;
1906 png_ptr->palette[i].green = (png_byte)component;
1907 }
Chris Craikb50c2172013-07-29 15:28:30 -07001908
1909 shift = 8 - png_ptr->sig_bit.blue;
Sireesh Tripurarib478e662014-05-09 15:15:10 +05301910 if (shift > 0 && shift < 8)
1911 for (i=0; i<istop; ++i)
1912 {
1913 int component = png_ptr->palette[i].blue;
Chris Craikb50c2172013-07-29 15:28:30 -07001914
Sireesh Tripurarib478e662014-05-09 15:15:10 +05301915 component >>= shift;
1916 png_ptr->palette[i].blue = (png_byte)component;
1917 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08001918 }
Matt Sarett9ea75692016-01-08 13:00:42 -05001919#endif /* READ_SHIFT */
The Android Open Source Project893912b2009-03-03 19:30:05 -08001920}
1921
1922/* Modify the info structure to reflect the transformations. The
1923 * info should be updated so a PNG file could be written with it,
1924 * assuming the transformations result in valid PNG data.
1925 */
1926void /* PRIVATE */
Chris Craikb50c2172013-07-29 15:28:30 -07001927png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001928{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07001929 png_debug(1, "in png_read_transform_info");
Patrick Scott5f6bd842010-06-28 16:55:16 -04001930
1931#ifdef PNG_READ_EXPAND_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05001932 if ((png_ptr->transformations & PNG_EXPAND) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001933 {
1934 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
1935 {
Chris Craikb50c2172013-07-29 15:28:30 -07001936 /* This check must match what actually happens in
1937 * png_do_expand_palette; if it ever checks the tRNS chunk to see if
1938 * it is all opaque we must do the same (at present it does not.)
1939 */
1940 if (png_ptr->num_trans > 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001941 info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
Chris Craikb50c2172013-07-29 15:28:30 -07001942
The Android Open Source Project893912b2009-03-03 19:30:05 -08001943 else
1944 info_ptr->color_type = PNG_COLOR_TYPE_RGB;
Chris Craikb50c2172013-07-29 15:28:30 -07001945
The Android Open Source Project893912b2009-03-03 19:30:05 -08001946 info_ptr->bit_depth = 8;
1947 info_ptr->num_trans = 0;
Sireesh Tripurarib478e662014-05-09 15:15:10 +05301948
1949 if (png_ptr->palette == NULL)
1950 png_error (png_ptr, "Palette is NULL in indexed image");
The Android Open Source Project893912b2009-03-03 19:30:05 -08001951 }
1952 else
1953 {
Matt Sarett9ea75692016-01-08 13:00:42 -05001954 if (png_ptr->num_trans != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001955 {
Matt Sarett9ea75692016-01-08 13:00:42 -05001956 if ((png_ptr->transformations & PNG_EXPAND_tRNS) != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001957 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001958 }
1959 if (info_ptr->bit_depth < 8)
1960 info_ptr->bit_depth = 8;
Chris Craikb50c2172013-07-29 15:28:30 -07001961
The Android Open Source Project893912b2009-03-03 19:30:05 -08001962 info_ptr->num_trans = 0;
1963 }
1964 }
1965#endif
1966
Chris Craikb50c2172013-07-29 15:28:30 -07001967#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
1968 defined(PNG_READ_ALPHA_MODE_SUPPORTED)
1969 /* The following is almost certainly wrong unless the background value is in
1970 * the screen space!
1971 */
Matt Sarett9ea75692016-01-08 13:00:42 -05001972 if ((png_ptr->transformations & PNG_COMPOSE) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08001973 info_ptr->background = png_ptr->background;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001974#endif
1975
Patrick Scott5f6bd842010-06-28 16:55:16 -04001976#ifdef PNG_READ_GAMMA_SUPPORTED
Chris Craikb50c2172013-07-29 15:28:30 -07001977 /* The following used to be conditional on PNG_GAMMA (prior to 1.5.4),
1978 * however it seems that the code in png_init_read_transformations, which has
1979 * been called before this from png_read_update_info->png_read_start_row
1980 * sometimes does the gamma transform and cancels the flag.
1981 *
1982 * TODO: this looks wrong; the info_ptr should end up with a gamma equal to
1983 * the screen_gamma value. The following probably results in weirdness if
1984 * the info_ptr is used by the app after the rows have been read.
1985 */
1986 info_ptr->colorspace.gamma = png_ptr->colorspace.gamma;
The Android Open Source Project893912b2009-03-03 19:30:05 -08001987#endif
1988
Chris Craikb50c2172013-07-29 15:28:30 -07001989 if (info_ptr->bit_depth == 16)
1990 {
1991# ifdef PNG_READ_16BIT_SUPPORTED
1992# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05001993 if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001994 info_ptr->bit_depth = 8;
1995# endif
1996
1997# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05001998 if ((png_ptr->transformations & PNG_16_TO_8) != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07001999 info_ptr->bit_depth = 8;
2000# endif
2001
2002# else
Matt Sarett9ea75692016-01-08 13:00:42 -05002003 /* No 16-bit support: force chopping 16-bit input down to 8, in this case
Chris Craikb50c2172013-07-29 15:28:30 -07002004 * the app program can chose if both APIs are available by setting the
2005 * correct scaling to use.
2006 */
2007# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
2008 /* For compatibility with previous versions use the strip method by
2009 * default. This code works because if PNG_SCALE_16_TO_8 is already
2010 * set the code below will do that in preference to the chop.
2011 */
2012 png_ptr->transformations |= PNG_16_TO_8;
2013 info_ptr->bit_depth = 8;
2014# else
2015
2016# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
2017 png_ptr->transformations |= PNG_SCALE_16_TO_8;
2018 info_ptr->bit_depth = 8;
2019# else
2020
2021 CONFIGURATION ERROR: you must enable at least one 16 to 8 method
2022# endif
2023# endif
Matt Sarett9ea75692016-01-08 13:00:42 -05002024#endif /* !READ_16BIT */
Chris Craikb50c2172013-07-29 15:28:30 -07002025 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08002026
Patrick Scott5f6bd842010-06-28 16:55:16 -04002027#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05002028 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07002029 info_ptr->color_type = (png_byte)(info_ptr->color_type |
2030 PNG_COLOR_MASK_COLOR);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002031#endif
2032
Patrick Scott5f6bd842010-06-28 16:55:16 -04002033#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05002034 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07002035 info_ptr->color_type = (png_byte)(info_ptr->color_type &
2036 ~PNG_COLOR_MASK_COLOR);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002037#endif
2038
Chris Craikb50c2172013-07-29 15:28:30 -07002039#ifdef PNG_READ_QUANTIZE_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05002040 if ((png_ptr->transformations & PNG_QUANTIZE) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002041 {
2042 if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002043 (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
Matt Sarett9ea75692016-01-08 13:00:42 -05002044 png_ptr->palette_lookup != 0 && info_ptr->bit_depth == 8)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002045 {
2046 info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
2047 }
2048 }
2049#endif
2050
Chris Craikb50c2172013-07-29 15:28:30 -07002051#ifdef PNG_READ_EXPAND_16_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05002052 if ((png_ptr->transformations & PNG_EXPAND_16) != 0 &&
2053 info_ptr->bit_depth == 8 &&
2054 info_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
Chris Craikb50c2172013-07-29 15:28:30 -07002055 {
2056 info_ptr->bit_depth = 16;
2057 }
2058#endif
2059
Patrick Scott5f6bd842010-06-28 16:55:16 -04002060#ifdef PNG_READ_PACK_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05002061 if ((png_ptr->transformations & PNG_PACK) != 0 &&
2062 (info_ptr->bit_depth < 8))
The Android Open Source Project893912b2009-03-03 19:30:05 -08002063 info_ptr->bit_depth = 8;
2064#endif
2065
2066 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
2067 info_ptr->channels = 1;
Chris Craikb50c2172013-07-29 15:28:30 -07002068
Matt Sarett9ea75692016-01-08 13:00:42 -05002069 else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002070 info_ptr->channels = 3;
Chris Craikb50c2172013-07-29 15:28:30 -07002071
The Android Open Source Project893912b2009-03-03 19:30:05 -08002072 else
2073 info_ptr->channels = 1;
2074
Patrick Scott5f6bd842010-06-28 16:55:16 -04002075#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05002076 if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07002077 {
2078 info_ptr->color_type = (png_byte)(info_ptr->color_type &
2079 ~PNG_COLOR_MASK_ALPHA);
2080 info_ptr->num_trans = 0;
2081 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08002082#endif
2083
Matt Sarett9ea75692016-01-08 13:00:42 -05002084 if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002085 info_ptr->channels++;
2086
Patrick Scott5f6bd842010-06-28 16:55:16 -04002087#ifdef PNG_READ_FILLER_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08002088 /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */
Matt Sarett9ea75692016-01-08 13:00:42 -05002089 if ((png_ptr->transformations & PNG_FILLER) != 0 &&
2090 (info_ptr->color_type == PNG_COLOR_TYPE_RGB ||
2091 info_ptr->color_type == PNG_COLOR_TYPE_GRAY))
The Android Open Source Project893912b2009-03-03 19:30:05 -08002092 {
2093 info_ptr->channels++;
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002094 /* If adding a true alpha channel not just filler */
Matt Sarett9ea75692016-01-08 13:00:42 -05002095 if ((png_ptr->transformations & PNG_ADD_ALPHA) != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07002096 info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002097 }
2098#endif
2099
2100#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \
2101defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
Matt Sarett9ea75692016-01-08 13:00:42 -05002102 if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07002103 {
Matt Sarett9ea75692016-01-08 13:00:42 -05002104 if (png_ptr->user_transform_depth != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002105 info_ptr->bit_depth = png_ptr->user_transform_depth;
Chris Craikb50c2172013-07-29 15:28:30 -07002106
Matt Sarett9ea75692016-01-08 13:00:42 -05002107 if (png_ptr->user_transform_channels != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002108 info_ptr->channels = png_ptr->user_transform_channels;
Chris Craikb50c2172013-07-29 15:28:30 -07002109 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08002110#endif
2111
2112 info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
Chris Craikb50c2172013-07-29 15:28:30 -07002113 info_ptr->bit_depth);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002114
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002115 info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002116
Chris Craikb50c2172013-07-29 15:28:30 -07002117 /* Adding in 1.5.4: cache the above value in png_struct so that we can later
2118 * check in png_rowbytes that the user buffer won't get overwritten. Note
2119 * that the field is not always set - if png_read_update_info isn't called
2120 * the application has to either not do any transforms or get the calculation
2121 * right itself.
2122 */
2123 png_ptr->info_rowbytes = info_ptr->rowbytes;
2124
Patrick Scott5f6bd842010-06-28 16:55:16 -04002125#ifndef PNG_READ_EXPAND_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05002126 if (png_ptr != NULL)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002127 return;
2128#endif
2129}
2130
Patrick Scott5f6bd842010-06-28 16:55:16 -04002131#ifdef PNG_READ_PACK_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08002132/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
2133 * without changing the actual values. Thus, if you had a row with
2134 * a bit depth of 1, you would end up with bytes that only contained
2135 * the numbers 0 or 1. If you would rather they contain 0 and 255, use
2136 * png_do_shift() after this.
2137 */
Sireesh Tripurarib478e662014-05-09 15:15:10 +05302138static void
The Android Open Source Project893912b2009-03-03 19:30:05 -08002139png_do_unpack(png_row_infop row_info, png_bytep row)
2140{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002141 png_debug(1, "in png_do_unpack");
Patrick Scott5f6bd842010-06-28 16:55:16 -04002142
The Android Open Source Project893912b2009-03-03 19:30:05 -08002143 if (row_info->bit_depth < 8)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002144 {
2145 png_uint_32 i;
2146 png_uint_32 row_width=row_info->width;
2147
2148 switch (row_info->bit_depth)
2149 {
2150 case 1:
2151 {
2152 png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
2153 png_bytep dp = row + (png_size_t)row_width - 1;
2154 png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);
2155 for (i = 0; i < row_width; i++)
2156 {
2157 *dp = (png_byte)((*sp >> shift) & 0x01);
Chris Craikb50c2172013-07-29 15:28:30 -07002158
The Android Open Source Project893912b2009-03-03 19:30:05 -08002159 if (shift == 7)
2160 {
2161 shift = 0;
2162 sp--;
2163 }
Chris Craikb50c2172013-07-29 15:28:30 -07002164
The Android Open Source Project893912b2009-03-03 19:30:05 -08002165 else
2166 shift++;
2167
2168 dp--;
2169 }
2170 break;
2171 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002172
The Android Open Source Project893912b2009-03-03 19:30:05 -08002173 case 2:
2174 {
2175
2176 png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
2177 png_bytep dp = row + (png_size_t)row_width - 1;
2178 png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
2179 for (i = 0; i < row_width; i++)
2180 {
2181 *dp = (png_byte)((*sp >> shift) & 0x03);
Chris Craikb50c2172013-07-29 15:28:30 -07002182
The Android Open Source Project893912b2009-03-03 19:30:05 -08002183 if (shift == 6)
2184 {
2185 shift = 0;
2186 sp--;
2187 }
Chris Craikb50c2172013-07-29 15:28:30 -07002188
The Android Open Source Project893912b2009-03-03 19:30:05 -08002189 else
2190 shift += 2;
2191
2192 dp--;
2193 }
2194 break;
2195 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002196
The Android Open Source Project893912b2009-03-03 19:30:05 -08002197 case 4:
2198 {
2199 png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
2200 png_bytep dp = row + (png_size_t)row_width - 1;
2201 png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
2202 for (i = 0; i < row_width; i++)
2203 {
2204 *dp = (png_byte)((*sp >> shift) & 0x0f);
Chris Craikb50c2172013-07-29 15:28:30 -07002205
The Android Open Source Project893912b2009-03-03 19:30:05 -08002206 if (shift == 4)
2207 {
2208 shift = 0;
2209 sp--;
2210 }
Chris Craikb50c2172013-07-29 15:28:30 -07002211
The Android Open Source Project893912b2009-03-03 19:30:05 -08002212 else
2213 shift = 4;
2214
2215 dp--;
2216 }
2217 break;
2218 }
Chris Craikb50c2172013-07-29 15:28:30 -07002219
2220 default:
2221 break;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002222 }
2223 row_info->bit_depth = 8;
2224 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
2225 row_info->rowbytes = row_width * row_info->channels;
2226 }
2227}
2228#endif
2229
Patrick Scott5f6bd842010-06-28 16:55:16 -04002230#ifdef PNG_READ_SHIFT_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08002231/* Reverse the effects of png_do_shift. This routine merely shifts the
2232 * pixels back to their significant bits values. Thus, if you have
2233 * a row of bit depth 8, but only 5 are significant, this will shift
2234 * the values back to 0 through 31.
2235 */
Sireesh Tripurarib478e662014-05-09 15:15:10 +05302236static void
Chris Craikb50c2172013-07-29 15:28:30 -07002237png_do_unshift(png_row_infop row_info, png_bytep row,
2238 png_const_color_8p sig_bits)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002239{
Chris Craikb50c2172013-07-29 15:28:30 -07002240 int color_type;
2241
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002242 png_debug(1, "in png_do_unshift");
Patrick Scott5f6bd842010-06-28 16:55:16 -04002243
Chris Craikb50c2172013-07-29 15:28:30 -07002244 /* The palette case has already been handled in the _init routine. */
2245 color_type = row_info->color_type;
2246
2247 if (color_type != PNG_COLOR_TYPE_PALETTE)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002248 {
2249 int shift[4];
2250 int channels = 0;
Chris Craikb50c2172013-07-29 15:28:30 -07002251 int bit_depth = row_info->bit_depth;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002252
Matt Sarett9ea75692016-01-08 13:00:42 -05002253 if ((color_type & PNG_COLOR_MASK_COLOR) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002254 {
Chris Craikb50c2172013-07-29 15:28:30 -07002255 shift[channels++] = bit_depth - sig_bits->red;
2256 shift[channels++] = bit_depth - sig_bits->green;
2257 shift[channels++] = bit_depth - sig_bits->blue;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002258 }
Chris Craikb50c2172013-07-29 15:28:30 -07002259
The Android Open Source Project893912b2009-03-03 19:30:05 -08002260 else
2261 {
Chris Craikb50c2172013-07-29 15:28:30 -07002262 shift[channels++] = bit_depth - sig_bits->gray;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002263 }
2264
Matt Sarett9ea75692016-01-08 13:00:42 -05002265 if ((color_type & PNG_COLOR_MASK_ALPHA) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002266 {
Chris Craikb50c2172013-07-29 15:28:30 -07002267 shift[channels++] = bit_depth - sig_bits->alpha;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002268 }
2269
The Android Open Source Project893912b2009-03-03 19:30:05 -08002270 {
Chris Craikb50c2172013-07-29 15:28:30 -07002271 int c, have_shift;
2272
2273 for (c = have_shift = 0; c < channels; ++c)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002274 {
Chris Craikb50c2172013-07-29 15:28:30 -07002275 /* A shift of more than the bit depth is an error condition but it
2276 * gets ignored here.
2277 */
2278 if (shift[c] <= 0 || shift[c] >= bit_depth)
2279 shift[c] = 0;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002280
Chris Craikb50c2172013-07-29 15:28:30 -07002281 else
2282 have_shift = 1;
2283 }
2284
Matt Sarett9ea75692016-01-08 13:00:42 -05002285 if (have_shift == 0)
Chris Craikb50c2172013-07-29 15:28:30 -07002286 return;
2287 }
2288
2289 switch (bit_depth)
2290 {
2291 default:
2292 /* Must be 1bpp gray: should not be here! */
2293 /* NOTREACHED */
2294 break;
2295
2296 case 2:
2297 /* Must be 2bpp gray */
2298 /* assert(channels == 1 && shift[0] == 1) */
2299 {
2300 png_bytep bp = row;
2301 png_bytep bp_end = bp + row_info->rowbytes;
2302
2303 while (bp < bp_end)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002304 {
Chris Craikb50c2172013-07-29 15:28:30 -07002305 int b = (*bp >> 1) & 0x55;
2306 *bp++ = (png_byte)b;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002307 }
2308 break;
2309 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002310
The Android Open Source Project893912b2009-03-03 19:30:05 -08002311 case 4:
Chris Craikb50c2172013-07-29 15:28:30 -07002312 /* Must be 4bpp gray */
2313 /* assert(channels == 1) */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002314 {
2315 png_bytep bp = row;
Chris Craikb50c2172013-07-29 15:28:30 -07002316 png_bytep bp_end = bp + row_info->rowbytes;
2317 int gray_shift = shift[0];
2318 int mask = 0xf >> gray_shift;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002319
Chris Craikb50c2172013-07-29 15:28:30 -07002320 mask |= mask << 4;
2321
2322 while (bp < bp_end)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002323 {
Chris Craikb50c2172013-07-29 15:28:30 -07002324 int b = (*bp >> gray_shift) & mask;
2325 *bp++ = (png_byte)b;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002326 }
2327 break;
2328 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002329
The Android Open Source Project893912b2009-03-03 19:30:05 -08002330 case 8:
Chris Craikb50c2172013-07-29 15:28:30 -07002331 /* Single byte components, G, GA, RGB, RGBA */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002332 {
2333 png_bytep bp = row;
Chris Craikb50c2172013-07-29 15:28:30 -07002334 png_bytep bp_end = bp + row_info->rowbytes;
2335 int channel = 0;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002336
Chris Craikb50c2172013-07-29 15:28:30 -07002337 while (bp < bp_end)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002338 {
Chris Craikb50c2172013-07-29 15:28:30 -07002339 int b = *bp >> shift[channel];
2340 if (++channel >= channels)
2341 channel = 0;
2342 *bp++ = (png_byte)b;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002343 }
2344 break;
2345 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002346
Chris Craikb50c2172013-07-29 15:28:30 -07002347#ifdef PNG_READ_16BIT_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08002348 case 16:
Chris Craikb50c2172013-07-29 15:28:30 -07002349 /* Double byte components, G, GA, RGB, RGBA */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002350 {
2351 png_bytep bp = row;
Chris Craikb50c2172013-07-29 15:28:30 -07002352 png_bytep bp_end = bp + row_info->rowbytes;
2353 int channel = 0;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002354
Chris Craikb50c2172013-07-29 15:28:30 -07002355 while (bp < bp_end)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002356 {
Chris Craikb50c2172013-07-29 15:28:30 -07002357 int value = (bp[0] << 8) + bp[1];
2358
2359 value >>= shift[channel];
2360 if (++channel >= channels)
2361 channel = 0;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002362 *bp++ = (png_byte)(value >> 8);
Matt Sarett9ea75692016-01-08 13:00:42 -05002363 *bp++ = (png_byte)value;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002364 }
2365 break;
2366 }
Chris Craikb50c2172013-07-29 15:28:30 -07002367#endif
The Android Open Source Project893912b2009-03-03 19:30:05 -08002368 }
2369 }
2370}
2371#endif
2372
Chris Craikb50c2172013-07-29 15:28:30 -07002373#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
2374/* Scale rows of bit depth 16 down to 8 accurately */
Sireesh Tripurarib478e662014-05-09 15:15:10 +05302375static void
Chris Craikb50c2172013-07-29 15:28:30 -07002376png_do_scale_16_to_8(png_row_infop row_info, png_bytep row)
2377{
2378 png_debug(1, "in png_do_scale_16_to_8");
2379
2380 if (row_info->bit_depth == 16)
2381 {
2382 png_bytep sp = row; /* source */
2383 png_bytep dp = row; /* destination */
2384 png_bytep ep = sp + row_info->rowbytes; /* end+1 */
2385
2386 while (sp < ep)
2387 {
Matt Sarett9ea75692016-01-08 13:00:42 -05002388 /* The input is an array of 16-bit components, these must be scaled to
2389 * 8 bits each. For a 16-bit value V the required value (from the PNG
Chris Craikb50c2172013-07-29 15:28:30 -07002390 * specification) is:
2391 *
2392 * (V * 255) / 65535
2393 *
2394 * This reduces to round(V / 257), or floor((V + 128.5)/257)
2395 *
2396 * Represent V as the two byte value vhi.vlo. Make a guess that the
2397 * result is the top byte of V, vhi, then the correction to this value
2398 * is:
2399 *
2400 * error = floor(((V-vhi.vhi) + 128.5) / 257)
2401 * = floor(((vlo-vhi) + 128.5) / 257)
2402 *
2403 * This can be approximated using integer arithmetic (and a signed
2404 * shift):
2405 *
2406 * error = (vlo-vhi+128) >> 8;
2407 *
2408 * The approximate differs from the exact answer only when (vlo-vhi) is
2409 * 128; it then gives a correction of +1 when the exact correction is
Matt Sarett9ea75692016-01-08 13:00:42 -05002410 * 0. This gives 128 errors. The exact answer (correct for all 16-bit
Chris Craikb50c2172013-07-29 15:28:30 -07002411 * input values) is:
2412 *
2413 * error = (vlo-vhi+128)*65535 >> 24;
2414 *
2415 * An alternative arithmetic calculation which also gives no errors is:
2416 *
2417 * (V * 255 + 32895) >> 16
2418 */
2419
2420 png_int_32 tmp = *sp++; /* must be signed! */
2421 tmp += (((int)*sp++ - tmp + 128) * 65535) >> 24;
2422 *dp++ = (png_byte)tmp;
2423 }
2424
2425 row_info->bit_depth = 8;
2426 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
2427 row_info->rowbytes = row_info->width * row_info->channels;
2428 }
2429}
2430#endif
2431
2432#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
Sireesh Tripurarib478e662014-05-09 15:15:10 +05302433static void
Chris Craikb50c2172013-07-29 15:28:30 -07002434/* Simply discard the low byte. This was the default behavior prior
2435 * to libpng-1.5.4.
2436 */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002437png_do_chop(png_row_infop row_info, png_bytep row)
2438{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002439 png_debug(1, "in png_do_chop");
Patrick Scott5f6bd842010-06-28 16:55:16 -04002440
The Android Open Source Project893912b2009-03-03 19:30:05 -08002441 if (row_info->bit_depth == 16)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002442 {
Chris Craikb50c2172013-07-29 15:28:30 -07002443 png_bytep sp = row; /* source */
2444 png_bytep dp = row; /* destination */
2445 png_bytep ep = sp + row_info->rowbytes; /* end+1 */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002446
Chris Craikb50c2172013-07-29 15:28:30 -07002447 while (sp < ep)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002448 {
Chris Craikb50c2172013-07-29 15:28:30 -07002449 *dp++ = *sp;
2450 sp += 2; /* skip low byte */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002451 }
Chris Craikb50c2172013-07-29 15:28:30 -07002452
The Android Open Source Project893912b2009-03-03 19:30:05 -08002453 row_info->bit_depth = 8;
2454 row_info->pixel_depth = (png_byte)(8 * row_info->channels);
2455 row_info->rowbytes = row_info->width * row_info->channels;
2456 }
2457}
2458#endif
2459
Patrick Scott5f6bd842010-06-28 16:55:16 -04002460#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
Sireesh Tripurarib478e662014-05-09 15:15:10 +05302461static void
The Android Open Source Project893912b2009-03-03 19:30:05 -08002462png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
2463{
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002464 png_debug(1, "in png_do_read_swap_alpha");
Patrick Scott5f6bd842010-06-28 16:55:16 -04002465
The Android Open Source Project893912b2009-03-03 19:30:05 -08002466 {
2467 png_uint_32 row_width = row_info->width;
2468 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
2469 {
2470 /* This converts from RGBA to ARGB */
2471 if (row_info->bit_depth == 8)
2472 {
2473 png_bytep sp = row + row_info->rowbytes;
2474 png_bytep dp = sp;
2475 png_byte save;
2476 png_uint_32 i;
2477
2478 for (i = 0; i < row_width; i++)
2479 {
2480 save = *(--sp);
2481 *(--dp) = *(--sp);
2482 *(--dp) = *(--sp);
2483 *(--dp) = *(--sp);
2484 *(--dp) = save;
2485 }
2486 }
Chris Craikb50c2172013-07-29 15:28:30 -07002487
2488#ifdef PNG_READ_16BIT_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08002489 /* This converts from RRGGBBAA to AARRGGBB */
2490 else
2491 {
2492 png_bytep sp = row + row_info->rowbytes;
2493 png_bytep dp = sp;
2494 png_byte save[2];
2495 png_uint_32 i;
2496
2497 for (i = 0; i < row_width; i++)
2498 {
2499 save[0] = *(--sp);
2500 save[1] = *(--sp);
2501 *(--dp) = *(--sp);
2502 *(--dp) = *(--sp);
2503 *(--dp) = *(--sp);
2504 *(--dp) = *(--sp);
2505 *(--dp) = *(--sp);
2506 *(--dp) = *(--sp);
2507 *(--dp) = save[0];
2508 *(--dp) = save[1];
2509 }
2510 }
Chris Craikb50c2172013-07-29 15:28:30 -07002511#endif
The Android Open Source Project893912b2009-03-03 19:30:05 -08002512 }
Chris Craikb50c2172013-07-29 15:28:30 -07002513
The Android Open Source Project893912b2009-03-03 19:30:05 -08002514 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2515 {
2516 /* This converts from GA to AG */
2517 if (row_info->bit_depth == 8)
2518 {
2519 png_bytep sp = row + row_info->rowbytes;
2520 png_bytep dp = sp;
2521 png_byte save;
2522 png_uint_32 i;
2523
2524 for (i = 0; i < row_width; i++)
2525 {
2526 save = *(--sp);
2527 *(--dp) = *(--sp);
2528 *(--dp) = save;
2529 }
2530 }
Chris Craikb50c2172013-07-29 15:28:30 -07002531
2532#ifdef PNG_READ_16BIT_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08002533 /* This converts from GGAA to AAGG */
2534 else
2535 {
2536 png_bytep sp = row + row_info->rowbytes;
2537 png_bytep dp = sp;
2538 png_byte save[2];
2539 png_uint_32 i;
2540
2541 for (i = 0; i < row_width; i++)
2542 {
2543 save[0] = *(--sp);
2544 save[1] = *(--sp);
2545 *(--dp) = *(--sp);
2546 *(--dp) = *(--sp);
2547 *(--dp) = save[0];
2548 *(--dp) = save[1];
2549 }
2550 }
Chris Craikb50c2172013-07-29 15:28:30 -07002551#endif
The Android Open Source Project893912b2009-03-03 19:30:05 -08002552 }
2553 }
2554}
2555#endif
2556
Patrick Scott5f6bd842010-06-28 16:55:16 -04002557#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
Sireesh Tripurarib478e662014-05-09 15:15:10 +05302558static void
The Android Open Source Project893912b2009-03-03 19:30:05 -08002559png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
2560{
Chris Craikb50c2172013-07-29 15:28:30 -07002561 png_uint_32 row_width;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002562 png_debug(1, "in png_do_read_invert_alpha");
Patrick Scott5f6bd842010-06-28 16:55:16 -04002563
Chris Craikb50c2172013-07-29 15:28:30 -07002564 row_width = row_info->width;
2565 if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002566 {
Chris Craikb50c2172013-07-29 15:28:30 -07002567 if (row_info->bit_depth == 8)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002568 {
2569 /* This inverts the alpha channel in RGBA */
Chris Craikb50c2172013-07-29 15:28:30 -07002570 png_bytep sp = row + row_info->rowbytes;
2571 png_bytep dp = sp;
2572 png_uint_32 i;
2573
2574 for (i = 0; i < row_width; i++)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002575 {
Chris Craikb50c2172013-07-29 15:28:30 -07002576 *(--dp) = (png_byte)(255 - *(--sp));
The Android Open Source Project893912b2009-03-03 19:30:05 -08002577
Chris Craikb50c2172013-07-29 15:28:30 -07002578/* This does nothing:
2579 *(--dp) = *(--sp);
2580 *(--dp) = *(--sp);
2581 *(--dp) = *(--sp);
2582 We can replace it with:
The Android Open Source Project893912b2009-03-03 19:30:05 -08002583*/
Chris Craikb50c2172013-07-29 15:28:30 -07002584 sp-=3;
2585 dp=sp;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002586 }
2587 }
Chris Craikb50c2172013-07-29 15:28:30 -07002588
2589#ifdef PNG_READ_16BIT_SUPPORTED
2590 /* This inverts the alpha channel in RRGGBBAA */
2591 else
2592 {
2593 png_bytep sp = row + row_info->rowbytes;
2594 png_bytep dp = sp;
2595 png_uint_32 i;
2596
2597 for (i = 0; i < row_width; i++)
2598 {
2599 *(--dp) = (png_byte)(255 - *(--sp));
2600 *(--dp) = (png_byte)(255 - *(--sp));
2601
2602/* This does nothing:
2603 *(--dp) = *(--sp);
2604 *(--dp) = *(--sp);
2605 *(--dp) = *(--sp);
2606 *(--dp) = *(--sp);
2607 *(--dp) = *(--sp);
2608 *(--dp) = *(--sp);
2609 We can replace it with:
2610*/
2611 sp-=6;
2612 dp=sp;
2613 }
2614 }
2615#endif
2616 }
2617 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2618 {
2619 if (row_info->bit_depth == 8)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002620 {
2621 /* This inverts the alpha channel in GA */
Chris Craikb50c2172013-07-29 15:28:30 -07002622 png_bytep sp = row + row_info->rowbytes;
2623 png_bytep dp = sp;
2624 png_uint_32 i;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002625
Chris Craikb50c2172013-07-29 15:28:30 -07002626 for (i = 0; i < row_width; i++)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002627 {
Chris Craikb50c2172013-07-29 15:28:30 -07002628 *(--dp) = (png_byte)(255 - *(--sp));
2629 *(--dp) = *(--sp);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002630 }
2631 }
Chris Craikb50c2172013-07-29 15:28:30 -07002632
2633#ifdef PNG_READ_16BIT_SUPPORTED
2634 else
2635 {
2636 /* This inverts the alpha channel in GGAA */
2637 png_bytep sp = row + row_info->rowbytes;
2638 png_bytep dp = sp;
2639 png_uint_32 i;
2640
2641 for (i = 0; i < row_width; i++)
2642 {
2643 *(--dp) = (png_byte)(255 - *(--sp));
2644 *(--dp) = (png_byte)(255 - *(--sp));
2645/*
2646 *(--dp) = *(--sp);
2647 *(--dp) = *(--sp);
2648*/
2649 sp-=2;
2650 dp=sp;
2651 }
2652 }
2653#endif
The Android Open Source Project893912b2009-03-03 19:30:05 -08002654 }
2655}
2656#endif
2657
Patrick Scott5f6bd842010-06-28 16:55:16 -04002658#ifdef PNG_READ_FILLER_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08002659/* Add filler channel if we have RGB color */
Sireesh Tripurarib478e662014-05-09 15:15:10 +05302660static void
The Android Open Source Project893912b2009-03-03 19:30:05 -08002661png_do_read_filler(png_row_infop row_info, png_bytep row,
Chris Craikb50c2172013-07-29 15:28:30 -07002662 png_uint_32 filler, png_uint_32 flags)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002663{
2664 png_uint_32 i;
2665 png_uint_32 row_width = row_info->width;
2666
Chris Craikb50c2172013-07-29 15:28:30 -07002667#ifdef PNG_READ_16BIT_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05002668 png_byte hi_filler = (png_byte)(filler>>8);
Chris Craikb50c2172013-07-29 15:28:30 -07002669#endif
Matt Sarett9ea75692016-01-08 13:00:42 -05002670 png_byte lo_filler = (png_byte)filler;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002671
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002672 png_debug(1, "in png_do_read_filler");
Patrick Scott5f6bd842010-06-28 16:55:16 -04002673
The Android Open Source Project893912b2009-03-03 19:30:05 -08002674 if (
The Android Open Source Project893912b2009-03-03 19:30:05 -08002675 row_info->color_type == PNG_COLOR_TYPE_GRAY)
2676 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002677 if (row_info->bit_depth == 8)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002678 {
Matt Sarett9ea75692016-01-08 13:00:42 -05002679 if ((flags & PNG_FLAG_FILLER_AFTER) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002680 {
Chris Craikb50c2172013-07-29 15:28:30 -07002681 /* This changes the data from G to GX */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002682 png_bytep sp = row + (png_size_t)row_width;
2683 png_bytep dp = sp + (png_size_t)row_width;
2684 for (i = 1; i < row_width; i++)
2685 {
2686 *(--dp) = lo_filler;
2687 *(--dp) = *(--sp);
2688 }
2689 *(--dp) = lo_filler;
2690 row_info->channels = 2;
2691 row_info->pixel_depth = 16;
2692 row_info->rowbytes = row_width * 2;
2693 }
Chris Craikb50c2172013-07-29 15:28:30 -07002694
The Android Open Source Project893912b2009-03-03 19:30:05 -08002695 else
2696 {
Chris Craikb50c2172013-07-29 15:28:30 -07002697 /* This changes the data from G to XG */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002698 png_bytep sp = row + (png_size_t)row_width;
2699 png_bytep dp = sp + (png_size_t)row_width;
2700 for (i = 0; i < row_width; i++)
2701 {
2702 *(--dp) = *(--sp);
2703 *(--dp) = lo_filler;
2704 }
2705 row_info->channels = 2;
2706 row_info->pixel_depth = 16;
2707 row_info->rowbytes = row_width * 2;
2708 }
2709 }
Chris Craikb50c2172013-07-29 15:28:30 -07002710
2711#ifdef PNG_READ_16BIT_SUPPORTED
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002712 else if (row_info->bit_depth == 16)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002713 {
Matt Sarett9ea75692016-01-08 13:00:42 -05002714 if ((flags & PNG_FLAG_FILLER_AFTER) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002715 {
Chris Craikb50c2172013-07-29 15:28:30 -07002716 /* This changes the data from GG to GGXX */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002717 png_bytep sp = row + (png_size_t)row_width * 2;
2718 png_bytep dp = sp + (png_size_t)row_width * 2;
2719 for (i = 1; i < row_width; i++)
2720 {
The Android Open Source Project893912b2009-03-03 19:30:05 -08002721 *(--dp) = lo_filler;
Matt Sarett9ea75692016-01-08 13:00:42 -05002722 *(--dp) = hi_filler;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002723 *(--dp) = *(--sp);
2724 *(--dp) = *(--sp);
2725 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08002726 *(--dp) = lo_filler;
Matt Sarett9ea75692016-01-08 13:00:42 -05002727 *(--dp) = hi_filler;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002728 row_info->channels = 2;
2729 row_info->pixel_depth = 32;
2730 row_info->rowbytes = row_width * 4;
2731 }
Chris Craikb50c2172013-07-29 15:28:30 -07002732
The Android Open Source Project893912b2009-03-03 19:30:05 -08002733 else
2734 {
Chris Craikb50c2172013-07-29 15:28:30 -07002735 /* This changes the data from GG to XXGG */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002736 png_bytep sp = row + (png_size_t)row_width * 2;
2737 png_bytep dp = sp + (png_size_t)row_width * 2;
2738 for (i = 0; i < row_width; i++)
2739 {
2740 *(--dp) = *(--sp);
2741 *(--dp) = *(--sp);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002742 *(--dp) = lo_filler;
Matt Sarett9ea75692016-01-08 13:00:42 -05002743 *(--dp) = hi_filler;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002744 }
2745 row_info->channels = 2;
2746 row_info->pixel_depth = 32;
2747 row_info->rowbytes = row_width * 4;
2748 }
2749 }
Chris Craikb50c2172013-07-29 15:28:30 -07002750#endif
The Android Open Source Project893912b2009-03-03 19:30:05 -08002751 } /* COLOR_TYPE == GRAY */
2752 else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
2753 {
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002754 if (row_info->bit_depth == 8)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002755 {
Matt Sarett9ea75692016-01-08 13:00:42 -05002756 if ((flags & PNG_FLAG_FILLER_AFTER) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002757 {
Chris Craikb50c2172013-07-29 15:28:30 -07002758 /* This changes the data from RGB to RGBX */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002759 png_bytep sp = row + (png_size_t)row_width * 3;
2760 png_bytep dp = sp + (png_size_t)row_width;
2761 for (i = 1; i < row_width; i++)
2762 {
2763 *(--dp) = lo_filler;
2764 *(--dp) = *(--sp);
2765 *(--dp) = *(--sp);
2766 *(--dp) = *(--sp);
2767 }
2768 *(--dp) = lo_filler;
2769 row_info->channels = 4;
2770 row_info->pixel_depth = 32;
2771 row_info->rowbytes = row_width * 4;
2772 }
Chris Craikb50c2172013-07-29 15:28:30 -07002773
The Android Open Source Project893912b2009-03-03 19:30:05 -08002774 else
2775 {
Chris Craikb50c2172013-07-29 15:28:30 -07002776 /* This changes the data from RGB to XRGB */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002777 png_bytep sp = row + (png_size_t)row_width * 3;
2778 png_bytep dp = sp + (png_size_t)row_width;
2779 for (i = 0; i < row_width; i++)
2780 {
2781 *(--dp) = *(--sp);
2782 *(--dp) = *(--sp);
2783 *(--dp) = *(--sp);
2784 *(--dp) = lo_filler;
2785 }
2786 row_info->channels = 4;
2787 row_info->pixel_depth = 32;
2788 row_info->rowbytes = row_width * 4;
2789 }
2790 }
Chris Craikb50c2172013-07-29 15:28:30 -07002791
2792#ifdef PNG_READ_16BIT_SUPPORTED
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002793 else if (row_info->bit_depth == 16)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002794 {
Matt Sarett9ea75692016-01-08 13:00:42 -05002795 if ((flags & PNG_FLAG_FILLER_AFTER) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002796 {
Chris Craikb50c2172013-07-29 15:28:30 -07002797 /* This changes the data from RRGGBB to RRGGBBXX */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002798 png_bytep sp = row + (png_size_t)row_width * 6;
2799 png_bytep dp = sp + (png_size_t)row_width * 2;
2800 for (i = 1; i < row_width; i++)
2801 {
The Android Open Source Project893912b2009-03-03 19:30:05 -08002802 *(--dp) = lo_filler;
Matt Sarett9ea75692016-01-08 13:00:42 -05002803 *(--dp) = hi_filler;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002804 *(--dp) = *(--sp);
2805 *(--dp) = *(--sp);
2806 *(--dp) = *(--sp);
2807 *(--dp) = *(--sp);
2808 *(--dp) = *(--sp);
2809 *(--dp) = *(--sp);
2810 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08002811 *(--dp) = lo_filler;
Matt Sarett9ea75692016-01-08 13:00:42 -05002812 *(--dp) = hi_filler;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002813 row_info->channels = 4;
2814 row_info->pixel_depth = 64;
2815 row_info->rowbytes = row_width * 8;
2816 }
Chris Craikb50c2172013-07-29 15:28:30 -07002817
The Android Open Source Project893912b2009-03-03 19:30:05 -08002818 else
2819 {
Chris Craikb50c2172013-07-29 15:28:30 -07002820 /* This changes the data from RRGGBB to XXRRGGBB */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002821 png_bytep sp = row + (png_size_t)row_width * 6;
2822 png_bytep dp = sp + (png_size_t)row_width * 2;
2823 for (i = 0; i < row_width; i++)
2824 {
2825 *(--dp) = *(--sp);
2826 *(--dp) = *(--sp);
2827 *(--dp) = *(--sp);
2828 *(--dp) = *(--sp);
2829 *(--dp) = *(--sp);
2830 *(--dp) = *(--sp);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002831 *(--dp) = lo_filler;
Matt Sarett9ea75692016-01-08 13:00:42 -05002832 *(--dp) = hi_filler;
The Android Open Source Project893912b2009-03-03 19:30:05 -08002833 }
Chris Craikb50c2172013-07-29 15:28:30 -07002834
The Android Open Source Project893912b2009-03-03 19:30:05 -08002835 row_info->channels = 4;
2836 row_info->pixel_depth = 64;
2837 row_info->rowbytes = row_width * 8;
2838 }
2839 }
Chris Craikb50c2172013-07-29 15:28:30 -07002840#endif
The Android Open Source Project893912b2009-03-03 19:30:05 -08002841 } /* COLOR_TYPE == RGB */
2842}
2843#endif
2844
Patrick Scott5f6bd842010-06-28 16:55:16 -04002845#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002846/* Expand grayscale files to RGB, with or without alpha */
Sireesh Tripurarib478e662014-05-09 15:15:10 +05302847static void
The Android Open Source Project893912b2009-03-03 19:30:05 -08002848png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
2849{
2850 png_uint_32 i;
2851 png_uint_32 row_width = row_info->width;
2852
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002853 png_debug(1, "in png_do_gray_to_rgb");
Patrick Scott5f6bd842010-06-28 16:55:16 -04002854
The Android Open Source Project893912b2009-03-03 19:30:05 -08002855 if (row_info->bit_depth >= 8 &&
Matt Sarett9ea75692016-01-08 13:00:42 -05002856 (row_info->color_type & PNG_COLOR_MASK_COLOR) == 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002857 {
2858 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
2859 {
2860 if (row_info->bit_depth == 8)
2861 {
Chris Craikb50c2172013-07-29 15:28:30 -07002862 /* This changes G to RGB */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002863 png_bytep sp = row + (png_size_t)row_width - 1;
2864 png_bytep dp = sp + (png_size_t)row_width * 2;
2865 for (i = 0; i < row_width; i++)
2866 {
2867 *(dp--) = *sp;
2868 *(dp--) = *sp;
2869 *(dp--) = *(sp--);
2870 }
2871 }
Chris Craikb50c2172013-07-29 15:28:30 -07002872
The Android Open Source Project893912b2009-03-03 19:30:05 -08002873 else
2874 {
Chris Craikb50c2172013-07-29 15:28:30 -07002875 /* This changes GG to RRGGBB */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002876 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2877 png_bytep dp = sp + (png_size_t)row_width * 4;
2878 for (i = 0; i < row_width; i++)
2879 {
2880 *(dp--) = *sp;
2881 *(dp--) = *(sp - 1);
2882 *(dp--) = *sp;
2883 *(dp--) = *(sp - 1);
2884 *(dp--) = *(sp--);
2885 *(dp--) = *(sp--);
2886 }
2887 }
2888 }
Chris Craikb50c2172013-07-29 15:28:30 -07002889
The Android Open Source Project893912b2009-03-03 19:30:05 -08002890 else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
2891 {
2892 if (row_info->bit_depth == 8)
2893 {
Chris Craikb50c2172013-07-29 15:28:30 -07002894 /* This changes GA to RGBA */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002895 png_bytep sp = row + (png_size_t)row_width * 2 - 1;
2896 png_bytep dp = sp + (png_size_t)row_width * 2;
2897 for (i = 0; i < row_width; i++)
2898 {
2899 *(dp--) = *(sp--);
2900 *(dp--) = *sp;
2901 *(dp--) = *sp;
2902 *(dp--) = *(sp--);
2903 }
2904 }
Chris Craikb50c2172013-07-29 15:28:30 -07002905
The Android Open Source Project893912b2009-03-03 19:30:05 -08002906 else
2907 {
Chris Craikb50c2172013-07-29 15:28:30 -07002908 /* This changes GGAA to RRGGBBAA */
The Android Open Source Project893912b2009-03-03 19:30:05 -08002909 png_bytep sp = row + (png_size_t)row_width * 4 - 1;
2910 png_bytep dp = sp + (png_size_t)row_width * 4;
2911 for (i = 0; i < row_width; i++)
2912 {
2913 *(dp--) = *(sp--);
2914 *(dp--) = *(sp--);
2915 *(dp--) = *sp;
2916 *(dp--) = *(sp - 1);
2917 *(dp--) = *sp;
2918 *(dp--) = *(sp - 1);
2919 *(dp--) = *(sp--);
2920 *(dp--) = *(sp--);
2921 }
2922 }
2923 }
Chris Craikb50c2172013-07-29 15:28:30 -07002924 row_info->channels = (png_byte)(row_info->channels + 2);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002925 row_info->color_type |= PNG_COLOR_MASK_COLOR;
2926 row_info->pixel_depth = (png_byte)(row_info->channels *
Chris Craikb50c2172013-07-29 15:28:30 -07002927 row_info->bit_depth);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002928 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08002929 }
2930}
2931#endif
2932
Patrick Scott5f6bd842010-06-28 16:55:16 -04002933#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
Patrick Scotta0bb96c2009-07-22 11:50:02 -04002934/* Reduce RGB files to grayscale, with or without alpha
Chris Craikb50c2172013-07-29 15:28:30 -07002935 * using the equation given in Poynton's ColorFAQ of 1998-01-04 at
2936 * <http://www.inforamp.net/~poynton/> (THIS LINK IS DEAD June 2008 but
2937 * versions dated 1998 through November 2002 have been archived at
2938 * http://web.archive.org/web/20000816232553/http://www.inforamp.net/
2939 * ~poynton/notes/colour_and_gamma/ColorFAQ.txt )
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002940 * Charles Poynton poynton at poynton.com
The Android Open Source Project893912b2009-03-03 19:30:05 -08002941 *
2942 * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
2943 *
The Android Open Source Project893912b2009-03-03 19:30:05 -08002944 * which can be expressed with integers as
2945 *
2946 * Y = (6969 * R + 23434 * G + 2365 * B)/32768
2947 *
Chris Craikb50c2172013-07-29 15:28:30 -07002948 * Poynton's current link (as of January 2003 through July 2011):
2949 * <http://www.poynton.com/notes/colour_and_gamma/>
2950 * has changed the numbers slightly:
The Android Open Source Project893912b2009-03-03 19:30:05 -08002951 *
Chris Craikb50c2172013-07-29 15:28:30 -07002952 * Y = 0.2126*R + 0.7152*G + 0.0722*B
2953 *
2954 * which can be expressed with integers as
2955 *
2956 * Y = (6966 * R + 23436 * G + 2366 * B)/32768
2957 *
2958 * Historically, however, libpng uses numbers derived from the ITU-R Rec 709
2959 * end point chromaticities and the D65 white point. Depending on the
2960 * precision used for the D65 white point this produces a variety of different
2961 * numbers, however if the four decimal place value used in ITU-R Rec 709 is
2962 * used (0.3127,0.3290) the Y calculation would be:
2963 *
2964 * Y = (6968 * R + 23435 * G + 2366 * B)/32768
2965 *
2966 * While this is correct the rounding results in an overflow for white, because
2967 * the sum of the rounded coefficients is 32769, not 32768. Consequently
2968 * libpng uses, instead, the closest non-overflowing approximation:
2969 *
2970 * Y = (6968 * R + 23434 * G + 2366 * B)/32768
2971 *
2972 * Starting with libpng-1.5.5, if the image being converted has a cHRM chunk
2973 * (including an sRGB chunk) then the chromaticities are used to calculate the
2974 * coefficients. See the chunk handling in pngrutil.c for more information.
2975 *
2976 * In all cases the calculation is to be done in a linear colorspace. If no
2977 * gamma information is available to correct the encoding of the original RGB
2978 * values this results in an implicit assumption that the original PNG RGB
2979 * values were linear.
2980 *
2981 * Other integer coefficents can be used via png_set_rgb_to_gray(). Because
2982 * the API takes just red and green coefficients the blue coefficient is
2983 * calculated to make the sum 32768. This will result in different rounding
2984 * to that used above.
The Android Open Source Project893912b2009-03-03 19:30:05 -08002985 */
Sireesh Tripurarib478e662014-05-09 15:15:10 +05302986static int
Chris Craikb50c2172013-07-29 15:28:30 -07002987png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002988
2989{
The Android Open Source Project893912b2009-03-03 19:30:05 -08002990 int rgb_error = 0;
2991
The Android Open Source Project4215dd12009-03-09 11:52:12 -07002992 png_debug(1, "in png_do_rgb_to_gray");
Patrick Scott5f6bd842010-06-28 16:55:16 -04002993
Matt Sarett9ea75692016-01-08 13:00:42 -05002994 if ((row_info->color_type & PNG_COLOR_MASK_PALETTE) == 0 &&
2995 (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08002996 {
Chris Craikb50c2172013-07-29 15:28:30 -07002997 PNG_CONST png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
2998 PNG_CONST png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
2999 PNG_CONST png_uint_32 bc = 32768 - rc - gc;
3000 PNG_CONST png_uint_32 row_width = row_info->width;
3001 PNG_CONST int have_alpha =
3002 (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003003
Chris Craikb50c2172013-07-29 15:28:30 -07003004 if (row_info->bit_depth == 8)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003005 {
Chris Craikb50c2172013-07-29 15:28:30 -07003006#ifdef PNG_READ_GAMMA_SUPPORTED
3007 /* Notice that gamma to/from 1 are not necessarily inverses (if
3008 * there is an overall gamma correction). Prior to 1.5.5 this code
3009 * checked the linearized values for equality; this doesn't match
3010 * the documentation, the original values must be checked.
3011 */
3012 if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003013 {
Chris Craikb50c2172013-07-29 15:28:30 -07003014 png_bytep sp = row;
3015 png_bytep dp = row;
3016 png_uint_32 i;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003017
Chris Craikb50c2172013-07-29 15:28:30 -07003018 for (i = 0; i < row_width; i++)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003019 {
Chris Craikb50c2172013-07-29 15:28:30 -07003020 png_byte red = *(sp++);
3021 png_byte green = *(sp++);
3022 png_byte blue = *(sp++);
3023
3024 if (red != green || red != blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003025 {
Chris Craikb50c2172013-07-29 15:28:30 -07003026 red = png_ptr->gamma_to_1[red];
3027 green = png_ptr->gamma_to_1[green];
3028 blue = png_ptr->gamma_to_1[blue];
3029
3030 rgb_error |= 1;
3031 *(dp++) = png_ptr->gamma_from_1[
3032 (rc*red + gc*green + bc*blue + 16384)>>15];
The Android Open Source Project893912b2009-03-03 19:30:05 -08003033 }
Chris Craikb50c2172013-07-29 15:28:30 -07003034
3035 else
3036 {
3037 /* If there is no overall correction the table will not be
3038 * set.
3039 */
3040 if (png_ptr->gamma_table != NULL)
3041 red = png_ptr->gamma_table[red];
3042
3043 *(dp++) = red;
3044 }
3045
Matt Sarett9ea75692016-01-08 13:00:42 -05003046 if (have_alpha != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07003047 *(dp++) = *(sp++);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003048 }
3049 }
Chris Craikb50c2172013-07-29 15:28:30 -07003050 else
The Android Open Source Project893912b2009-03-03 19:30:05 -08003051#endif
Chris Craikb50c2172013-07-29 15:28:30 -07003052 {
3053 png_bytep sp = row;
3054 png_bytep dp = row;
3055 png_uint_32 i;
3056
3057 for (i = 0; i < row_width; i++)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003058 {
Chris Craikb50c2172013-07-29 15:28:30 -07003059 png_byte red = *(sp++);
3060 png_byte green = *(sp++);
3061 png_byte blue = *(sp++);
3062
3063 if (red != green || red != blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003064 {
Chris Craikb50c2172013-07-29 15:28:30 -07003065 rgb_error |= 1;
3066 /* NOTE: this is the historical approach which simply
3067 * truncates the results.
3068 */
3069 *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003070 }
Chris Craikb50c2172013-07-29 15:28:30 -07003071
3072 else
3073 *(dp++) = red;
3074
Matt Sarett9ea75692016-01-08 13:00:42 -05003075 if (have_alpha != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07003076 *(dp++) = *(sp++);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003077 }
3078 }
3079 }
Chris Craikb50c2172013-07-29 15:28:30 -07003080
3081 else /* RGB bit_depth == 16 */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003082 {
Chris Craikb50c2172013-07-29 15:28:30 -07003083#ifdef PNG_READ_GAMMA_SUPPORTED
3084 if (png_ptr->gamma_16_to_1 != NULL && png_ptr->gamma_16_from_1 != NULL)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003085 {
Chris Craikb50c2172013-07-29 15:28:30 -07003086 png_bytep sp = row;
3087 png_bytep dp = row;
3088 png_uint_32 i;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003089
Chris Craikb50c2172013-07-29 15:28:30 -07003090 for (i = 0; i < row_width; i++)
3091 {
3092 png_uint_16 red, green, blue, w;
Matt Sarett9ea75692016-01-08 13:00:42 -05003093 png_byte hi,lo;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003094
Matt Sarett9ea75692016-01-08 13:00:42 -05003095 hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo));
3096 hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo));
3097 hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo));
Chris Craikb50c2172013-07-29 15:28:30 -07003098
3099 if (red == green && red == blue)
3100 {
3101 if (png_ptr->gamma_16_table != NULL)
Matt Sarett9ea75692016-01-08 13:00:42 -05003102 w = png_ptr->gamma_16_table[(red & 0xff)
3103 >> png_ptr->gamma_shift][red >> 8];
Chris Craikb50c2172013-07-29 15:28:30 -07003104
The Android Open Source Project893912b2009-03-03 19:30:05 -08003105 else
Chris Craikb50c2172013-07-29 15:28:30 -07003106 w = red;
3107 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08003108
Chris Craikb50c2172013-07-29 15:28:30 -07003109 else
3110 {
Matt Sarett9ea75692016-01-08 13:00:42 -05003111 png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red & 0xff)
Chris Craikb50c2172013-07-29 15:28:30 -07003112 >> png_ptr->gamma_shift][red>>8];
3113 png_uint_16 green_1 =
Matt Sarett9ea75692016-01-08 13:00:42 -05003114 png_ptr->gamma_16_to_1[(green & 0xff) >>
Chris Craikb50c2172013-07-29 15:28:30 -07003115 png_ptr->gamma_shift][green>>8];
Matt Sarett9ea75692016-01-08 13:00:42 -05003116 png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue & 0xff)
Chris Craikb50c2172013-07-29 15:28:30 -07003117 >> png_ptr->gamma_shift][blue>>8];
3118 png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
3119 + bc*blue_1 + 16384)>>15);
Matt Sarett9ea75692016-01-08 13:00:42 -05003120 w = png_ptr->gamma_16_from_1[(gray16 & 0xff) >>
Chris Craikb50c2172013-07-29 15:28:30 -07003121 png_ptr->gamma_shift][gray16 >> 8];
3122 rgb_error |= 1;
3123 }
3124
3125 *(dp++) = (png_byte)((w>>8) & 0xff);
3126 *(dp++) = (png_byte)(w & 0xff);
3127
Matt Sarett9ea75692016-01-08 13:00:42 -05003128 if (have_alpha != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07003129 {
3130 *(dp++) = *(sp++);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003131 *(dp++) = *(sp++);
3132 }
3133 }
Chris Craikb50c2172013-07-29 15:28:30 -07003134 }
3135 else
The Android Open Source Project893912b2009-03-03 19:30:05 -08003136#endif
Chris Craikb50c2172013-07-29 15:28:30 -07003137 {
3138 png_bytep sp = row;
3139 png_bytep dp = row;
3140 png_uint_32 i;
3141
3142 for (i = 0; i < row_width; i++)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003143 {
Chris Craikb50c2172013-07-29 15:28:30 -07003144 png_uint_16 red, green, blue, gray16;
Matt Sarett9ea75692016-01-08 13:00:42 -05003145 png_byte hi,lo;
Chris Craikb50c2172013-07-29 15:28:30 -07003146
Matt Sarett9ea75692016-01-08 13:00:42 -05003147 hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo));
3148 hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo));
3149 hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo));
Chris Craikb50c2172013-07-29 15:28:30 -07003150
3151 if (red != green || red != blue)
3152 rgb_error |= 1;
3153
Matt Sarett9ea75692016-01-08 13:00:42 -05003154 /* From 1.5.5 in the 16-bit case do the accurate conversion even
Chris Craikb50c2172013-07-29 15:28:30 -07003155 * in the 'fast' case - this is because this is where the code
Matt Sarett9ea75692016-01-08 13:00:42 -05003156 * ends up when handling linear 16-bit data.
Chris Craikb50c2172013-07-29 15:28:30 -07003157 */
3158 gray16 = (png_uint_16)((rc*red + gc*green + bc*blue + 16384) >>
3159 15);
Matt Sarett9ea75692016-01-08 13:00:42 -05003160 *(dp++) = (png_byte)((gray16 >> 8) & 0xff);
Chris Craikb50c2172013-07-29 15:28:30 -07003161 *(dp++) = (png_byte)(gray16 & 0xff);
3162
Matt Sarett9ea75692016-01-08 13:00:42 -05003163 if (have_alpha != 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003164 {
Chris Craikb50c2172013-07-29 15:28:30 -07003165 *(dp++) = *(sp++);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003166 *(dp++) = *(sp++);
3167 }
3168 }
3169 }
3170 }
Chris Craikb50c2172013-07-29 15:28:30 -07003171
3172 row_info->channels = (png_byte)(row_info->channels - 2);
3173 row_info->color_type = (png_byte)(row_info->color_type &
3174 ~PNG_COLOR_MASK_COLOR);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003175 row_info->pixel_depth = (png_byte)(row_info->channels *
Chris Craikb50c2172013-07-29 15:28:30 -07003176 row_info->bit_depth);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003177 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003178 }
3179 return rgb_error;
3180}
3181#endif
3182
Chris Craikb50c2172013-07-29 15:28:30 -07003183#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
3184 defined(PNG_READ_ALPHA_MODE_SUPPORTED)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003185/* Replace any alpha or transparency with the supplied background color.
3186 * "background" is already in the screen gamma, while "background_1" is
3187 * at a gamma of 1.0. Paletted files have already been taken care of.
3188 */
Sireesh Tripurarib478e662014-05-09 15:15:10 +05303189static void
Chris Craikb50c2172013-07-29 15:28:30 -07003190png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003191{
Chris Craikb50c2172013-07-29 15:28:30 -07003192#ifdef PNG_READ_GAMMA_SUPPORTED
3193 png_const_bytep gamma_table = png_ptr->gamma_table;
3194 png_const_bytep gamma_from_1 = png_ptr->gamma_from_1;
3195 png_const_bytep gamma_to_1 = png_ptr->gamma_to_1;
3196 png_const_uint_16pp gamma_16 = png_ptr->gamma_16_table;
3197 png_const_uint_16pp gamma_16_from_1 = png_ptr->gamma_16_from_1;
3198 png_const_uint_16pp gamma_16_to_1 = png_ptr->gamma_16_to_1;
3199 int gamma_shift = png_ptr->gamma_shift;
3200 int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0;
3201#endif
3202
3203 png_bytep sp;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003204 png_uint_32 i;
Chris Craikb50c2172013-07-29 15:28:30 -07003205 png_uint_32 row_width = row_info->width;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003206 int shift;
3207
Chris Craikb50c2172013-07-29 15:28:30 -07003208 png_debug(1, "in png_do_compose");
Patrick Scott5f6bd842010-06-28 16:55:16 -04003209
The Android Open Source Project893912b2009-03-03 19:30:05 -08003210 {
3211 switch (row_info->color_type)
3212 {
3213 case PNG_COLOR_TYPE_GRAY:
3214 {
3215 switch (row_info->bit_depth)
3216 {
3217 case 1:
3218 {
3219 sp = row;
3220 shift = 7;
3221 for (i = 0; i < row_width; i++)
3222 {
3223 if ((png_uint_16)((*sp >> shift) & 0x01)
Chris Craikb50c2172013-07-29 15:28:30 -07003224 == png_ptr->trans_color.gray)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003225 {
Chris Craikb50c2172013-07-29 15:28:30 -07003226 unsigned int tmp = *sp & (0x7f7f >> (7 - shift));
3227 tmp |= png_ptr->background.gray << shift;
3228 *sp = (png_byte)(tmp & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003229 }
Chris Craikb50c2172013-07-29 15:28:30 -07003230
Matt Sarett9ea75692016-01-08 13:00:42 -05003231 if (shift == 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003232 {
3233 shift = 7;
3234 sp++;
3235 }
Chris Craikb50c2172013-07-29 15:28:30 -07003236
The Android Open Source Project893912b2009-03-03 19:30:05 -08003237 else
3238 shift--;
3239 }
3240 break;
3241 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003242
The Android Open Source Project893912b2009-03-03 19:30:05 -08003243 case 2:
3244 {
Patrick Scott5f6bd842010-06-28 16:55:16 -04003245#ifdef PNG_READ_GAMMA_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003246 if (gamma_table != NULL)
3247 {
3248 sp = row;
3249 shift = 6;
3250 for (i = 0; i < row_width; i++)
3251 {
3252 if ((png_uint_16)((*sp >> shift) & 0x03)
Chris Craikb50c2172013-07-29 15:28:30 -07003253 == png_ptr->trans_color.gray)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003254 {
Chris Craikb50c2172013-07-29 15:28:30 -07003255 unsigned int tmp = *sp & (0x3f3f >> (6 - shift));
3256 tmp |= png_ptr->background.gray << shift;
3257 *sp = (png_byte)(tmp & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003258 }
Chris Craikb50c2172013-07-29 15:28:30 -07003259
The Android Open Source Project893912b2009-03-03 19:30:05 -08003260 else
3261 {
Chris Craikb50c2172013-07-29 15:28:30 -07003262 unsigned int p = (*sp >> shift) & 0x03;
3263 unsigned int g = (gamma_table [p | (p << 2) |
3264 (p << 4) | (p << 6)] >> 6) & 0x03;
3265 unsigned int tmp = *sp & (0x3f3f >> (6 - shift));
3266 tmp |= g << shift;
3267 *sp = (png_byte)(tmp & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003268 }
Chris Craikb50c2172013-07-29 15:28:30 -07003269
Matt Sarett9ea75692016-01-08 13:00:42 -05003270 if (shift == 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003271 {
3272 shift = 6;
3273 sp++;
3274 }
Chris Craikb50c2172013-07-29 15:28:30 -07003275
The Android Open Source Project893912b2009-03-03 19:30:05 -08003276 else
3277 shift -= 2;
3278 }
3279 }
Chris Craikb50c2172013-07-29 15:28:30 -07003280
The Android Open Source Project893912b2009-03-03 19:30:05 -08003281 else
3282#endif
3283 {
3284 sp = row;
3285 shift = 6;
3286 for (i = 0; i < row_width; i++)
3287 {
3288 if ((png_uint_16)((*sp >> shift) & 0x03)
Chris Craikb50c2172013-07-29 15:28:30 -07003289 == png_ptr->trans_color.gray)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003290 {
Chris Craikb50c2172013-07-29 15:28:30 -07003291 unsigned int tmp = *sp & (0x3f3f >> (6 - shift));
3292 tmp |= png_ptr->background.gray << shift;
3293 *sp = (png_byte)(tmp & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003294 }
Chris Craikb50c2172013-07-29 15:28:30 -07003295
Matt Sarett9ea75692016-01-08 13:00:42 -05003296 if (shift == 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003297 {
3298 shift = 6;
3299 sp++;
3300 }
Chris Craikb50c2172013-07-29 15:28:30 -07003301
The Android Open Source Project893912b2009-03-03 19:30:05 -08003302 else
3303 shift -= 2;
3304 }
3305 }
3306 break;
3307 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003308
The Android Open Source Project893912b2009-03-03 19:30:05 -08003309 case 4:
3310 {
Patrick Scott5f6bd842010-06-28 16:55:16 -04003311#ifdef PNG_READ_GAMMA_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003312 if (gamma_table != NULL)
3313 {
3314 sp = row;
3315 shift = 4;
3316 for (i = 0; i < row_width; i++)
3317 {
3318 if ((png_uint_16)((*sp >> shift) & 0x0f)
Chris Craikb50c2172013-07-29 15:28:30 -07003319 == png_ptr->trans_color.gray)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003320 {
Matt Sarett9ea75692016-01-08 13:00:42 -05003321 unsigned int tmp = *sp & (0x0f0f >> (4 - shift));
Chris Craikb50c2172013-07-29 15:28:30 -07003322 tmp |= png_ptr->background.gray << shift;
3323 *sp = (png_byte)(tmp & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003324 }
Chris Craikb50c2172013-07-29 15:28:30 -07003325
The Android Open Source Project893912b2009-03-03 19:30:05 -08003326 else
3327 {
Chris Craikb50c2172013-07-29 15:28:30 -07003328 unsigned int p = (*sp >> shift) & 0x0f;
3329 unsigned int g = (gamma_table[p | (p << 4)] >> 4) &
3330 0x0f;
Matt Sarett9ea75692016-01-08 13:00:42 -05003331 unsigned int tmp = *sp & (0x0f0f >> (4 - shift));
Chris Craikb50c2172013-07-29 15:28:30 -07003332 tmp |= g << shift;
3333 *sp = (png_byte)(tmp & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003334 }
Chris Craikb50c2172013-07-29 15:28:30 -07003335
Matt Sarett9ea75692016-01-08 13:00:42 -05003336 if (shift == 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003337 {
3338 shift = 4;
3339 sp++;
3340 }
Chris Craikb50c2172013-07-29 15:28:30 -07003341
The Android Open Source Project893912b2009-03-03 19:30:05 -08003342 else
3343 shift -= 4;
3344 }
3345 }
Chris Craikb50c2172013-07-29 15:28:30 -07003346
The Android Open Source Project893912b2009-03-03 19:30:05 -08003347 else
3348#endif
3349 {
3350 sp = row;
3351 shift = 4;
3352 for (i = 0; i < row_width; i++)
3353 {
3354 if ((png_uint_16)((*sp >> shift) & 0x0f)
Chris Craikb50c2172013-07-29 15:28:30 -07003355 == png_ptr->trans_color.gray)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003356 {
Matt Sarett9ea75692016-01-08 13:00:42 -05003357 unsigned int tmp = *sp & (0x0f0f >> (4 - shift));
Chris Craikb50c2172013-07-29 15:28:30 -07003358 tmp |= png_ptr->background.gray << shift;
3359 *sp = (png_byte)(tmp & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003360 }
Chris Craikb50c2172013-07-29 15:28:30 -07003361
Matt Sarett9ea75692016-01-08 13:00:42 -05003362 if (shift == 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003363 {
3364 shift = 4;
3365 sp++;
3366 }
Chris Craikb50c2172013-07-29 15:28:30 -07003367
The Android Open Source Project893912b2009-03-03 19:30:05 -08003368 else
3369 shift -= 4;
3370 }
3371 }
3372 break;
3373 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003374
The Android Open Source Project893912b2009-03-03 19:30:05 -08003375 case 8:
3376 {
Patrick Scott5f6bd842010-06-28 16:55:16 -04003377#ifdef PNG_READ_GAMMA_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003378 if (gamma_table != NULL)
3379 {
3380 sp = row;
3381 for (i = 0; i < row_width; i++, sp++)
3382 {
Chris Craikb50c2172013-07-29 15:28:30 -07003383 if (*sp == png_ptr->trans_color.gray)
3384 *sp = (png_byte)png_ptr->background.gray;
3385
The Android Open Source Project893912b2009-03-03 19:30:05 -08003386 else
The Android Open Source Project893912b2009-03-03 19:30:05 -08003387 *sp = gamma_table[*sp];
The Android Open Source Project893912b2009-03-03 19:30:05 -08003388 }
3389 }
3390 else
3391#endif
3392 {
3393 sp = row;
3394 for (i = 0; i < row_width; i++, sp++)
3395 {
Chris Craikb50c2172013-07-29 15:28:30 -07003396 if (*sp == png_ptr->trans_color.gray)
3397 *sp = (png_byte)png_ptr->background.gray;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003398 }
3399 }
3400 break;
3401 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003402
The Android Open Source Project893912b2009-03-03 19:30:05 -08003403 case 16:
3404 {
Patrick Scott5f6bd842010-06-28 16:55:16 -04003405#ifdef PNG_READ_GAMMA_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003406 if (gamma_16 != NULL)
3407 {
3408 sp = row;
3409 for (i = 0; i < row_width; i++, sp += 2)
3410 {
3411 png_uint_16 v;
3412
3413 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Chris Craikb50c2172013-07-29 15:28:30 -07003414
3415 if (v == png_ptr->trans_color.gray)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003416 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003417 /* Background is already in screen gamma */
Chris Craikb50c2172013-07-29 15:28:30 -07003418 *sp = (png_byte)((png_ptr->background.gray >> 8)
3419 & 0xff);
3420 *(sp + 1) = (png_byte)(png_ptr->background.gray
3421 & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003422 }
Chris Craikb50c2172013-07-29 15:28:30 -07003423
The Android Open Source Project893912b2009-03-03 19:30:05 -08003424 else
3425 {
3426 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
3427 *sp = (png_byte)((v >> 8) & 0xff);
3428 *(sp + 1) = (png_byte)(v & 0xff);
3429 }
3430 }
3431 }
3432 else
3433#endif
3434 {
3435 sp = row;
3436 for (i = 0; i < row_width; i++, sp += 2)
3437 {
3438 png_uint_16 v;
3439
3440 v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Chris Craikb50c2172013-07-29 15:28:30 -07003441
3442 if (v == png_ptr->trans_color.gray)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003443 {
Chris Craikb50c2172013-07-29 15:28:30 -07003444 *sp = (png_byte)((png_ptr->background.gray >> 8)
3445 & 0xff);
3446 *(sp + 1) = (png_byte)(png_ptr->background.gray
3447 & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003448 }
3449 }
3450 }
3451 break;
3452 }
Chris Craikb50c2172013-07-29 15:28:30 -07003453
3454 default:
3455 break;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003456 }
3457 break;
3458 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003459
The Android Open Source Project893912b2009-03-03 19:30:05 -08003460 case PNG_COLOR_TYPE_RGB:
3461 {
3462 if (row_info->bit_depth == 8)
3463 {
Patrick Scott5f6bd842010-06-28 16:55:16 -04003464#ifdef PNG_READ_GAMMA_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003465 if (gamma_table != NULL)
3466 {
3467 sp = row;
3468 for (i = 0; i < row_width; i++, sp += 3)
3469 {
Chris Craikb50c2172013-07-29 15:28:30 -07003470 if (*sp == png_ptr->trans_color.red &&
3471 *(sp + 1) == png_ptr->trans_color.green &&
3472 *(sp + 2) == png_ptr->trans_color.blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003473 {
Chris Craikb50c2172013-07-29 15:28:30 -07003474 *sp = (png_byte)png_ptr->background.red;
3475 *(sp + 1) = (png_byte)png_ptr->background.green;
3476 *(sp + 2) = (png_byte)png_ptr->background.blue;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003477 }
Chris Craikb50c2172013-07-29 15:28:30 -07003478
The Android Open Source Project893912b2009-03-03 19:30:05 -08003479 else
3480 {
3481 *sp = gamma_table[*sp];
3482 *(sp + 1) = gamma_table[*(sp + 1)];
3483 *(sp + 2) = gamma_table[*(sp + 2)];
3484 }
3485 }
3486 }
3487 else
3488#endif
3489 {
3490 sp = row;
3491 for (i = 0; i < row_width; i++, sp += 3)
3492 {
Chris Craikb50c2172013-07-29 15:28:30 -07003493 if (*sp == png_ptr->trans_color.red &&
3494 *(sp + 1) == png_ptr->trans_color.green &&
3495 *(sp + 2) == png_ptr->trans_color.blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003496 {
Chris Craikb50c2172013-07-29 15:28:30 -07003497 *sp = (png_byte)png_ptr->background.red;
3498 *(sp + 1) = (png_byte)png_ptr->background.green;
3499 *(sp + 2) = (png_byte)png_ptr->background.blue;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003500 }
3501 }
3502 }
3503 }
3504 else /* if (row_info->bit_depth == 16) */
3505 {
Patrick Scott5f6bd842010-06-28 16:55:16 -04003506#ifdef PNG_READ_GAMMA_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003507 if (gamma_16 != NULL)
3508 {
3509 sp = row;
3510 for (i = 0; i < row_width; i++, sp += 6)
3511 {
3512 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Chris Craikb50c2172013-07-29 15:28:30 -07003513
3514 png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
3515 + *(sp + 3));
3516
3517 png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
3518 + *(sp + 5));
3519
3520 if (r == png_ptr->trans_color.red &&
3521 g == png_ptr->trans_color.green &&
3522 b == png_ptr->trans_color.blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003523 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003524 /* Background is already in screen gamma */
Chris Craikb50c2172013-07-29 15:28:30 -07003525 *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
3526 *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
3527 *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
3528 & 0xff);
3529 *(sp + 3) = (png_byte)(png_ptr->background.green
3530 & 0xff);
3531 *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
3532 & 0xff);
3533 *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003534 }
Chris Craikb50c2172013-07-29 15:28:30 -07003535
The Android Open Source Project893912b2009-03-03 19:30:05 -08003536 else
3537 {
3538 png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
3539 *sp = (png_byte)((v >> 8) & 0xff);
3540 *(sp + 1) = (png_byte)(v & 0xff);
Chris Craikb50c2172013-07-29 15:28:30 -07003541
The Android Open Source Project893912b2009-03-03 19:30:05 -08003542 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
3543 *(sp + 2) = (png_byte)((v >> 8) & 0xff);
3544 *(sp + 3) = (png_byte)(v & 0xff);
Chris Craikb50c2172013-07-29 15:28:30 -07003545
The Android Open Source Project893912b2009-03-03 19:30:05 -08003546 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
3547 *(sp + 4) = (png_byte)((v >> 8) & 0xff);
3548 *(sp + 5) = (png_byte)(v & 0xff);
3549 }
3550 }
3551 }
Chris Craikb50c2172013-07-29 15:28:30 -07003552
The Android Open Source Project893912b2009-03-03 19:30:05 -08003553 else
3554#endif
3555 {
3556 sp = row;
3557 for (i = 0; i < row_width; i++, sp += 6)
3558 {
Chris Craikb50c2172013-07-29 15:28:30 -07003559 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
The Android Open Source Project893912b2009-03-03 19:30:05 -08003560
Chris Craikb50c2172013-07-29 15:28:30 -07003561 png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
3562 + *(sp + 3));
3563
3564 png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
3565 + *(sp + 5));
3566
3567 if (r == png_ptr->trans_color.red &&
3568 g == png_ptr->trans_color.green &&
3569 b == png_ptr->trans_color.blue)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003570 {
Chris Craikb50c2172013-07-29 15:28:30 -07003571 *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
3572 *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
3573 *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
3574 & 0xff);
3575 *(sp + 3) = (png_byte)(png_ptr->background.green
3576 & 0xff);
3577 *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
3578 & 0xff);
3579 *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003580 }
3581 }
3582 }
3583 }
3584 break;
3585 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003586
The Android Open Source Project893912b2009-03-03 19:30:05 -08003587 case PNG_COLOR_TYPE_GRAY_ALPHA:
3588 {
3589 if (row_info->bit_depth == 8)
3590 {
Patrick Scott5f6bd842010-06-28 16:55:16 -04003591#ifdef PNG_READ_GAMMA_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003592 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
3593 gamma_table != NULL)
3594 {
3595 sp = row;
Chris Craikb50c2172013-07-29 15:28:30 -07003596 for (i = 0; i < row_width; i++, sp += 2)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003597 {
3598 png_uint_16 a = *(sp + 1);
3599
3600 if (a == 0xff)
Chris Craikb50c2172013-07-29 15:28:30 -07003601 *sp = gamma_table[*sp];
3602
The Android Open Source Project893912b2009-03-03 19:30:05 -08003603 else if (a == 0)
3604 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003605 /* Background is already in screen gamma */
Chris Craikb50c2172013-07-29 15:28:30 -07003606 *sp = (png_byte)png_ptr->background.gray;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003607 }
Chris Craikb50c2172013-07-29 15:28:30 -07003608
The Android Open Source Project893912b2009-03-03 19:30:05 -08003609 else
3610 {
3611 png_byte v, w;
3612
3613 v = gamma_to_1[*sp];
Chris Craikb50c2172013-07-29 15:28:30 -07003614 png_composite(w, v, a, png_ptr->background_1.gray);
Matt Sarett9ea75692016-01-08 13:00:42 -05003615 if (optimize == 0)
Chris Craikb50c2172013-07-29 15:28:30 -07003616 w = gamma_from_1[w];
3617 *sp = w;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003618 }
3619 }
3620 }
3621 else
3622#endif
3623 {
3624 sp = row;
Chris Craikb50c2172013-07-29 15:28:30 -07003625 for (i = 0; i < row_width; i++, sp += 2)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003626 {
3627 png_byte a = *(sp + 1);
3628
Chris Craikb50c2172013-07-29 15:28:30 -07003629 if (a == 0)
3630 *sp = (png_byte)png_ptr->background.gray;
3631
3632 else if (a < 0xff)
3633 png_composite(*sp, *sp, a, png_ptr->background.gray);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003634 }
3635 }
3636 }
3637 else /* if (png_ptr->bit_depth == 16) */
3638 {
Patrick Scott5f6bd842010-06-28 16:55:16 -04003639#ifdef PNG_READ_GAMMA_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003640 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3641 gamma_16_to_1 != NULL)
3642 {
3643 sp = row;
Chris Craikb50c2172013-07-29 15:28:30 -07003644 for (i = 0; i < row_width; i++, sp += 4)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003645 {
Chris Craikb50c2172013-07-29 15:28:30 -07003646 png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8)
3647 + *(sp + 3));
The Android Open Source Project893912b2009-03-03 19:30:05 -08003648
3649 if (a == (png_uint_16)0xffff)
3650 {
3651 png_uint_16 v;
3652
3653 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Chris Craikb50c2172013-07-29 15:28:30 -07003654 *sp = (png_byte)((v >> 8) & 0xff);
3655 *(sp + 1) = (png_byte)(v & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003656 }
Chris Craikb50c2172013-07-29 15:28:30 -07003657
The Android Open Source Project893912b2009-03-03 19:30:05 -08003658 else if (a == 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003659 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003660 /* Background is already in screen gamma */
Chris Craikb50c2172013-07-29 15:28:30 -07003661 *sp = (png_byte)((png_ptr->background.gray >> 8)
3662 & 0xff);
3663 *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003664 }
Chris Craikb50c2172013-07-29 15:28:30 -07003665
The Android Open Source Project893912b2009-03-03 19:30:05 -08003666 else
3667 {
3668 png_uint_16 g, v, w;
3669
3670 g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
Chris Craikb50c2172013-07-29 15:28:30 -07003671 png_composite_16(v, g, a, png_ptr->background_1.gray);
Matt Sarett9ea75692016-01-08 13:00:42 -05003672 if (optimize != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07003673 w = v;
3674 else
Matt Sarett9ea75692016-01-08 13:00:42 -05003675 w = gamma_16_from_1[(v & 0xff) >>
3676 gamma_shift][v >> 8];
Chris Craikb50c2172013-07-29 15:28:30 -07003677 *sp = (png_byte)((w >> 8) & 0xff);
3678 *(sp + 1) = (png_byte)(w & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003679 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08003680 }
3681 }
3682 else
3683#endif
3684 {
3685 sp = row;
Chris Craikb50c2172013-07-29 15:28:30 -07003686 for (i = 0; i < row_width; i++, sp += 4)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003687 {
Chris Craikb50c2172013-07-29 15:28:30 -07003688 png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8)
3689 + *(sp + 3));
3690
3691 if (a == 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003692 {
Chris Craikb50c2172013-07-29 15:28:30 -07003693 *sp = (png_byte)((png_ptr->background.gray >> 8)
3694 & 0xff);
3695 *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003696 }
Chris Craikb50c2172013-07-29 15:28:30 -07003697
3698 else if (a < 0xffff)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003699 {
3700 png_uint_16 g, v;
3701
3702 g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
Chris Craikb50c2172013-07-29 15:28:30 -07003703 png_composite_16(v, g, a, png_ptr->background.gray);
3704 *sp = (png_byte)((v >> 8) & 0xff);
3705 *(sp + 1) = (png_byte)(v & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003706 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08003707 }
3708 }
3709 }
3710 break;
3711 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003712
The Android Open Source Project893912b2009-03-03 19:30:05 -08003713 case PNG_COLOR_TYPE_RGB_ALPHA:
3714 {
3715 if (row_info->bit_depth == 8)
3716 {
Patrick Scott5f6bd842010-06-28 16:55:16 -04003717#ifdef PNG_READ_GAMMA_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003718 if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
3719 gamma_table != NULL)
3720 {
3721 sp = row;
Chris Craikb50c2172013-07-29 15:28:30 -07003722 for (i = 0; i < row_width; i++, sp += 4)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003723 {
3724 png_byte a = *(sp + 3);
3725
3726 if (a == 0xff)
3727 {
Chris Craikb50c2172013-07-29 15:28:30 -07003728 *sp = gamma_table[*sp];
3729 *(sp + 1) = gamma_table[*(sp + 1)];
3730 *(sp + 2) = gamma_table[*(sp + 2)];
The Android Open Source Project893912b2009-03-03 19:30:05 -08003731 }
Chris Craikb50c2172013-07-29 15:28:30 -07003732
The Android Open Source Project893912b2009-03-03 19:30:05 -08003733 else if (a == 0)
3734 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003735 /* Background is already in screen gamma */
Chris Craikb50c2172013-07-29 15:28:30 -07003736 *sp = (png_byte)png_ptr->background.red;
3737 *(sp + 1) = (png_byte)png_ptr->background.green;
3738 *(sp + 2) = (png_byte)png_ptr->background.blue;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003739 }
Chris Craikb50c2172013-07-29 15:28:30 -07003740
The Android Open Source Project893912b2009-03-03 19:30:05 -08003741 else
3742 {
3743 png_byte v, w;
3744
3745 v = gamma_to_1[*sp];
Chris Craikb50c2172013-07-29 15:28:30 -07003746 png_composite(w, v, a, png_ptr->background_1.red);
Matt Sarett9ea75692016-01-08 13:00:42 -05003747 if (optimize == 0) w = gamma_from_1[w];
Chris Craikb50c2172013-07-29 15:28:30 -07003748 *sp = w;
3749
The Android Open Source Project893912b2009-03-03 19:30:05 -08003750 v = gamma_to_1[*(sp + 1)];
Chris Craikb50c2172013-07-29 15:28:30 -07003751 png_composite(w, v, a, png_ptr->background_1.green);
Matt Sarett9ea75692016-01-08 13:00:42 -05003752 if (optimize == 0) w = gamma_from_1[w];
Chris Craikb50c2172013-07-29 15:28:30 -07003753 *(sp + 1) = w;
3754
The Android Open Source Project893912b2009-03-03 19:30:05 -08003755 v = gamma_to_1[*(sp + 2)];
Chris Craikb50c2172013-07-29 15:28:30 -07003756 png_composite(w, v, a, png_ptr->background_1.blue);
Matt Sarett9ea75692016-01-08 13:00:42 -05003757 if (optimize == 0) w = gamma_from_1[w];
Chris Craikb50c2172013-07-29 15:28:30 -07003758 *(sp + 2) = w;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003759 }
3760 }
3761 }
3762 else
3763#endif
3764 {
3765 sp = row;
Chris Craikb50c2172013-07-29 15:28:30 -07003766 for (i = 0; i < row_width; i++, sp += 4)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003767 {
3768 png_byte a = *(sp + 3);
3769
Chris Craikb50c2172013-07-29 15:28:30 -07003770 if (a == 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003771 {
Chris Craikb50c2172013-07-29 15:28:30 -07003772 *sp = (png_byte)png_ptr->background.red;
3773 *(sp + 1) = (png_byte)png_ptr->background.green;
3774 *(sp + 2) = (png_byte)png_ptr->background.blue;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003775 }
Chris Craikb50c2172013-07-29 15:28:30 -07003776
3777 else if (a < 0xff)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003778 {
Chris Craikb50c2172013-07-29 15:28:30 -07003779 png_composite(*sp, *sp, a, png_ptr->background.red);
3780
3781 png_composite(*(sp + 1), *(sp + 1), a,
3782 png_ptr->background.green);
3783
3784 png_composite(*(sp + 2), *(sp + 2), a,
3785 png_ptr->background.blue);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003786 }
3787 }
3788 }
3789 }
3790 else /* if (row_info->bit_depth == 16) */
3791 {
Patrick Scott5f6bd842010-06-28 16:55:16 -04003792#ifdef PNG_READ_GAMMA_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003793 if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
3794 gamma_16_to_1 != NULL)
3795 {
3796 sp = row;
Chris Craikb50c2172013-07-29 15:28:30 -07003797 for (i = 0; i < row_width; i++, sp += 8)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003798 {
3799 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
3800 << 8) + (png_uint_16)(*(sp + 7)));
Chris Craikb50c2172013-07-29 15:28:30 -07003801
The Android Open Source Project893912b2009-03-03 19:30:05 -08003802 if (a == (png_uint_16)0xffff)
3803 {
3804 png_uint_16 v;
3805
3806 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
Chris Craikb50c2172013-07-29 15:28:30 -07003807 *sp = (png_byte)((v >> 8) & 0xff);
3808 *(sp + 1) = (png_byte)(v & 0xff);
3809
The Android Open Source Project893912b2009-03-03 19:30:05 -08003810 v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
Chris Craikb50c2172013-07-29 15:28:30 -07003811 *(sp + 2) = (png_byte)((v >> 8) & 0xff);
3812 *(sp + 3) = (png_byte)(v & 0xff);
3813
The Android Open Source Project893912b2009-03-03 19:30:05 -08003814 v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
Chris Craikb50c2172013-07-29 15:28:30 -07003815 *(sp + 4) = (png_byte)((v >> 8) & 0xff);
3816 *(sp + 5) = (png_byte)(v & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003817 }
Chris Craikb50c2172013-07-29 15:28:30 -07003818
The Android Open Source Project893912b2009-03-03 19:30:05 -08003819 else if (a == 0)
3820 {
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003821 /* Background is already in screen gamma */
Chris Craikb50c2172013-07-29 15:28:30 -07003822 *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
3823 *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
3824 *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
3825 & 0xff);
3826 *(sp + 3) = (png_byte)(png_ptr->background.green
3827 & 0xff);
3828 *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
3829 & 0xff);
3830 *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003831 }
Chris Craikb50c2172013-07-29 15:28:30 -07003832
The Android Open Source Project893912b2009-03-03 19:30:05 -08003833 else
3834 {
Chris Craikb50c2172013-07-29 15:28:30 -07003835 png_uint_16 v, w;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003836
3837 v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
Chris Craikb50c2172013-07-29 15:28:30 -07003838 png_composite_16(w, v, a, png_ptr->background_1.red);
Matt Sarett9ea75692016-01-08 13:00:42 -05003839 if (optimize == 0)
3840 w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >>
Chris Craikb50c2172013-07-29 15:28:30 -07003841 8];
3842 *sp = (png_byte)((w >> 8) & 0xff);
3843 *(sp + 1) = (png_byte)(w & 0xff);
3844
The Android Open Source Project893912b2009-03-03 19:30:05 -08003845 v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
Chris Craikb50c2172013-07-29 15:28:30 -07003846 png_composite_16(w, v, a, png_ptr->background_1.green);
Matt Sarett9ea75692016-01-08 13:00:42 -05003847 if (optimize == 0)
3848 w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >>
Chris Craikb50c2172013-07-29 15:28:30 -07003849 8];
3850
3851 *(sp + 2) = (png_byte)((w >> 8) & 0xff);
3852 *(sp + 3) = (png_byte)(w & 0xff);
3853
The Android Open Source Project893912b2009-03-03 19:30:05 -08003854 v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
Chris Craikb50c2172013-07-29 15:28:30 -07003855 png_composite_16(w, v, a, png_ptr->background_1.blue);
Matt Sarett9ea75692016-01-08 13:00:42 -05003856 if (optimize == 0)
3857 w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >>
Chris Craikb50c2172013-07-29 15:28:30 -07003858 8];
3859
3860 *(sp + 4) = (png_byte)((w >> 8) & 0xff);
3861 *(sp + 5) = (png_byte)(w & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003862 }
3863 }
3864 }
Chris Craikb50c2172013-07-29 15:28:30 -07003865
The Android Open Source Project893912b2009-03-03 19:30:05 -08003866 else
3867#endif
3868 {
3869 sp = row;
Chris Craikb50c2172013-07-29 15:28:30 -07003870 for (i = 0; i < row_width; i++, sp += 8)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003871 {
3872 png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
Chris Craikb50c2172013-07-29 15:28:30 -07003873 << 8) + (png_uint_16)(*(sp + 7)));
3874
3875 if (a == 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003876 {
Chris Craikb50c2172013-07-29 15:28:30 -07003877 *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
3878 *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
3879 *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
3880 & 0xff);
3881 *(sp + 3) = (png_byte)(png_ptr->background.green
3882 & 0xff);
3883 *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
3884 & 0xff);
3885 *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003886 }
Chris Craikb50c2172013-07-29 15:28:30 -07003887
3888 else if (a < 0xffff)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003889 {
3890 png_uint_16 v;
3891
3892 png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
3893 png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
3894 + *(sp + 3));
3895 png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
3896 + *(sp + 5));
3897
Chris Craikb50c2172013-07-29 15:28:30 -07003898 png_composite_16(v, r, a, png_ptr->background.red);
3899 *sp = (png_byte)((v >> 8) & 0xff);
3900 *(sp + 1) = (png_byte)(v & 0xff);
3901
3902 png_composite_16(v, g, a, png_ptr->background.green);
3903 *(sp + 2) = (png_byte)((v >> 8) & 0xff);
3904 *(sp + 3) = (png_byte)(v & 0xff);
3905
3906 png_composite_16(v, b, a, png_ptr->background.blue);
3907 *(sp + 4) = (png_byte)((v >> 8) & 0xff);
3908 *(sp + 5) = (png_byte)(v & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08003909 }
3910 }
3911 }
3912 }
3913 break;
3914 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08003915
Chris Craikb50c2172013-07-29 15:28:30 -07003916 default:
3917 break;
The Android Open Source Project893912b2009-03-03 19:30:05 -08003918 }
3919 }
3920}
Matt Sarett9ea75692016-01-08 13:00:42 -05003921#endif /* READ_BACKGROUND || READ_ALPHA_MODE */
The Android Open Source Project893912b2009-03-03 19:30:05 -08003922
Patrick Scott5f6bd842010-06-28 16:55:16 -04003923#ifdef PNG_READ_GAMMA_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08003924/* Gamma correct the image, avoiding the alpha channel. Make sure
3925 * you do this after you deal with the transparency issue on grayscale
3926 * or RGB images. If your bit depth is 8, use gamma_table, if it
3927 * is 16, use gamma_16_table and gamma_shift. Build these with
3928 * build_gamma_table().
3929 */
Sireesh Tripurarib478e662014-05-09 15:15:10 +05303930static void
Chris Craikb50c2172013-07-29 15:28:30 -07003931png_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr)
The Android Open Source Project893912b2009-03-03 19:30:05 -08003932{
Chris Craikb50c2172013-07-29 15:28:30 -07003933 png_const_bytep gamma_table = png_ptr->gamma_table;
3934 png_const_uint_16pp gamma_16_table = png_ptr->gamma_16_table;
3935 int gamma_shift = png_ptr->gamma_shift;
3936
The Android Open Source Project893912b2009-03-03 19:30:05 -08003937 png_bytep sp;
3938 png_uint_32 i;
3939 png_uint_32 row_width=row_info->width;
3940
The Android Open Source Project4215dd12009-03-09 11:52:12 -07003941 png_debug(1, "in png_do_gamma");
Patrick Scott5f6bd842010-06-28 16:55:16 -04003942
Chris Craikb50c2172013-07-29 15:28:30 -07003943 if (((row_info->bit_depth <= 8 && gamma_table != NULL) ||
3944 (row_info->bit_depth == 16 && gamma_16_table != NULL)))
The Android Open Source Project893912b2009-03-03 19:30:05 -08003945 {
3946 switch (row_info->color_type)
3947 {
3948 case PNG_COLOR_TYPE_RGB:
3949 {
3950 if (row_info->bit_depth == 8)
3951 {
3952 sp = row;
3953 for (i = 0; i < row_width; i++)
3954 {
3955 *sp = gamma_table[*sp];
3956 sp++;
3957 *sp = gamma_table[*sp];
3958 sp++;
3959 *sp = gamma_table[*sp];
3960 sp++;
3961 }
3962 }
Chris Craikb50c2172013-07-29 15:28:30 -07003963
The Android Open Source Project893912b2009-03-03 19:30:05 -08003964 else /* if (row_info->bit_depth == 16) */
3965 {
3966 sp = row;
3967 for (i = 0; i < row_width; i++)
3968 {
3969 png_uint_16 v;
3970
3971 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3972 *sp = (png_byte)((v >> 8) & 0xff);
3973 *(sp + 1) = (png_byte)(v & 0xff);
3974 sp += 2;
Chris Craikb50c2172013-07-29 15:28:30 -07003975
The Android Open Source Project893912b2009-03-03 19:30:05 -08003976 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3977 *sp = (png_byte)((v >> 8) & 0xff);
3978 *(sp + 1) = (png_byte)(v & 0xff);
3979 sp += 2;
Chris Craikb50c2172013-07-29 15:28:30 -07003980
The Android Open Source Project893912b2009-03-03 19:30:05 -08003981 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
3982 *sp = (png_byte)((v >> 8) & 0xff);
3983 *(sp + 1) = (png_byte)(v & 0xff);
3984 sp += 2;
3985 }
3986 }
3987 break;
3988 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04003989
The Android Open Source Project893912b2009-03-03 19:30:05 -08003990 case PNG_COLOR_TYPE_RGB_ALPHA:
3991 {
3992 if (row_info->bit_depth == 8)
3993 {
3994 sp = row;
3995 for (i = 0; i < row_width; i++)
3996 {
3997 *sp = gamma_table[*sp];
3998 sp++;
Chris Craikb50c2172013-07-29 15:28:30 -07003999
The Android Open Source Project893912b2009-03-03 19:30:05 -08004000 *sp = gamma_table[*sp];
4001 sp++;
Chris Craikb50c2172013-07-29 15:28:30 -07004002
The Android Open Source Project893912b2009-03-03 19:30:05 -08004003 *sp = gamma_table[*sp];
4004 sp++;
Chris Craikb50c2172013-07-29 15:28:30 -07004005
The Android Open Source Project893912b2009-03-03 19:30:05 -08004006 sp++;
4007 }
4008 }
Chris Craikb50c2172013-07-29 15:28:30 -07004009
The Android Open Source Project893912b2009-03-03 19:30:05 -08004010 else /* if (row_info->bit_depth == 16) */
4011 {
4012 sp = row;
4013 for (i = 0; i < row_width; i++)
4014 {
4015 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
4016 *sp = (png_byte)((v >> 8) & 0xff);
4017 *(sp + 1) = (png_byte)(v & 0xff);
4018 sp += 2;
Chris Craikb50c2172013-07-29 15:28:30 -07004019
The Android Open Source Project893912b2009-03-03 19:30:05 -08004020 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
4021 *sp = (png_byte)((v >> 8) & 0xff);
4022 *(sp + 1) = (png_byte)(v & 0xff);
4023 sp += 2;
Chris Craikb50c2172013-07-29 15:28:30 -07004024
The Android Open Source Project893912b2009-03-03 19:30:05 -08004025 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
4026 *sp = (png_byte)((v >> 8) & 0xff);
4027 *(sp + 1) = (png_byte)(v & 0xff);
4028 sp += 4;
4029 }
4030 }
4031 break;
4032 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004033
The Android Open Source Project893912b2009-03-03 19:30:05 -08004034 case PNG_COLOR_TYPE_GRAY_ALPHA:
4035 {
4036 if (row_info->bit_depth == 8)
4037 {
4038 sp = row;
4039 for (i = 0; i < row_width; i++)
4040 {
4041 *sp = gamma_table[*sp];
4042 sp += 2;
4043 }
4044 }
Chris Craikb50c2172013-07-29 15:28:30 -07004045
The Android Open Source Project893912b2009-03-03 19:30:05 -08004046 else /* if (row_info->bit_depth == 16) */
4047 {
4048 sp = row;
4049 for (i = 0; i < row_width; i++)
4050 {
4051 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
4052 *sp = (png_byte)((v >> 8) & 0xff);
4053 *(sp + 1) = (png_byte)(v & 0xff);
4054 sp += 4;
4055 }
4056 }
4057 break;
4058 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004059
The Android Open Source Project893912b2009-03-03 19:30:05 -08004060 case PNG_COLOR_TYPE_GRAY:
4061 {
4062 if (row_info->bit_depth == 2)
4063 {
4064 sp = row;
4065 for (i = 0; i < row_width; i += 4)
4066 {
4067 int a = *sp & 0xc0;
4068 int b = *sp & 0x30;
4069 int c = *sp & 0x0c;
4070 int d = *sp & 0x03;
4071
4072 *sp = (png_byte)(
Patrick Scott5f6bd842010-06-28 16:55:16 -04004073 ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
4074 ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
4075 ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
4076 ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
The Android Open Source Project893912b2009-03-03 19:30:05 -08004077 sp++;
4078 }
4079 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004080
The Android Open Source Project893912b2009-03-03 19:30:05 -08004081 if (row_info->bit_depth == 4)
4082 {
4083 sp = row;
4084 for (i = 0; i < row_width; i += 2)
4085 {
4086 int msb = *sp & 0xf0;
4087 int lsb = *sp & 0x0f;
4088
4089 *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)
Patrick Scott5f6bd842010-06-28 16:55:16 -04004090 | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
The Android Open Source Project893912b2009-03-03 19:30:05 -08004091 sp++;
4092 }
4093 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004094
The Android Open Source Project893912b2009-03-03 19:30:05 -08004095 else if (row_info->bit_depth == 8)
4096 {
4097 sp = row;
4098 for (i = 0; i < row_width; i++)
4099 {
4100 *sp = gamma_table[*sp];
4101 sp++;
4102 }
4103 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004104
The Android Open Source Project893912b2009-03-03 19:30:05 -08004105 else if (row_info->bit_depth == 16)
4106 {
4107 sp = row;
4108 for (i = 0; i < row_width; i++)
4109 {
4110 png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
4111 *sp = (png_byte)((v >> 8) & 0xff);
4112 *(sp + 1) = (png_byte)(v & 0xff);
4113 sp += 2;
4114 }
4115 }
4116 break;
4117 }
Chris Craikb50c2172013-07-29 15:28:30 -07004118
4119 default:
4120 break;
The Android Open Source Project893912b2009-03-03 19:30:05 -08004121 }
4122 }
4123}
4124#endif
4125
Chris Craikb50c2172013-07-29 15:28:30 -07004126#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
4127/* Encode the alpha channel to the output gamma (the input channel is always
4128 * linear.) Called only with color types that have an alpha channel. Needs the
4129 * from_1 tables.
4130 */
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304131static void
Chris Craikb50c2172013-07-29 15:28:30 -07004132png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr)
4133{
4134 png_uint_32 row_width = row_info->width;
4135
4136 png_debug(1, "in png_do_encode_alpha");
4137
Matt Sarett9ea75692016-01-08 13:00:42 -05004138 if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0)
Chris Craikb50c2172013-07-29 15:28:30 -07004139 {
4140 if (row_info->bit_depth == 8)
4141 {
4142 PNG_CONST png_bytep table = png_ptr->gamma_from_1;
4143
4144 if (table != NULL)
4145 {
4146 PNG_CONST int step =
4147 (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 4 : 2;
4148
4149 /* The alpha channel is the last component: */
4150 row += step - 1;
4151
4152 for (; row_width > 0; --row_width, row += step)
4153 *row = table[*row];
4154
4155 return;
4156 }
4157 }
4158
4159 else if (row_info->bit_depth == 16)
4160 {
4161 PNG_CONST png_uint_16pp table = png_ptr->gamma_16_from_1;
4162 PNG_CONST int gamma_shift = png_ptr->gamma_shift;
4163
4164 if (table != NULL)
4165 {
4166 PNG_CONST int step =
4167 (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 8 : 4;
4168
4169 /* The alpha channel is the last component: */
4170 row += step - 2;
4171
4172 for (; row_width > 0; --row_width, row += step)
4173 {
4174 png_uint_16 v;
4175
4176 v = table[*(row + 1) >> gamma_shift][*row];
4177 *row = (png_byte)((v >> 8) & 0xff);
4178 *(row + 1) = (png_byte)(v & 0xff);
4179 }
4180
4181 return;
4182 }
4183 }
4184 }
4185
4186 /* Only get to here if called with a weird row_info; no harm has been done,
4187 * so just issue a warning.
4188 */
4189 png_warning(png_ptr, "png_do_encode_alpha: unexpected call");
4190}
4191#endif
4192
Patrick Scott5f6bd842010-06-28 16:55:16 -04004193#ifdef PNG_READ_EXPAND_SUPPORTED
The Android Open Source Project893912b2009-03-03 19:30:05 -08004194/* Expands a palette row to an RGB or RGBA row depending
4195 * upon whether you supply trans and num_trans.
4196 */
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304197static void
The Android Open Source Project893912b2009-03-03 19:30:05 -08004198png_do_expand_palette(png_row_infop row_info, png_bytep row,
Chris Craikb50c2172013-07-29 15:28:30 -07004199 png_const_colorp palette, png_const_bytep trans_alpha, int num_trans)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004200{
4201 int shift, value;
4202 png_bytep sp, dp;
4203 png_uint_32 i;
4204 png_uint_32 row_width=row_info->width;
4205
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004206 png_debug(1, "in png_do_expand_palette");
Patrick Scott5f6bd842010-06-28 16:55:16 -04004207
Chris Craikb50c2172013-07-29 15:28:30 -07004208 if (row_info->color_type == PNG_COLOR_TYPE_PALETTE)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004209 {
4210 if (row_info->bit_depth < 8)
4211 {
4212 switch (row_info->bit_depth)
4213 {
4214 case 1:
4215 {
4216 sp = row + (png_size_t)((row_width - 1) >> 3);
4217 dp = row + (png_size_t)row_width - 1;
4218 shift = 7 - (int)((row_width + 7) & 0x07);
4219 for (i = 0; i < row_width; i++)
4220 {
4221 if ((*sp >> shift) & 0x01)
4222 *dp = 1;
Chris Craikb50c2172013-07-29 15:28:30 -07004223
The Android Open Source Project893912b2009-03-03 19:30:05 -08004224 else
4225 *dp = 0;
Chris Craikb50c2172013-07-29 15:28:30 -07004226
The Android Open Source Project893912b2009-03-03 19:30:05 -08004227 if (shift == 7)
4228 {
4229 shift = 0;
4230 sp--;
4231 }
Chris Craikb50c2172013-07-29 15:28:30 -07004232
The Android Open Source Project893912b2009-03-03 19:30:05 -08004233 else
4234 shift++;
4235
4236 dp--;
4237 }
4238 break;
4239 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004240
The Android Open Source Project893912b2009-03-03 19:30:05 -08004241 case 2:
4242 {
4243 sp = row + (png_size_t)((row_width - 1) >> 2);
4244 dp = row + (png_size_t)row_width - 1;
4245 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
4246 for (i = 0; i < row_width; i++)
4247 {
4248 value = (*sp >> shift) & 0x03;
4249 *dp = (png_byte)value;
4250 if (shift == 6)
4251 {
4252 shift = 0;
4253 sp--;
4254 }
Chris Craikb50c2172013-07-29 15:28:30 -07004255
The Android Open Source Project893912b2009-03-03 19:30:05 -08004256 else
4257 shift += 2;
4258
4259 dp--;
4260 }
4261 break;
4262 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004263
The Android Open Source Project893912b2009-03-03 19:30:05 -08004264 case 4:
4265 {
4266 sp = row + (png_size_t)((row_width - 1) >> 1);
4267 dp = row + (png_size_t)row_width - 1;
4268 shift = (int)((row_width & 0x01) << 2);
4269 for (i = 0; i < row_width; i++)
4270 {
4271 value = (*sp >> shift) & 0x0f;
4272 *dp = (png_byte)value;
4273 if (shift == 4)
4274 {
4275 shift = 0;
4276 sp--;
4277 }
Chris Craikb50c2172013-07-29 15:28:30 -07004278
The Android Open Source Project893912b2009-03-03 19:30:05 -08004279 else
4280 shift += 4;
4281
4282 dp--;
4283 }
4284 break;
4285 }
Chris Craikb50c2172013-07-29 15:28:30 -07004286
4287 default:
4288 break;
The Android Open Source Project893912b2009-03-03 19:30:05 -08004289 }
4290 row_info->bit_depth = 8;
4291 row_info->pixel_depth = 8;
4292 row_info->rowbytes = row_width;
4293 }
Chris Craikb50c2172013-07-29 15:28:30 -07004294
4295 if (row_info->bit_depth == 8)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004296 {
The Android Open Source Project893912b2009-03-03 19:30:05 -08004297 {
Chris Craikb50c2172013-07-29 15:28:30 -07004298 if (num_trans > 0)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004299 {
4300 sp = row + (png_size_t)row_width - 1;
4301 dp = row + (png_size_t)(row_width << 2) - 1;
4302
4303 for (i = 0; i < row_width; i++)
4304 {
4305 if ((int)(*sp) >= num_trans)
4306 *dp-- = 0xff;
Chris Craikb50c2172013-07-29 15:28:30 -07004307
The Android Open Source Project893912b2009-03-03 19:30:05 -08004308 else
Chris Craikb50c2172013-07-29 15:28:30 -07004309 *dp-- = trans_alpha[*sp];
4310
The Android Open Source Project893912b2009-03-03 19:30:05 -08004311 *dp-- = palette[*sp].blue;
4312 *dp-- = palette[*sp].green;
4313 *dp-- = palette[*sp].red;
4314 sp--;
4315 }
4316 row_info->bit_depth = 8;
4317 row_info->pixel_depth = 32;
4318 row_info->rowbytes = row_width * 4;
4319 row_info->color_type = 6;
4320 row_info->channels = 4;
4321 }
Chris Craikb50c2172013-07-29 15:28:30 -07004322
The Android Open Source Project893912b2009-03-03 19:30:05 -08004323 else
4324 {
4325 sp = row + (png_size_t)row_width - 1;
4326 dp = row + (png_size_t)(row_width * 3) - 1;
4327
4328 for (i = 0; i < row_width; i++)
4329 {
4330 *dp-- = palette[*sp].blue;
4331 *dp-- = palette[*sp].green;
4332 *dp-- = palette[*sp].red;
4333 sp--;
4334 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004335
The Android Open Source Project893912b2009-03-03 19:30:05 -08004336 row_info->bit_depth = 8;
4337 row_info->pixel_depth = 24;
4338 row_info->rowbytes = row_width * 3;
4339 row_info->color_type = 2;
4340 row_info->channels = 3;
4341 }
The Android Open Source Project893912b2009-03-03 19:30:05 -08004342 }
4343 }
4344 }
4345}
4346
4347/* If the bit depth < 8, it is expanded to 8. Also, if the already
4348 * expanded transparency value is supplied, an alpha channel is built.
4349 */
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304350static void
The Android Open Source Project893912b2009-03-03 19:30:05 -08004351png_do_expand(png_row_infop row_info, png_bytep row,
Chris Craikb50c2172013-07-29 15:28:30 -07004352 png_const_color_16p trans_color)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004353{
4354 int shift, value;
4355 png_bytep sp, dp;
4356 png_uint_32 i;
4357 png_uint_32 row_width=row_info->width;
4358
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004359 png_debug(1, "in png_do_expand");
Patrick Scott5f6bd842010-06-28 16:55:16 -04004360
The Android Open Source Project893912b2009-03-03 19:30:05 -08004361 {
4362 if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
4363 {
Matt Sarett9ea75692016-01-08 13:00:42 -05004364 unsigned int gray = trans_color != NULL ? trans_color->gray : 0;
The Android Open Source Project893912b2009-03-03 19:30:05 -08004365
4366 if (row_info->bit_depth < 8)
4367 {
4368 switch (row_info->bit_depth)
4369 {
4370 case 1:
4371 {
Chris Craikb50c2172013-07-29 15:28:30 -07004372 gray = (gray & 0x01) * 0xff;
The Android Open Source Project893912b2009-03-03 19:30:05 -08004373 sp = row + (png_size_t)((row_width - 1) >> 3);
4374 dp = row + (png_size_t)row_width - 1;
4375 shift = 7 - (int)((row_width + 7) & 0x07);
4376 for (i = 0; i < row_width; i++)
4377 {
4378 if ((*sp >> shift) & 0x01)
4379 *dp = 0xff;
Chris Craikb50c2172013-07-29 15:28:30 -07004380
The Android Open Source Project893912b2009-03-03 19:30:05 -08004381 else
4382 *dp = 0;
Chris Craikb50c2172013-07-29 15:28:30 -07004383
The Android Open Source Project893912b2009-03-03 19:30:05 -08004384 if (shift == 7)
4385 {
4386 shift = 0;
4387 sp--;
4388 }
Chris Craikb50c2172013-07-29 15:28:30 -07004389
The Android Open Source Project893912b2009-03-03 19:30:05 -08004390 else
4391 shift++;
4392
4393 dp--;
4394 }
4395 break;
4396 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004397
The Android Open Source Project893912b2009-03-03 19:30:05 -08004398 case 2:
4399 {
Chris Craikb50c2172013-07-29 15:28:30 -07004400 gray = (gray & 0x03) * 0x55;
The Android Open Source Project893912b2009-03-03 19:30:05 -08004401 sp = row + (png_size_t)((row_width - 1) >> 2);
4402 dp = row + (png_size_t)row_width - 1;
4403 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
4404 for (i = 0; i < row_width; i++)
4405 {
4406 value = (*sp >> shift) & 0x03;
4407 *dp = (png_byte)(value | (value << 2) | (value << 4) |
4408 (value << 6));
4409 if (shift == 6)
4410 {
4411 shift = 0;
4412 sp--;
4413 }
Chris Craikb50c2172013-07-29 15:28:30 -07004414
The Android Open Source Project893912b2009-03-03 19:30:05 -08004415 else
4416 shift += 2;
4417
4418 dp--;
4419 }
4420 break;
4421 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004422
The Android Open Source Project893912b2009-03-03 19:30:05 -08004423 case 4:
4424 {
Chris Craikb50c2172013-07-29 15:28:30 -07004425 gray = (gray & 0x0f) * 0x11;
The Android Open Source Project893912b2009-03-03 19:30:05 -08004426 sp = row + (png_size_t)((row_width - 1) >> 1);
4427 dp = row + (png_size_t)row_width - 1;
4428 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
4429 for (i = 0; i < row_width; i++)
4430 {
4431 value = (*sp >> shift) & 0x0f;
4432 *dp = (png_byte)(value | (value << 4));
4433 if (shift == 4)
4434 {
4435 shift = 0;
4436 sp--;
4437 }
Chris Craikb50c2172013-07-29 15:28:30 -07004438
The Android Open Source Project893912b2009-03-03 19:30:05 -08004439 else
4440 shift = 4;
4441
4442 dp--;
4443 }
4444 break;
4445 }
Chris Craikb50c2172013-07-29 15:28:30 -07004446
4447 default:
4448 break;
The Android Open Source Project893912b2009-03-03 19:30:05 -08004449 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004450
The Android Open Source Project893912b2009-03-03 19:30:05 -08004451 row_info->bit_depth = 8;
4452 row_info->pixel_depth = 8;
4453 row_info->rowbytes = row_width;
4454 }
4455
Chris Craikb50c2172013-07-29 15:28:30 -07004456 if (trans_color != NULL)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004457 {
4458 if (row_info->bit_depth == 8)
4459 {
4460 gray = gray & 0xff;
4461 sp = row + (png_size_t)row_width - 1;
4462 dp = row + (png_size_t)(row_width << 1) - 1;
Chris Craikb50c2172013-07-29 15:28:30 -07004463
The Android Open Source Project893912b2009-03-03 19:30:05 -08004464 for (i = 0; i < row_width; i++)
4465 {
Matt Sarett9ea75692016-01-08 13:00:42 -05004466 if ((*sp & 0xffU) == gray)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004467 *dp-- = 0;
Chris Craikb50c2172013-07-29 15:28:30 -07004468
The Android Open Source Project893912b2009-03-03 19:30:05 -08004469 else
4470 *dp-- = 0xff;
Chris Craikb50c2172013-07-29 15:28:30 -07004471
The Android Open Source Project893912b2009-03-03 19:30:05 -08004472 *dp-- = *sp--;
4473 }
4474 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004475
The Android Open Source Project893912b2009-03-03 19:30:05 -08004476 else if (row_info->bit_depth == 16)
4477 {
Chris Craikb50c2172013-07-29 15:28:30 -07004478 unsigned int gray_high = (gray >> 8) & 0xff;
4479 unsigned int gray_low = gray & 0xff;
The Android Open Source Project893912b2009-03-03 19:30:05 -08004480 sp = row + row_info->rowbytes - 1;
4481 dp = row + (row_info->rowbytes << 1) - 1;
4482 for (i = 0; i < row_width; i++)
4483 {
Matt Sarett9ea75692016-01-08 13:00:42 -05004484 if ((*(sp - 1) & 0xffU) == gray_high &&
4485 (*(sp) & 0xffU) == gray_low)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004486 {
4487 *dp-- = 0;
4488 *dp-- = 0;
4489 }
Chris Craikb50c2172013-07-29 15:28:30 -07004490
The Android Open Source Project893912b2009-03-03 19:30:05 -08004491 else
4492 {
4493 *dp-- = 0xff;
4494 *dp-- = 0xff;
4495 }
Chris Craikb50c2172013-07-29 15:28:30 -07004496
The Android Open Source Project893912b2009-03-03 19:30:05 -08004497 *dp-- = *sp--;
4498 *dp-- = *sp--;
4499 }
4500 }
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004501
The Android Open Source Project893912b2009-03-03 19:30:05 -08004502 row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
4503 row_info->channels = 2;
4504 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
4505 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
4506 row_width);
4507 }
4508 }
Matt Sarett9ea75692016-01-08 13:00:42 -05004509 else if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
4510 trans_color != NULL)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004511 {
4512 if (row_info->bit_depth == 8)
4513 {
Chris Craikb50c2172013-07-29 15:28:30 -07004514 png_byte red = (png_byte)(trans_color->red & 0xff);
4515 png_byte green = (png_byte)(trans_color->green & 0xff);
4516 png_byte blue = (png_byte)(trans_color->blue & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08004517 sp = row + (png_size_t)row_info->rowbytes - 1;
4518 dp = row + (png_size_t)(row_width << 2) - 1;
4519 for (i = 0; i < row_width; i++)
4520 {
4521 if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue)
4522 *dp-- = 0;
Chris Craikb50c2172013-07-29 15:28:30 -07004523
The Android Open Source Project893912b2009-03-03 19:30:05 -08004524 else
4525 *dp-- = 0xff;
Chris Craikb50c2172013-07-29 15:28:30 -07004526
The Android Open Source Project893912b2009-03-03 19:30:05 -08004527 *dp-- = *sp--;
4528 *dp-- = *sp--;
4529 *dp-- = *sp--;
4530 }
4531 }
4532 else if (row_info->bit_depth == 16)
4533 {
Chris Craikb50c2172013-07-29 15:28:30 -07004534 png_byte red_high = (png_byte)((trans_color->red >> 8) & 0xff);
4535 png_byte green_high = (png_byte)((trans_color->green >> 8) & 0xff);
4536 png_byte blue_high = (png_byte)((trans_color->blue >> 8) & 0xff);
4537 png_byte red_low = (png_byte)(trans_color->red & 0xff);
4538 png_byte green_low = (png_byte)(trans_color->green & 0xff);
4539 png_byte blue_low = (png_byte)(trans_color->blue & 0xff);
The Android Open Source Project893912b2009-03-03 19:30:05 -08004540 sp = row + row_info->rowbytes - 1;
4541 dp = row + (png_size_t)(row_width << 3) - 1;
4542 for (i = 0; i < row_width; i++)
4543 {
4544 if (*(sp - 5) == red_high &&
Chris Craikb50c2172013-07-29 15:28:30 -07004545 *(sp - 4) == red_low &&
4546 *(sp - 3) == green_high &&
4547 *(sp - 2) == green_low &&
4548 *(sp - 1) == blue_high &&
4549 *(sp ) == blue_low)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004550 {
4551 *dp-- = 0;
4552 *dp-- = 0;
4553 }
Chris Craikb50c2172013-07-29 15:28:30 -07004554
The Android Open Source Project893912b2009-03-03 19:30:05 -08004555 else
4556 {
4557 *dp-- = 0xff;
4558 *dp-- = 0xff;
4559 }
Chris Craikb50c2172013-07-29 15:28:30 -07004560
The Android Open Source Project893912b2009-03-03 19:30:05 -08004561 *dp-- = *sp--;
4562 *dp-- = *sp--;
4563 *dp-- = *sp--;
4564 *dp-- = *sp--;
4565 *dp-- = *sp--;
4566 *dp-- = *sp--;
4567 }
4568 }
4569 row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
4570 row_info->channels = 4;
4571 row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004572 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08004573 }
4574 }
4575}
4576#endif
4577
Chris Craikb50c2172013-07-29 15:28:30 -07004578#ifdef PNG_READ_EXPAND_16_SUPPORTED
4579/* If the bit depth is 8 and the color type is not a palette type expand the
4580 * whole row to 16 bits. Has no effect otherwise.
4581 */
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304582static void
Chris Craikb50c2172013-07-29 15:28:30 -07004583png_do_expand_16(png_row_infop row_info, png_bytep row)
4584{
4585 if (row_info->bit_depth == 8 &&
4586 row_info->color_type != PNG_COLOR_TYPE_PALETTE)
4587 {
4588 /* The row have a sequence of bytes containing [0..255] and we need
4589 * to turn it into another row containing [0..65535], to do this we
4590 * calculate:
4591 *
4592 * (input / 255) * 65535
4593 *
4594 * Which happens to be exactly input * 257 and this can be achieved
4595 * simply by byte replication in place (copying backwards).
4596 */
4597 png_byte *sp = row + row_info->rowbytes; /* source, last byte + 1 */
4598 png_byte *dp = sp + row_info->rowbytes; /* destination, end + 1 */
4599 while (dp > sp)
4600 dp[-2] = dp[-1] = *--sp, dp -= 2;
4601
4602 row_info->rowbytes *= 2;
4603 row_info->bit_depth = 16;
4604 row_info->pixel_depth = (png_byte)(row_info->channels * 16);
4605 }
4606}
4607#endif
4608
4609#ifdef PNG_READ_QUANTIZE_SUPPORTED
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304610static void
Chris Craikb50c2172013-07-29 15:28:30 -07004611png_do_quantize(png_row_infop row_info, png_bytep row,
4612 png_const_bytep palette_lookup, png_const_bytep quantize_lookup)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004613{
4614 png_bytep sp, dp;
4615 png_uint_32 i;
4616 png_uint_32 row_width=row_info->width;
4617
Chris Craikb50c2172013-07-29 15:28:30 -07004618 png_debug(1, "in png_do_quantize");
Patrick Scott5f6bd842010-06-28 16:55:16 -04004619
Chris Craikb50c2172013-07-29 15:28:30 -07004620 if (row_info->bit_depth == 8)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004621 {
Chris Craikb50c2172013-07-29 15:28:30 -07004622 if (row_info->color_type == PNG_COLOR_TYPE_RGB && palette_lookup)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004623 {
4624 int r, g, b, p;
4625 sp = row;
4626 dp = row;
4627 for (i = 0; i < row_width; i++)
4628 {
4629 r = *sp++;
4630 g = *sp++;
4631 b = *sp++;
4632
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004633 /* This looks real messy, but the compiler will reduce
4634 * it down to a reasonable formula. For example, with
4635 * 5 bits per color, we get:
4636 * p = (((r >> 3) & 0x1f) << 10) |
4637 * (((g >> 3) & 0x1f) << 5) |
4638 * ((b >> 3) & 0x1f);
4639 */
Chris Craikb50c2172013-07-29 15:28:30 -07004640 p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) &
4641 ((1 << PNG_QUANTIZE_RED_BITS) - 1)) <<
4642 (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) |
4643 (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) &
4644 ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) <<
4645 (PNG_QUANTIZE_BLUE_BITS)) |
4646 ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) &
4647 ((1 << PNG_QUANTIZE_BLUE_BITS) - 1));
The Android Open Source Project893912b2009-03-03 19:30:05 -08004648
4649 *dp++ = palette_lookup[p];
4650 }
Chris Craikb50c2172013-07-29 15:28:30 -07004651
The Android Open Source Project893912b2009-03-03 19:30:05 -08004652 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
4653 row_info->channels = 1;
4654 row_info->pixel_depth = row_info->bit_depth;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004655 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08004656 }
Chris Craikb50c2172013-07-29 15:28:30 -07004657
The Android Open Source Project893912b2009-03-03 19:30:05 -08004658 else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
Chris Craikb50c2172013-07-29 15:28:30 -07004659 palette_lookup != NULL)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004660 {
4661 int r, g, b, p;
4662 sp = row;
4663 dp = row;
4664 for (i = 0; i < row_width; i++)
4665 {
4666 r = *sp++;
4667 g = *sp++;
4668 b = *sp++;
4669 sp++;
4670
Chris Craikb50c2172013-07-29 15:28:30 -07004671 p = (((r >> (8 - PNG_QUANTIZE_RED_BITS)) &
4672 ((1 << PNG_QUANTIZE_RED_BITS) - 1)) <<
4673 (PNG_QUANTIZE_GREEN_BITS + PNG_QUANTIZE_BLUE_BITS)) |
4674 (((g >> (8 - PNG_QUANTIZE_GREEN_BITS)) &
4675 ((1 << PNG_QUANTIZE_GREEN_BITS) - 1)) <<
4676 (PNG_QUANTIZE_BLUE_BITS)) |
4677 ((b >> (8 - PNG_QUANTIZE_BLUE_BITS)) &
4678 ((1 << PNG_QUANTIZE_BLUE_BITS) - 1));
The Android Open Source Project893912b2009-03-03 19:30:05 -08004679
4680 *dp++ = palette_lookup[p];
4681 }
Chris Craikb50c2172013-07-29 15:28:30 -07004682
The Android Open Source Project893912b2009-03-03 19:30:05 -08004683 row_info->color_type = PNG_COLOR_TYPE_PALETTE;
4684 row_info->channels = 1;
4685 row_info->pixel_depth = row_info->bit_depth;
The Android Open Source Project4215dd12009-03-09 11:52:12 -07004686 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width);
The Android Open Source Project893912b2009-03-03 19:30:05 -08004687 }
Chris Craikb50c2172013-07-29 15:28:30 -07004688
The Android Open Source Project893912b2009-03-03 19:30:05 -08004689 else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
Chris Craikb50c2172013-07-29 15:28:30 -07004690 quantize_lookup)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004691 {
4692 sp = row;
Chris Craikb50c2172013-07-29 15:28:30 -07004693
The Android Open Source Project893912b2009-03-03 19:30:05 -08004694 for (i = 0; i < row_width; i++, sp++)
4695 {
Chris Craikb50c2172013-07-29 15:28:30 -07004696 *sp = quantize_lookup[*sp];
The Android Open Source Project893912b2009-03-03 19:30:05 -08004697 }
4698 }
4699 }
4700}
Matt Sarett9ea75692016-01-08 13:00:42 -05004701#endif /* READ_QUANTIZE */
The Android Open Source Project893912b2009-03-03 19:30:05 -08004702
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304703/* Transform the row. The order of transformations is significant,
4704 * and is very touchy. If you add a transformation, take care to
4705 * decide how it fits in with the other transformations here.
4706 */
The Android Open Source Project893912b2009-03-03 19:30:05 -08004707void /* PRIVATE */
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304708png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004709{
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304710 png_debug(1, "in png_do_read_transformations");
Patrick Scott5f6bd842010-06-28 16:55:16 -04004711
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304712 if (png_ptr->row_buf == NULL)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004713 {
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304714 /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this
4715 * error is incredibly rare and incredibly easy to debug without this
4716 * information.
4717 */
4718 png_error(png_ptr, "NULL row buffer");
4719 }
Chris Craikb50c2172013-07-29 15:28:30 -07004720
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304721 /* The following is debugging; prior to 1.5.4 the code was never compiled in;
4722 * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro
4723 * PNG_WARN_UNINITIALIZED_ROW removed. In 1.6 the new flag is set only for
4724 * all transformations, however in practice the ROW_INIT always gets done on
4725 * demand, if necessary.
4726 */
4727 if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 &&
Matt Sarett9ea75692016-01-08 13:00:42 -05004728 (png_ptr->flags & PNG_FLAG_ROW_INIT) == 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304729 {
4730 /* Application has failed to call either png_read_start_image() or
4731 * png_read_update_info() after setting transforms that expand pixels.
4732 * This check added to libpng-1.2.19 (but not enabled until 1.5.4).
4733 */
4734 png_error(png_ptr, "Uninitialized row");
4735 }
4736
4737#ifdef PNG_READ_EXPAND_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004738 if ((png_ptr->transformations & PNG_EXPAND) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304739 {
4740 if (row_info->color_type == PNG_COLOR_TYPE_PALETTE)
The Android Open Source Project893912b2009-03-03 19:30:05 -08004741 {
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304742 png_do_expand_palette(row_info, png_ptr->row_buf + 1,
4743 png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans);
The Android Open Source Project893912b2009-03-03 19:30:05 -08004744 }
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304745
4746 else
The Android Open Source Project893912b2009-03-03 19:30:05 -08004747 {
Matt Sarett9ea75692016-01-08 13:00:42 -05004748 if (png_ptr->num_trans != 0 &&
4749 (png_ptr->transformations & PNG_EXPAND_tRNS) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304750 png_do_expand(row_info, png_ptr->row_buf + 1,
4751 &(png_ptr->trans_color));
Patrick Scotta0bb96c2009-07-22 11:50:02 -04004752
The Android Open Source Project893912b2009-03-03 19:30:05 -08004753 else
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304754 png_do_expand(row_info, png_ptr->row_buf + 1,
4755 NULL);
The Android Open Source Project893912b2009-03-03 19:30:05 -08004756 }
4757 }
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304758#endif
4759
4760#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004761 if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 &&
4762 (png_ptr->transformations & PNG_COMPOSE) == 0 &&
4763 (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
4764 row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304765 png_do_strip_channel(row_info, png_ptr->row_buf + 1,
4766 0 /* at_start == false, because SWAP_ALPHA happens later */);
4767#endif
4768
4769#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004770 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304771 {
4772 int rgb_error =
4773 png_do_rgb_to_gray(png_ptr, row_info,
4774 png_ptr->row_buf + 1);
4775
Matt Sarett9ea75692016-01-08 13:00:42 -05004776 if (rgb_error != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304777 {
4778 png_ptr->rgb_to_gray_status=1;
4779 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
4780 PNG_RGB_TO_GRAY_WARN)
4781 png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
4782
4783 if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
4784 PNG_RGB_TO_GRAY_ERR)
4785 png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
4786 }
4787 }
4788#endif
4789
4790/* From Andreas Dilger e-mail to png-implement, 26 March 1998:
4791 *
4792 * In most cases, the "simple transparency" should be done prior to doing
4793 * gray-to-RGB, or you will have to test 3x as many bytes to check if a
4794 * pixel is transparent. You would also need to make sure that the
4795 * transparency information is upgraded to RGB.
4796 *
4797 * To summarize, the current flow is:
4798 * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
4799 * with background "in place" if transparent,
4800 * convert to RGB if necessary
4801 * - Gray + alpha -> composite with gray background and remove alpha bytes,
4802 * convert to RGB if necessary
4803 *
4804 * To support RGB backgrounds for gray images we need:
4805 * - Gray + simple transparency -> convert to RGB + simple transparency,
4806 * compare 3 or 6 bytes and composite with
4807 * background "in place" if transparent
4808 * (3x compare/pixel compared to doing
4809 * composite with gray bkgrnd)
4810 * - Gray + alpha -> convert to RGB + alpha, composite with background and
4811 * remove alpha bytes (3x float
4812 * operations/pixel compared with composite
4813 * on gray background)
4814 *
4815 * Greg's change will do this. The reason it wasn't done before is for
4816 * performance, as this increases the per-pixel operations. If we would check
4817 * in advance if the background was gray or RGB, and position the gray-to-RGB
4818 * transform appropriately, then it would save a lot of work/time.
4819 */
4820
4821#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
4822 /* If gray -> RGB, do so now only if background is non-gray; else do later
4823 * for performance reasons
4824 */
Matt Sarett9ea75692016-01-08 13:00:42 -05004825 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 &&
4826 (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) == 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304827 png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1);
4828#endif
4829
4830#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
4831 defined(PNG_READ_ALPHA_MODE_SUPPORTED)
Matt Sarett9ea75692016-01-08 13:00:42 -05004832 if ((png_ptr->transformations & PNG_COMPOSE) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304833 png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr);
4834#endif
4835
4836#ifdef PNG_READ_GAMMA_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004837 if ((png_ptr->transformations & PNG_GAMMA) != 0 &&
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304838#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
4839 /* Because RGB_TO_GRAY does the gamma transform. */
Matt Sarett9ea75692016-01-08 13:00:42 -05004840 (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0 &&
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304841#endif
4842#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
4843 defined(PNG_READ_ALPHA_MODE_SUPPORTED)
4844 /* Because PNG_COMPOSE does the gamma transform if there is something to
4845 * do (if there is an alpha channel or transparency.)
4846 */
Matt Sarett9ea75692016-01-08 13:00:42 -05004847 !((png_ptr->transformations & PNG_COMPOSE) != 0 &&
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304848 ((png_ptr->num_trans != 0) ||
Matt Sarett9ea75692016-01-08 13:00:42 -05004849 (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)) &&
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304850#endif
4851 /* Because png_init_read_transformations transforms the palette, unless
4852 * RGB_TO_GRAY will do the transform.
4853 */
4854 (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
4855 png_do_gamma(row_info, png_ptr->row_buf + 1, png_ptr);
4856#endif
4857
4858#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004859 if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 &&
4860 (png_ptr->transformations & PNG_COMPOSE) != 0 &&
4861 (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA ||
4862 row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA))
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304863 png_do_strip_channel(row_info, png_ptr->row_buf + 1,
Matt Sarett9ea75692016-01-08 13:00:42 -05004864 0 /* at_start == false, because SWAP_ALPHA happens later */);
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304865#endif
4866
4867#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004868 if ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 &&
4869 (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304870 png_do_encode_alpha(row_info, png_ptr->row_buf + 1, png_ptr);
4871#endif
4872
4873#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004874 if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304875 png_do_scale_16_to_8(row_info, png_ptr->row_buf + 1);
4876#endif
4877
4878#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
4879 /* There is no harm in doing both of these because only one has any effect,
4880 * by putting the 'scale' option first if the app asks for scale (either by
4881 * calling the API or in a TRANSFORM flag) this is what happens.
4882 */
Matt Sarett9ea75692016-01-08 13:00:42 -05004883 if ((png_ptr->transformations & PNG_16_TO_8) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304884 png_do_chop(row_info, png_ptr->row_buf + 1);
4885#endif
4886
4887#ifdef PNG_READ_QUANTIZE_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004888 if ((png_ptr->transformations & PNG_QUANTIZE) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304889 {
4890 png_do_quantize(row_info, png_ptr->row_buf + 1,
4891 png_ptr->palette_lookup, png_ptr->quantize_index);
4892
4893 if (row_info->rowbytes == 0)
4894 png_error(png_ptr, "png_do_quantize returned rowbytes=0");
4895 }
Matt Sarett9ea75692016-01-08 13:00:42 -05004896#endif /* READ_QUANTIZE */
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304897
4898#ifdef PNG_READ_EXPAND_16_SUPPORTED
4899 /* Do the expansion now, after all the arithmetic has been done. Notice
4900 * that previous transformations can handle the PNG_EXPAND_16 flag if this
4901 * is efficient (particularly true in the case of gamma correction, where
4902 * better accuracy results faster!)
4903 */
Matt Sarett9ea75692016-01-08 13:00:42 -05004904 if ((png_ptr->transformations & PNG_EXPAND_16) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304905 png_do_expand_16(row_info, png_ptr->row_buf + 1);
4906#endif
4907
4908#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
4909 /* NOTE: moved here in 1.5.4 (from much later in this list.) */
Matt Sarett9ea75692016-01-08 13:00:42 -05004910 if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 &&
4911 (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304912 png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1);
4913#endif
4914
4915#ifdef PNG_READ_INVERT_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004916 if ((png_ptr->transformations & PNG_INVERT_MONO) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304917 png_do_invert(row_info, png_ptr->row_buf + 1);
4918#endif
4919
4920#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004921 if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304922 png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1);
4923#endif
4924
4925#ifdef PNG_READ_SHIFT_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004926 if ((png_ptr->transformations & PNG_SHIFT) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304927 png_do_unshift(row_info, png_ptr->row_buf + 1,
4928 &(png_ptr->shift));
4929#endif
4930
4931#ifdef PNG_READ_PACK_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004932 if ((png_ptr->transformations & PNG_PACK) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304933 png_do_unpack(row_info, png_ptr->row_buf + 1);
4934#endif
4935
4936#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
4937 /* Added at libpng-1.5.10 */
4938 if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
4939 png_ptr->num_palette_max >= 0)
4940 png_do_check_palette_indexes(png_ptr, row_info);
4941#endif
4942
4943#ifdef PNG_READ_BGR_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004944 if ((png_ptr->transformations & PNG_BGR) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304945 png_do_bgr(row_info, png_ptr->row_buf + 1);
4946#endif
4947
4948#ifdef PNG_READ_PACKSWAP_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004949 if ((png_ptr->transformations & PNG_PACKSWAP) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304950 png_do_packswap(row_info, png_ptr->row_buf + 1);
4951#endif
4952
4953#ifdef PNG_READ_FILLER_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004954 if ((png_ptr->transformations & PNG_FILLER) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304955 png_do_read_filler(row_info, png_ptr->row_buf + 1,
4956 (png_uint_32)png_ptr->filler, png_ptr->flags);
4957#endif
4958
4959#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004960 if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304961 png_do_read_swap_alpha(row_info, png_ptr->row_buf + 1);
4962#endif
4963
4964#ifdef PNG_READ_16BIT_SUPPORTED
4965#ifdef PNG_READ_SWAP_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004966 if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304967 png_do_swap(row_info, png_ptr->row_buf + 1);
4968#endif
4969#endif
4970
4971#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004972 if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0)
4973 {
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304974 if (png_ptr->read_user_transform_fn != NULL)
4975 (*(png_ptr->read_user_transform_fn)) /* User read transform function */
4976 (png_ptr, /* png_ptr */
4977 row_info, /* row_info: */
4978 /* png_uint_32 width; width of row */
4979 /* png_size_t rowbytes; number of bytes in row */
4980 /* png_byte color_type; color type of pixels */
4981 /* png_byte bit_depth; bit depth of samples */
4982 /* png_byte channels; number of channels (1-4) */
4983 /* png_byte pixel_depth; bits per pixel (depth*channels) */
4984 png_ptr->row_buf + 1); /* start of pixel data for row */
4985#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
Matt Sarett9ea75692016-01-08 13:00:42 -05004986 if (png_ptr->user_transform_depth != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304987 row_info->bit_depth = png_ptr->user_transform_depth;
4988
Matt Sarett9ea75692016-01-08 13:00:42 -05004989 if (png_ptr->user_transform_channels != 0)
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304990 row_info->channels = png_ptr->user_transform_channels;
4991#endif
4992 row_info->pixel_depth = (png_byte)(row_info->bit_depth *
4993 row_info->channels);
4994
4995 row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width);
4996 }
4997#endif
The Android Open Source Project893912b2009-03-03 19:30:05 -08004998}
Sireesh Tripurarib478e662014-05-09 15:15:10 +05304999
Matt Sarett9ea75692016-01-08 13:00:42 -05005000#endif /* READ_TRANSFORMS */
5001#endif /* READ */