From cde9b583a89ba2b7154c6fe2ea20b41fae0ca429 Mon Sep 17 00:00:00 2001 From: John Bowler Date: Wed, 4 May 2016 17:02:20 -0700 Subject: [PATCH] Write code update Implemented better defaulting of zlib settings based on image properties. Implemented pass-through of png_write_rows when the rows can be used directly (a common case) optimizing the handling of previous-row buffering. Removed the METHODICAL filter selection method and disabled the HEURISTIC one; the first was ridiculously slow (though useful for experiments) the second doesn't work. Filter selection is temporarily disabled (it defaults to the lowest numbered filter in the list; typically 'none'). New handling of compression settings (incomplete), new PNG compression level (not yet visible in an API). Back ported 'PNG_FAST_FILTERS' from 1.6 (in png.h). There are minimal API changes beyond removal of the selection options. Work is still to be done to investigate a filter selection mechanism that is at least as good as the previous one. Signed-off-by: John Bowler --- contrib/examples/pngcp.c | 15 +- png.h | 43 +- pngpriv.h | 22 +- pngstruct.h | 67 +- pngtest.png | Bin 5731 -> 5711 bytes pngwio.c | 11 - pngwrite.c | 416 +++--- pngwutil.c | 2546 ++++++++++++++++++++------------- scripts/pnglibconf.dfa | 36 +- scripts/pnglibconf.h.prebuilt | 8 +- 10 files changed, 1834 insertions(+), 1330 deletions(-) diff --git a/contrib/examples/pngcp.c b/contrib/examples/pngcp.c index 9a9083228..50a6e5e44 100644 --- a/contrib/examples/pngcp.c +++ b/contrib/examples/pngcp.c @@ -1609,10 +1609,10 @@ read_png(struct display *dp, const char *filename) png_alloc_size_t rb = png_get_rowbytes(dp->read_pp, dp->ip); /* The size calc can overflow. */ - if (MAX_SIZE/rb < dp->h) + if ((MAX_SIZE-dp->h)/rb < dp->h) png_error(dp->read_pp, "image too large"); - dp->size = rb * dp->h; + dp->size = rb * dp->h + dp->h/*filter byte*/; } display_clean_read(dp); @@ -1826,18 +1826,21 @@ write_png(struct display *dp, const char *destname) static void set_windowBits_hi(struct display *dp) { - /* windowBits is in the range 8..15, but it is said that setting '8' - * prevents adequate search even if the image size is 256 bytes or less. + /* windowBits is in the range 8..15 but zlib maps '8' to '9' so it is only + * worth using if the data size is 256 byte or less. */ int wb = MAX_WBITS; /* for large images */ int i = VLSIZE(windowBits_IDAT); - while (wb > 9 && dp->size <= 1U<<(wb-1)) --wb; + while (wb > 8 && dp->size <= 1U<<(wb-1)) --wb; while (--i >= 0) if (VLNAME(windowBits_IDAT)[i].name == range_hi) break; - assert(i > 0); /* vl_windowBits_IDAT always has a RANGE() */ + assert(i > 1); /* vl_windowBits_IDAT always has a RANGE() */ VLNAME(windowBits_IDAT)[i].value = wb; + + assert(VLNAME(windowBits_IDAT)[--i].name == range_lo); + VLNAME(windowBits_IDAT)[i].value = wb > 8 ? 9 : 8; } static int diff --git a/png.h b/png.h index 358616374..b01ca51da 100644 --- a/png.h +++ b/png.h @@ -1690,25 +1690,14 @@ PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, * ignored if SUB is set; this is because these filter pairs are equivalent * when there is no previous row. * - * 2) PNG_SELECT_FILTER_METHODICALLY_SUPPORTED: - * If SELECT_FILTER_METHODICALLY is 'on' libpng tries all the filters in the - * list and selects the one which gives the shortest compressed row, favoring - * earlier filters. + * 2) PNG_SELECT_FILTER_SUPPORTED: + * libpng will buffer rows until enough data is available to perform a + * reasonable filter selection heuristic then select filters for at least the + * first buffered row. * - * 3) PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED: - * If SELECT_FILTER_HEURISTICALLY is 'on' libpng tests the start of each row - * (a few thousand bytes at most) to see which filter is likely to produce - * best compression. - * - * 4) If neither (2) nor (3) libpng selects the first filter in the list (there - * is no warning that this will happen - check the #defines if you need to - * know.) - * - * The seletion options are turned 'on' using png_set_option(method, - * PNG_OPTION_ON) and turned off with PNG_OPTION_OFF. If a selection method is - * turned off it will never be used, if neither option is turned on or off (i.e. - * if png_set_option is not called) the first supported option (2) or (3) will - * be used. + * 3) !PNG_SELECT_FILTER_SUPPORTED: + * libpng selects the first filter in the list (there is no warning that this + * will happen - check the #defines if you need to know.) * * If you intend to use 'previous row' filters in an image set either the UP or * PAETH filter before the first call to png_write_row, depending on whether you @@ -1717,12 +1706,6 @@ PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, * You can also select AVG on the first row; it uses half the value of the * preceding byte as a predictor and is not likely to have very good * performance. - * - * The SELECT_FILTER_METHODICALLY option is slow and memory intensive, but it is - * almost certain to produce the smallest PNG file. Depending on the image data - * the HEURISTIC option may improve results significantly over the NONE filter - * and it has little overall effect on compression speed, however it can - * sometimes produce larger files than not using any filtering. */ PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method, int filters)); @@ -1752,12 +1735,12 @@ PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method, #define PNG_FILTER_AVG PNG_FILTER_MASK(PNG_FILTER_VALUE_AVG) #define PNG_FILTER_PAETH PNG_FILTER_MASK(PNG_FILTER_VALUE_PAETH) -/* Then two convenience values. PNG_NO_FILTERS is the same as +/* Then three convenience values. PNG_NO_FILTERS is the same as * PNG_FILTER_VALUE_NONE, but this is harmless because they mean the same thing. */ -#define PNG_NO_FILTERS 0x00 -#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \ - PNG_FILTER_AVG | PNG_FILTER_PAETH) +#define PNG_NO_FILTERS 0x00 +#define PNG_FAST_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP) +#define PNG_ALL_FILTERS (PNG_FAST_FILTERS | PNG_FILTER_AVG | PNG_FILTER_PAETH) #ifdef PNG_WRITE_SUPPORTED #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */ @@ -3629,9 +3612,7 @@ PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory, #define PNG_EXTENSIONS 0 /* BOTH: enable or disable extensions */ #define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */ #define PNG_SKIP_sRGB_CHECK_PROFILE 4 /* SOFTWARE: Check ICC profile for sRGB */ -#define PNG_SELECT_FILTER_HEURISTICALLY 6 /* SOFTWARE: see png_set_filter */ -#define PNG_SELECT_FILTER_METHODICALLY 8 /* SOFTWARE: see png_set_filter */ -#define PNG_OPTION_NEXT 10 /* Next option - numbers must be even */ +#define PNG_OPTION_NEXT 6 /* Next option - numbers must be even */ /* Return values: NOTE: there are four values and 'off' is *not* zero */ #define PNG_OPTION_UNSET 0 /* Unset - defaults to off */ diff --git a/pngpriv.h b/pngpriv.h index af8780896..55aff2bed 100644 --- a/pngpriv.h +++ b/pngpriv.h @@ -1080,10 +1080,6 @@ PNG_INTERNAL_FUNCTION(int,png_crc_finish,(png_structrp png_ptr, PNG_INTERNAL_FUNCTION(void,png_calculate_crc,(png_structrp png_ptr, png_const_voidp ptr, png_size_t length),PNG_EMPTY); -#ifdef PNG_WRITE_FLUSH_SUPPORTED -PNG_INTERNAL_FUNCTION(void,png_flush,(png_structrp png_ptr),PNG_EMPTY); -#endif - /* Write various chunks */ /* Write the IHDR chunk, and update the png_struct with the necessary @@ -1199,9 +1195,9 @@ PNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr, #endif #ifdef PNG_WRITE_SUPPORTED -/* Initialize the row compression mechanism. */ -PNG_INTERNAL_FUNCTION(void, png_write_start_IDAT, (png_structp png_ptr), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_start_IDAT,(png_structrp png_ptr), + PNG_EMPTY); + /* Do any required initialization before IDAT or row processing starts. */ /* Choose the best filter to use and filter the row data then write it out. If * WRITE_FILTERING is not supported this just writes the data out with a zero @@ -1226,11 +1222,21 @@ enum # define PNG_IDAT_END(f) (((f) & ~png_pass_first_row) == \ (png_row_end+png_pass_last_row+png_pass_last)) }; -PNG_INTERNAL_FUNCTION(void, png_write_filter_row, (png_structrp png_ptr, +PNG_INTERNAL_FUNCTION(void,png_write_png_data,(png_structrp png_ptr, png_bytep prev_pixels, png_const_bytep unfiltered_row, png_uint_32 x, unsigned int width/*pixels*/, unsigned int row_info_flags), PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_png_rows,(png_structrp png_ptr, + png_const_bytep *rows, png_uint_32 num_rows), PNG_EMPTY); + /* As above but rows[num_rows] of correctly (PNG) formated but unfiltered + * data are passed in. For an interlaced image the rows will be interlaced + * rows and therefore may be narrower than the image width. + * + * This function advances png_structp::pass and png_structp::row_number as + * required. + */ + /* Release memory used by the deflate mechanism */ PNG_INTERNAL_FUNCTION(void, png_deflate_destroy, (png_structp png_ptr), PNG_EMPTY); diff --git a/pngstruct.h b/pngstruct.h index bff8855cc..449a1e733 100644 --- a/pngstruct.h +++ b/pngstruct.h @@ -26,14 +26,14 @@ #ifndef ZLIB_CONST /* We must ensure that zlib uses 'const' in declarations. */ # define ZLIB_CONST -#endif +#endif /* !ZLIB_CONST */ #include PNG_ZLIB_HEADER #ifdef const /* zlib.h sometimes #defines const to nothing, undo this. */ # undef const -#endif +#endif /* const */ /* zlib.h has mediocre z_const use before 1.2.6, this stuff is for compatibility * with older builds. @@ -41,10 +41,10 @@ #if ZLIB_VERNUM < 0x1260 # define PNGZ_MSG_CAST(s) png_constcast(char*,s) # define PNGZ_INPUT_CAST(b) png_constcast(png_bytep,b) -#else +#else /* ZLIB_VERNUM >= 0x1260 */ # define PNGZ_MSG_CAST(s) (s) # define PNGZ_INPUT_CAST(b) (b) -#endif +#endif /* ZLIB_VERNUM >= 0x1260 */ /* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib * can handle at once. This type need be no larger than 16 bits (so maximum of @@ -57,17 +57,17 @@ #ifndef ZLIB_IO_MAX # ifdef __COVERITY__ # define ZLIB_IO_MAX ((uInt)255U) /* else COVERITY whines */ -# else +# else /* !COVERITY */ # define ZLIB_IO_MAX ((uInt)-1) -# endif /* COVERITY */ -#endif +# endif /* !COVERITY */ +#endif /* !ZLIB_IO_MAX */ #ifdef PNG_WRITE_SUPPORTED /* The write compression control (allocated on demand). * TODO: use this for the read state too. */ typedef struct png_zlib_state *png_zlib_statep; -#endif +#endif /* WRITE */ /* Colorspace support; structures used in png_struct, png_info and in internal * functions to hold and communicate information about the color space. @@ -114,13 +114,13 @@ typedef struct png_colorspace { #ifdef PNG_GAMMA_SUPPORTED png_fixed_point gamma; /* File gamma */ -#endif +#endif /* GAMMA */ #ifdef PNG_COLORSPACE_SUPPORTED png_xy end_points_xy; /* End points as chromaticities */ png_XYZ end_points_XYZ; /* End points as CIE XYZ colorant values */ png_uint_16 rendering_intent; /* Rendering intent of a profile */ -#endif +#endif /* COLORSPACE */ /* Flags are always defined to simplify the code. */ png_uint_16 flags; /* As defined below */ @@ -182,7 +182,7 @@ typedef struct * during PNG_TC_INIT_FINAL. The field is only used on read; write * transforms do not modify the gamma of the data. */ -# endif +# endif /* READ_GAMMA */ unsigned int format; /* As pngstruct::row_format below */ unsigned int range; /* Count of range transforms */ # define PNG_TC_CHANNELS(tc) PNG_FORMAT_CHANNELS((tc).format) @@ -364,7 +364,7 @@ struct png_struct_def * accessed.) */ jmp_buf jmp_buf_local; -#endif +#endif /* SETJMP */ /* Next the frequently accessed fields. Many processors perform arithmetic * in the address pipeline, but frequently the amount of addition or @@ -420,7 +420,7 @@ struct png_struct_def /* Options */ #ifdef PNG_SET_OPTION_SUPPORTED png_uint_32 options; /* On/off state (up to 16 options) */ -#endif +#endif /* SET_OPTIONS */ #ifdef PNG_READ_SUPPORTED #if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) @@ -428,13 +428,13 @@ struct png_struct_def * is in (just) the info_struct. */ png_colorspace colorspace; -#endif +#endif /* COLORSPACE || GAMMA */ #endif /* READ */ /* Transform handling */ #ifdef PNG_TRANSFORM_MECH_SUPPORTED png_transformp transform_list; /* List of transformation to perform. */ -#endif +#endif /* TRANSFORM_MECH */ /* ROW BUFFERS and CONTROL * @@ -442,9 +442,9 @@ struct png_struct_def * filter byte (which is in next_filter.) All fields are only used during * IDAT processing and start of 0. */ -#if defined(PNG_WRITE_FILTER_SUPPORTED) || defined(PNG_READ_SUPPORTED) +#ifdef PNG_READ_SUPPORTED png_bytep row_buffer; /* primary row buffer */ -#endif /* WRITE_FILTER || READ */ +#endif /* READ */ #if (defined(PNG_PROGRESSIVE_READ_SUPPORTED) ||\ defined(PNG_READ_INTERLACING_SUPPORTED)) &&\ defined(PNG_TRANSFORM_MECH_SUPPORTED) @@ -482,10 +482,12 @@ struct png_struct_def unsigned int invalid_info; /* PNG_INFO_* for invalidated chunks */ unsigned int palette_updated:1; /* png_struct::palette changed */ #endif /* READ_TRANSFORMS */ - +#ifdef PNG_WRITE_SUPPORTED + unsigned int write_rows :1; /* libpng has complete rows to write */ +#endif /* WRITE */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED unsigned int read_started :1; /* at least one call to png_read_row */ -#endif +#endif /* SEQUENTIAL_READ */ #if defined (PNG_READ_INTERLACING_SUPPORTED) ||\ defined (PNG_WRITE_INTERLACING_SUPPORTED) unsigned int do_interlace :1; /* libpng handles the interlace */ @@ -574,7 +576,7 @@ struct png_struct_def * available to zlib during read decompression. */ png_alloc_size_t read_buffer_size; /* current size of the buffer */ -#endif +#endif /* READ */ #if defined(PNG_SEQUENTIAL_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) png_uint_32 IDAT_size; /* limit on IDAT read and write IDAT size */ @@ -585,13 +587,13 @@ struct png_struct_def jmp_buf *jmp_buf_ptr; /* passed to longjmp_fn */ png_longjmp_ptr longjmp_fn; /* setjmp non-local goto function. */ size_t jmp_buf_size; /* size of *jmp_buf_ptr, if allocated */ -#endif +#endif /* SETJMP */ /* Error/warning callbacks */ png_error_ptr error_fn; /* print an error message and abort */ #ifdef PNG_WARNINGS_SUPPORTED png_error_ptr warning_fn; /* print a warning and continue */ -#endif +#endif /* WARNINGS */ png_voidp error_ptr; /* user supplied data for the above */ /* MEMORY ALLOCATION */ @@ -599,7 +601,7 @@ struct png_struct_def png_malloc_ptr malloc_fn; /* allocate memory */ png_free_ptr free_fn; /* free memory */ png_voidp mem_ptr; /* user supplied data for the above */ -#endif +#endif /* USER_MEM */ /* IO and BASIC READ/WRITE SUPPORT */ png_voidp io_ptr; /* user supplied data for IO callbacks */ @@ -622,8 +624,7 @@ struct png_struct_def #ifdef PNG_WRITE_FLUSH_SUPPORTED png_flush_ptr output_flush_fn; /* Function for flushing output */ -#endif - +#endif /* WRITE_FLUSH */ #endif /* WRITE */ #ifdef PNG_SET_USER_LIMITS_SUPPORTED @@ -634,14 +635,14 @@ struct png_struct_def * - it is decremented as memory is allocated. */ png_alloc_size_t user_chunk_malloc_max; -#endif +#endif /* SET_USER_LIMITS */ #ifdef PNG_USER_LIMITS_SUPPORTED /* limit on total *number* of sPLT, text and unknown chunks that can be * stored. 0 means unlimited. This field is a counter - it is decremented * as chunks are encountered. */ png_uint_32 user_chunk_cache_max; -#endif +#endif /* USER_LIMITS */ /* The progressive reader gets passed data and calls application handling * functions when appropriate. @@ -672,7 +673,7 @@ struct png_struct_def #ifdef PNG_IO_STATE_SUPPORTED png_uint_32 io_state; /* tells the app read/write progress */ -#endif +#endif /* IO_STATE */ /* UNKNOWN CHUNK HANDLING */ /* TODO: this is excessively complicated, there are multiple ways of doing @@ -686,12 +687,12 @@ struct png_struct_def * set_unknown_chunks interface.) */ png_voidp user_chunk_ptr; -#endif +#endif /* USER_CHUNKS */ #ifdef PNG_READ_USER_CHUNKS_SUPPORTED /* This is called back from the unknown chunk handling */ png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ -#endif +#endif /* READ_USER_CHUNKS */ #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED png_uint_32 known_unknown; /* Bit mask of known chunks to be treated as @@ -703,7 +704,7 @@ struct png_struct_def * 'known & ~save'. */ # define png_IDATs_skipped(pp) (((pp)->known_unknown & ~(pp)->save_unknown)&1U) -#else +#else /* !SAVE_UNKNOWN_CHUNKS */ # define png_IDATs_skipped(pp) ((pp)->known_unknown & 1U) #endif /* !SAVE_UNKNOWN_CHUNKS */ #endif /* HANDLE_AS_UNKNOWN */ @@ -713,7 +714,7 @@ struct png_struct_def * followed by a PNG_HANDLE_* byte */ unsigned int unknown_default :2; /* As PNG_HANDLE_* */ unsigned int num_chunk_list; /* Number of entries in the list */ -#endif +#endif /* SET_UNKNOWN_CHUNKS */ /* COMPRESSION AND DECOMPRESSION SUPPORT. * @@ -738,7 +739,7 @@ struct png_struct_def /* MNG SUPPORT */ #ifdef PNG_MNG_FEATURES_SUPPORTED unsigned int mng_features_permitted :3; -#endif +#endif /* MNG_FEATURES */ /* SCRATCH buffers, used when control returns to the application or a read * loop. diff --git a/pngtest.png b/pngtest.png index d64780caae577061f62ff38d140eb6c01bb91070..fe4101e4af544bc56c44643f7c2f8a8d72af1248 100644 GIT binary patch delta 5187 zcmV-J6uj%>EYB>kVgY|Em*uR|Mn)pBNF=f>5{bkjk;vFcWMph)WMtdOkt095<@Xcn z2q?n7c2Cdrd1u};wN}>j>`OK&in=`Y0ApVvMoCGCRR(F9AGdC zgHbpKgCGUY!C){7J*ew1XeHX6MyK1GQt*_l#$ax~5RF1#U!*T+Dcn=lJyqM6%G>DB zC~^PGlY@=^UXw-1hitV#qa*@7#}W)KRb|ShR5DUhpyT~Z%_|qPZs0t z)PAK50~1{jb14^I=iEDB=FeZ}K=&Pyh$)N*ycl)W>&`aoS7(P-3?XT}(_ zT5j0`zH5K{uY?aweEQ3Ow0Mx2u@Cr;9}zwbV(jA4Lo@t{7$w{i>{UEk!nK91@q;6; z=G7dLhvG+~EhF5L#i_1HE%`>?&nSO^$K+A+;clcx-9+fI`W13o%zF3Q?7T~I14@P0M8YSnjMvHr0 zg+=e>DMnX<%IGxq7RDGWD=m9KC3&0JU=&UsF1`D`^^j|{)u#g{tJ@FXo1-r(@Sx~X zFMJq8vKpI=v;Q+p4T8e7sm*$r21Et1(%9 z_1M$RNIxYM4}bbbx59_ve=`y(!Jk(Xzk`qio@yeuC5w}TmhAl_qNQ+KvX?uT#u(d2 zhf65lid-iJ&7aPgJ|lt;P|6}x9shMzV70^?N)G6>M5{$}tqx?3pR&1%Um{k^%Nl=8 z(}=sKf>R75h#+%@yrPwIke#@a{Bf*pbuF*EIfNBh*1P%jxoPoa*J}@zP zz|jLntIJir`<848#~?8ph0&IzgDQWZH5#15wLO9=gL=!c=3^yr<{C_&#w^AdNZ}?A zm+TGhqs7U=@$9pVu`@vSgDwe5F^xF@Rqhx|fNh!3nk;T(K*5XeR)TLv3EU@-MoR=K zTHdmRqH!{dKGCGhX<1AvegH$6gDC^A10#rGs)L?9pyUGzJ`_wS8q`u$=m&rB$N{%0 z;5Ma$4};TEU@#izVB6xGTu~0eE3O;p?X}beY_&`u8hA;(WXp~E*JZ0Y+PX>=w>cg1hX^eL7ubU`%9R2DpEO^10DzT!O(h znvX5aHgI1w(WcH6?S@Vp{pX7pqPk$X3r54h#2n1?K=P}k6eO&Nek)K zeZM@#U8Aj$trR!OJwUWs0q5Zri2dJ`TubmJS`0>Q;u#3`SN>)4N6a)Rk%Cc~4@?L? zxL;C5f0axQE;#^B0a|}#+*5H1zh!})y}8U4=cnLC0Mr}|zHGI9l?($DR?D=6`#d`u zeJsHu)M#9)p0mEJ;MQGD`em}ll85hO`PV3MRa;6vq%B$8N7oXuJ{xo(OU@I_>q6mI ziU--i%ex*eV`7P>HG(O!YZGAj`Hy(+SY%0Z0}X{m3mfZe^cHS z#P6jE9};SUl`_pd)dXp4O%{89TQCugb1*n{Q0KGiT?zi$ruo1`FlsA#ZPDaXE1DkC zWQ?(7HPRHj+K1_dfSY}E%>#fGhXaLMa=4EUQw7(la;LvRiOaiH{GO=tE>Hv2kscK8 z6^f`mx2wgpCX0VdD2we*({;)x2NI>D3(VmquHHNY;fDV~Wu0^p?0&@U7rhwmS$BMDC7_FALPod!_t^z=B zqr+(QmA8NB|8`p9XiNL%WiQl$%yaEqG)J#XV`}XN?W+$iC6{b~&oOy?n<9deP^TF| z2|RMV>Y3&MxFy$6fM*x=S6>DgCAeF{x!_344vLdsqd{4xSxeq17IZDq;*lf%|DLJQ zh(-zgmcy0Fcp8sy zQ@|YT(X^FZMXV^amq8bBNS&9KS4<733v%_4R6)WACJ4Z}0t_o7Xo=>E(LvY;`PqW} zo68(5uFI-{xSBT(Rh$i$DV&T^TUt*R365 z@6lDp7*m1+WrNRtbEvL%A8msUtiI3DpUUXq*pqFXz}^kfLg`Ilt|>OzK7M;<3}b%)edn+Il|M=ZADjnuiJu`q{*@w9a0q`^9a8|z zp=9>^Xj@q`I(<-PR=Te*=&FC^UXkd=}mu+FP(g|XC?6;FOm;H7;kyl!hS6kY$*mMAD&to9~cmY zk|v1&4YFcFD{qlU!j=05&AX`jKPkh&1SpX_s62afJfauB5?Qithe1{aBeQ`Otk=U>A*Z1zNIyaiy+ir8cYAfj1GARTfKndPs|wdo{ZQW5Q~AAxj{F~#4-6c zX7cfbADf%2cNtoWgAapy_B=l<17l6mb4}>Ur;SzNt)EtNPg;L+qtl(z&mKv%sxr{U z9neyKr}CJ)Ntyz@#Nf0P8#UrdiP4lD7}4rY3ZBWwl0}zBe&KrTwaZ1U10^_0!JCpn zii>y=V829^;BNFq=}R;?R|J)M>wTm)s*tJHSn^du{By@{@O6Uf;R?wpk!t&+DIj~( z_RZgJZ6OhSa8`fIOV8YKTH@Oja36hBGWlBSm(pg8WAeDvaYC`!%sy$cWT4TgZSrvB znwey8j+YIvM?&Q)?fD@~>Mv>*BuiTn44%0!v}RgQDWRs<9HH(1?G?UMpPGZcJgd&2 zwl7JcZ&So0hpVl;S{AFN!w)Dvkh0%{*ZD9w!G{D&Tqu7Xq-R^YGJXlB^@Tr;LVA$f z()nrvif?n!{vs9$aU5ui5YY&zdr92*v34A(!@kCnC6p!aaT`4vE$<#c34TDwIQce5 z+^5idaA|^{L2h*Ah>Imw>kbyR6iErbX<3xnXBgM4m9y!7m1B3?IZAQ#6HHnMa+_RH z9CbBMLX>}Mm#xefqs3LRKzm1QH_-ljlLw5n=cM+&qg9oQWbw!W-==_XIpP@XRca;q zkcf|Dl)!B)91jY5eSC2sn>$>ZtFw)A(JS!Pb-SG^8r|F`?H>7*q8Tf_7@9F+A>3Lr z4TL(vsj(eOz#Bc(7I$fLlQo)3JEAjhv^=u{4+?+hXmL#rzt0i(DdMq=c-iNMun9gS zS(Ob+U=9|)%@L=1I!S*O?#kJlFIyg6b8&rI*9w-Kzn@J2Z5YWOaQPXIxDw@Lh+^4* zeN)$WOX?)=7P1-b`J976U$_CN1aAx^8fdO5C3NXlk4NNSa7zxq<$&wx@%xhS`!b>u z0_cC>8RE+nzwaCQ`1Xoc*ZY-K_cpppeR;I`@0Qu}?VDBr00aX`L_t(^b9Kxo3W|k@ z@e?$0DLCwv@=aE1^qGrN3Pyg?>gpS75TR_O6$jnqP>xI!LjJW?ZdxKpaRj5cExBUp zu_%5^9v!IEBXZH|#>wo#B643&%Z5*Hb>Dv#9ryJr2EDo*6k^C;Nl~?H`*~1mv~VFS z%>mGN$}qYveJvX>v{xk)jhG&~KO3kU@P!T~>Z!qGX>?Faze{>c4!2Y?ipj%?IaBJH z+|}x7;1Nh1y>7%S3T||;(XHEgMuEF^QKN;HjnrrUd^2H<=CW6xO@yjb*{4!y1Lc2G zt3k?KTHdQqg?Bi_g+ALWsQ(-RONDcIx&WH|T=-S!;G{@vDKZp3cT4@0;HV^T`zOoB zP=|9p`=ig2dRBB#-+MF}(df3XhYak~$_}75vh1a%a=Fs3_f)FJx#rg85H;O+jKr=p z>YNmstV*i95PPF>!^~Nz)E%~0%W{8o`k>#U6-0ZO=Kxn5nFx<@P6muNL9ejJp{yARbpE?1G1LDEbEfZ6kZg=^ zeQs+eveNC22CHQzWp7=cJ68kH4+;xD4B)EbttMK!Z3>!0Ip4q=h2F>pHH3eTV>h}& zp`RSI^VOnJjloDc_ooXREz4GC%9%+q9#r$$l-Bi`goBbY^%hM;R3gL@ZJstX^xQlm zUsbET3p!c~M>{b}AyhJ^y_{$GG$R-o6ClNwti~nSHc4x$I8bFrwms)?J>JuOsJ7+h zbW8S%GWx?JIR`@Jh$BS`R9Z)t?p^B?15nONLC1sIqEVX?-2HHu;xihw1alS!P!86v9rnXPNqyd<8vK=e`47&KeI-UCfLfD<72fV->ec`N delta 5207 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 zoutput_flush_fn != NULL) - png_ptr->output_flush_fn(png_ptr); -} - # ifdef PNG_STDIO_SUPPORTED void PNGCBAPI png_default_flush(png_structp png_ptr) diff --git a/pngwrite.c b/pngwrite.c index f2fc4f3ea..ff1555361 100644 --- a/pngwrite.c +++ b/pngwrite.c @@ -487,7 +487,8 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) */ # ifdef PNG_WRITE_FLUSH_SUPPORTED # ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED - png_flush(png_ptr); + if (png_ptr->output_flush_fn != NULL) + png_ptr->output_flush_fn(png_ptr); # endif # endif } @@ -570,65 +571,6 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, } -/* Write a few rows of image data. If the image is interlaced, - * either you will have to write the 7 sub images, or, if you - * have called png_set_interlace_handling(), you will have to - * "write" the image seven times. - */ -void PNGAPI -png_write_rows(png_structrp png_ptr, png_bytepp row, - png_uint_32 num_rows) -{ - png_debug(1, "in png_write_rows"); - - if (png_ptr == NULL || row == NULL) - return; - - /* Loop through the rows */ - while (num_rows-- > 0) - png_write_row(png_ptr, *row++); -} - -/* Write the image. You only need to call this function once, even - * if you are writing an interlaced image. - */ -void PNGAPI -png_write_image(png_structrp png_ptr, png_bytepp image) -{ - int num_pass; /* pass variables */ - - if (png_ptr == NULL || image == NULL) - return; - - png_debug(1, "in png_write_image"); - -#ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* Initialize interlace handling. If image is not interlaced, - * this will set pass to 1 - */ - num_pass = png_set_interlace_handling(png_ptr); -#else - num_pass = 1; - - if (png_ptr->interlaced) - { - png_app_error(png_ptr, "no interlace support"); - return; - } -#endif - - /* Loop through passes */ - while (num_pass-- > 0) - { - png_bytepp rp = image; /* points to current row */ - png_uint_32 num_rows = png_ptr->height; - - /* Loop through image */ - while (num_rows-- > 0) - png_write_row(png_ptr, *rp++); - } -} - #if defined(PNG_WRITE_INTERLACING_SUPPORTED) ||\ defined(PNG_WRITE_TRANSFORMS_SUPPORTED) static void @@ -707,10 +649,10 @@ write_row_buffered(png_structrp png_ptr, } # endif /* WRITE_TRANSFORMS */ - /* Call png_write_filter_row to write this block of data, the test on + /* Call png_write_png_data to write this block of data, the test on * maxpixels says if this is the final block in the row. */ - png_write_filter_row(png_ptr, prev_pixels, pixel_buffer.buffer, x, + png_write_png_data(png_ptr, prev_pixels, pixel_buffer.buffer, x, max_pixels, row_info_flags); } } @@ -824,47 +766,7 @@ interlace_row_byte(png_const_structrp png_ptr, png_bytep dp, png_const_bytep sp, } #endif /* WRITE_INTERLACING */ -static void -write_row_unbuffered(png_structrp png_ptr, png_const_bytep row, - unsigned int row_info_flags) -{ - /* Split the row into blocks of the appropriate size: */ - const unsigned int input_depth = png_ptr->row_input_pixel_depth; - unsigned int max_pixels = png_max_pixel_block(png_ptr); - png_uint_32 max_bytes = max_pixels; - const unsigned int pass = png_ptr->pass; - const png_uint_32 width = png_ptr->interlaced == PNG_INTERLACE_NONE ? - png_ptr->width : PNG_PASS_COLS(png_ptr->width, pass); - png_uint_32 x; - png_byte prev_pixels[4*2*2]; /* 2 pixels up to 4 2-byte channels each */ - - /* max_pixels is at most 16 bits, input_depth is at most 64, so the product - * always fits in 32 bits: - */ - max_bytes *= input_depth; /* bits */ - debug(input_depth <= 64 && (max_bytes & 7U) == 0U); - max_bytes >>= 3; - - memset(prev_pixels, 0U, sizeof prev_pixels); - - for (x = 0U; x < width; x += max_pixels, row += max_bytes) - { - if (max_pixels > width - x) - { - max_bytes = width - x; - max_pixels = (unsigned int)/*SAFE*/max_bytes; - max_bytes = (max_bytes * input_depth + 7U) >> 3; - } - - debug((row_info_flags & png_row_end) == 0U); /* must be set here at end */ - if (x + max_pixels >= width) - row_info_flags |= png_row_end; - - png_write_filter_row(png_ptr, prev_pixels, row, x, max_pixels, - row_info_flags); - } -} - +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED static void write_row_core(png_structrp png_ptr, png_const_bytep row, unsigned int row_info_flags) @@ -880,7 +782,8 @@ write_row_core(png_structrp png_ptr, png_const_bytep row, /* If control reaches this point the intermediate buffer is not required and * the input data can be used unmodified. */ - write_row_unbuffered(png_ptr, row, row_info_flags); + png_write_png_rows(png_ptr, &row, 1U); + PNG_UNUSED(row_info_flags) } /* Write a single non-interlaced row. */ @@ -888,75 +791,53 @@ static void write_row_non_interlaced(png_structrp png_ptr, png_const_bytep row) { const png_uint_32 row_number = png_ptr->row_number+1U; - const int last_pass_row = row_number == png_ptr->height; - /* There is only one pass, so this is the last pass: */ - write_row_core(png_ptr, row, - (row_number == 1U ? png_pass_first_row : 0) | - (last_pass_row ? png_pass_last_row : 0) | - png_pass_last); + const unsigned int row_info_flags = + (row_number == 1U ? png_pass_first_row : 0) | + (row_number >= png_ptr->height ? png_pass_last_row : 0) | + png_pass_last; - if (!last_pass_row) - png_ptr->row_number = row_number; + debug(png_ptr->interlaced == PNG_INTERLACE_NONE); - else - { - png_ptr->row_number = 0U; - png_ptr->pass = 7U; - } + write_row_core(png_ptr, row, row_info_flags); } /* Write a single interlaced row. */ static void write_row_interlaced(png_structrp png_ptr, png_const_bytep row) { - /* row_number is the row in the pass. The app must only call png_write_row - * the correct number of times. 'pass' is set to 7U after the end. - */ const png_uint_32 row_number = png_ptr->row_number+1U; - unsigned int pass = png_ptr->pass; - const int last_pass_row = row_number == PNG_PASS_ROWS(png_ptr->height, pass); + const png_uint_32 height = png_ptr->height; + const unsigned int pass = png_ptr->pass; + const unsigned int row_info_flags = + (row_number == 1U ? png_pass_first_row : 0) | + (row_number == PNG_PASS_ROWS(height, pass) ? png_pass_last_row : 0) | + (pass == PNG_LAST_PASS(png_ptr->width, height) ? png_pass_last : 0); - write_row_core(png_ptr, row, - (row_number == 1U ? png_pass_first_row : 0) | - (last_pass_row ? png_pass_last_row : 0) | - (pass == PNG_LAST_PASS(png_ptr->width, png_ptr->height) ? - png_pass_last : 0)); +# ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Check that libpng is not doing the interlace: */ + debug(png_ptr->interlaced != PNG_INTERLACE_NONE && + !png_ptr->do_interlace); +# endif /* WRITE_INTERLACING */ - if (!last_pass_row) - png_ptr->row_number = row_number; - - else - { - png_ptr->row_number = 0U; - - do - ++pass; - while (pass < 7U && - !PNG_PASS_IN_IMAGE(png_ptr->width, png_ptr->height, pass)); - - png_ptr->pass = 0x7U & pass; - } + write_row_core(png_ptr, row, row_info_flags); } +#endif /* WRITE_TRANSFORMS */ #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Interlace a row then write it out. */ -static int +static void interlace_row(png_structrp png_ptr, png_const_bytep row) { - /* row_number is in the image, it may not be in the pass and, likewise, the - * pass may not exist. - */ + /* The row may not exist in the image (for this pass). */ const png_uint_32 row_number = png_ptr->row_number; /* in image */ const unsigned int pass = png_ptr->pass; - const int write_row = png_ptr->width > PNG_PASS_START_COL(pass) && - PNG_ROW_IN_INTERLACE_PASS(row_number, pass); - if (write_row) + if (png_ptr->width > PNG_PASS_START_COL(pass) && + PNG_ROW_IN_INTERLACE_PASS(row_number, pass)) { const unsigned int row_info_flags = - (row_number == PNG_PASS_START_ROW(pass) ? - png_pass_first_row : 0) | + (row_number == PNG_PASS_START_ROW(pass) ? png_pass_first_row : 0) | (PNG_LAST_PASS_ROW(row_number, pass, png_ptr->height) ? png_pass_last_row : 0) | (pass == PNG_LAST_PASS(png_ptr->width, png_ptr->height) ? @@ -991,79 +872,214 @@ interlace_row(png_structrp png_ptr, png_const_bytep row) interlace_row_byte, input_depth >> 3); break; } - } + } /* pass < 6 */ - else /* pass 6; no interlacing required */ + else /* pass 6: no interlacing required */ write_row_core(png_ptr, row, row_info_flags); } - if (row_number+1U < png_ptr->height) - png_ptr->row_number = row_number+1U; - else { - png_ptr->row_number = 0U; - png_ptr->pass = 0x7U & (pass+1U); - } + /* This code must advance row_number/pass itself; the row has been + * skipped. + */ + if (row_number+1U < png_ptr->height) + png_ptr->row_number = row_number+1U; - return write_row; + else + { + png_ptr->row_number = 0U; + png_ptr->pass = 0x7U & (pass+1U); + } + } } #endif /* WRITE_INTERLACING */ -/* Called by user to write a row of image data */ -void PNGAPI -png_write_row(png_structrp png_ptr, png_const_bytep row) +/* Bottleneck API to actually write a number of rows, only exists because the + * rows parameter to png_write_rows is wrong. + */ +static void +png_write_rows_internal(png_structrp png_ptr, png_const_bytep *rows, + png_uint_32 num_rows) { - if (png_ptr != NULL) + if (png_ptr != NULL && num_rows > 0U && rows != NULL) { - const unsigned int pass = png_ptr->pass; - const png_uint_32 row_number = png_ptr->row_number; - /* Unlike the read code initialization happens automatically: */ - if (row_number == 0 && pass == 0) - png_write_start_IDAT(png_ptr); /* doesn't change row/pass/width */ + if (png_ptr->row_number == 0U && png_ptr->pass == 0U) + { + png_init_row_info(png_ptr); - else if (pass == 7U) /* too many calls; write already ended */ +# ifdef PNG_WRITE_TRANSFORMS_SUPPORTED + /* If the app takes a png_info from a read operation and if the app has + * performed transforms on the data the png_info can contain IHDR + * information that cannot be represented in PNG. The code that writes + * the IHDR takes the color type from the png_info::format. The app + * adds transforms, before or after writing the IHDR, then the IHDR + * color_type stored in png_struct::color_type is used in + * png_init_row_info above to work out the actual row format. + * + * Prior to 1.7.0 this was not verified (there was no easy way to do + * so). Now we can check it here, however this is an: + * + * API CHANGE: in 1.7.0 an error may be flagged against bogus + * info_struct formats even though the app had removed them itself. + * It's just a warning at present. + * + * The test is that either the row_format produced by the write + * transforms exactly matches that in the original info_struct::format + * or that the info_struct::format was a simple mapping of the + * color_type that ended up in the IHDR: + */ + if (png_ptr->row_format != png_ptr->info_format && + PNG_FORMAT_FROM_COLOR_TYPE(png_ptr->color_type) != + png_ptr->info_format) + png_app_warning(png_ptr, "info_struct format does not match IHDR"); +# endif /* WRITE_TRANSFORMS */ + + /* Perform initialization required before IDATs are written. */ + png_write_start_IDAT(png_ptr); + } + + else if (png_ptr->pass >= 7U) /* too many calls; write already ended */ { debug(png_ptr->row_number == 0U); png_app_error(png_ptr, "Too many calls to png_write_row"); return; } - /* Make sure there is a row to write: */ - if (row == NULL) - { - png_app_error(png_ptr, "NULL row pointer to png_write_row"); - return; - } - - if (png_ptr->interlaced == PNG_INTERLACE_NONE) - write_row_non_interlaced(png_ptr, row); + /* The remainder of these tests detect internal errors in libpng */ + else if (png_ptr->interlaced == PNG_INTERLACE_NONE) + affirm(png_ptr->row_number < png_ptr->height && png_ptr->pass == 0U); # ifdef PNG_WRITE_INTERLACING_SUPPORTED - /* Optional: libpng does the interlacing, app passes every row of the - * image the required number of times. - */ - else if (png_ptr->do_interlace != 0U) - { - if (!interlace_row(png_ptr, row)) - return; /* row skipped; skip the write callback */ - } -# endif + else if (png_ptr->do_interlace) + affirm(png_ptr->row_number < png_ptr->height); +# endif /* WRITE_INTERLACING */ - else /* app does the interlacing */ - write_row_interlaced(png_ptr, row); + else /* app does interlace */ + affirm( + PNG_PASS_IN_IMAGE(png_ptr->width, png_ptr->height, png_ptr->pass) && + png_ptr->row_number < PNG_PASS_ROWS(png_ptr->height, png_ptr->pass) + ); - /* API CHANGE: 1.7.0: this is now called after png_struct::row_number and - * png_struct::pass have been updated and, at the end of the image, after - * the deflate stream has been closed. The order of the call with respect - * to the flush operation has also changed. The callback can't discover - * any of this unless it relies on the write callbacks to find the row - * data, and that was never predictable. + /* First handle rows that require buffering because of the need to + * interlace them or the need to perform write transforms. */ - if (png_ptr->write_row_fn != NULL) - (*(png_ptr->write_row_fn))(png_ptr, row_number, pass); - } /* png_ptr != NULL */ +# ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* libpng is doing the interlacing, but this only makes a difference to + * the first six passes (numbered, in libpng, 0..5); the seventh pass + * (numbered 6 by libpng) consists of complete image rows. + */ + if (png_ptr->do_interlace) while (num_rows > 0U && png_ptr->pass < 6) + interlace_row(png_ptr, *rows++), --num_rows; +# endif /* WRITE_INTERLACING */ + +# ifdef PNG_WRITE_TRANSFORMS_SUPPORTED + /* Transforms required however the row interlacing has already been + * handled and we have a complete (PNG) row. + */ + if (png_ptr->transform_list != NULL) + { + if (png_ptr->interlaced == PNG_INTERLACE_NONE) + while (num_rows > 0U) + write_row_non_interlaced(png_ptr, *rows++), --num_rows; + +# ifdef PNG_WRITE_INTERLACING_SUPPORTED + else if (png_ptr->do_interlace) + while (num_rows > 0U) + interlace_row(png_ptr, *rows++), --num_rows; +# endif /* WRITE_INTERLACING */ + + else /* app does the interlacing */ + while (num_rows > 0U) + write_row_interlaced(png_ptr, *rows++), --num_rows; + } +# endif /* WRITE_TRANSFORMS */ + + /* Finally handle any remaining rows that require no (libpng) interlace + * and no transforms. + */ + if (num_rows > 0U) + png_write_png_rows(png_ptr, rows, num_rows); + + /* Repeat the checks above, but allow for end-of-image. */ + if (png_ptr->pass < 7U) + { + if (png_ptr->interlaced == PNG_INTERLACE_NONE) + affirm(png_ptr->row_number < png_ptr->height && + png_ptr->pass == 0U); + +# ifdef PNG_WRITE_INTERLACING_SUPPORTED + else if (png_ptr->do_interlace) + affirm(png_ptr->row_number < png_ptr->height); +# endif /* WRITE_INTERLACING */ + + else /* app does interlace */ + affirm(PNG_PASS_IN_IMAGE(png_ptr->width, png_ptr->height, + png_ptr->pass) && + png_ptr->row_number < + PNG_PASS_ROWS(png_ptr->height, png_ptr->pass)); + } + } /* png_ptr, rows, num_rows all valid */ + + else if (png_ptr != NULL) + png_app_warning(png_ptr, "Missing rows to row write API"); +} + +/* ROW WRITE APIs */ +/* Called by user to write a single row of image data */ +void PNGAPI +png_write_row(png_structrp png_ptr, png_const_bytep row) +{ + png_debug(1, "in png_write_row"); + png_write_rows_internal(png_ptr, &row, 1U); +} + +/* Write a few rows of image data. If the image is interlaced, + * either you will have to write the 7 sub images, or, if you + * have called png_set_interlace_handling(), you will have to + * "write" the image seven times. + */ +void PNGAPI +png_write_rows(png_structrp png_ptr, png_bytepp rows, png_uint_32 num_rows) +{ + png_debug(1, "in png_write_rows"); + + if (png_ptr != NULL) + png_write_rows_internal(png_ptr, png_constcast(png_const_bytep*,rows), + num_rows); +} + +/* Write the image. You only need to call this function once, even + * if you are writing an interlaced image. + */ +void PNGAPI +png_write_image(png_structrp png_ptr, png_bytepp image) +{ + png_debug(1, "in png_write_image"); + + if (png_ptr != NULL) + { + int num_pass = 1; + + /* The image is always an non-interlaced image. To write it as interlaced + * interlace handling must be present: + */ + if (png_ptr->interlaced) + { +# ifdef PNG_WRITE_INTERLACING_SUPPORTED + num_pass = png_set_interlace_handling(png_ptr); +# else /* !WRITE_INTERLACING */ + /* There is no recovery because the IHDR has already been written. + */ + png_error(png_ptr, "No interlace support"); +# endif /* !WRITE_INTERLACING */ + } + + /* And write the whole thing, 7 times if interlacing it: */ + for (; num_pass > 0; --num_pass) + png_write_rows(png_ptr, image, png_ptr->height); + } } /* Free any memory used in png_ptr struct without freeing the struct itself. */ @@ -1074,10 +1090,6 @@ png_write_destroy(png_structrp png_ptr) png_deflate_destroy(png_ptr); -#ifdef PNG_WRITE_FILTER_SUPPORTED - png_free(png_ptr, png_ptr->row_buffer); - png_ptr->row_buffer = NULL; -#endif /* WRITE_FILTER */ #ifdef PNG_TRANSFORM_MECH_SUPPORTED png_transform_free(png_ptr, &png_ptr->transform_list); #endif diff --git a/pngwutil.c b/pngwutil.c index a79e86cf7..f7c650d3f 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -198,25 +198,129 @@ png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string, length); } -/* This is used below to find the size of an image to pass to png_deflate_claim, - * so it only needs to be accurate if the size is less than 16384 bytes (the - * point at which a lower LZ window size can be used.) +static png_alloc_size_t +png_write_row_buffer_size(png_const_structrp png_ptr) + /* Returns the width of the widest pass in the first row of an interlaced + * image. Passes in the first row are: 0.5.3.5.1.5.3.5, so the widest row is + * normally the one from pass 5. The only exception is if the image is only + * one pixel wide, so: + */ +#define PNG_FIRST_ROW_MAX_WIDTH(w) (w > 1U ? PNG_PASS_COLS(w, 5U) : 1U) + + /* For interlaced images the count of pixels is rounded up to a the number of + * pixels in the first pass (numbered 0). This ensures that passes before + * the last can be packed in the buffer without overflow. + */ +{ + png_alloc_size_t w; + + /* If the image is interlaced adjust 'w' for the interlacing: */ + if (png_ptr->interlaced != PNG_INTERLACE_NONE) + { + /* Take advantage of the fact that 1-row interlaced PNGs require half the + * normal row width: + */ + if (png_ptr->height == 1U) /* no pass 6 */ + w = PNG_FIRST_ROW_MAX_WIDTH(png_ptr->width); + + /* Otherwise round up to a multiple of 8. This may waste a few (less + * than 8) bytes for PNGs with a height less than 57 but this hardly + * matters. + */ + else + w = (png_ptr->width + 7U) & ~7U; + } + + else + w = png_ptr->width; + + /* The rounding above may leave 'w' exactly 2^31 */ + debug(w <= 0x80000000U); + + switch (png_ptr->row_output_pixel_depth) + { + /* This would happen if the function is called before png_write_IHDR. */ + default: NOT_REACHED; return 0; + + case 1: w = (w+7) >> 3; break; + case 2: w = (w+3) >> 2; break; + case 4: w = (w+1) >> 1; break; + case 8: break; + case 16: w <<= 1; break; /* overflow: w is set to 0, which is OK */ + + /* For the remaining cases the answer is w*bytes; where bytes is 3,4,6 + * or 8. This may overflow 32 bits. There is no way to compute the + * result on an arbitrary platform, so test the maximum of a (size_t) + * against w for each possible byte depth: + */ +# define CASE(b)\ + case b*8:\ + if (w <= (PNG_SIZE_MAX/b)/*compile-time constant*/)\ + return w * b;\ + return 0; + + CASE(3) + CASE(4) + CASE(6) + CASE(8) + +# undef CASE + } + + /* This is the low bit depth case. The following can never be false on + * systems with a 32-bit or greater size_t: + */ + if (w <= PNG_SIZE_MAX) + return w; + + return 0U; +} + +/* This is used below to find the size of an image to pass to png_deflate_claim. + * It returns 0xFFFFFFFFU for images whose size would overflow a 32-bit integer + * or have rows which cannot be allocated. */ static png_alloc_size_t -png_image_size(png_const_structrp png_ptr) +png_image_size_checked(png_const_structrp png_ptr) { - /* Only return sizes up to the maximum of a png_uint_32; do this by limiting - * the width and height used to 15 bits. + /* The size returned here is limited to PNG_SIZE_MAX, if the size would + * exceed that (or is close to exceeding that) 0 is returned. See below for + * a variant that limits the size of 0xFFFFFFFFU. */ const png_uint_32 h = png_ptr->height; - const png_uint_32 w = png_ptr->width; - const unsigned int pd = PNG_PIXEL_DEPTH(*png_ptr); - png_alloc_size_t rowbytes = PNG_ROWBYTES(pd, w); + const png_alloc_size_t rowbytes = png_write_row_buffer_size(png_ptr); - if (rowbytes < 32768 && h < 32768) + /* NON-INTERLACED: (1+rowbytes) * h + * INTERLACED: Each pixel is transmitted exactly once, so the size is + * (rowbytes * h) + the count of filter bytes. Each complete + * block of 8 image rows generates at most 15 output rows + * (less for narrow images), so the filter byte count is + * at most (15*h/8)+14. Because the original rows are split + * extra byte passing may be introduced. Account for this by + * allowing an extra 1 byte per output row; that's two bytes + * including the filer byte. + * + * So: + * NON-INTERLACED: (rowbytes * h) + h + * INTERLACED: < (rowbytes * h) + 2*(15 * h/8) + 2*15 + * + * Hence: + */ + if (rowbytes != 0) { - if (png_ptr->interlaced != 0) + if (png_ptr->interlaced == PNG_INTERLACE_NONE) { + const png_alloc_size_t limit = PNG_SIZE_MAX / h; + + /* On 16-bit systems the above might be 0, so: */ + if (rowbytes width; + /* Interlacing makes the image larger because of the replication of * both the filter byte and the padding to a byte boundary. */ @@ -225,21 +329,54 @@ png_image_size(png_const_structrp png_ptr) for (cb_base=0, pass=0; pass 0) - cb_base += (PNG_ROWBYTES(pd, pw)+1) * PNG_PASS_ROWS(h, pass); + if (pass_w > 0) + { + const png_uint_32 pass_h = PNG_PASS_ROWS(h, pass); + + if (pass_h > 0) + { + /* This is the number of bytes available for each row of this + * pass: + */ + const png_alloc_size_t limit = (PNG_SIZE_MAX - cb_base)/pass_h; + /* This cannot overflow because if it did rowbytes would + * have been 0 above. + */ + const png_alloc_size_t pass_bytes = + PNG_ROWBYTES(png_ptr->row_output_pixel_depth, pass_w); + + if (pass_bytes 0U && size < 0xffffffffU) + return size; + + return 0xffffffffU; } /* Release memory used by the deflate mechanism */ @@ -657,6 +794,10 @@ png_compress( case Z_BUF_ERROR: /* This means that we are flushing all the output; expect * avail_out and input_len to be 0. + * + * NOTE: if png_compress is called with input_len 0 and flush set + * to Z_NO_FLUSH this affirm will fire because zlib will have no + * work to do. */ affirm(input_len == 0U && pz->zs.avail_out == extra); /* Allocate another buffer */ @@ -682,32 +823,71 @@ png_compress( typedef struct png_zlib_state { png_zlib_compress s; /* Primary compression state */ - -# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED - /* The 'methodical' method uses up to PNG_FILTER_VALUE_LAST of these to - * test each possible filter: - */ - png_zlib_compress filter[PNG_FILTER_VALUE_LAST]; -# endif /* SELECT_FILTER_METHODICALLY */ - png_compression_bufferp stash; /* Unused compression buffers */ -# ifdef PNG_WRITE_FLUSH_SUPPORTED - png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */ - png_uint_32 flush_rows; /* number of rows written since last flush */ -# endif /* WRITE_FLUSH */ +# define ps_png_ptr(ps) png_upcast(png_const_structrp, (ps)->s.zs.opaque) + /* A png_ptr, used below in functions that only have a png_zlib_state. + * NOTE: the png_zlib_compress must have been initialized! + */ -#ifdef PNG_WRITE_FILTER_SUPPORTED - unsigned int filter_mask :8; /* mask of filters to consider on write */ - unsigned int filters :8; /* Filters for current row */ - unsigned int filter_oom :1; /* ran out of memory */ -#endif /* WRITE_FILTER */ + png_uint_32 zlib_max_pixels; + /* Maximum number of pixels that zlib can handle at once; the lesser of + * the PNG maximum and the maximum that will fit in (uInt)-1 bytes. This + * number of pixels may not be byte aligned. + */ + png_uint_32 zlib_max_aligned_pixels; + /* The maximum number of pixels that zlib can handle while maintaining a + * buffer byte alignment of PNG_ROW_BUFFER_BYTE_ALIGN; <= the previous + * value. + */ + +# ifdef PNG_WRITE_FILTER_SUPPORTED + /* During write libpng needs the previous row when writing a new row with + * up, avg or paeth and one or more image rows when performing filter + * selection. So if performing filter selection typically two or more + * rows are required while if no filter selection is to be done only the + * previous row pointer is required. + */ + png_bytep previous_write_row; + png_alloc_size_t write_row_size; /* Actual size of the buffers */ + png_alloc_size_t write_buffer_limit; /* Limit on total allocation */ + +# ifdef PNG_SELECT_FILTER_SUPPORTED + png_bytep *saved_rows; /* Rows saved by libpng */ + png_bytep saved_filters; /* Filters for those rows */ + png_alloc_size_t saved_offset; /* First saved bytes in: */ + png_uint_32 saved_first; /* First buffer in use */ + png_uint_32 maximum_saved_rows; /* Size of the above buffers */ + png_uint_32 current_saved_rows; +# endif /* SELECT_FILTER */ + + png_uint_32 save_row_count; /* Total number to be buffered */ +# define SAVE_ROW_COUNT_UNSET 0xFFFFFFFFU + + unsigned int row_buffer_max_pixels; + /* The maximum number of pixels that can fit in PNG_ROW_BUFFER_SIZE + * bytes; not necessary a whole number of bytes. + */ + unsigned int row_buffer_max_aligned_pixels; + /* The maximum number of pixels that can fit in PNG_ROW_BUFFER_SIZE + * bytes while maintaining PNG_ROW_BUFFER_BYTE_ALIGN alignment. + */ + + unsigned int filter_mask :8; /* mask of filters to consider on NEXT row */ + unsigned int filters :8; /* Filters for current row */ + unsigned int do_select :1; /* Set if filter selection should be done */ +# endif /* WRITE_FILTER */ /* Compression settings: see below for how these are encoded. */ png_uint_32 pz_IDAT; /* Settings for the image */ png_uint_32 pz_iCCP; /* Settings for iCCP chunks */ png_uint_32 pz_text; /* Settings for text chunks */ png_uint_32 pz_current; /* Last set settings */ + +# ifdef PNG_WRITE_FLUSH_SUPPORTED + png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */ + png_uint_32 flush_rows; /* number of rows written since last flush */ +# endif /* WRITE_FLUSH */ } png_zlib_state; /* Create the zlib state: */ @@ -724,17 +904,10 @@ png_create_zlib_state(png_structrp png_ptr) png_ptr->zlib_state = ps; png_zlib_compress_init(png_ptr, &ps->s); -# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED - { - unsigned int i; - - for (i=0; ifilter[i].zs.opaque = NULL; - } -# endif /* SELECT_FILTER_METHODICALLY */ - - ps->stash = NULL; - +# ifdef PNG_WRITE_FILTER_SUPPORTED + ps->write_buffer_limit = PNG_COMPRESSION_BUFFER_LIMIT; + ps->save_row_count = SAVE_ROW_COUNT_UNSET; +# endif /* WRITE_FILTER */ # ifdef PNG_WRITE_FLUSH_SUPPORTED /* Set this to prevent flushing by making it larger than the number * of rows in the largest interlaced PNG; PNG_UINT_31_MAX times @@ -750,22 +923,43 @@ png_create_zlib_state(png_structrp png_ptr) static void /* PRIVATE */ png_deflate_release(png_structrp png_ptr, png_zlib_statep ps, int check) { - /* This must happen before ps->s is destroyed below because the structures - * may be shared: - */ -# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED - unsigned int i; - - /* Note that png_zlib_compress_destroy checks the 'opaque' pointer and - * does nothing if it is NULL. - */ - for (i=0U; ifilter[i].zs.state != ps->s.zs.state) +# ifdef PNG_WRITE_FILTER_SUPPORTED + /* Free any mode-specific data that is owned here: */ +# ifdef PNG_SELECT_FILTER_SUPPORTED + if (ps->saved_rows != NULL) { - png_zlib_compress_destroy(&ps->filter[i], 0/*check*/); - ps->filter[i].zs.opaque = NULL; + /* If the saved row array was allocated the previous row pointer was + * *not* allocated. Free any saved row memory: + */ + png_bytep *save = ps->saved_rows; + png_uint_32 i = ps->maximum_saved_rows; + + ps->saved_rows = NULL; + + while (i > 0) + png_free(png_ptr, save[--i]); + + png_free(png_ptr, save); + + if (ps->saved_filters != NULL) + { + png_bytep p = ps->saved_filters; + ps->saved_filters = NULL; + png_free(png_ptr, p); + } } -# endif /* SELECT_FILTER_METHODICALLY */ + + else +# else /* !SELECT_FILTER */ + if (ps->previous_write_row != NULL) + { + /* No saved rows, so the previous row buffer was allocated: */ + png_bytep p = ps->previous_write_row; + ps->previous_write_row = NULL; + png_free(png_ptr, p); + } +# endif /* !SELECT_FILTER */ +# endif /* WRITE_FILTER */ /* The main z_stream opaque pointer needs to remain set to png_ptr; it is * only set once. @@ -789,13 +983,15 @@ png_deflate_destroy(png_structrp png_ptr) /* Compression settings. * - * These are stored packed into 16 bits to make comparison with the current - * setting quick. The packing method uses four bits for each setting and - * reserves '0' for unset. + * These are stored packed into a png_uint_32 to make comparison with the + * current setting quick. The packing method uses four bits for each setting + * and reserves '0' for unset. * * ps__base: The lowest valid value (encoded as 1). - * ps__max: The highest valie value. + * ps__max: The highest valid value. * ps__pos: The position in the range 0..3 (shift of 0..12). + * + * The low 16 bits are the zlib compression parameters: */ #define pz_level_base (-1) #define pz_level_max 9 @@ -809,6 +1005,11 @@ png_deflate_destroy(png_structrp png_ptr) #define pz_strategy_base 0 #define pz_strategy_max 4 #define pz_strategy_pos 3 +#define pz_zlib_bits 0xFFFFU +/* Anything below this is not used directly by zlib: */ +#define pz_png_level_base 0 /* libpng equivalent of zlib level */ +#define pz_png_level_max 10 +#define pz_png_level_pos 4 #define pz_offset(name) (pz_ ## name ## _base - 1) /* setting_value == pz_offset(setting)+encoded_value */ @@ -824,8 +1025,8 @@ png_deflate_destroy(png_structrp png_ptr) #define pz_value(name,x) (pz_bits(name,x)+pz_offset(name)) /* Assignments: */ -#define pz_clear(name,x) ((x)&~(0xFU< 256U && pz_value(windowBits, settings) == 8) + if (windowBits == 8 && data_size > 256U && strategy != Z_HUFFMAN_ONLY && + zlib_level != Z_NO_COMPRESSION) settings = pz_change(windowBits, settings, 9); - if (!pz_isset(level, settings)) - { - int setting; - - switch (pz_value(strategy, settings)) - { - case Z_HUFFMAN_ONLY: - case Z_RLE: - /* The 'level' doesn't make any significant difference to the - * compression with these strategies; in a test set of about 3GByte - * of PNG files the total compressed size changed under 20 bytes - * with libpng 1.6! - */ - setting = 1; - break; - - default: /* Z_FIXED, Z_FILTERED, Z_DEFAULT_STRATEGY */ - /* Everything that uses the window seems to show rapidly diminishing - * returns above level 6 (at least with libpng 1.6). - * Z_DEFAULT_COMPRESSION is, in fact, level 6 so Mark seems to - * concur. - */ - setting = default_level; - break; - } - - settings |= pz_encode(level, setting); - } - /* For memLevel this just increases the memory used but can help with the * Huffman code generation even to level 9 (the maximum), so just set the - * max: + * max. This affects memory used, not (apparently) compression speed so apps + * with limited memory requirements may need to override it. */ if (!pz_isset(memLevel, settings)) settings |= pz_encode(memLevel, MAX_MEM_LEVEL/*from zconf.h*/); @@ -1001,30 +1313,25 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, switch (owner) { case png_IDAT: - settings = pz_default_settings(ps->pz_IDAT, - PNG_Z_DEFAULT_STRATEGY, PNG_Z_DEFAULT_COMPRESSION, data_size); + settings = ps->pz_IDAT; break; case png_iCCP: - /* Use the IDAT strategy by default; iCCP chunks are not text and - * are therefore fundamentally different in compression. - */ - settings = pz_default_settings(ps->pz_iCCP, - PNG_Z_DEFAULT_STRATEGY, PNG_Z_DEFAULT_COMPRESSION, data_size); + settings = ps->pz_iCCP; break; default: /* text chunk */ - settings = pz_default_settings(ps->pz_text, - PNG_TEXT_Z_DEFAULT_STRATEGY, PNG_TEXT_Z_DEFAULT_COMPRESSION, - data_size); + settings = ps->pz_text; break; } + settings = pz_default_settings(settings, owner, data_size); + /* Check against the previous initialized values, if any. The relevant * settings are in the low 16 bits. */ if (ps->s.zs.state != NULL && - ((settings ^ ps->pz_current) & 0xFFFFU) != 0U) + ((settings ^ ps->pz_current) & pz_zlib_bits) != 0U) png_deflateEnd(png_ptr, &ps->s.zs, 0/*check*/); /* For safety clear out the input and output pointers (currently zlib @@ -1054,12 +1361,11 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, ret = deflateReset(&ps->s.zs); else - { - ps->pz_current = settings; ret = deflateInit2(&ps->s.zs, pz_value(level, settings), Z_DEFLATED, pz_value(windowBits, settings), pz_value(memLevel, settings), pz_value(strategy, settings)); - } + + ps->pz_current = settings; /* The return code is from either deflateReset or deflateInit2; they have * pretty much the same set of error codes. @@ -2299,55 +2605,6 @@ png_write_tIME(png_structrp png_ptr, png_const_timep mod_time) } #endif -/* These two #defines simplify writing code that depends on one or the other of - * the options being both supported and on: - */ -#ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED -# define methodical_option\ - ((png_ptr->options >> PNG_SELECT_FILTER_METHODICALLY) & 3U) -#else -# define methodical_option PNG_OPTION_OFF -#endif - -#ifdef PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED -# define heuristic_option\ - ((png_ptr->options >> PNG_SELECT_FILTER_HEURISTICALLY) & 3U) -#else /* !SELECT_FILTER_HEURISTICALLY */ -# define heuristic_option PNG_OPTION_OFF -#endif /* !SELECT_FILTER_HEURISTICALLY */ - -/* Handle the writing of IDAT chunks from the png_zlib_state in - * png_ptr->zlib_state. - */ -static void -png_start_IDAT(png_structrp png_ptr) -{ - png_zlib_statep ps = png_ptr->zlib_state; - - affirm(ps != NULL); - -# ifdef PNG_WRITE_FILTER_SUPPORTED - /* Default both filter_mask and zlib_strategy here, now that png_ptr has - * all the IHDR fields set. - */ - if (ps->filter_mask == PNG_NO_FILTERS/*unset*/) - { - /* If there is no filter selection algorithm enabled then the only - * option is PNG_FILTER_NONE. - */ - if (methodical_option != PNG_OPTION_ON && - heuristic_option == PNG_OPTION_OFF) - ps->filter_mask = PNG_FILTER_NONE; - - else - ps->filter_mask = PNG_ALL_FILTERS; - } -# endif /* WRITE_FILTER */ - - /* This always succeeds or does a png_error: */ - png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)); -} - static void png_end_IDAT(png_structrp png_ptr) { @@ -2509,9 +2766,13 @@ png_write_IDAT(png_structrp png_ptr, int flush) * stash (only used for IDAT compression.) */ static int -png_compress_IDAT_data(png_const_structrp png_ptr, png_zlib_statep ps, +png_compress_IDAT_data(png_structrp png_ptr, png_zlib_statep ps, png_zlib_compressp pz, png_const_voidp input, uInt input_len, int flush) { + /* Delay initialize the z_stream. */ + if (png_ptr->zowner != png_IDAT) + png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)); + affirm(png_ptr->zowner == png_IDAT && pz->end != NULL && *pz->end == NULL); /* z_stream::{next,avail}_out are set by png_compress to point into the @@ -2546,7 +2807,7 @@ png_compress_IDAT_data(png_const_structrp png_ptr, png_zlib_statep ps, } /* Compress some image data using the main png_zlib_compress. Write the result - * out if there is sufficient data. png_start_IDAT must have been called. + * out if there is sufficient data. */ static void png_compress_IDAT(png_structrp png_ptr, png_const_voidp input, uInt input_len, @@ -2569,6 +2830,107 @@ png_compress_IDAT(png_structrp png_ptr, png_const_voidp input, uInt input_len, } } +/* This is called at the end of every row to handle the required callbacks and + * advance png_struct::row_number and png_struct::pass. + */ +static void +png_write_end_row(png_structrp png_ptr, int flush) +{ + png_uint_32 row_number = png_ptr->row_number; + unsigned int pass = png_ptr->pass; + + debug(pass < 7U); + implies(flush == Z_FINISH, png_ptr->zowner == 0U); + + /* API NOTE: the write callback is made before any changes to the row number + * or pass however, in 1.7.0, the zlib stream can be closed before the + * callback is made (this is new). The application flush function happens + * afterward as was the case before. In 1.7.0 this is solely determined by + * the order of the code that follows. + */ + if (png_ptr->write_row_fn != NULL) + png_ptr->write_row_fn(png_ptr, row_number, pass); + +# ifdef PNG_WRITE_FLUSH_SUPPORTED + if (flush == Z_SYNC_FLUSH) + { + if (png_ptr->output_flush_fn != NULL) + png_ptr->output_flush_fn(png_ptr); + png_ptr->zlib_state->flush_rows = 0U; + } +# else /* !WRITE_FLUSH */ + PNG_UNUSED(flush) +# endif /* !WRITE_FLUSH */ + + /* Finally advance to the next row/pass: */ + if (png_ptr->interlaced == PNG_INTERLACE_NONE) + { + debug(row_number < png_ptr->height); + + if (++row_number == png_ptr->height) /* last row */ + { + row_number = 0U; + debug(flush == Z_FINISH); + png_ptr->pass = 7U; + } + } + +# ifdef PNG_WRITE_INTERLACING_SUPPORTED + else /* interlaced */ if (png_ptr->do_interlace) + { + /* This gets called only for rows that are processed; i.e. rows that + * are in the pass of a pass which is itself in the output. + */ + debug(row_number < png_ptr->height && + PNG_PASS_IN_IMAGE(png_ptr->width, png_ptr->height, pass) && + pass <= PNG_LAST_PASS(png_ptr->width, png_ptr->height) && + PNG_ROW_IN_INTERLACE_PASS(row_number, pass)); + + /* NOTE: the last row of the original image may not be in the pass, in + * this case the code which skipped the row must do the increment + * below! See 'interlace_row' in pngwrite.c and the code in + * write_png_rows below. + * + * In that case an earlier row will be the last one in the pass (if the + * pass is in the output), check this here: + */ + implies(pass == PNG_LAST_PASS(png_ptr->width, png_ptr->height) && + PNG_LAST_PASS_ROW(row_number, pass, png_ptr->height), + flush == Z_FINISH); + + if (++row_number == png_ptr->height) /* last row */ + { + row_number = 0U; + png_ptr->pass = 0x7U & ++pass; + } + } +# endif /* WRITE_INTERLACING */ + + else /* application does interlace */ + { + implies(png_ptr->height == 1U, pass != 6U); + debug(PNG_PASS_IN_IMAGE(png_ptr->width, png_ptr->height, pass) && + row_number < PNG_PASS_ROWS(png_ptr->height, pass)); + + if (++row_number == PNG_PASS_ROWS(png_ptr->height, pass)) + { + /* last row in this pass, next one may be empty. */ + row_number = 0U; + + do + ++pass; + while (pass < 7U && + !PNG_PASS_IN_IMAGE(png_ptr->width, png_ptr->height, pass)); + + implies(png_ptr->height == 1U, pass != 6U); + implies(pass == 7U, flush == Z_FINISH); + png_ptr->pass = 0x7U & pass; + } + } + + png_ptr->row_number = row_number; +} + /* This returns the zlib compression state for APIs that may be called before * the first call to png_write_row (so when the state might not exist). It * performs initialization as required. @@ -2622,11 +2984,10 @@ png_write_flush(png_structrp png_ptr) { png_debug(1, "in png_write_flush"); - /* Before the start of the IDAT and after the end of the image zowner will be - * something other than png_IDAT: + /* Force a flush at the end of the current row by setting 'flush_rows' to the + * maximum: */ - if (png_ptr != NULL && png_ptr->zlib_state != NULL && - png_ptr->zowner == png_IDAT) + if (png_ptr != NULL && png_ptr->zlib_state != NULL) png_ptr->zlib_state->flush_rows = 0xEFFFFFFF; } @@ -2638,7 +2999,7 @@ row_flush(png_zlib_statep ps, unsigned int row_info_flags) return Z_FINISH; else if ((row_info_flags & png_row_end) != 0 && - ps->flush_rows >= ps->flush_dist) + ++ps->flush_rows >= ps->flush_dist) return Z_SYNC_FLUSH; else @@ -2847,6 +3208,26 @@ filter_block(png_const_bytep prev_row, png_bytep prev_pixels, unfiltered_row, prev_row, prev_pixels); } +#if defined(PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED) +static void +multi_filter_row(png_const_bytep prev_row, png_bytep prev_pixels, + png_const_bytep unfiltered_row, unsigned int row_bits, unsigned int bpp, + unsigned int filters_to_try, + png_byte filtered_row[4][PNG_ROW_BUFFER_SIZE]) +{ + /* filters_to_try identifies multiple filters. */ + filter_block(prev_row, prev_pixels, unfiltered_row, row_bits, bpp, + (filters_to_try & PNG_FILTER_SUB) != 0U ? + filtered_row[PNG_FILTER_VALUE_SUB-1U] : NULL, + (filters_to_try & PNG_FILTER_UP) != 0U ? + filtered_row[PNG_FILTER_VALUE_UP-1U] : NULL, + (filters_to_try & PNG_FILTER_AVG) != 0U ? + filtered_row[PNG_FILTER_VALUE_AVG-1U] : NULL, + (filters_to_try & PNG_FILTER_PAETH) != 0U ? + filtered_row[PNG_FILTER_VALUE_PAETH-1U] : NULL); +} +#endif /* SELECT_FILTER_HEURISTICALLY */ + static void filter_row(png_structrp png_ptr, png_const_bytep prev_row, png_bytep prev_pixels, png_const_bytep unfiltered_row, @@ -2872,6 +3253,229 @@ filter_row(png_structrp png_ptr, png_const_bytep prev_row, } #ifdef PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED +static unsigned int +fls(size_t x) + /* As ffs but find the last set bit; the most significant */ +{ + unsigned int result = 0U; + unsigned int shift = + (PNG_SIZE_MAX > 0xFFFFFFFFU ? 32U : (PNG_SIZE_MAX > 0xFFFFU ? 16U : 8U)); + size_t test = PNG_SIZE_MAX; + + do + { + if (x & (test << shift)) result += shift, x >>= shift; + shift >>= 1; + } + while (shift); + + /* Returns 0 for both 1U and 0U. */ + return result; +} + +static unsigned int +log2_metric(size_t x) +{ + /* Return an approximation to log2(x). Since a Huffman code necessarily uses + * a whole number of bits for the code for each symbol this is very + * approximate; it uses the first two bits after the most significant to + * approximate the first two fractional bits of the log2. + */ + const unsigned int result = fls(x); + + switch (result) + { + default: x >>= result-2U; break; + case 2U: break; + case 1U: x <<= 1; break; + case 0U: return 0U; /* for x == 0 and x == 1 */ + } + + return result * 4U + (unsigned int)/*SAFE*/(x & 0x3U); +} + +static png_alloc_size_t +huffman_metric(png_byte prefix, png_const_bytep data, size_t length) + /* Given a buffer data[length] return an estimate of the length in bits of + * the same byte sequence when the bytes are coded using Huffman codes. The + * estimate is really the length in bits of the corresponding arithmetic + * code, but this is likely to be a good enough metric and it is fast to + * calculate. + */ +{ + unsigned int number_of_symbols; /* distinct symbols */ + size_t count[256]; + + /* Build a symbol count array */ + memset(count, 0, sizeof count); + count[prefix] = 1U; /* the filter byte */ + number_of_symbols = 1U; + { + size_t i; + + for (i=0U; i < length; ++i) + if (++count[data[i]] == 1U) /* a new symbol */ + ++number_of_symbols; + } + + ++length; /* for the prefix */ + + /* Estimate the number of bits used to code each symbol optimally: + * + * log2(length/count[symbol]) + * + * (The arithmetic code length, I believe, but that is based on my own work + * so it could quite easily be wrong. JB 20160202). + * + * So ideally: + * + * log2(length) - log2(count[symbol]) + * + * Although any log base is fine for the metric. pngrtran.c has a fast and + * accurate integer log2 implementation, but that is overkill here. Instead + * the caller passes in a shift (based on log2(length)), this is applied to + * the count (which must be <= length) and the per-symbol metric is looked up + * in a fixed table. + * + * The deflate (RFC1951) coding used in the zlib (RFC1950) format has a + * Huffman code length limit of 15, so any symbol must occupy at least + * 1/32768 of the code space. Zlib also shows some unexpected behavior with + * window size increases; data compression can decrease, leading me (JB + * 20160202) to hypothesise that the addition of extra, infrequently used, + * zlib length codes damages the overall compression by reducing the + * efficiency of the Huffman coding. + * + * This shortens the code for those symbols (to 15 bits) at the cost of + * reducing the code space for the remainder of the symbols by 1/32768 for + * each such symbol. + * + * First bin by the above expression, as returned by the log2_metric + * function. This gives a .2-bit fractional number. Limit the value to 14.5 + * for the above reason; place anything at or above 14.5 into the last bin. + */ + { + unsigned int i, step; + const size_t low_count = length / 23170U; /* 2^14.5 */ + const unsigned int l2_length = log2_metric(length); + size_t weight; + unsigned int distinct_suffix_count[64]; + /* The number of distinct suffices held in this bin. */ + size_t total_count_in_data[64]; + /* The total number of instances of those distinct suffices. */ + size_t bits_used[64]; + /* The bits used so far to encode the suffixes in the bin. */ + + memset(distinct_suffix_count, 0U, sizeof distinct_suffix_count); + memset(total_count_in_data, 0U, sizeof total_count_in_data); + + for (i=0; i<256; ++i) + { + size_t c = count[i]; + + if (c > 0U) + { + const unsigned int symbol_weight = + c > low_count ? l2_length - log2_metric(c) : 63U; + + ++distinct_suffix_count[symbol_weight]; + total_count_in_data[symbol_weight] += c; + } + } + + /* Work backward through the bins distributing the suffices between code + * lengths. This approach reflects the Huffman coding method of + * allocating the lowest count first but without the need to sort the + * symbols by count or, indeed, remember the symbols. It is necessarily + * approximate as a result. + */ + memset(bits_used, 0U, sizeof bits_used); + + for (i=63U, step=4U; i >= 2U; --i) + { + unsigned int suffix_count = distinct_suffix_count[i]; + size_t data_count = total_count_in_data[i]; + + /* Encode these suffices with 1 bit to divide the bin into two equal + * halves with twice the data count; there may be an odd suffix, + * this is promoted to the next bin. + */ + if ((suffix_count & 1U) != 0U) + { + size_t remainder = data_count / suffix_count; + + ++distinct_suffix_count[i-1U]; + total_count_in_data[i-1U] += remainder; + --suffix_count; + data_count -= remainder; + } + + distinct_suffix_count[i-step] = suffix_count >> 1; + total_count_in_data[i-step] += data_count; + bits_used[i-step] += data_count + bits_used[i]; + + /* This causes bins 3 and 2 to push into bins 1 and 0 respectively. */ + if (i == 4U) + step = 2U; + } + + { + unsigned int suffix_count = distinct_suffix_count[0]; + + weight = bits_used[0]; + + /* There may only be one bin left, check: */ + if (distinct_suffix_count[1] > 0) + { + suffix_count += distinct_suffix_count[1]; + weight += bits_used[1]; + } + + /* We still have to encode suffix_count separate suffices: */ + if (suffix_count > 1) + { + unsigned int bits = fls(suffix_count); + + if ((suffix_count & ~(1U<filter[i].zs.opaque != NULL) /* else not initialized */ - { - /* First put the buffer list back into the cache, when this function is - * called the list should be correctly terminated at *end. - */ - { - png_compression_bufferp list = ps->filter[i].list; - - if (list != NULL) - { - ps->filter[i].list = NULL; - - /* Return the list to the stash. */ - affirm(ps->filter[i].end != NULL); - - /* In the normal case 'end' is the end of this list and it is - * pre-pended to the cache. In the error case (png_error during a - * deflate operation) the list will be the entire stash and the - * stash will be NULL. - * - * If both pointers are non-NULL clean up by making the 'end' - * pointer NULL (freeing anything it points to). This is - * unexpected. - */ - if (ps->stash != NULL) - { - debug(*ps->filter[i].end == NULL); - /* Clean up on error: */ - png_free_compression_buffer(png_ptr, ps->filter[i].end); - *ps->filter[i].end = ps->stash; - } - - ps->stash = list; - } - - ps->filter[i].end = &ps->filter[i].list; /* safety */ - } - - /* Now use the standard 'destroy' function to handle the z_stream; the - * list has already been made NULL above. If the structure is sharing - * state with the main compress structure do not free it! - */ - if (ps->filter[i].zs.state != ps->s.zs.state) - png_zlib_compress_destroy(&ps->filter[i], 0/*check*/); - - /* Then this indicates that the structure is not in use: */ - ps->filter[i].zs.opaque = NULL; - } - - else - debug(ps->filter[i].list == NULL); -} - -static int /* success */ -png_zlib_filter_compress(png_structrp png_ptr, png_zlib_statep ps, png_byte i, - png_const_voidp input, uInt input_len, int flush) -{ - png_zlib_compressp pz = &ps->filter[i]; - int ret = png_compress_IDAT_data(png_ptr, ps, pz, input, input_len, flush); - - if (ret == Z_OK || ret == Z_STREAM_END) - return 1; /* success */ - - else - { - /* If ret is not Z_OK then this stream gets aborted, this is recoverable - * so long as this is not the only stream left. There are only two likely - * causes of failure; an internal libpng bug or out-of-memory. Given an - * assumption of infalibility this means that the app is out of memory and - * it makes sense to release as much as possible. Note that it is - * conceivable that OOM may cause an error other than Z_MEM_ERROR, though - * this is unlikely. - */ - png_zstream_error(&pz->zs, ret); - png_warning(png_ptr, pz->zs.msg); - png_zlib_filter_release(png_ptr, ps, i); - return 0; /* failure */ - } -} - -static int /* success */ -png_zlib_filter_init(png_structrp png_ptr, png_zlib_statep ps, png_byte i, - int copy) -{ - png_zlib_compressp pz = &ps->filter[i]; - - /* Make sure that we don't overwrite previously allocated stuff: */ - debug(pz->zs.opaque == NULL && pz->list == NULL); - - /* Initialize the list and count fields: */ - pz->end = &pz->list; - pz->len = 0U; - pz->overflow = 0U; - pz->start = 0U; - - /* If 'copy' is true a complete copy is made of the main z_stream, otherwise - * the stream is shared. deflateCopy actually does a memcpy over the - * destination z_stream, so no further initialization is required. - */ - if (copy) - { - int ret = deflateCopy(&pz->zs, &ps->s.zs); - - if (ret != Z_OK) - { - /* If this fails and png_chunk_report returns we can continue because - * the caller handles the error: - */ - pz->zs.opaque = NULL; - png_zstream_error(&pz->zs, ret); - png_chunk_report(png_ptr, pz->zs.msg, PNG_CHUNK_WRITE_ERROR); - return 0; - } - } - - else - pz->zs = ps->s.zs; /* see png_zlib_filter_release */ - - /* Either way the {next,avail}_{in.out} fields got copied, however they must - * not be used so: - */ - ps->filter[i].zs.next_in = ps->filter[i].zs.next_out = NULL; - ps->filter[i].zs.avail_in = ps->filter[i].zs.avail_out = 0U; - ps->filter[i].zs.msg = PNGZ_MSG_CAST("zlib copy ok"); /* safety */ - - /* If there is a partial buffer in the main stream a partial buffer is - * required here: - */ - { - uInt start = ps->s.zs.avail_out; - - if (start > 0U && start < sizeof ps->s.list->output) - { - uInt avail_out; - - start = (uInt)/*SAFE*/(sizeof ps->s.list->output) - start; - pz->list = ps->stash; - ps->stash = NULL; - avail_out = png_zlib_compress_avail_out(pz); - ps->stash = *pz->end; - *pz->end = NULL; - - if (avail_out >= start) - { - pz->zs.next_out += start; - pz->zs.avail_out -= start; - pz->start = start; - } - - else /* OOM */ - { - png_warning(png_ptr, "filter selection: out of memory"); - png_zlib_filter_release(png_ptr, ps, i); - return 0; /* failure */ - } - } - } - - /* Finally compress the filter byte into the copied/shared z_stream. */ - { - png_byte b[1]; - - b[0] = i; - return png_zlib_filter_compress(png_ptr, ps, i, b, 1U, Z_NO_FLUSH); - } -} - -/* Revert to using the main z_stream. This just moves the given filter (which - * must have been initialized) back to the main stream leaving the filter ready - * to be released. - */ -static void -png_zlib_filter_revert(png_structrp png_ptr, png_zlib_statep ps, png_byte i) -{ - png_zlib_compressp pz = &ps->filter[i]; - - affirm(pz->zs.opaque != NULL); - png_zlib_compress_validate(pz, 0/*in_use*/); - - /* First merge the buffer lists. */ - if (pz->overflow > 0U || pz->len > 0U) - { - affirm(pz->list != NULL); - debug(ps->s.end != NULL && *ps->s.end == NULL); - - /* The deflate operation produced some output, if pz->start is non-zero - * the first buffer in pz->list must be merged with the current buffer in - * the main z_stream, if pz->zs.next_out still points into this buffer the - * pointer must be updated to point to the old buffer. - */ - if (ps->s.zs.avail_out > 0U) - { - affirm(ps->s.zs.avail_out + pz->start == sizeof ps->s.list->output); - /* Copy everything after pz->start into the old buffer. */ - memcpy(ps->s.zs.next_out, pz->list->output + pz->start, - ps->s.zs.avail_out); - - /* Unlink the remainder of the list, if any, and append it to the - * output. - */ - if (pz->list->next != NULL) - { - debug(pz->end != &pz->list->next); - *ps->s.end = pz->list->next; - pz->list->next = NULL; - ps->s.end = pz->end; - pz->end = &pz->list->next; /* To be deleted later */ - } - - /* If pz->s.next_out still points into the first buffer (the case for - * the final row of small images) update it to point to the old buffer - * instead so that the copy below works. - */ - if (pz->zs.next_out >= pz->list->output && - pz->zs.next_out <= pz->list->output + (sizeof pz->list->output)) - { - debug(pz->overflow == 0U && - pz->len + pz->start <= (sizeof pz->list->output) && - pz->zs.next_out + pz->zs.avail_out == - pz->list->output + (sizeof pz->list->output) && - ps->s.zs.avail_out > pz->zs.avail_out); - pz->zs.next_out = ps->s.zs.next_out + ps->s.zs.avail_out - - pz->zs.avail_out; - } - } - - else - { - affirm(pz->start == 0U); - - /* Nothing to copy, the whole new list is appended to the existing one. - */ - *ps->s.end = pz->list; - pz->list = NULL; - ps->s.end = pz->end; - pz->end = &pz->list; - } - - /* Update the length fields; 'start' remains correct. */ - ps->s.overflow += pz->overflow; - if (((ps->s.len += pz->len) & 0x80000000U) != 0) - ++ps->s.overflow, ps->s.len &= 0x7FFFFFFFU; - } - - else - { - /* deflate produced no additional output; all the state is in the - * z_stream. Copy it back without changing anything else. - */ - debug(pz->zs.avail_out == ps->s.zs.avail_out); - pz->zs.next_out = ps->s.zs.next_out; - } - - /* The buffer list has been fixed, the z_stream must be copied. All fields - * are relevant. This is done as a simple swap. - */ - { - z_stream zs = ps->s.zs; - - ps->s.zs = pz->zs; - png_zlib_compress_validate(&ps->s, 0/*in_use*/); - zs.next_in = zs.next_out = NULL; - zs.avail_in = zs.avail_out = 0U; - zs.msg = PNGZ_MSG_CAST("invalid"); - pz->zs = zs; - } -} - -/* As above but release all the filters as well. */ -static void -png_zlib_filter_revert_and_release(png_structrp png_ptr, png_zlib_statep ps, - png_byte i) -{ - /* The other filters must be released first to correctly handle the - * non-copied one: - */ - png_byte f; - - for (f=0U; f < PNG_FILTER_VALUE_LAST; ++f) - if (f != i) - png_zlib_filter_release(png_ptr, ps, f); - - png_zlib_filter_revert(png_ptr, ps, i); - png_zlib_filter_release(png_ptr, ps, i); -} - -static png_byte /* filters being tried */ -select_filter_methodically_init(png_structrp png_ptr, - const unsigned int filters_to_try) -{ - png_zlib_statep ps = png_ptr->zlib_state; - - affirm(ps != NULL); - - /* Now activate the decompressor for each filter in the list. Skip the first - * filter; this will share the main state. - */ - { - unsigned int filters = 0U; - png_byte filter, first_filter = PNG_FILTER_VALUE_LAST; - - for (filter=0U; filter < PNG_FILTER_VALUE_LAST; ++filter) - if ((filters_to_try & PNG_FILTER_MASK(filter)) != 0U) - { - if (first_filter == PNG_FILTER_VALUE_LAST) - first_filter = filter; - - else if (png_zlib_filter_init(png_ptr, ps, filter, 1/*copy*/)) - filters |= PNG_FILTER_MASK(filter); - - else /* OOM, probably; give up */ - { - ps->filter_oom = 1U; - break; - } - } - - /* If none of that worked abort the filter selection by returning just the - * first filter. Note that a filter value is returned here. - */ - if (filters == 0U) - return first_filter; - - /* Finally initialize the first filter. */ - if (png_zlib_filter_init(png_ptr, ps, first_filter, 0/*!copy*/)) - return PNG_ALL_FILTERS & (filters | PNG_FILTER_MASK(first_filter)); - - /* This is an error condition but there is still a working z_stream - * structure. The z_stream has had the filter byte written to it, so teh - * standard code cannot be used. Simply fake the multi-filter case. The - * low three bits ensure that there are multiple bits in the result. - */ - ps->filter_oom = 1U; - return PNG_ALL_FILTERS & (filters | 0x7U); - } -} - -static int -select_filter_methodically_better(png_structrp png_ptr, png_zlib_compressp pz, - png_uint_32p op/*high 32 bits*/, png_uint_32p lp/*low 31 bits*/, - Bytef *scratch_out, uInt avail_out, int flush) - /* Called at the end of a row for each filter being tested to work out if - * this filter is apparently producing better results than {*op,*lp}, which - * is preset to a number larger than any possible 63-bit value and then set, - * here, as required to {overflow,len} from a selected filter. - */ -{ - /* The pre-check here is that the data already produced by the compression - * engine does not exceed the best count found so far: - */ - png_uint_32 o = pz->overflow, l = pz->len; - - png_zlib_compress_validate(pz, 0/*in_use*/); - - if (o < *op || (o == *op && l < *lp)) - { - /* But if the stream hasn't been flushed this proves nothing; test the - * pending output by using an appropriate flush: - */ - if (flush == Z_NO_FLUSH) - { - int ret; - z_stream zs; - - ret = deflateCopy(&zs, &pz->zs); - - if (ret == Z_OK) - { - zs.next_in = NULL; - zs.avail_in = 0U; - - /* Extract all the output from zlib by doing dummy deflates. Note - * that all the flush possibilites give approximately the same - * result but PARTIAL, SYNC and FULL seem to be mildly better - * probably because they avoid the rounding and block overhead. - * - * Z_PARTIAL_FLUSH 1 - * Z_SYNC_FLUSH 2 - * Z_FULL_FLUSH 3 - * Z_FINISH 4 - * Z_BLOCK 5 - */ - flush = Z_PARTIAL_FLUSH; - - do - { - if (l & 0x80000000U) - ++o, l &= 0x7FFFFFFFU; - - zs.next_out = scratch_out; - zs.avail_out = avail_out; - l += avail_out; - - ret = deflate(&zs, flush); - } while (ret == Z_OK && zs.avail_out == 0U); - -#if 0 - /* TODO: fix this (Coverity issue Z_STREAM_END is dead code) */ - if (ret == (flush == Z_FINISH ? Z_STREAM_END : Z_OK)) -#else - if (ret == Z_OK) -#endif /* 0 */ - { - /* This cannot underflow because the check above is performed - * before adding 'avail_out' to l: - */ - l -= zs.avail_out; - (void)deflateEnd(&zs); - png_zlib_compress_validate(pz, 0/*in_use*/); - - if (l & 0x80000000U) - ++o, l &= 0x7FFFFFFFU; - - if (o < *op || (o == *op && l < *lp)) - { - *op = o; - *lp = l; - return 1; - } - - /* No errors but the result was longer (this can't be the first - * filter.) - */ - return 0; - } - - else /* problem in deflate */ - (void)deflateEnd(&zs); - } - - /* We arrive here if there was an error somewhere inside zlib. */ - png_zstream_error(&zs, ret); - png_warning(png_ptr, zs.msg); - } - - else /* flush already performed */ - { - *op = o; - *lp = l; - return 1; - } - } - - /* This is the failure case, however if this is the first filter to be tested - * return success anyway, without resetting {op,lp}: - */ - return *op == 0xFFFFFFFFU && *lp == 0xFFFFFFFFU; -} - -/* The algorithm here is to test the result of zlib compression with each - * possible filter. This was originally suggested on png-mng-implement by - * Bjoern Hoehrmann on 20110401; he referenced pngwolf (see github). - */ -static void -select_filter_methodically(png_structrp png_ptr, png_const_bytep prev_row, - png_bytep prev_pixels, png_const_bytep unfiltered_row, - unsigned int row_bits, unsigned int bpp, unsigned int filters_to_try, - int end_of_row, int flush) -{ - png_zlib_statep ps = png_ptr->zlib_state; - const unsigned int row_bytes = (row_bits+7U) >> 3; - png_byte test_buffers[4][PNG_ROW_BUFFER_SIZE]; /* for each filter */ - - affirm(row_bytes <= PNG_ROW_BUFFER_SIZE && ps != NULL); - debug((row_bits % bpp) == 0U && filters_to_try > 0x7U); - - filter_block(prev_row, prev_pixels, unfiltered_row, row_bits, bpp, - test_buffers[PNG_FILTER_VALUE_SUB-1U], - test_buffers[PNG_FILTER_VALUE_UP-1U], - test_buffers[PNG_FILTER_VALUE_AVG-1U], - test_buffers[PNG_FILTER_VALUE_PAETH-1U]); - - /* Add each test buffer, and the unfiltered row if required, to the current - * list. - */ - { - png_byte filter, ok_filter = PNG_FILTER_VALUE_LAST; - - for (filter=0U; filter < PNG_FILTER_VALUE_LAST; ++filter) - if ((filters_to_try & PNG_FILTER_MASK(filter)) != 0U) - { - if (png_zlib_filter_compress(png_ptr, ps, filter, - filter == PNG_FILTER_VALUE_NONE ? - unfiltered_row : test_buffers[filter-1], row_bytes, flush)) - ok_filter = filter; - - else /* remove this filter from the test list: */ - filters_to_try &= PNG_BIC_MASK(PNG_FILTER_MASK(filter)); - } - - /* If nothing worked then there is no recovery possible. */ - if (ok_filter == PNG_FILTER_VALUE_LAST) - png_error(png_ptr, "filter selection: everything failed"); - - /* At end_of_row choose the best filter; it is stored in ok_filter. */ - if (end_of_row) - { - png_uint_32 o, l; - - o = l = 0xFFFFFFFFU; - ok_filter = PNG_FILTER_VALUE_LAST; - - for (filter=0U; filter < PNG_FILTER_VALUE_LAST; ++filter) - if ((filters_to_try & PNG_FILTER_MASK(filter)) != 0U && - select_filter_methodically_better(png_ptr, &ps->filter[filter], - &o, &l, test_buffers[0], sizeof test_buffers, flush)) - ok_filter = filter; - } - - /* Keep going if there is more than one filter left, otherwise, if there - * is only one left (because of OOM killing filters) swap back to the - * main-line code using 'ok_filter'. - */ - else if ((filters_to_try & (filters_to_try-1U)) != 0U) - ok_filter = PNG_FILTER_VALUE_LAST; /* keep going */ - - /* Swap back to the mainline code at end of row or when the available - * filter count drops to one because of OOM. - */ - if (ok_filter < PNG_FILTER_VALUE_LAST) - { - png_zlib_filter_revert_and_release(png_ptr, ps, ok_filter); - png_write_IDAT(png_ptr, flush == Z_FINISH); - ps->filters = ok_filter; - } - - else - { - ps->filters = PNG_ALL_FILTERS & (filters_to_try &= PNG_ALL_FILTERS); - debug((filters_to_try & (filters_to_try-1U)) != 0U); - } - } -} -#endif /* SELECT_FILTER_METHODICALLY */ - -/* This filters the row, chooses which filter to use, if it has not already - * been specified by the application, and then writes the row out with the - * chosen filter. - */ -void /* PRIVATE */ -png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels, - png_const_bytep unfiltered_row, png_uint_32 x, - unsigned int width/*pixels*/, unsigned int row_info_flags) -{ - png_zlib_statep ps = png_ptr->zlib_state; - png_bytep prev_row = png_ptr->row_buffer; - const unsigned int bpp = png_ptr->row_output_pixel_depth; - const unsigned int row_bits = width * bpp; - unsigned int filters_to_try; - int flush; - - /* These invariants are expected from the caller: */ - affirm(ps != NULL && width < 65536U && bpp <= 64U && width < 65536U/bpp && - row_bits <= 8U*PNG_ROW_BUFFER_SIZE); - - flush = row_flush(ps, row_info_flags); - - if (x == 0U) /* start of row */ - { - /* Now work out the filters to try for this row: */ - filters_to_try = ps->filter_mask; - - /* If this has a previous row filter in the set to try ensure the row - * buffer exists and ensure it is empty when first allocated and at - * the start of the pass. - */ - if ((filters_to_try & (PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH)) - != 0U) - { - if (prev_row == NULL) - { - /* Just allocate for the total output row bytes; a three-row - * interlaced image requires less, but this is safe. - */ - prev_row = png_voidcast(png_bytep, png_malloc(png_ptr, - png_calc_rowbytes(png_ptr, bpp, png_ptr->width))); - png_ptr->row_buffer = prev_row; - - /* If that buffer would have been required for this row issue an - * app warning and disable the filters that would have required - * the data. - */ - if (!(row_info_flags & png_pass_first_row)) - { - png_app_warning(png_ptr, "Previous row filters ignored"); - /* And always turn off the filters, to prevent using - * uninitialized data. - */ - filters_to_try &= PNG_BIC_MASK( - PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH); - - if (filters_to_try == 0U) - filters_to_try = PNG_FILTER_NONE; - } - } - } - - if ((row_info_flags & png_pass_first_row) != 0U) - { - /* On the first row UP and NONE are the same, PAETH and SUB are the - * same, so if both members of a pair occur together eliminate the one - * that depends on the previous row. This will avoid the filter - * selection code while allowing the app to ensure all the filters can - * be used (prev_row is allocated) on the first row. - */ -# define match(mask) (filters_to_try & (mask)) == mask - if (match(PNG_FILTER_NONE+PNG_FILTER_UP)) - filters_to_try &= PNG_BIC_MASK(PNG_FILTER_UP); - - if (match(PNG_FILTER_SUB+PNG_FILTER_PAETH)) - filters_to_try &= PNG_BIC_MASK(PNG_FILTER_PAETH); -# undef match - } - - /* If there is no selection algorithm enabled choose the first filter - * in the list, otherwise do algorithm-specific initialization. - */ - if ((filters_to_try & (filters_to_try-1U)) != 0U) - { - /* Multiple filters in the list. */ -# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED - if (!ps->filter_oom && - (methodical_option == PNG_OPTION_ON || - (methodical_option != PNG_OPTION_OFF && - heuristic_option == PNG_OPTION_OFF))) - filters_to_try = - select_filter_methodically_init(png_ptr, filters_to_try); - - else /* don't do methodical selection */ -# endif /* SELECT_FILTER_METHODICALLY */ -# ifdef PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED - if (heuristic_option != PNG_OPTION_OFF) /* use heuristics */ - { - /* The heuristic must select a single filter based on the first - * block of pixels; it updates zbuffer_filter to a single filter - * value. - */ - ps->filters = select_filter_heuristically(png_ptr, - filters_to_try, - (row_info_flags & png_pass_first_row) ? NULL : prev_row, - prev_pixels, unfiltered_row, row_bits, bpp, flush); - - /* This has selected one filter and has already processed it but - * the current row must still be retained regardless if prev_row - * is non-NULL. - */ - goto copy_row; - } - - else /* don't use heuristic selection */ -# endif /* SELECT_FILTER_HEURISTICALLY */ - filters_to_try &= -filters_to_try; - } - - /* If there is just one bit set in filters_to_try convert it to the filter - * value and store that. - */ - if ((filters_to_try & (filters_to_try-1U)) == 0U) switch (filters_to_try) - { - case PNG_FILTER_NONE: filters_to_try = PNG_FILTER_VALUE_NONE; break; - case PNG_FILTER_SUB: filters_to_try = PNG_FILTER_VALUE_SUB; break; - case PNG_FILTER_UP: filters_to_try = PNG_FILTER_VALUE_UP; break; - case PNG_FILTER_AVG: filters_to_try = PNG_FILTER_VALUE_AVG; break; - case PNG_FILTER_PAETH: filters_to_try = PNG_FILTER_VALUE_PAETH; break; - default: - impossible("bad filter mask"); - } - - ps->filters = PNG_ALL_FILTERS & filters_to_try; - } /* start of row */ - - else - { - if (prev_row != NULL) - { - /* Advance prev_row to the corresponding pixel above row[x], must use - * png_calc_rowbytes here otherwise the calculation using x might - * overflow. - */ - debug(((x * bpp) & 7U) == 0U); - prev_row += png_calc_rowbytes(png_ptr, bpp, x); - } - - filters_to_try = ps->filters; - } - - /* Now choose the correct filter implementation according to the number of - * filters in the filters_to_try list. The prev_row parameter is made NULL - * on the first row because it is uninitialized at that point. - */ - if (filters_to_try == PNG_FILTER_VALUE_NONE) - write_unfiltered_rowbits(png_ptr, unfiltered_row, row_bits, - x == 0 ? PNG_FILTER_VALUE_NONE : PNG_FILTER_VALUE_LAST, flush); - - else - { - png_const_bytep prev = - (row_info_flags & png_pass_first_row) ? NULL : prev_row; - - /* Is just one bit set in 'filters_to_try'? */ - if (filters_to_try < PNG_FILTER_VALUE_LAST) - filter_row(png_ptr, prev, prev_pixels, unfiltered_row, row_bits, bpp, - filters_to_try, x == 0, flush); - - else -# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED - select_filter_methodically(png_ptr, prev, prev_pixels, - unfiltered_row, row_bits, bpp, filters_to_try, - (row_info_flags & png_row_end) != 0U, flush); -# else - impossible("bad filter select logic"); -# endif /* SELECT_FILTER_METHODICALLY */ - } - -# ifdef PNG_WRITE_FLUSH_SUPPORTED - if (flush == Z_SYNC_FLUSH) - { - png_flush(png_ptr); - ps->flush_rows = 0U; - } -# endif /* WRITE_FLUSH */ - - /* Copy the current row into the previous row buffer, if available, unless - * this is the last row in the pass, when there is no point. Note that - * prev_row may have garbage in a partial byte at the end. - */ -copy_row: - if (prev_row != NULL && !(row_info_flags & png_pass_last_row)) - memcpy(prev_row, unfiltered_row, (row_bits + 7U) >> 3); -} - /* Allow the application to select one or more row filters to use. */ void PNGAPI png_set_filter(png_structrp png_ptr, int method, int filtersIn) { png_zlib_statep ps = png_get_zlib_state(png_ptr); - unsigned int filters; png_debug(1, "in png_set_filter"); if (ps == NULL) return; + /* See png_write_IHDR above; this limits the filter method to one of the + * values permitted in png_write_IHDR unless that has not been called in + * which case only the 'base' method is permitted because that is the initial + * value of png_struct::filter_method (i.e. 0). + */ if (method != png_ptr->filter_method) { + ps->filter_mask = 0U; /* safety: uninitialized */ png_app_error(png_ptr, "png_set_filter: method does not match IHDR"); return; } - /* PNG and MNG use the same base adaptive filter types: */ - if (method != PNG_FILTER_TYPE_BASE && method != PNG_INTRAPIXEL_DIFFERENCING) - { - png_app_error(png_ptr, "png_set_filter: unsupported method"); - return; - } - /* Notice that PNG_NO_FILTERS is 0 and passes this test; this is OK * because filters then gets set to PNG_FILTER_NONE, as is required. */ - if (filtersIn >= 0 && filtersIn < PNG_FILTER_VALUE_LAST) - filters = 8U << filtersIn; + if (filtersIn >= 0 && filtersIn < PNG_FILTER_NONE) + filtersIn = PNG_FILTER_MASK(filtersIn); - else if ((filtersIn & PNG_BIC_MASK(PNG_ALL_FILTERS)) == 0) - filters = filtersIn & PNG_ALL_FILTERS; + /* PNG_ALL_FILTERS is a constant, unfortunately it is nominally signed, for + * historical reasons, hence the 'unsigned' here. The '&' can be omitted + * anyway because of the check. + */ + if ((filtersIn & PNG_BIC_MASK(PNG_ALL_FILTERS)) == 0) + { +# ifndef PNG_SELECT_FILTER_SUPPORTED + if (filtersIn & (filtersIn-1)) /* remove LSBit */ + { +#if TEMPORARY + png_app_warning(png_ptr, + "png_set_filter: filter selection not supported"); +#endif + filtersIn &= -filtersIn; /* Use lowest set bit */ + } +# endif /* !SELECT_FILTER */ + + ps->filter_mask = filtersIn & (unsigned)PNG_ALL_FILTERS; + } else { - png_app_error(png_ptr, "png_set_filter: invalid filters mask/value"); - /* Prior to 1.7.0 this ignored the error and just used the bits that - * are present, now it does nothing; this seems a lot safer. + * are present, now it resets to the uninitialized value: */ - return; + ps->filter_mask = 0U; /* safety: uninitialized */ + png_app_error(png_ptr, "png_set_filter: invalid filter mask/value"); + } +} +#endif /* WRITE_FILTER */ + +/* This is the common function to write multiple rows of PNG data. The data is + * in the relevant PNG format but has had no filtering done. + */ +static void +write_png_rows(png_structrp png_ptr, png_const_bytep *rows, + png_uint_32 num_rows) +{ + const png_zlib_statep ps = png_ptr->zlib_state; + const unsigned int bpp = png_ptr->row_output_pixel_depth; +# ifdef PNG_WRITE_FILTER_SUPPORTED + const png_byte filter = ps->filters; + png_const_bytep previous_row = ps->previous_write_row; + const png_uint_32 max_pixels = filter == PNG_FILTER_VALUE_NONE ? + ps->zlib_max_pixels : ps->row_buffer_max_pixels; + const png_uint_32 block_pixels = filter == PNG_FILTER_VALUE_NONE ? + ps->row_buffer_max_aligned_pixels : ps->zlib_max_aligned_pixels; +# else /* !WRITE_FILTER */ + const png_byte filter = PNG_FILTER_VALUE_NONE; + const png_uint_32 max_pixels = ps->zlib_max_pixels; + const png_uint_32 block_pixels = ps->zlib_max_aligned_pixels; +# endif /* !WRITE_FILTER */ + /* Write the given rows handling the png_compress_IDAT argument limitations + * (uInt) and any valid row width. + */ + png_uint_32 last_row_in_pass = 0U; /* Actual last, not last+1! */ + png_uint_32 pixels_in_pass = 0U; + unsigned int first_row_in_pass = 0U; /* For do_interlace */ + unsigned int pixels_at_end = 0U; /* for a partial byte at the end */ + unsigned int row_info_flags = png_row_end; + int pass = -1; /* Invalid: force calculation first time round */ + + debug(png_ptr->row_output_pixel_depth == PNG_PIXEL_DEPTH(*png_ptr)); + + while (num_rows-- > 0U) + { + if (png_ptr->pass != pass) + { + /* Recalcuate the row bytes and partial bits */ + pass = png_ptr->pass; + pixels_in_pass = png_ptr->width; + + if (png_ptr->interlaced == PNG_INTERLACE_NONE) + { + debug(pass == 0); + last_row_in_pass = png_ptr->height - 1U; + row_info_flags |= png_pass_last; /* there is only one */ + } + + else + { + const png_uint_32 height = png_ptr->height; + + last_row_in_pass = PNG_PASS_ROWS(height, pass); + +# ifdef PNG_WRITE_INTERLACING_SUPPORTED + if (png_ptr->do_interlace) + { + /* libpng is doing the interlace handling and this is pass 6. + * The row may have to be skipped below. + */ + affirm(pass == 6); /* so pixels_in_pass is correct */ + + /* This overflows for 1 pixel high PNG, this does not matter; + * the result is 0xffffffff which is fine. + */ + last_row_in_pass = + PNG_ROW_FROM_PASS_ROW(last_row_in_pass-1U, pass); + first_row_in_pass = 1U; + row_info_flags |= png_pass_last; /* if there are any rows */ + } + + else /* Application handles the interlace */ +# endif /* WRITE_INTERLACING */ + { + /* The row does exist, so this works without checking the column + * count. + */ + + debug(pass < 7 && last_row_in_pass > 0U); + last_row_in_pass -= 1U; + + if (pass == PNG_LAST_PASS(pixels_in_pass/*PNG width*/, height)) + row_info_flags |= png_pass_last; + + /* Finally, adjust pixels_in_pass for the interlacing: */ + pixels_in_pass = PNG_PASS_COLS(pixels_in_pass, pass); + } + } + + /* Mask out the bits in a partial byte. */ + pixels_at_end = pixels_in_pass & PNG_ADDOF(bpp); + +# ifdef PNG_WRITE_FILTER_SUPPORTED + /* Reset the previous_row pointer correctly; NULL at the start of + * the pass. If row_number is not 0 then a previous write_rows was + * interrupted in mid-pass and any required buffer should be in + * previous_write_row (set in the initializer). + */ + if (png_ptr->row_number == first_row_in_pass) + previous_row = NULL; +# endif /* WRITE_FILTER */ + } + +# ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* When libpng is handling the interlace we see rows that must be + * skipped. + */ + if (!png_ptr->do_interlace || + PNG_ROW_IN_INTERLACE_PASS(png_ptr->row_number, pass)) +# endif /* WRITE_INTERLACING */ + { + const int flush = row_flush(ps, row_info_flags | + (png_ptr->row_number == + first_row_in_pass ? png_pass_first_row : 0) | + (png_ptr->row_number == last_row_in_pass ? png_pass_last_row : 0)); + png_const_bytep row = *rows; + png_uint_32 pixels_to_go = pixels_in_pass; + + /* The row handling uses png_compress_IDAT directly if there is no + * filter to be applied, otherwise it uses filter_row. + */ +# ifdef PNG_WRITE_FILTER_SUPPORTED + if (filter != PNG_FILTER_VALUE_NONE) + { + int start_of_row = 1; + png_byte prev_pixels[4*2*2]; /* 2 pixels up to 4x2-bytes each */ + + memset(prev_pixels, 0U, sizeof prev_pixels); + + while (pixels_to_go > max_pixels) + { + /* Write a block at once to maintain alignment */ + filter_row(png_ptr, previous_row, prev_pixels, row, + bpp * block_pixels, bpp, filter, start_of_row, + Z_NO_FLUSH); + + if (previous_row != NULL) + previous_row += (block_pixels * bpp) >> 3; + + row += (block_pixels * bpp) >> 3; + pixels_to_go -= block_pixels; + start_of_row = 0; + } + + /* The filter code handles the partial byte at the end correctly, + * so this is all that is required: + */ + filter_row(png_ptr, previous_row, prev_pixels, row, + bpp * pixels_to_go, bpp, filter, start_of_row, + flush); + } + + else +# endif /* WRITE_FILTER */ + + { + /* The no-filter case. */ + const uInt block_bytes = (uInt)/*SAFE*/( + bpp <= 8U ? + block_pixels >> PNG_SHIFTOF(bpp) : + block_pixels * (bpp >> 3)); + + /* png_write_start_IDAT guarantees this, but double check for + * overflow above in debug: + */ + debug((block_bytes & (PNG_ROW_BUFFER_BYTE_ALIGN-1U)) == 0U); + + /* The filter has to be written here: */ + png_compress_IDAT(png_ptr, &filter, 1U/*len*/, Z_NO_FLUSH); + + /* Process blocks of pixels up to the limit. */ + while (pixels_to_go > max_pixels) + { + png_compress_IDAT(png_ptr, row, block_bytes, Z_NO_FLUSH); + row += block_bytes; + pixels_to_go -= block_pixels; + } + + /* Now compress the remainder; pixels_to_go <= max_pixels so it will + * fit in a uInt. + */ + { + const png_uint_32 remainder = + bpp <= 8U + ? (pixels_to_go-pixels_at_end) >> PNG_SHIFTOF(bpp) + : (pixels_to_go-pixels_at_end) * (bpp >> 3); + + if (remainder > 0U) + png_compress_IDAT(png_ptr, row, remainder, + pixels_at_end > 0U ? Z_NO_FLUSH : flush); + + else + debug(pixels_at_end > 0U); + + if (pixels_at_end > 0U) + { + /* There is a final partial byte. This is PNG format so the + * left-most bits are the most significant. + */ + const png_byte last = PNG_BYTE(row[remainder] & + ~(0xFFU >> (pixels_at_end * bpp))); + + png_compress_IDAT(png_ptr, &last, 1U, flush); + } + } + } + + png_write_end_row(png_ptr, flush); + +# ifdef PNG_WRITE_FILTER_SUPPORTED + previous_row = *rows; +# endif /* WRITE_FILTER */ +# undef HANDLE + } /* row in pass */ + +# ifdef PNG_WRITE_INTERLACING_SUPPORTED + else /* row not in pass; just skip it */ + { + if (++png_ptr->row_number >= png_ptr->height) + { + debug(png_ptr->row_number == png_ptr->height); + + png_ptr->row_number = 0U; + png_ptr->pass = 0x7U & (pass+1U); + } + } +# endif /* WRITE_INTERLACING */ + + ++rows; + } /* while num_rows */ + +# ifdef PNG_WRITE_FILTER_SUPPORTED + /* previous_row must be copied back unless we don't need it because the + * next row is the first one in the pass (this relies on png_write_end_row + * setting row_number to 0 at the end!) + * + * png_write_start_row (below) creates the buffer if it may be needed. + * + * NOTE: when libpng handles an interlaced image the entire loop may be + * skipped above and previous_row will still be NULL. + * + * TODO: delay this. + */ + if (png_ptr->row_number != 0U && ps->previous_write_row != NULL && + previous_row != NULL) + memcpy(ps->previous_write_row, previous_row, + png_calc_rowbytes(png_ptr, bpp, pixels_in_pass)); +# endif +} + +static png_zlib_statep +write_start_IDAT(png_structrp png_ptr) + /* Shared code which does everything except the filter support */ +{ + png_zlib_statep ps = png_ptr->zlib_state; + + /* Set up the IDAT compression state. Expect the state to have been released + * by the previous owner, but it doesn't much matter if there was an error. + * Note that the stream is not claimed yet. + */ + debug(png_ptr->zowner == 0U); + + /* Create the zlib state if ncessary: */ + if (ps == NULL) + png_create_zlib_state(png_ptr), ps = png_ptr->zlib_state; + + /* Delayed initialization of the zlib state maxima; this is not done above in + * case the zlib_state is created before the IHDR has been written, which + * would lead to the various png_struct fields used below being + * uninitialized. + */ + { + /* Initialization of the buffer size constants. */ + const unsigned int bpp = PNG_PIXEL_DEPTH(*png_ptr); + const unsigned int byte_pp = bpp >> 3; /* May be 0 */ + const unsigned int pixel_block = + /* Number of pixels required to maintain PNG_ROW_BUFFER_BYTE_ALIGN + * alignment. For multi-byte pixels use the first set bit to determine + * if the pixels have a greater alignment already. + */ + bpp < 8U ? + PNG_ROW_BUFFER_BYTE_ALIGN * (8U/bpp) : + PNG_ROW_BUFFER_BYTE_ALIGN <= (byte_pp & -byte_pp) ? + 1U : + PNG_ROW_BUFFER_BYTE_ALIGN / (byte_pp & -byte_pp); + + /* pixel_block must always be a power of two: */ + debug(bpp > 0 && pixel_block > 0 && + (pixel_block & -pixel_block) == pixel_block && + ((8U*PNG_ROW_BUFFER_BYTE_ALIGN-1U) & (pixel_block*bpp)) == 0U); + + /* Zlib maxima */ + { + png_uint_32 max = (uInt)-1; /* max bytes */ + + if (bpp <= 8U) + { + /* Maximum number of bytes PNG can generate in the lower bit depth + * cases: + */ + png_uint_32 png_max = + (0x7FFFFFFF + PNG_ADDOF(bpp)) >> PNG_SHIFTOF(bpp); + + if (png_max < max) + max = 0x7FFFFFFF; + } + + else /* bpp > 8U */ + { + max /= byte_pp; + if (max > 0x7FFFFFFF) + max = 0x7FFFFFFF; + } + + /* So this is the maximum number of pixels regardless of alignment: */ + ps->zlib_max_pixels = max; + + /* For byte alignment the value has to be a multiple of pixel_block and + * that is a power of 2, so: + */ + ps->zlib_max_aligned_pixels = max & ~(pixel_block-1U); + } + +# ifdef PNG_WRITE_FILTER_SUPPORTED + /* PNG_ROW_BUFFER maxima; this is easier because PNG_ROW_BUFFER_SIZE is + * limited so that the number of bits fits in any ANSI-C + * (unsigned int). + */ + { + const unsigned int max = (8U * PNG_ROW_BUFFER_SIZE) / bpp; + + ps->row_buffer_max_pixels = max; + ps->row_buffer_max_aligned_pixels = max & ~(pixel_block-1U); + } +# endif /* WRITE_FILTER */ } - debug(filters != 0U && (filters & PNG_BIC_MASK(PNG_ALL_FILTERS)) == 0U); - ps->filter_mask = png_check_bits(png_ptr, filters, 8); + { + const png_alloc_size_t image_size = png_image_size_checked(png_ptr); + const png_uint_32 settings = pz_default_settings(ps->pz_IDAT, png_IDAT, + image_size > 0 && image_size < 0xffffffffU ? image_size : 0xffffffffU); + + /* Freeze the settings now; this avoids the need to call + * pz_default_settings again when the zlib stream is initialized. Also, + * the caller relies on this. + */ + ps->pz_IDAT = settings; + } + + return ps; +} + +#ifdef PNG_WRITE_FILTER_SUPPORTED +void /* PRIVATE */ +png_write_start_IDAT(png_structrp png_ptr) +{ + png_zlib_statep ps = write_start_IDAT(png_ptr); + png_byte mask; + + { + /* Now default the filter mask if it hasn't been set already: */ + mask = ps->filter_mask; + + if (mask == 0) + { +# ifdef PNG_SELECT_FILTER_SUPPORTED + /* The result depends on the png compression level: */ + const int png_level = pz_value(png_level, ps->pz_IDAT); + + if (png_level < 4) + mask = PNG_FILTER_NONE; /* NOTE: the mask, not the value! */ + + else if (png_level < 7) + mask = PNG_FAST_FILTERS; + + else + mask = PNG_ALL_FILTERS; +# else /* !SELECT_FILTER */ + mask = PNG_FILTER_NONE; +# endif /* !SELECT_FILTER */ + + ps->filter_mask = mask; + } + } + + { + const png_alloc_size_t write_row_size = + png_write_row_buffer_size(png_ptr); /* may be 0 */ + png_uint_32 src = ps->save_row_count; /* may be set by the app */; + + ps->write_row_size = write_row_size; + + /* If the row is too long to buffer on this system skip the allocation; + * the per-row code will handle the absence of the buffer. + */ + if (write_row_size == 0U) /* row too large to buffer */ + ps->save_row_count = 0U;/* no buffering; filters will be NONE or SUB */ + +# ifdef PNG_SELECT_FILTER_SUPPORTED + else if ((src == SAVE_ROW_COUNT_UNSET && (mask & (mask-1)) != 0U) + /* default to selection */ || + (src < SAVE_ROW_COUNT_UNSET && src >= 2U) + /* app turned selection on */) + { + /* Filter selection support required. save_row_count is a measure + * of the amount of PNG encoded but uncompressed data to use in + * making a filter selection plus one row for previous row filter + * handling. + * + * The amount of data buffered is limited by all of: + * + * 1) ps->write_buffer_limit + * 2) ps->save_row_count + * 3) png_ptr->height + */ + if (src > png_ptr->height) + src = png_ptr->height; + + if (src > 2U) + { + /* Check ps->write_buffer_limit too, this requires more + * calculation so is done last. Notice that write_buffer_limit + * is the maximum number of bytes the deflate implementation + * requires, so the calculation here is to find out the minimum + * number of buffers to accomodate that limit. + * + * The calculation required is: + * + * write_buffer_limit / PNG-row-bytes + * + * Where PNG-row-bytes is the actual PNG row bytes including the + * filter byte. Unfortunately the latter calculation can + * overflow a 32-bit unsigned value. + */ + const unsigned int pixel_bits = PNG_PIXEL_DEPTH(*png_ptr); + +# if PNG_COMPRESSION_BUFFER_LIMIT > 0xFFFFFFFFU / 8U +# error LibPNG COMPRESSION BUFFER LIMIT setting too large +# endif /* COMPRESSION_BUFFER_LIMIT test */ + + /* Therefore this will not overflow a png_uint_32: */ + const png_alloc_size_t pixel_limit = + (8U*ps->write_buffer_limit + pixel_bits - 1U)/pixel_bits; + + if (pixel_limit < png_ptr->width) + src = 2U; /* clamp to the minimum required */ + + else + { + /* pixel_limit >= png_ptr->width, so this cannot overflow: */ + const png_alloc_size_t rb = + PNG_ROWBYTES(pixel_bits, png_ptr->width); + const png_alloc_size_t row_limit = + (ps->write_buffer_limit + rb) / (rb+1U); + + if (row_limit < src) + src = (png_uint_32)/*SAFE*/row_limit; + + if (src < 2U) + src = 2U; + } + } + + /* save_row_count will be just 1 for a single pixel high image, so + * an extra flag is required to record that filter selection is + * being done. + */ + ps->save_row_count = src; + ps->do_select = 1U; + } + + else +# endif /* SELECT_FILTER */ + + /* If unset no filter selection is required (or, maybe, available), + * respect the app setting if the buffering has been set to 'off' or + * 'previous row': + */ + if (src >= 2U) + { + /* This is slightly more complicated. The previous-row filters only + * actually require a previous row after the first row in the pass, so + * only if height is 2 or more in a non-interlaced image and 3 or more + * in an interlaced image. Set save_row_count to 1 or 0 as + * appropriate: + * + * If the app set save_row_count to 2 or more then filter selection is + * compiled out, use the same logic to check height: + */ + ps->save_row_count = + (src < SAVE_ROW_COUNT_UNSET /* app setting */ || + (src == SAVE_ROW_COUNT_UNSET /* default */ && + (mask & (PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH)) != 0U)) + && png_ptr->height > 1U+(png_ptr->interlaced != PNG_INTERLACE_NONE); + } + } + + /* Don't allocate anything yet. png_write_rows_internal (pngwrite.c) may end + * up passing the whole pass or the whole image, in which case extra + * buffering is not required. + */ +} + +static void +png_write_start_row(png_zlib_statep ps) + /* Called at the start of a row to set up anything required for filter + * handling in the row. Sets png_zlib_state::filters to a single filter. + * + * NOTE: this is not called at the start of *every* row. If multiple rows + * are processed at once it is only called once. + */ +{ + /* No filter selection, so choose the first filter */ + unsigned int mask = ps->filter_mask; + + if (ps->save_row_count < 1U) /* no previous row support */ + mask &= PNG_BIC_MASK(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH); + + /* Convert the lowest set bit into the corresponding value. If no bits + * are set select NONE. After this switch statement the value of + * ps->filters is guaranteed to just be a single filter. + */ + switch (mask & -mask) + { + default: ps->filters = PNG_FILTER_VALUE_NONE; break; + case PNG_FILTER_SUB: ps->filters = PNG_FILTER_VALUE_SUB; break; + case PNG_FILTER_UP: ps->filters = PNG_FILTER_VALUE_UP; break; + case PNG_FILTER_AVG: ps->filters = PNG_FILTER_VALUE_AVG; break; + case PNG_FILTER_PAETH: ps->filters = PNG_FILTER_VALUE_PAETH; break; + } + + /* If previous row filters are enabled make sure that the previous row + * buffer is allocated. + */ + if (ps->save_row_count != 0U && ps->previous_write_row == NULL) + { + /* OOM is handled silently, as is the case where the row is too large + * to buffer. + */ + ps->previous_write_row = png_voidcast(png_bytep, + png_malloc_base(ps_png_ptr(ps), ps->write_row_size)); + + if (ps->previous_write_row == NULL) + { + ps->save_row_count = 0U; /* OOM */ + if (ps->filters > PNG_FILTER_VALUE_SUB) + ps->filters = PNG_FILTER_VALUE_NONE; + } + } +} + +/* This filters the row, chooses which filter to use, if it has not already + * been specified by the application, and then writes the row out with the + * chosen filter. + */ +static void +write_png_data(png_structrp png_ptr, png_const_bytep prev_row, + png_bytep prev_pixels, png_const_bytep unfiltered_row, png_uint_32 x, + unsigned int row_bits, unsigned int row_info_flags) + /* This filters the row appropriately and returns an updated prev_row + * (updated for 'x'). + */ +{ + const png_zlib_statep ps = png_ptr->zlib_state; + const unsigned int bpp = png_ptr->row_output_pixel_depth; + const int flush = row_flush(ps, row_info_flags); + const png_byte filter = ps->filters; /* just one */ + + /* These invariants are expected from the caller: */ + affirm(row_bits <= 8U*PNG_ROW_BUFFER_SIZE); + debug(filter < PNG_FILTER_VALUE_LAST/*sic: last+1*/); + + /* Now choose the correct filter implementation according to the number of + * filters in the filters_to_try list. The prev_row parameter is made + * NULL on the first row because it is uninitialized at that point. + */ + if (filter == PNG_FILTER_VALUE_NONE) + write_unfiltered_rowbits(png_ptr, unfiltered_row, row_bits, + x == 0 ? PNG_FILTER_VALUE_NONE : PNG_FILTER_VALUE_LAST, flush); + + else + filter_row(png_ptr, + (row_info_flags & png_pass_first_row) ? NULL : prev_row, + prev_pixels, unfiltered_row, row_bits, bpp, filter, x == 0, flush); + + /* Handle end of row: */ + if ((row_info_flags & png_row_end) != 0) + png_write_end_row(png_ptr, flush); +} + +void /* PRIVATE */ +png_write_png_data(png_structrp png_ptr, png_bytep prev_pixels, + png_const_bytep unfiltered_row, png_uint_32 x, + unsigned int width/*pixels*/, unsigned int row_info_flags) +{ + const png_zlib_statep ps = png_ptr->zlib_state; + + affirm(ps != NULL); + +# ifdef PNG_SELECT_FILTER_SUPPORTED + /* The data will be buffered for later use. */ + if (ps->do_select) + png_write_buffer_row(ps, unfiltered_row, x, width, row_info_flags); + + else /* no filter selection */ +# endif /* SELECT_FILTER */ + { + const unsigned int bpp = png_ptr->row_output_pixel_depth; + const unsigned int row_bits = width * bpp; + png_bytep prev_row; + + debug(bpp <= 64U && width <= 65535U && + width < 65535U/bpp); /* Expensive: only matters on 16-bit */ + + /* This is called once before starting a new row here, but below it is + * only called once between starting a new list of rows. + */ + if (x == 0) + png_write_start_row(ps); + + /* prev_row is either NULL or the position in the previous row buffer */ + prev_row = ps->previous_write_row; + + if (prev_row != NULL && x > 0) + prev_row += png_calc_rowbytes(png_ptr, bpp, x); + + /* This is the single filter case (no selection): */ + write_png_data(png_ptr, prev_row, prev_pixels, unfiltered_row, x, + row_bits, row_info_flags); + + /* Copy the current row into the previous row buffer, if available, unless + * this is the last row in the pass, when there is no point. Note that + * prev_row may have garbage in a partial byte at the end. + */ + if (prev_row != NULL && !(row_info_flags & png_pass_last_row)) + memcpy(prev_row, unfiltered_row, (row_bits + 7U) >> 3); + } +} + +void /*PRIVATE */ +png_write_png_rows(png_structrp png_ptr, png_const_bytep *rows, + png_uint_32 num_rows) + /* This is the fast version of the above which receives complete rows. The + * final byte may still require separate handling. + */ +{ + const png_zlib_statep ps = png_ptr->zlib_state; + + affirm(ps != NULL); + +# ifdef PNG_SELECT_FILTER_SUPPORTED + if (ps->do_select) + select_png_rows(ps, rows, num_rows); + + else +# endif /* !SELECT_FILTER */ + { + /* Set the filter to use: */ + png_write_start_row(ps); + + /* Now write all the rows with the same filter: */ + write_png_rows(png_ptr, rows, num_rows); + } } #else /* !WRITE_FILTER */ void /* PRIVATE */ -png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels, +png_write_start_IDAT(png_structrp png_ptr) +{ + (void)write_start_IDAT(png_ptr); +} + +void /* PRIVATE */ +png_write_png_data(png_structrp png_ptr, png_bytep prev_pixels, png_const_bytep unfiltered_row, png_uint_32 x, unsigned int width/*pixels*/, unsigned int row_info_flags) { @@ -3750,15 +4281,21 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels, write_unfiltered_rowbits(png_ptr, unfiltered_row, row_bits, x == 0 ? PNG_FILTER_VALUE_NONE : PNG_FILTER_VALUE_LAST, flush); -# ifdef PNG_WRITE_FLUSH_SUPPORTED - if (flush == Z_SYNC_FLUSH) - { - png_flush(png_ptr); - png_ptr->zlib_state->flush_rows = 0U; - } -# endif /* WRITE_FLUSH */ - PNG_UNUSED(prev_pixels); + + /* Handle end of row: */ + if ((row_info_flags & png_row_end) != 0) + png_write_end_row(png_ptr, flush); +} + +void /*PRIVATE */ +png_write_png_rows(png_structrp png_ptr, png_const_bytep *rows, + png_uint_32 num_rows) + /* This is the fast version of the above which receives complete rows. The + * final byte may still require separate handling. + */ +{ + write_png_rows(png_ptr, rows, num_rows); } #endif /* !WRITE_FILTER */ @@ -3911,45 +4448,4 @@ png_set_text_compression_method(png_structrp png_ptr, int method) } #endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ /* end of API added to libpng-1.5.4 */ - -void /*PRIVATE*/ -png_write_start_IDAT(png_structrp png_ptr) -{ - png_init_row_info(png_ptr); - -# ifdef PNG_WRITE_TRANSFORMS_SUPPORTED - /* If the app takes a png_info from a read operation and if the app has - * performed transforms on the data the png_info can contain IHDR - * information that cannot be represented in PNG. The code that writes - * the IHDR takes the color type from the png_info::format. The app adds - * transforms, before or after writing the IHDR, then the IHDR color_type - * stored in png_struct::color_type is used in png_init_row_info above to - * work out the actual row format. - * - * Prior to 1.7.0 this was not verified (there was no easy way to do so). - * Now we can check it here, however this is an: - * - * API CHANGE: in 1.7.0 an error may be flagged against bogus info_struct - * formats even though the app had removed them itself. It's just a - * warning at present. - * - * The test is that either the row_format produced by the write transforms - * exactly matches that in the original info_struct::format or that the - * info_struct::format was a simple mapping of the color_type that ended - * up in the IHDR: - */ - if (png_ptr->row_format != png_ptr->info_format && - PNG_FORMAT_FROM_COLOR_TYPE(png_ptr->color_type) != - png_ptr->info_format) - png_app_warning(png_ptr, "info_struct format does not match IHDR"); -# endif /* WRITE_TRANSFORMS */ - - /* Create the zlib state if ncessary: */ - if (png_ptr->zlib_state == NULL) - png_create_zlib_state(png_ptr); - - /* Set up the IDAT zlib compression. */ - debug(png_ptr->zowner != png_IDAT); - png_start_IDAT(png_ptr); -} #endif /* WRITE */ diff --git a/scripts/pnglibconf.dfa b/scripts/pnglibconf.dfa index 2065b80f2..510fce3f0 100644 --- a/scripts/pnglibconf.dfa +++ b/scripts/pnglibconf.dfa @@ -930,20 +930,36 @@ option CONVERT_tIME requires WRITE_ANCILLARY_CHUNKS # png_set_filter interface allowing the application to select the filter # used for each row. # -# SELECT_FILTER_HEURISTICALLY -# Enables code to cause libpng to choose a filter from a set passed to -# png_set_filter. Without this code libpng just chooses the first filter in -# the list if multiple are given. +# SELECT_FILTER +# Enables code to select between multiple filters on write. Without this +# the 'first' (lowest numbered) filter will be selected an this typically +# works out as PNG_FILTER_VALUE_NONE. # -# SELECT_FILTER_METHODICALLY -# Enables code to try all the filters in the list passed to png_set_filter -# and choose the one which results in the least number of compressed bytes -# added by the current row. +# COMPRESSION_BUFFER_MAX +# WARNING: take care if you set this. This is the maximum amount of input +# data that the implementation of deflate can consume before it outputs a +# Huffman table for that data. I.e. before it commits to an encoding of the +# data it has read. This is used solely to implement a limit on the amount +# of image data buffering that occurs inside libpng before filter selection +# is done. Normally the limit is never reached because of the next setting, +# but this is a compile time limit and it is intended to prevent a potential +# DNS service as a result of an application setting the libpng equivalent of +# volume level 11 (read the wikipedia article on "Up to eleven"). +# +# NOTE: the image of a black cat in a coal mine obviously requires this +# limit, but some more valid images can get very close; well over 8MByte. +# +# COMPRESSION_BUFFER_LIMIT +# This is the (overrideable) default for the amount of memory libpng will +# buffer before selecting a filter for a row. It is limited itself to +# COMPRESSION_BUFFER_MAX as values above that level make no change (see the +# previous paragraph.) # # See png.h for more description of these options. option WRITE_FILTER requires WRITE -option SELECT_FILTER_HEURISTICALLY requires WRITE_FILTER enables SET_OPTION -option SELECT_FILTER_METHODICALLY requires WRITE_FILTER enables SET_OPTION +option SELECT_FILTER requires WRITE_FILTER disabled +setting COMPRESSION_BUFFER_MAX default 8453377 +setting COMPRESSION_BUFFER_LIMIT default 8453377 # added at libpng-1.5.4 diff --git a/scripts/pnglibconf.h.prebuilt b/scripts/pnglibconf.h.prebuilt index 31985e80c..27abfc786 100644 --- a/scripts/pnglibconf.h.prebuilt +++ b/scripts/pnglibconf.h.prebuilt @@ -1,8 +1,7 @@ /* libpng 1.7.0beta80 STANDARD API DEFINITION */ - /* pnglibconf.h - library build configuration */ -/* Libpng version 1.7.0beta80, March 9, 2016 */ +/* libpng version 1.7.0beta80, March 9, 2016 */ /* Copyright (c) 1998-2016 Glenn Randers-Pehrson */ @@ -100,8 +99,7 @@ #define PNG_READ_tRNS_SUPPORTED #define PNG_READ_zTXt_SUPPORTED #define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED -#define PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED -#define PNG_SELECT_FILTER_METHODICALLY_SUPPORTED +/*#undef PNG_SELECT_FILTER_SUPPORTED*/ #define PNG_SEQUENTIAL_READ_SUPPORTED #define PNG_SETJMP_SUPPORTED #define PNG_SETTING_SUPPORTED @@ -193,6 +191,8 @@ /* settings */ #define PNG_ABORT { (abort()); } #define PNG_API_RULE 0 +#define PNG_COMPRESSION_BUFFER_LIMIT 8453377 +#define PNG_COMPRESSION_BUFFER_MAX 8453377 #define PNG_DEFAULT_GAMMA_ACCURACY 665 #define PNG_DEFAULT_READ_MACROS 1 #define PNG_GAMMA_THRESHOLD_FIXED 153