/* pngread.c - read a PNG file * * 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 routines that an application calls directly to * read a PNG file or stream. */ #include "pngpriv.h" #if defined(PNG_SIMPLIFIED_READ_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) # include <errno.h> #endif #ifdef PNG_READ_SUPPORTED /* Create a PNG structure for reading, and allocate any memory needed. */ PNG_FUNCTION(…) { … /* Alternate create PNG structure for reading, and allocate any memory * needed. */ PNG_FUNCTION(png_structp,PNGAPI png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) { … } #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the information before the actual image data. This has been * changed in v0.90 to allow reading a file that already has the magic * bytes read from the stream. You can tell libpng how many bytes have * been read from the beginning of the stream (up to the maximum of 8) * via png_set_sig_bytes(), and we will only check the remaining bytes * here. The application can then have access to the signature bytes we * read if it is determined that this isn't a valid PNG file. */ void PNGAPI png_read_info(png_structrp png_ptr, png_inforp info_ptr) { … } #endif /* SEQUENTIAL_READ */ /* Optional call to update the users info_ptr structure */ void PNGAPI png_read_update_info(png_structrp png_ptr, png_inforp info_ptr) { … } #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Initialize palette, background, etc, after transformations * are set, but before any reading takes place. This allows * the user to obtain a gamma-corrected palette, for example. * If the user doesn't call this, we will do it ourselves. */ void PNGAPI png_start_read_image(png_structrp png_ptr) { … } #endif /* SEQUENTIAL_READ */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED #ifdef PNG_MNG_FEATURES_SUPPORTED /* Undoes intrapixel differencing, * NOTE: this is apparently only supported in the 'sequential' reader. */ static void png_do_read_intrapixel(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_read_intrapixel"); if ( (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) { int bytes_per_pixel; png_uint_32 row_width = row_info->width; if (row_info->bit_depth == 8) { png_bytep rp; png_uint_32 i; if (row_info->color_type == PNG_COLOR_TYPE_RGB) bytes_per_pixel = 3; else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) bytes_per_pixel = 4; else return; for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) { *(rp) = (png_byte)((256 + *rp + *(rp + 1)) & 0xff); *(rp+2) = (png_byte)((256 + *(rp + 2) + *(rp + 1)) & 0xff); } } else if (row_info->bit_depth == 16) { png_bytep rp; png_uint_32 i; if (row_info->color_type == PNG_COLOR_TYPE_RGB) bytes_per_pixel = 6; else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) bytes_per_pixel = 8; else return; for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) { png_uint_32 s0 = (png_uint_32)(*(rp ) << 8) | *(rp + 1); png_uint_32 s1 = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3); png_uint_32 s2 = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5); png_uint_32 red = (s0 + s1 + 65536) & 0xffff; png_uint_32 blue = (s2 + s1 + 65536) & 0xffff; *(rp ) = (png_byte)((red >> 8) & 0xff); *(rp + 1) = (png_byte)(red & 0xff); *(rp + 4) = (png_byte)((blue >> 8) & 0xff); *(rp + 5) = (png_byte)(blue & 0xff); } } } } #endif /* MNG_FEATURES */ void PNGAPI png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) { … } #endif /* SEQUENTIAL_READ */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read one or more rows of image data. If the image is interlaced, * and png_set_interlace_handling() has been called, the rows need to * contain the contents of the rows from the previous pass. If the * image has alpha or transparency, and png_handle_alpha()[*] has been * called, the rows contents must be initialized to the contents of the * screen. * * "row" holds the actual image, and pixels are placed in it * as they arrive. If the image is displayed after each pass, it will * appear to "sparkle" in. "display_row" can be used to display a * "chunky" progressive image, with finer detail added as it becomes * available. If you do not want this "chunky" display, you may pass * NULL for display_row. If you do not want the sparkle display, and * you have not called png_handle_alpha(), you may pass NULL for rows. * If you have called png_handle_alpha(), and the image has either an * alpha channel or a transparency chunk, you must provide a buffer for * rows. In this case, you do not have to provide a display_row buffer * also, but you may. If the image is not interlaced, or if you have * not called png_set_interlace_handling(), the display_row buffer will * be ignored, so pass NULL to it. * * [*] png_handle_alpha() does not exist yet, as of this version of libpng */ void PNGAPI png_read_rows(png_structrp png_ptr, png_bytepp row, png_bytepp display_row, png_uint_32 num_rows) { … } #endif /* SEQUENTIAL_READ */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the entire image. If the image has an alpha channel or a tRNS * chunk, and you have called png_handle_alpha()[*], you will need to * initialize the image to the current image that PNG will be overlaying. * We set the num_rows again here, in case it was incorrectly set in * png_read_start_row() by a call to png_read_update_info() or * png_start_read_image() if png_set_interlace_handling() wasn't called * prior to either of these functions like it should have been. You can * only call this function once. If you desire to have an image for * each pass of a interlaced image, use png_read_rows() instead. * * [*] png_handle_alpha() does not exist yet, as of this version of libpng */ void PNGAPI png_read_image(png_structrp png_ptr, png_bytepp image) { … } #endif /* SEQUENTIAL_READ */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the end of the PNG file. Will not read past the end of the * file, will verify the end is accurate, and will read any comments * or time information at the end of the file, if info is not NULL. */ void PNGAPI png_read_end(png_structrp png_ptr, png_inforp info_ptr) { … } #endif /* SEQUENTIAL_READ */ /* Free all memory used in the read struct */ static void png_read_destroy(png_structrp png_ptr) { … } /* Free all memory used by the read */ void PNGAPI png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr) { … } void PNGAPI png_set_read_status_fn(png_structrp png_ptr, png_read_status_ptr read_row_fn) { … } #ifdef PNG_SEQUENTIAL_READ_SUPPORTED #ifdef PNG_INFO_IMAGE_SUPPORTED void PNGAPI png_read_png(png_structrp png_ptr, png_inforp info_ptr, int transforms, voidp params) { … } #endif /* INFO_IMAGE */ #endif /* SEQUENTIAL_READ */ #ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* SIMPLIFIED READ * * This code currently relies on the sequential reader, though it could easily * be made to work with the progressive one. */ /* Arguments to png_image_finish_read: */ /* Encoding of PNG data (used by the color-map code) */ #define P_NOTSET … #define P_sRGB … #define P_LINEAR … #define P_FILE … #define P_LINEAR8 … /* Color-map processing: after libpng has run on the PNG image further * processing may be needed to convert the data to color-map indices. */ #define PNG_CMAP_NONE … #define PNG_CMAP_GA … #define PNG_CMAP_TRANS … #define PNG_CMAP_RGB … #define PNG_CMAP_RGB_ALPHA … /* The following document where the background is for each processing case. */ #define PNG_CMAP_NONE_BACKGROUND … #define PNG_CMAP_GA_BACKGROUND … #define PNG_CMAP_TRANS_BACKGROUND … #define PNG_CMAP_RGB_BACKGROUND … #define PNG_CMAP_RGB_ALPHA_BACKGROUND … png_image_read_control; /* Do all the *safe* initialization - 'safe' means that png_error won't be * called, so setting up the jmp_buf is not required. This means that anything * called from here must *not* call png_malloc - it has to call png_malloc_warn * instead so that control is returned safely back to this routine. */ static int png_image_read_init(png_imagep image) { … } /* Utility to find the base format of a PNG file from a png_struct. */ static png_uint_32 png_image_format(png_structrp png_ptr) { … } /* Is the given gamma significantly different from sRGB? The test is the same * one used in pngrtran.c when deciding whether to do gamma correction. The * arithmetic optimizes the division by using the fact that the inverse of the * file sRGB gamma is 2.2 */ static int png_gamma_not_sRGB(png_fixed_point g) { … } /* Do the main body of a 'png_image_begin_read' function; read the PNG file * header and fill in all the information. This is executed in a safe context, * unlike the init routine above. */ static int png_image_read_header(png_voidp argument) { … } #ifdef PNG_STDIO_SUPPORTED int PNGAPI png_image_begin_read_from_stdio(png_imagep image, FILE* file) { … } int PNGAPI png_image_begin_read_from_file(png_imagep image, const char *file_name) { … } #endif /* STDIO */ static void PNGCBAPI png_image_memory_read(png_structp png_ptr, png_bytep out, size_t need) { … } int PNGAPI png_image_begin_read_from_memory(png_imagep image, png_const_voidp memory, size_t size) { … } /* Utility function to skip chunks that are not used by the simplified image * read functions and an appropriate macro to call it. */ #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED static void png_image_skip_unused_chunks(png_structrp png_ptr) { … } #define PNG_SKIP_CHUNKS(p) … #else #define PNG_SKIP_CHUNKS … #endif /* HANDLE_AS_UNKNOWN */ /* The following macro gives the exact rounded answer for all values in the * range 0..255 (it actually divides by 51.2, but the rounding still generates * the correct numbers 0..5 */ #define PNG_DIV51(v8) … /* Utility functions to make particular color-maps */ static void set_file_encoding(png_image_read_control *display) { … } static unsigned int decode_gamma(png_image_read_control *display, png_uint_32 value, int encoding) { … } static png_uint_32 png_colormap_compose(png_image_read_control *display, png_uint_32 foreground, int foreground_encoding, png_uint_32 alpha, png_uint_32 background, int encoding) { … } /* NOTE: P_LINEAR values to this routine must be 16-bit, but P_FILE values must * be 8-bit. */ static void png_create_colormap_entry(png_image_read_control *display, png_uint_32 ip, png_uint_32 red, png_uint_32 green, png_uint_32 blue, png_uint_32 alpha, int encoding) { … } static int make_gray_file_colormap(png_image_read_control *display) { … } static int make_gray_colormap(png_image_read_control *display) { … } #define PNG_GRAY_COLORMAP_ENTRIES … static int make_ga_colormap(png_image_read_control *display) { … } #define PNG_GA_COLORMAP_ENTRIES … static int make_rgb_colormap(png_image_read_control *display) { … } #define PNG_RGB_COLORMAP_ENTRIES … /* Return a palette index to the above palette given three 8-bit sRGB values. */ #define PNG_RGB_INDEX(r,g,b) … static int png_image_read_colormap(png_voidp argument) { … } /* The final part of the color-map read called from png_image_finish_read. */ static int png_image_read_and_map(png_voidp argument) { … } static int png_image_read_colormapped(png_voidp argument) { … } /* Just the row reading part of png_image_read. */ static int png_image_read_composite(png_voidp argument) { … } /* The do_local_background case; called when all the following transforms are to * be done: * * PNG_RGB_TO_GRAY * PNG_COMPOSITE * PNG_GAMMA * * This is a work-around for the fact that both the PNG_RGB_TO_GRAY and * PNG_COMPOSITE code performs gamma correction, so we get double gamma * correction. The fix-up is to prevent the PNG_COMPOSITE operation from * happening inside libpng, so this routine sees an 8 or 16-bit gray+alpha * row and handles the removal or pre-multiplication of the alpha channel. */ static int png_image_read_background(png_voidp argument) { … } /* The guts of png_image_finish_read as a png_safe_execute callback. */ static int png_image_read_direct(png_voidp argument) { … } int PNGAPI png_image_finish_read(png_imagep image, png_const_colorp background, void *buffer, png_int_32 row_stride, void *colormap) { … } #endif /* SIMPLIFIED_READ */ #endif /* READ */