Change option (SUPPORTED) names, dummy code

The filter selection options are made more intuitive (IMO, but I am not an
Intuitive User).  Dummy code added for methodical filter selection.

Signed-off-by: John Bowler <jbowler@acm.org>
This commit is contained in:
John Bowler 2015-12-02 19:03:28 -08:00
parent 71c5123a4d
commit 9fce04fcd6
5 changed files with 102 additions and 61 deletions

38
png.h
View File

@ -1661,22 +1661,26 @@ 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.
*
* PNG_WRITE_OPTIMIZE_FITLER_SUPPORTED:
* 2) If WRITE_OPTIMIZE_FILTER is supported and it has not been disabled by
* png_set_option(PNG_DISABLE_OPTIMIZE_FILTER, PNG_OPTION_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_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.
*
* PNG_WRITE_HEURISTIC_FITLER_SUPPORTED:
* 3) If not (2) an WRITE_HEURISTIC_FILTER is supported and has not been
* disabled by png_set_option(PNG_DISABLE_HEURISTIC_FILTER, PNG_OPTION_ON)
* libpng tests the start of each row (a few thousand bytes at most) to see
* which filter is likely to produce best compression.
* 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.
*
* 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
* want to use NONE or SUB on the first row.
@ -1685,11 +1689,11 @@ PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action,
* preceding byte as a predictor and is not likely to have very good
* performance.
*
* The WRITE_OPTIMIZE_FILTER option is slow and memory intensive, but it is
* likely to produce the smallest PNG file. Depending on the image data the
* HEURISTIC option may improve results and has little overall effect on
* compression speed, however it can sometimes produce larger files than not
* using any filtering.
* 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));
@ -3491,8 +3495,8 @@ PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file,
#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_DISABLE_HEURISTIC_FILTER 6 /* SOFTWARE: see png_set_filter */
#define PNG_DISABLE_OPTIMIZE_FILTER 8 /* SOFTWARE: see png_set_filter */
#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 */
/* Return values: NOTE: there are four values and 'off' is *not* zero */

View File

@ -751,6 +751,9 @@ struct png_struct_def
png_compression_bufferp *zbuffer_end; /* 'next' field of current buffer */
png_uint_32 zbuffer_len; /* Length of data in list */
unsigned int zbuffer_start; /* Bytes written from start */
# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
png_voidp zbuffer_select;
# endif /* SELECT_FILTER_METHODICALLY */
# endif /* WRITE */
# ifdef PNG_READ_SUPPORTED
unsigned int zstream_ended:1; /* no more zlib output available [read] */

View File

@ -2375,16 +2375,16 @@ filter_row(png_structrp png_ptr, png_const_bytep prev_row,
/* These two #defines simplify writing code that depends on one or the other of
* the options being both supported and on:
*/
#ifdef PNG_WRITE_OPTIMIZE_FILTER_SUPPORTED
# define optimize_filters\
(((png_ptr->options >> PNG_DISABLE_OPTIMIZE_FILTER)&3) != PNG_OPTION_ON)
#ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
# define methodical_option\
((png_ptr->options >> PNG_SELECT_FILTER_METHODICALLY) & 3U)
#else
# define optimize_filters 0
# define methodical_option PNG_OPTION_OFF
#endif
#ifdef PNG_WRITE_HEURISTIC_FILTER_SUPPORTED
# define heuristic_filters\
(((png_ptr->options >> PNG_DISABLE_HEURISTIC_FILTER)&3) != PNG_OPTION_ON)
#ifdef PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED
# define heuristic_option\
((png_ptr->options >> PNG_SELECT_FILTER_HEURISTICALLY) & 3U)
static unsigned int
select_filter_heuristically(png_structrp png_ptr, png_const_bytep prev_row,
@ -2451,9 +2451,41 @@ select_filter_heuristically(png_structrp png_ptr, png_const_bytep prev_row,
return PNG_FILTER_MASK(best_filter);
}
}
#else /* !WRITE_HEURISTIC_FILTER */
# define heuristic_filters 0
#endif /* !WRITE_HEURISTIC_FILTER */
#else /* !SELECT_FILTER_HEURISTICALLY */
# define heuristic_option PNG_OPTION_OFF
#endif /* !SELECT_FILTER_HEURISTICALLY */
#ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
static void
select_filters_methodically_init(png_structrp png_ptr)
{
affirm(png_ptr->zbuffer_select == NULL);
}
static int
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_image)
{
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);
debug((row_bits % bpp) == 0U);
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]);
write_unfiltered_rowbits(png_ptr, unfiltered_row, row_bits,
PNG_FILTER_VALUE_LAST, end_of_image);
return filters_to_try;
}
#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
@ -2481,8 +2513,10 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels,
{
/* Delaying initialization of the filter stuff. */
if (png_ptr->filter_mask == 0U)
png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, (optimize_filters ||
heuristic_filters) ? PNG_ALL_FILTERS : PNG_NO_FILTERS);
png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE,
(methodical_option != PNG_OPTION_OFF ||
heuristic_option != PNG_OPTION_OFF) ?
PNG_ALL_FILTERS : PNG_NO_FILTERS);
/* Now work out the filters to try for this row: */
filters_to_try = png_ptr->filter_mask; /* else caller must preserve */
@ -2539,19 +2573,20 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels,
# undef match
}
/* Is this a list of filters which can be simplified to a single filter?
* If there is no selection algorithm enabled do so now:
*
* (Errors in the logic here trigger the 'impossible' else below.)
/* If there is no selection algorithm enabled choose the first filter
* in the list, otherwise do algorithm-specific initialization.
*/
# ifdef PNG_WRITE_OPTIMIZE_FILTER_SUPPORTED
if (((png_ptr->options >> PNG_DISABLE_OPTIMIZE_FILTER) & 3) ==
PNG_OPTION_ON) /* optimize supported but disabled */
# endif /* WRITE_OPTIMIZE_FILTER */
# ifdef PNG_WRITE_HEURISTIC_FILTER_SUPPORTED
if (((png_ptr->options >> PNG_DISABLE_HEURISTIC_FILTER) & 3) ==
PNG_OPTION_ON) /* heuristic supported but disabled */
# endif /* WRITE_HEURISTIC_FILTER */
# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
if (methodical_option == PNG_OPTION_ON ||
(methodical_option != PNG_OPTION_OFF &&
heuristic_option != PNG_OPTION_ON))
select_filters_methodically_init(png_ptr);
else /* don't do methodical selection */
# endif /* SELECT_FILTER_METHODICALLY */
# ifdef PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED
if (heuristic_option == PNG_OPTION_OFF) /* don't use heuristics */
# endif /* SELECT_FILTER_HEURISTICALLY */
filters_to_try &= -filters_to_try;
} /* start of row */
@ -2579,25 +2614,24 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels,
prev_pixels, unfiltered_row, row_bits, bpp, filters_to_try, x == 0,
end_of_image);
# ifdef PNG_WRITE_OPTIMIZE_FILTER_SUPPORTED
#if 0
else if (((png_ptr->options >> PNG_DISABLE_OPTIMIZE_FILTER) & 3) !=
PNG_OPTION_ON) /* optimize supported and not disabled */
impossible("optimize filters NYI");
#endif
# endif /* WRITE_OPTIMIZE_FITLER */
# ifdef PNG_WRITE_HEURISTIC_FILTER_SUPPORTED
# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
else if (png_ptr->zbuffer_select != NULL)
filters_to_try = select_filter_methodically(png_ptr,
first_row_in_pass ? NULL : prev_row, prev_pixels, unfiltered_row,
row_bits, bpp, filters_to_try, end_of_image);
# endif /* SELECT_FILTER_METHODICALLY */
# ifdef PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED
/* The heuristic must select a single filter based on the first block of
* pixels:
*/
else if (((png_ptr->options >> PNG_DISABLE_HEURISTIC_FILTER) & 3) !=
PNG_OPTION_ON)
else
filters_to_try = select_filter_heuristically(png_ptr,
first_row_in_pass ? NULL : prev_row, prev_pixels, unfiltered_row,
row_bits, bpp, filters_to_try, end_of_image);
# endif /* WRITE_HEURISTIC_FITLER */
else
impossible("bad filter select logic");
# else /* !SELECT_FILTER_HEURISTICALLY */
else
impossible("bad filter select logic");
# endif /* !SELECT_FILTER_HEURISTICALLY */
/* 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

View File

@ -925,24 +925,24 @@ option CONVERT_tIME requires WRITE_ANCILLARY_CHUNKS
#
# WRITE_FILTER
# Enables code to do PNG row filtering on write. If not enabled rows will
# be written without filtering, the 'NONE' filter. This enables the
# be written without filtering; the 'NONE' filter. This enables the
# png_set_filter interface allowing the application to select the filter
# used for each row.
#
# WRITE_HEURISTIC_FILTER
# 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.
#
# WRITE_OPTIMIZE_FILTER
# 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.
#
# See png.h for more description of these options.
option WRITE_FILTER requires WRITE
option WRITE_HEURISTIC_FILTER requires WRITE_FILTER enables SET_OPTION
option WRITE_OPTIMIZE_FILTER requires WRITE_FILTER enables SET_OPTION
option SELECT_FILTER_HEURISTICALLY requires WRITE_FILTER enables SET_OPTION
option SELECT_FILTER_METHODICALLY requires WRITE_FILTER enables SET_OPTION
# added at libpng-1.5.4

View File

@ -134,13 +134,13 @@
#define PNG_WRITE_FILTER_SUPPORTED
#define PNG_WRITE_FLUSH_SUPPORTED
#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED
#define PNG_WRITE_HEURISTIC_FILTER_SUPPORTED
#define PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED
#define PNG_WRITE_INTERLACING_SUPPORTED
#define PNG_WRITE_INT_FUNCTIONS_SUPPORTED
#define PNG_WRITE_INVERT_ALPHA_SUPPORTED
#define PNG_WRITE_INVERT_SUPPORTED
#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
#define PNG_WRITE_OPTIMIZE_FILTER_SUPPORTED
#define PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
#define PNG_WRITE_PACKSWAP_SUPPORTED
#define PNG_WRITE_PACK_SUPPORTED
#define PNG_WRITE_PNG_SUPPORTED