/* pngrtran.c - transforms the data in a row for PNG readers
*
* Last changed in libpng 1.6.4 [August 21, 2013]
* Copyright (c) 1998-2013 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
*
* This file contains functions optionally called by an application
* in order to tell libpng how to handle data when reading a PNG.
* Transformations that are used in both reading and writing are
* in pngtrans.c.
*/
#include "pngpriv.h"
#ifdef PNG_READ_SUPPORTED
/* Set the action on getting a CRC error for an ancillary or critical chunk. */
void PNGAPI
png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action)
{
png_debug(1, "in png_set_crc_action");
if (png_ptr == NULL)
return;
/* Tell libpng how we react to CRC errors in critical chunks */
switch (crit_action)
{
case PNG_CRC_NO_CHANGE: /* Leave setting as is */
break;
case PNG_CRC_WARN_USE: /* Warn/use data */
png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;
break;
case PNG_CRC_QUIET_USE: /* Quiet/use data */
png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |
PNG_FLAG_CRC_CRITICAL_IGNORE;
break;
case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */
png_warning(png_ptr,
"Can't discard critical data on CRC error");
case PNG_CRC_ERROR_QUIT: /* Error/quit */
case PNG_CRC_DEFAULT:
default:
png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
break;
}
/* Tell libpng how we react to CRC errors in ancillary chunks */
switch (ancil_action)
{
case PNG_CRC_NO_CHANGE: /* Leave setting as is */
break;
case PNG_CRC_WARN_USE: /* Warn/use data */
png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
break;
case PNG_CRC_QUIET_USE: /* Quiet/use data */
png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |
PNG_FLAG_CRC_ANCILLARY_NOWARN;
break;
case PNG_CRC_ERROR_QUIT: /* Error/quit */
png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;
break;
case PNG_CRC_WARN_DISCARD: /* Warn/discard data */
case PNG_CRC_DEFAULT:
default:
png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
break;
}
}
#ifdef PNG_READ_TRANSFORMS_SUPPORTED
/* Is it OK to set a transformation now? Only if png_start_read_image or
* png_read_update_info have not been called. It is not necessary for the IHDR
* to have been read in all cases, the parameter allows for this check too.
*/
static int
png_rtran_ok(png_structrp png_ptr, int need_IHDR)
{
if (png_ptr != NULL)
{
if (png_ptr->flags & PNG_FLAG_ROW_INIT)
png_app_error(png_ptr,
"invalid after png_start_read_image or png_read_update_info");
else if (need_IHDR && (png_ptr->mode & PNG_HAVE_IHDR) == 0)
png_app_error(png_ptr, "invalid before the PNG header has been read");
else
{
/* Turn on failure to initialize correctly for all transforms. */
png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED;
return 1; /* Ok */
}
}
return 0; /* no png_error possible! */
}
#endif
#ifdef PNG_READ_BACKGROUND_SUPPORTED
/* Handle alpha and tRNS via a background color */
void PNGFAPI
png_set_background_fixed(png_structrp png_ptr,
png_const_color_16p background_color, int background_gamma_code,
int need_expand, png_fixed_point background_gamma)
{
png_debug(1, "in png_set_background_fixed");
if (!png_rtran_ok(png_ptr, 0) || background_color == NULL)
return;
if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
{
png_warning(png_ptr, "Application must supply a known background gamma");
return;
}
png_ptr->transformations |= PNG_COMPOSE | PNG_STRIP_ALPHA;
png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
png_ptr->background = *background_color;
png_ptr->background_gamma = background_gamma;
png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
if (need_expand)
png_ptr->transformations |= PNG_BACKGROUND_EXPAND;
else
png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;
}
# ifdef PNG_FLOATING_POINT_SUPPORTED
void PNGAPI
png_set_background(png_structrp png_ptr,
png_const_color_16p background_color, int background_gamma_code,
int need_expand, double background_gamma)
{
png_set_background_fixed(png_ptr, background_color, background_gamma_code,
need_expand, png_fixed(png_ptr, background_gamma, "png_set_background"));
}
# endif /* FLOATING_POINT */
#endif /* READ_BACKGROUND */
/* Scale 16-bit depth files to 8-bit depth. If both of these are set then the
* one that pngrtran does first (scale) happens. This is necessary to allow the
* TRANSFORM and API behavior to be somewhat consistent, and it's simpler.
*/
#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED
void PNGAPI
png_set_scale_16(png_structrp png_ptr)
{
png_debug(1, "in png_set_scale_16");
if (!png_rtran_ok(png_ptr, 0))
return;
png_ptr->transformations |= PNG_SCALE_16_TO_8;
}
#endif
#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED
/* Chop 16-bit depth files to 8-bit depth */
void PNGAPI
png_set_strip_16(png_structrp png_ptr)
{
png_debug(1, "in png_set_strip_16");
if (!png_rtran_ok(png_ptr, 0))
return;
png_ptr->transformations |= PNG_16_TO_8;
}
#endif
#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
void PNGAPI
png_set_strip_alpha(png_structrp png_ptr)
{
png_debug(1, "in png_set_strip_alpha");
if (!png_rtran_ok(png_ptr, 0))
return;
png_ptr->transformations |= PNG_STRIP_ALPHA;
}
#endif
#if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED)
static png_fixed_point
translate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma,
int is_screen)
{
/* Check for flag values. The main reason for having the old Mac value as a
* flag is that it is pretty near impossible to work out what the correct
* value is from Apple documentation - a working Mac system is needed to
* discover the value!
*/
if (output_gamma == PNG_DEFAULT_sRGB ||
output_gamma == PNG_FP_1 / PNG_DEFAULT_sRGB)
{
/* If there is no sRGB support this just sets the gamma to the standard
* sRGB value. (This is a side effect of using this function!)
*/
# ifdef PNG_READ_sRGB_SUPPORTED
png_ptr->flags |= PNG_FLAG_ASSUME_sRGB;
# else
PNG_UNUSED(png_ptr)
# endif
if (is_screen)
output_gamma = PNG_GAMMA_sRGB;
else
output_gamma = PNG_GAMMA_sRGB_INVERSE;
}
else if (output_gamma == PNG_GAMMA_MAC_18 ||
output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18)
{
if (is_screen)
output_gamma = PNG_GAMMA_MAC_OLD;
else
output_gamma = PNG_GAMMA_MAC_INVERSE;
}
return output_gamma;
}
# ifdef PNG_FLOATING_POINT_SUPPORTED
static png_fixed_point
convert_gamma_value(png_structrp png_ptr, double output_gamma)
{
/* The following silently ignores cases where fixed point (times 100,000)
* gamma values are passed to the floating point API. This is safe and it
* means the fix