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 * ignored if SUB is set; this is because these filter pairs are equivalent
* when there is no previous row. * when there is no previous row.
* *
* PNG_WRITE_OPTIMIZE_FITLER_SUPPORTED: * 2) PNG_SELECT_FILTER_METHODICALLY_SUPPORTED:
* 2) If WRITE_OPTIMIZE_FILTER is supported and it has not been disabled by * If SELECT_FILTER_METHODICALLY is 'on' libpng tries all the filters in the
* png_set_option(PNG_DISABLE_OPTIMIZE_FILTER, PNG_OPTION_ON) libpng tries * list and selects the one which gives the shortest compressed row, favoring
* all the filters in the list and selects the one which gives the shortest * earlier filters.
* compressed row, favoring earlier filters.
* *
* PNG_WRITE_HEURISTIC_FITLER_SUPPORTED: * 3) PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED:
* 3) If not (2) an WRITE_HEURISTIC_FILTER is supported and has not been * If SELECT_FILTER_HEURISTICALLY is 'on' libpng tests the start of each row
* disabled by png_set_option(PNG_DISABLE_HEURISTIC_FILTER, PNG_OPTION_ON) * (a few thousand bytes at most) to see which filter is likely to produce
* libpng tests the start of each row (a few thousand bytes at most) to see * best compression.
* which filter is likely to produce best compression.
* *
* 4) If neither (2) nor (3) libpng selects the first filter in the list (there * 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 * is no warning that this will happen - check the #defines if you need to
* know.) * 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 * 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 * PAETH filter before the first call to png_write_row, depending on whether you
* want to use NONE or SUB on the first row. * 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 * preceding byte as a predictor and is not likely to have very good
* performance. * performance.
* *
* The WRITE_OPTIMIZE_FILTER option is slow and memory intensive, but it is * The SELECT_FILTER_METHODICALLY option is slow and memory intensive, but it is
* likely to produce the smallest PNG file. Depending on the image data the * almost certain to produce the smallest PNG file. Depending on the image data
* HEURISTIC option may improve results and has little overall effect on * the HEURISTIC option may improve results significantly over the NONE filter
* compression speed, however it can sometimes produce larger files than not * and it has little overall effect on compression speed, however it can
* using any filtering. * sometimes produce larger files than not using any filtering.
*/ */
PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method, PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method,
int filters)); 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_EXTENSIONS 0 /* BOTH: enable or disable extensions */
#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */ #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_SKIP_sRGB_CHECK_PROFILE 4 /* SOFTWARE: Check ICC profile for sRGB */
#define PNG_DISABLE_HEURISTIC_FILTER 6 /* SOFTWARE: see png_set_filter */ #define PNG_SELECT_FILTER_HEURISTICALLY 6 /* SOFTWARE: see png_set_filter */
#define PNG_DISABLE_OPTIMIZE_FILTER 8 /* 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 10 /* Next option - numbers must be even */
/* Return values: NOTE: there are four values and 'off' is *not* zero */ /* 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_compression_bufferp *zbuffer_end; /* 'next' field of current buffer */
png_uint_32 zbuffer_len; /* Length of data in list */ png_uint_32 zbuffer_len; /* Length of data in list */
unsigned int zbuffer_start; /* Bytes written from start */ unsigned int zbuffer_start; /* Bytes written from start */
# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
png_voidp zbuffer_select;
# endif /* SELECT_FILTER_METHODICALLY */
# endif /* WRITE */ # endif /* WRITE */
# ifdef PNG_READ_SUPPORTED # ifdef PNG_READ_SUPPORTED
unsigned int zstream_ended:1; /* no more zlib output available [read] */ 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 /* These two #defines simplify writing code that depends on one or the other of
* the options being both supported and on: * the options being both supported and on:
*/ */
#ifdef PNG_WRITE_OPTIMIZE_FILTER_SUPPORTED #ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
# define optimize_filters\ # define methodical_option\
(((png_ptr->options >> PNG_DISABLE_OPTIMIZE_FILTER)&3) != PNG_OPTION_ON) ((png_ptr->options >> PNG_SELECT_FILTER_METHODICALLY) & 3U)
#else #else
# define optimize_filters 0 # define methodical_option PNG_OPTION_OFF
#endif #endif
#ifdef PNG_WRITE_HEURISTIC_FILTER_SUPPORTED #ifdef PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED
# define heuristic_filters\ # define heuristic_option\
(((png_ptr->options >> PNG_DISABLE_HEURISTIC_FILTER)&3) != PNG_OPTION_ON) ((png_ptr->options >> PNG_SELECT_FILTER_HEURISTICALLY) & 3U)
static unsigned int static unsigned int
select_filter_heuristically(png_structrp png_ptr, png_const_bytep prev_row, 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); return PNG_FILTER_MASK(best_filter);
} }
} }
#else /* !WRITE_HEURISTIC_FILTER */ #else /* !SELECT_FILTER_HEURISTICALLY */
# define heuristic_filters 0 # define heuristic_option PNG_OPTION_OFF
#endif /* !WRITE_HEURISTIC_FILTER */ #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 /* 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 * 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. */ /* Delaying initialization of the filter stuff. */
if (png_ptr->filter_mask == 0U) if (png_ptr->filter_mask == 0U)
png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, (optimize_filters || png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE,
heuristic_filters) ? PNG_ALL_FILTERS : PNG_NO_FILTERS); (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: */ /* Now work out the filters to try for this row: */
filters_to_try = png_ptr->filter_mask; /* else caller must preserve */ 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 # undef match
} }
/* Is this a list of filters which can be simplified to a single filter? /* If there is no selection algorithm enabled choose the first filter
* If there is no selection algorithm enabled do so now: * in the list, otherwise do algorithm-specific initialization.
*
* (Errors in the logic here trigger the 'impossible' else below.)
*/ */
# ifdef PNG_WRITE_OPTIMIZE_FILTER_SUPPORTED # ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
if (((png_ptr->options >> PNG_DISABLE_OPTIMIZE_FILTER) & 3) == if (methodical_option == PNG_OPTION_ON ||
PNG_OPTION_ON) /* optimize supported but disabled */ (methodical_option != PNG_OPTION_OFF &&
# endif /* WRITE_OPTIMIZE_FILTER */ heuristic_option != PNG_OPTION_ON))
# ifdef PNG_WRITE_HEURISTIC_FILTER_SUPPORTED select_filters_methodically_init(png_ptr);
if (((png_ptr->options >> PNG_DISABLE_HEURISTIC_FILTER) & 3) ==
PNG_OPTION_ON) /* heuristic supported but disabled */ else /* don't do methodical selection */
# endif /* WRITE_HEURISTIC_FILTER */ # 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; filters_to_try &= -filters_to_try;
} /* start of row */ } /* 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, prev_pixels, unfiltered_row, row_bits, bpp, filters_to_try, x == 0,
end_of_image); end_of_image);
# ifdef PNG_WRITE_OPTIMIZE_FILTER_SUPPORTED # ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
#if 0 else if (png_ptr->zbuffer_select != NULL)
else if (((png_ptr->options >> PNG_DISABLE_OPTIMIZE_FILTER) & 3) != filters_to_try = select_filter_methodically(png_ptr,
PNG_OPTION_ON) /* optimize supported and not disabled */ first_row_in_pass ? NULL : prev_row, prev_pixels, unfiltered_row,
impossible("optimize filters NYI"); row_bits, bpp, filters_to_try, end_of_image);
#endif # endif /* SELECT_FILTER_METHODICALLY */
# endif /* WRITE_OPTIMIZE_FITLER */ # ifdef PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED
# ifdef PNG_WRITE_HEURISTIC_FILTER_SUPPORTED
/* The heuristic must select a single filter based on the first block of /* The heuristic must select a single filter based on the first block of
* pixels: * pixels:
*/ */
else if (((png_ptr->options >> PNG_DISABLE_HEURISTIC_FILTER) & 3) != else
PNG_OPTION_ON)
filters_to_try = select_filter_heuristically(png_ptr, filters_to_try = select_filter_heuristically(png_ptr,
first_row_in_pass ? NULL : prev_row, prev_pixels, unfiltered_row, first_row_in_pass ? NULL : prev_row, prev_pixels, unfiltered_row,
row_bits, bpp, filters_to_try, end_of_image); row_bits, bpp, filters_to_try, end_of_image);
# endif /* WRITE_HEURISTIC_FITLER */ # else /* !SELECT_FILTER_HEURISTICALLY */
else else
impossible("bad filter select logic"); impossible("bad filter select logic");
# endif /* !SELECT_FILTER_HEURISTICALLY */
/* Copy the current row into the previous row buffer, if available, unless /* 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 * 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 # WRITE_FILTER
# Enables code to do PNG row filtering on write. If not enabled rows will # 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 # png_set_filter interface allowing the application to select the filter
# used for each row. # used for each row.
# #
# WRITE_HEURISTIC_FILTER # SELECT_FILTER_HEURISTICALLY
# Enables code to cause libpng to choose a filter from a set passed to # 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 # png_set_filter. Without this code libpng just chooses the first filter in
# the list if multiple are given. # 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 # 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 # and choose the one which results in the least number of compressed bytes
# added by the current row. # added by the current row.
# #
# See png.h for more description of these options. # See png.h for more description of these options.
option WRITE_FILTER requires WRITE option WRITE_FILTER requires WRITE
option WRITE_HEURISTIC_FILTER requires WRITE_FILTER enables SET_OPTION option SELECT_FILTER_HEURISTICALLY requires WRITE_FILTER enables SET_OPTION
option WRITE_OPTIMIZE_FILTER requires WRITE_FILTER enables SET_OPTION option SELECT_FILTER_METHODICALLY requires WRITE_FILTER enables SET_OPTION
# added at libpng-1.5.4 # added at libpng-1.5.4

View File

@ -134,13 +134,13 @@
#define PNG_WRITE_FILTER_SUPPORTED #define PNG_WRITE_FILTER_SUPPORTED
#define PNG_WRITE_FLUSH_SUPPORTED #define PNG_WRITE_FLUSH_SUPPORTED
#define PNG_WRITE_GET_PALETTE_MAX_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_INTERLACING_SUPPORTED
#define PNG_WRITE_INT_FUNCTIONS_SUPPORTED #define PNG_WRITE_INT_FUNCTIONS_SUPPORTED
#define PNG_WRITE_INVERT_ALPHA_SUPPORTED #define PNG_WRITE_INVERT_ALPHA_SUPPORTED
#define PNG_WRITE_INVERT_SUPPORTED #define PNG_WRITE_INVERT_SUPPORTED
#define PNG_WRITE_OPTIMIZE_CMF_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_PACKSWAP_SUPPORTED
#define PNG_WRITE_PACK_SUPPORTED #define PNG_WRITE_PACK_SUPPORTED
#define PNG_WRITE_PNG_SUPPORTED #define PNG_WRITE_PNG_SUPPORTED