/* pngrtran.c - transforms the data in a row for PNG readers * * Copyright (c) 2018-2024 Cosmin Truta * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson * Copyright (c) 1996-1997 Andreas Dilger * 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_ARM_NEON_IMPLEMENTATION # if PNG_ARM_NEON_IMPLEMENTATION == 1 #define PNG_ARM_NEON_INTRINSICS_AVAILABLE # if defined(_MSC_VER) && !defined(__clang__) && defined(_M_ARM64) # include <arm64_neon.h> # else # include <arm_neon.h> # endif # endif #endif #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) { … } #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 need_IHDR parameter allows for this * check too. */ static int png_rtran_ok(png_structrp png_ptr, int need_IHDR) { … } #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) { … } # 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) { … } # 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) { … } #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) { … } #endif #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED void PNGAPI png_set_strip_alpha(png_structrp png_ptr) { … } #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) { … } # ifdef PNG_FLOATING_POINT_SUPPORTED static png_fixed_point convert_gamma_value(png_structrp png_ptr, double output_gamma) { … } # endif #endif /* READ_ALPHA_MODE || READ_GAMMA */ #ifdef PNG_READ_ALPHA_MODE_SUPPORTED void PNGFAPI png_set_alpha_mode_fixed(png_structrp png_ptr, int mode, png_fixed_point output_gamma) { … } # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma) { … } # endif #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED /* Dither file to 8-bit. Supply a palette, the current number * of elements in the palette, the maximum number of elements * allowed, and a histogram if possible. If the current number * of colors is greater than the maximum number, the palette will be * modified to fit in the maximum number. "full_quantize" indicates * whether we need a quantizing cube set up for RGB images, or if we * simply are reducing the number of colors in a paletted image. */ png_dsort; png_dsortp; png_dsortpp; void PNGAPI png_set_quantize(png_structrp png_ptr, png_colorp palette, int num_palette, int maximum_colors, png_const_uint_16p histogram, int full_quantize) { … } #endif /* READ_QUANTIZE */ #ifdef PNG_READ_GAMMA_SUPPORTED void PNGFAPI png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma, png_fixed_point file_gamma) { … } # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI png_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma) { … } # endif /* FLOATING_POINT */ #endif /* READ_GAMMA */ #ifdef PNG_READ_EXPAND_SUPPORTED /* Expand paletted images to RGB, expand grayscale images of * less than 8-bit depth to 8-bit depth, and expand tRNS chunks * to alpha channels. */ void PNGAPI png_set_expand(png_structrp png_ptr) { … } /* GRR 19990627: the following three functions currently are identical * to png_set_expand(). However, it is entirely reasonable that someone * might wish to expand an indexed image to RGB but *not* expand a single, * fully transparent palette entry to a full alpha channel--perhaps instead * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace * the transparent color with a particular RGB value, or drop tRNS entirely. * IOW, a future version of the library may make the transformations flag * a bit more fine-grained, with separate bits for each of these three * functions. * * More to the point, these functions make it obvious what libpng will be * doing, whereas "expand" can (and does) mean any number of things. * * GRP 20060307: In libpng-1.2.9, png_set_gray_1_2_4_to_8() was modified * to expand only the sample depth but not to expand the tRNS to alpha * and its name was changed to png_set_expand_gray_1_2_4_to_8(). */ /* Expand paletted images to RGB. */ void PNGAPI png_set_palette_to_rgb(png_structrp png_ptr) { … } /* Expand grayscale images of less than 8-bit depth to 8 bits. */ void PNGAPI png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr) { … } /* Expand tRNS chunks to alpha channels. */ void PNGAPI png_set_tRNS_to_alpha(png_structrp png_ptr) { … } #endif /* READ_EXPAND */ #ifdef PNG_READ_EXPAND_16_SUPPORTED /* Expand to 16-bit channels, expand the tRNS chunk too (because otherwise * it may not work correctly.) */ void PNGAPI png_set_expand_16(png_structrp png_ptr) { … } #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED void PNGAPI png_set_gray_to_rgb(png_structrp png_ptr) { … } #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED void PNGFAPI png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action, png_fixed_point red, png_fixed_point green) { … } #ifdef PNG_FLOATING_POINT_SUPPORTED /* Convert a RGB image to a grayscale of the same width. This allows us, * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image. */ void PNGAPI png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red, double green) { … } #endif /* FLOATING POINT */ #endif /* RGB_TO_GRAY */ #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) void PNGAPI png_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr read_user_transform_fn) { … } #endif #ifdef PNG_READ_TRANSFORMS_SUPPORTED #ifdef PNG_READ_GAMMA_SUPPORTED /* In the case of gamma transformations only do transformations on images where * the [file] gamma and screen_gamma are not close reciprocals, otherwise it * slows things down slightly, and also needlessly introduces small errors. */ static int /* PRIVATE */ png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma) { … } #endif /* Initialize everything needed for the read. This includes modifying * the palette. */ /* For the moment 'png_init_palette_transformations' and * 'png_init_rgb_transformations' only do some flag canceling optimizations. * The intent is that these two routines should have palette or rgb operations * extracted from 'png_init_read_transformations'. */ static void /* PRIVATE */ png_init_palette_transformations(png_structrp png_ptr) { … } static void /* PRIVATE */ png_init_rgb_transformations(png_structrp png_ptr) { … } void /* PRIVATE */ png_init_read_transformations(png_structrp png_ptr) { … } /* Modify the info structure to reflect the transformations. The * info should be updated so a PNG file could be written with it, * assuming the transformations result in valid PNG data. */ void /* PRIVATE */ png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) { … } #ifdef PNG_READ_PACK_SUPPORTED /* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel, * without changing the actual values. Thus, if you had a row with * a bit depth of 1, you would end up with bytes that only contained * the numbers 0 or 1. If you would rather they contain 0 and 255, use * png_do_shift() after this. */ static void png_do_unpack(png_row_infop row_info, png_bytep row) { … } #endif #ifdef PNG_READ_SHIFT_SUPPORTED /* Reverse the effects of png_do_shift. This routine merely shifts the * pixels back to their significant bits values. Thus, if you have * a row of bit depth 8, but only 5 are significant, this will shift * the values back to 0 through 31. */ static void png_do_unshift(png_row_infop row_info, png_bytep row, png_const_color_8p sig_bits) { … } #endif #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED /* Scale rows of bit depth 16 down to 8 accurately */ static void png_do_scale_16_to_8(png_row_infop row_info, png_bytep row) { … } #endif #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED static void /* Simply discard the low byte. This was the default behavior prior * to libpng-1.5.4. */ png_do_chop(png_row_infop row_info, png_bytep row) { … } #endif #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED static void png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) { … } #endif #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED static void png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) { … } #endif #ifdef PNG_READ_FILLER_SUPPORTED /* Add filler channel if we have RGB color */ static void png_do_read_filler(png_row_infop row_info, png_bytep row, png_uint_32 filler, png_uint_32 flags) { … } #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED /* Expand grayscale files to RGB, with or without alpha */ static void png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) { … } #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED /* Reduce RGB files to grayscale, with or without alpha * using the equation given in Poynton's ColorFAQ of 1998-01-04 at * <http://www.inforamp.net/~poynton/> (THIS LINK IS DEAD June 2008 but * versions dated 1998 through November 2002 have been archived at * https://web.archive.org/web/20000816232553/www.inforamp.net/ * ~poynton/notes/colour_and_gamma/ColorFAQ.txt ) * Charles Poynton poynton at poynton.com * * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B * * which can be expressed with integers as * * Y = (6969 * R + 23434 * G + 2365 * B)/32768 * * Poynton's current link (as of January 2003 through July 2011): * <http://www.poynton.com/notes/colour_and_gamma/> * has changed the numbers slightly: * * Y = 0.2126*R + 0.7152*G + 0.0722*B * * which can be expressed with integers as * * Y = (6966 * R + 23436 * G + 2366 * B)/32768 * * Historically, however, libpng uses numbers derived from the ITU-R Rec 709 * end point chromaticities and the D65 white point. Depending on the * precision used for the D65 white point this produces a variety of different * numbers, however if the four decimal place value used in ITU-R Rec 709 is * used (0.3127,0.3290) the Y calculation would be: * * Y = (6968 * R + 23435 * G + 2366 * B)/32768 * * While this is correct the rounding results in an overflow for white, because * the sum of the rounded coefficients is 32769, not 32768. Consequently * libpng uses, instead, the closest non-overflowing approximation: * * Y = (6968 * R + 23434 * G + 2366 * B)/32768 * * Starting with libpng-1.5.5, if the image being converted has a cHRM chunk * (including an sRGB chunk) then the chromaticities are used to calculate the * coefficients. See the chunk handling in pngrutil.c for more information. * * In all cases the calculation is to be done in a linear colorspace. If no * gamma information is available to correct the encoding of the original RGB * values this results in an implicit assumption that the original PNG RGB * values were linear. * * Other integer coefficients can be used via png_set_rgb_to_gray(). Because * the API takes just red and green coefficients the blue coefficient is * calculated to make the sum 32768. This will result in different rounding * to that used above. */ static int png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) { … } #endif #if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ defined(PNG_READ_ALPHA_MODE_SUPPORTED) /* Replace any alpha or transparency with the supplied background color. * "background" is already in the screen gamma, while "background_1" is * at a gamma of 1.0. Paletted files have already been taken care of. */ static void png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr) { … } #endif /* READ_BACKGROUND || READ_ALPHA_MODE */ #ifdef PNG_READ_GAMMA_SUPPORTED /* Gamma correct the image, avoiding the alpha channel. Make sure * you do this after you deal with the transparency issue on grayscale * or RGB images. If your bit depth is 8, use gamma_table, if it * is 16, use gamma_16_table and gamma_shift. Build these with * build_gamma_table(). */ static void png_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr) { … } #endif #ifdef PNG_READ_ALPHA_MODE_SUPPORTED /* Encode the alpha channel to the output gamma (the input channel is always * linear.) Called only with color types that have an alpha channel. Needs the * from_1 tables. */ static void png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr) { … } #endif #ifdef PNG_READ_EXPAND_SUPPORTED /* Expands a palette row to an RGB or RGBA row depending * upon whether you supply trans and num_trans. */ static void png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info, png_bytep row, png_const_colorp palette, png_const_bytep trans_alpha, int num_trans) { … } /* If the bit depth < 8, it is expanded to 8. Also, if the already * expanded transparency value is supplied, an alpha channel is built. */ static void png_do_expand(png_row_infop row_info, png_bytep row, png_const_color_16p trans_color) { … } #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED /* If the bit depth is 8 and the color type is not a palette type expand the * whole row to 16 bits. Has no effect otherwise. */ static void png_do_expand_16(png_row_infop row_info, png_bytep row) { … } #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED static void png_do_quantize(png_row_infop row_info, png_bytep row, png_const_bytep palette_lookup, png_const_bytep quantize_lookup) { … } #endif /* READ_QUANTIZE */ /* Transform the row. The order of transformations is significant, * and is very touchy. If you add a transformation, take care to * decide how it fits in with the other transformations here. */ void /* PRIVATE */ png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info) { … } #endif /* READ_TRANSFORMS */ #endif /* READ */