diff --git a/contrib/pngminus/CHANGES.txt b/contrib/pngminus/CHANGES.txt index 4e64e5ee6..2001f3189 100644 --- a/contrib/pngminus/CHANGES.txt +++ b/contrib/pngminus/CHANGES.txt @@ -3,7 +3,7 @@ pnm2png / png2pnm --- conversion from PBM/PGM/PPM-file to PNG-file copyright (C) 1999-2019 by Willem van Schaik version 1.0 - 1999.10.15 - First version. - 1.1 - 2015.07.29 - Fixed leaks (Glenn Randers-Pehrson) + 1.1 - 2015.07.29 - Fix memory leaks (Glenn Randers-Pehrson) 1.2 - 2017.04.22 - Add buffer-size check 1.3 - 2017.08.24 - Fix potential overflow in buffer-size check (Glenn Randers-Pehrson) @@ -11,3 +11,4 @@ version 1.0 - 1999.10.15 - First version. 1.5 - 2018.08.05 - Fix buffer overflow in tokenizer (Cosmin Truta) 1.6 - 2018.08.05 - Improve portability and fix style (Cosmin Truta) 1.7 - 2019.01.22 - Change license to MIT (Willem van Schaik) + 1.8 - 2024.01.08 - Fix, improve, modernize (Cosmin Truta) diff --git a/contrib/pngminus/png2pnm.c b/contrib/pngminus/png2pnm.c index 547b7718d..de58dfdc3 100644 --- a/contrib/pngminus/png2pnm.c +++ b/contrib/pngminus/png2pnm.c @@ -20,11 +20,6 @@ #define FALSE ((BOOL) 0) #endif -/* make png2pnm verbose so we can find problems (needs to be before png.h) */ -#ifndef PNG_DEBUG -#define PNG_DEBUG 0 -#endif - #include "png.h" /* function prototypes */ @@ -33,6 +28,9 @@ int main (int argc, char *argv[]); void usage (); BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, BOOL raw, BOOL alpha); +BOOL png2pnm_internal (png_struct *png_ptr, png_info *info_ptr, + FILE *pnm_file, FILE *alpha_file, + BOOL raw, BOOL alpha); /* * main @@ -163,35 +161,11 @@ void usage () BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, BOOL raw, BOOL alpha) { - png_struct *png_ptr = NULL; - png_info *info_ptr = NULL; - png_byte buf[8]; - png_byte *png_pixels = NULL; - png_byte **row_pointers = NULL; - png_byte *pix_ptr = NULL; - png_uint_32 row_bytes; + png_struct *png_ptr; + png_info *info_ptr; + BOOL ret; - png_uint_32 width; - png_uint_32 height; - int bit_depth; - int channels; - int color_type; - int alpha_present; - int row, col; - int ret; - int i; - long dep_16; - - /* read and check signature in PNG file */ - ret = fread (buf, 1, 8, png_file); - if (ret != 8) - return FALSE; - - ret = png_sig_cmp (buf, 0, 8); - if (ret != 0) - return FALSE; - - /* create png and info structures */ + /* initialize the libpng structures for reading from png_file */ png_ptr = png_create_read_struct (png_get_libpng_ver(NULL), NULL, NULL, NULL); @@ -208,33 +182,49 @@ BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, if (setjmp (png_jmpbuf (png_ptr))) { png_destroy_read_struct (&png_ptr, &info_ptr, NULL); - return FALSE; + return FALSE; /* generic libpng error */ } - /* set up the input control for C streams */ png_init_io (png_ptr, png_file); - png_set_sig_bytes (png_ptr, 8); /* we already read the 8 signature bytes */ - /* read the file information */ - png_read_info (png_ptr, info_ptr); + /* do the actual conversion */ + ret = png2pnm_internal (png_ptr, info_ptr, pnm_file, alpha_file, raw, alpha); - /* get size and bit-depth of the PNG-image */ - png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, - NULL, NULL, NULL); + /* clean up the libpng structures and their internally-managed data */ + png_destroy_read_struct (&png_ptr, &info_ptr, NULL); - /* set-up the transformations */ + return ret; +} - /* transform paletted images into full-color rgb */ - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_expand (png_ptr); - /* expand images to bit-depth 8 (only applicable for grayscale images) */ - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) - png_set_expand (png_ptr); - /* transform transparency maps into full alpha-channel */ - if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) - png_set_expand (png_ptr); +/* + * png2pnm_internal + */ -#ifdef NJET +BOOL png2pnm_internal (png_struct *png_ptr, png_info *info_ptr, + FILE *pnm_file, FILE *alpha_file, + BOOL raw, BOOL alpha) +{ + png_byte **row_pointers; + png_byte *pix_ptr; + png_uint_32 width; + png_uint_32 height; + int bit_depth; + int channels; + int color_type; + int alpha_present; + png_uint_32 row, col, i; + long dep_16; + + /* set up the image transformations that are necessary for the PNM format */ + + /* set up (if applicable) the expansion of paletted images to full-color rgb, + * and the expansion of transparency maps to full alpha-channel */ + png_set_expand (png_ptr); + + /* set up (if applicable) the expansion of grayscale images to bit-depth 8 */ + png_set_expand_gray_1_2_4_to_8 (png_ptr); + +#ifdef NJET /* FIXME */ /* downgrade 16-bit images to 8-bit */ if (bit_depth == 16) png_set_strip_16 (png_ptr); @@ -247,16 +237,14 @@ BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, png_set_gamma (png_ptr, (double) 2.2, file_gamma); #endif - /* all transformations have been registered; now update info_ptr data, - * get rowbytes and channels, and allocate image memory */ + /* read the image file, with all of the above image transforms applied */ + png_read_png (png_ptr, info_ptr, 0, NULL); - png_read_update_info (png_ptr, info_ptr); - - /* get the new color-type and bit-depth (after expansion/stripping) */ + /* get the image size, bit-depth and color-type */ png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); - /* calculate new number of channels and store alpha-presence */ + /* calculate the number of channels and store alpha-presence */ if (color_type == PNG_COLOR_TYPE_GRAY) channels = 1; else if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA) @@ -273,47 +261,12 @@ BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, if (alpha && !alpha_present) { fprintf (stderr, "PNG2PNM\n"); - fprintf (stderr, "Error: PNG-file doesn't contain alpha channel\n"); - exit (1); - } - - /* row_bytes is the width x number of channels x (bit-depth / 8) */ - row_bytes = png_get_rowbytes (png_ptr, info_ptr); - - if ((row_bytes == 0) || - ((size_t) height > (size_t) (-1) / (size_t) row_bytes)) - { - /* too big */ - png_destroy_read_struct (&png_ptr, &info_ptr, NULL); - return FALSE; - } - if ((png_pixels = (png_byte *) - malloc ((size_t) row_bytes * (size_t) height)) == NULL) - { - png_destroy_read_struct (&png_ptr, &info_ptr, NULL); + fprintf (stderr, "Warning: no alpha channel in PNG file\n"); return FALSE; } - if ((row_pointers = (png_byte **) - malloc ((size_t) height * sizeof (png_byte *))) == NULL) - { - png_destroy_read_struct (&png_ptr, &info_ptr, NULL); - free (png_pixels); - return FALSE; - } - - /* set the individual row_pointers to point at the correct offsets */ - for (i = 0; i < ((int) height); i++) - row_pointers[i] = png_pixels + i * row_bytes; - - /* now we can go ahead and just read the whole image */ - png_read_image (png_ptr, row_pointers); - - /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ - png_read_end (png_ptr, info_ptr); - - /* clean up after the read, and free any memory allocated - REQUIRED */ - png_destroy_read_struct (&png_ptr, &info_ptr, NULL); + /* get address of internally-allocated image data */ + row_pointers = png_get_rows (png_ptr, info_ptr); /* write header of PNM file */ @@ -344,13 +297,13 @@ BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, } /* write data to PNM file */ - pix_ptr = png_pixels; - for (row = 0; row < (int) height; row++) + for (row = 0; row < height; row++) { - for (col = 0; col < (int) width; col++) + pix_ptr = row_pointers[row]; + for (col = 0; col < width; col++) { - for (i = 0; i < (channels - alpha_present); i++) + for (i = 0; i < (png_uint_32) (channels - alpha_present); i++) { if (raw) { @@ -416,10 +369,5 @@ BOOL png2pnm (FILE *png_file, FILE *pnm_file, FILE *alpha_file, fprintf (pnm_file, "\n"); } /* end for row */ - if (row_pointers != NULL) - free (row_pointers); - if (png_pixels != NULL) - free (png_pixels); - return TRUE; } /* end of source */ diff --git a/contrib/pngminus/pnm2png.c b/contrib/pngminus/pnm2png.c index e966a49c2..5558023be 100644 --- a/contrib/pngminus/pnm2png.c +++ b/contrib/pngminus/pnm2png.c @@ -21,11 +21,6 @@ #define FALSE ((BOOL) 0) #endif -/* make pnm2png verbose so we can find problems (needs to be before png.h) */ -#ifndef PNG_DEBUG -#define PNG_DEBUG 0 -#endif - #include "png.h" /* function prototypes */ @@ -34,6 +29,9 @@ int main (int argc, char *argv[]); void usage (); BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace, BOOL alpha); +BOOL pnm2png_internal (png_struct *png_ptr, png_info *info_ptr, + FILE *pnm_file, FILE *alpha_file, + BOOL interlace, BOOL alpha); int fscan_pnm_magic (FILE *pnm_file, char *magic_buf, size_t magic_buf_size); int fscan_pnm_token (FILE *pnm_file, char *token_buf, size_t token_buf_size); int fscan_pnm_uint_32 (FILE *pnm_file, png_uint_32 *num_ptr); @@ -166,11 +164,52 @@ void usage () BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, BOOL interlace, BOOL alpha) { - png_struct *png_ptr = NULL; - png_info *info_ptr = NULL; - png_byte *png_pixels = NULL; - png_byte **row_pointers = NULL; - png_byte *pix_ptr = NULL; + png_struct *png_ptr; + png_info *info_ptr; + BOOL ret; + + /* initialize the libpng structures for writing to png_file */ + + png_ptr = png_create_write_struct (png_get_libpng_ver(NULL), + NULL, NULL, NULL); + if (!png_ptr) + return FALSE; /* out of memory */ + + info_ptr = png_create_info_struct (png_ptr); + if (!info_ptr) + { + png_destroy_write_struct (&png_ptr, NULL); + return FALSE; /* out of memory */ + } + + if (setjmp (png_jmpbuf (png_ptr))) + { + png_destroy_write_struct (&png_ptr, &info_ptr); + return FALSE; /* generic libpng error */ + } + + png_init_io (png_ptr, png_file); + + /* do the actual conversion */ + ret = pnm2png_internal (png_ptr, info_ptr, + pnm_file, alpha_file, interlace, alpha); + + /* clean up the libpng structures and their internally-managed data */ + png_destroy_write_struct (&png_ptr, &info_ptr); + + return ret; +} + +/* + * pnm2png_internal + */ + +BOOL pnm2png_internal (png_struct *png_ptr, png_info *info_ptr, + FILE *pnm_file, FILE *alpha_file, + BOOL interlace, BOOL alpha) +{ + png_byte **row_pointers; + png_byte *pix_ptr; int bit_depth; int color_type; int channels; @@ -336,18 +375,27 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, /* too big */ return FALSE; } - if ((png_pixels = (png_byte *) - malloc ((size_t) row_bytes * (size_t) height)) == NULL) + + /* allocate the rows using the same memory layout as libpng, and transfer + * their ownership to libpng, with the responsibility to clean everything up; + * please note the use of png_calloc instead of png_malloc */ + row_pointers = (png_byte **) + png_calloc (png_ptr, height * sizeof (png_byte *)); + png_set_rows (png_ptr, info_ptr, row_pointers); + png_data_freer (png_ptr, info_ptr, PNG_DESTROY_WILL_FREE_DATA, PNG_FREE_ALL); + for (row = 0; row < height; row++) { - /* out of memory */ - return FALSE; + /* the individual rows should only be allocated after all the previous + * steps completed successfully, because libpng must handle correctly + * any image allocation left incomplete after an out-of-memory error */ + row_pointers[row] = (png_byte *) png_malloc (png_ptr, row_bytes); } - /* read data from PNM file */ - pix_ptr = png_pixels; + /* read the data from PNM file */ for (row = 0; row < height; row++) { + pix_ptr = row_pointers[row]; #if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) if (packed_bitmap) { @@ -413,21 +461,10 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, } /* end for col */ } /* end for row */ - /* prepare the standard PNG structures */ - png_ptr = png_create_write_struct (png_get_libpng_ver(NULL), - NULL, NULL, NULL); - if (!png_ptr) - { - free (png_pixels); - return FALSE; - } - info_ptr = png_create_info_struct (png_ptr); - if (!info_ptr) - { - png_destroy_write_struct (&png_ptr, NULL); - free (png_pixels); - return FALSE; - } + /* we're going to write more or less the same PNG as the input file */ + png_set_IHDR (png_ptr, info_ptr, width, height, bit_depth, color_type, + (!interlace) ? PNG_INTERLACE_NONE : PNG_INTERLACE_ADAM7, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); #if defined(PNG_WRITE_INVERT_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) if (packed_bitmap == TRUE) @@ -437,54 +474,15 @@ BOOL pnm2png (FILE *pnm_file, FILE *png_file, FILE *alpha_file, } #endif - if (setjmp (png_jmpbuf (png_ptr))) - { - png_destroy_write_struct (&png_ptr, &info_ptr); - free (png_pixels); - return FALSE; - } - - /* initialize the png structure */ - png_init_io (png_ptr, png_file); - - /* we're going to write more or less the same PNG as the input file */ - png_set_IHDR (png_ptr, info_ptr, width, height, bit_depth, color_type, - (!interlace) ? PNG_INTERLACE_NONE : PNG_INTERLACE_ADAM7, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - /* write the file header information */ png_write_info (png_ptr, info_ptr); - /* if needed we will allocate memory for an new array of row-pointers */ - if (row_pointers == NULL) - { - if ((row_pointers = (png_byte **) - malloc (height * sizeof (png_byte *))) == NULL) - { - png_destroy_write_struct (&png_ptr, &info_ptr); - free (png_pixels); - return FALSE; - } - } - - /* set the individual row_pointers to point at the correct offsets */ - for (i = 0; i < height; i++) - row_pointers[i] = png_pixels + i * row_bytes; - /* write out the entire image data in one call */ png_write_image (png_ptr, row_pointers); /* write the additional chunks to the PNG file (not really needed) */ png_write_end (png_ptr, info_ptr); - /* clean up after the write, and free any memory allocated */ - png_destroy_write_struct (&png_ptr, &info_ptr); - - if (row_pointers != NULL) - free (row_pointers); - if (png_pixels != NULL) - free (png_pixels); - return TRUE; } /* end of pnm2png */