From 45d90b68f1150d799cccbefca9caaa348ea542da Mon Sep 17 00:00:00 2001 From: Lovell Fuller Date: Sat, 25 Oct 2014 15:42:10 +0100 Subject: [PATCH] Expose ability to control libpng's row filter Disabling adaptive filters can improve image size --- libvips/foreign/foreign.c | 4 ++++ libvips/foreign/pngsave.c | 14 ++++++++++++-- libvips/foreign/vipspng.c | 16 +++++++++++----- libvips/foreign/vipspng.h | 5 +++-- libvips/include/vips/enumtypes.h | 2 ++ libvips/include/vips/foreign.h | 22 ++++++++++++++++++++++ libvips/iofuncs/enumtypes.c | 22 ++++++++++++++++++++++ 7 files changed, 76 insertions(+), 9 deletions(-) diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index daa7f0bd..b3723eee 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -2487,6 +2487,7 @@ vips_pngload_buffer( void *buf, size_t len, VipsImage **out, ... ) * @compression: compression level * @interlace: interlace image * @profile: ICC profile to embed + * @filter: libpng row filter flag(s) * * Write a VIPS image to a file as PNG. * @@ -2506,6 +2507,8 @@ vips_pngload_buffer( void *buf, size_t len, VipsImage **out, ... ) * contains an ICC profile named VIPS_META_ICC_NAME ("icc-profile-data"), the * profile from the VIPS header will be attached. * + * Use @filter to specify one or more filters (instead of adaptive filtering). + * * The image is automatically converted to RGB, RGBA, Monochrome or Mono + * alpha before saving. Images with more than one byte per band element are * saved as 16-bit PNG, others are saved as 8-bit PNG. @@ -2539,6 +2542,7 @@ vips_pngsave( VipsImage *in, const char *filename, ... ) * @compression: compression level * @interlace: interlace image * @profile: ICC profile to embed + * @filter: libpng row filter flag(s) * * As vips_pngsave(), but save to a memory buffer. * diff --git a/libvips/foreign/pngsave.c b/libvips/foreign/pngsave.c index 18582082..777d07f1 100644 --- a/libvips/foreign/pngsave.c +++ b/libvips/foreign/pngsave.c @@ -59,6 +59,7 @@ typedef struct _VipsForeignSavePng { int compression; gboolean interlace; char *profile; + VipsForeignPngFilter filter; } VipsForeignSavePng; typedef VipsForeignSaveClass VipsForeignSavePngClass; @@ -124,12 +125,21 @@ vips_foreign_save_png_class_init( VipsForeignSavePngClass *class ) G_STRUCT_OFFSET( VipsForeignSavePng, profile ), NULL ); + VIPS_ARG_FLAGS( class, "filter", 12, + _( "Filter" ), + _( "libpng row filter flag(s)" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsForeignSavePng, filter ), + VIPS_TYPE_FOREIGN_PNG_FILTER, + VIPS_FOREIGN_PNG_FILTER_ALL ); + } static void vips_foreign_save_png_init( VipsForeignSavePng *png ) { png->compression = 6; + png->filter = VIPS_FOREIGN_PNG_FILTER_ALL; } typedef struct _VipsForeignSavePngFile { @@ -155,7 +165,7 @@ vips_foreign_save_png_file_build( VipsObject *object ) return( -1 ); if( vips__png_write( save->ready, png_file->filename, - png->compression, png->interlace, png->profile ) ) + png->compression, png->interlace, png->profile, png->filter ) ) return( -1 ); return( 0 ); @@ -213,7 +223,7 @@ vips_foreign_save_png_buffer_build( VipsObject *object ) return( -1 ); if( vips__png_write_buf( save->ready, &obuf, &olen, - png->compression, png->interlace, png->profile ) ) + png->compression, png->interlace, png->profile, png->filter ) ) return( -1 ); blob = vips_blob_new( (VipsCallbackFn) vips_free, obuf, olen ); diff --git a/libvips/foreign/vipspng.c b/libvips/foreign/vipspng.c index c639c9fa..171d0541 100644 --- a/libvips/foreign/vipspng.c +++ b/libvips/foreign/vipspng.c @@ -783,7 +783,8 @@ write_png_block( VipsRegion *region, VipsRect *area, void *a ) /* Write a VIPS image to PNG. */ static int -write_vips( Write *write, int compress, int interlace, const char *profile ) +write_vips( Write *write, int compress, int interlace, const char *profile, + VipsForeignPngFilter filter ) { VipsImage *in = write->in; @@ -824,6 +825,10 @@ write_vips( Write *write, int compress, int interlace, const char *profile ) */ png_set_compression_level( write->pPng, compress ); + /* Set row filter. + */ + png_set_filter( write->pPng, 0, filter ); + bit_depth = in->BandFmt == VIPS_FORMAT_UCHAR ? 8 : 16; switch( in->Bands ) { @@ -921,7 +926,8 @@ write_vips( Write *write, int compress, int interlace, const char *profile ) int vips__png_write( VipsImage *in, const char *filename, - int compress, int interlace, const char *profile ) + int compress, int interlace, const char *profile, + VipsForeignPngFilter filter ) { Write *write; @@ -940,7 +946,7 @@ vips__png_write( VipsImage *in, const char *filename, /* Convert it! */ - if( write_vips( write, compress, interlace, profile ) ) { + if( write_vips( write, compress, interlace, profile, filter ) ) { vips_error( "vips2png", _( "unable to write \"%s\"" ), filename ); @@ -1027,7 +1033,7 @@ user_write_data( png_structp png_ptr, png_bytep data, png_size_t length ) int vips__png_write_buf( VipsImage *in, void **obuf, size_t *olen, int compression, int interlace, - const char *profile ) + const char *profile, VipsForeignPngFilter filter ) { WriteBuf *wbuf; Write *write; @@ -1043,7 +1049,7 @@ vips__png_write_buf( VipsImage *in, /* Convert it! */ - if( write_vips( write, compression, interlace, profile ) ) { + if( write_vips( write, compression, interlace, profile, filter ) ) { write_buf_free( wbuf ); vips_error( "vips2png", "%s", _( "unable to write to buffer" ) ); diff --git a/libvips/foreign/vipspng.h b/libvips/foreign/vipspng.h index feb1eddd..843999b6 100644 --- a/libvips/foreign/vipspng.h +++ b/libvips/foreign/vipspng.h @@ -46,10 +46,11 @@ int vips__png_read_buffer( char *buffer, size_t length, VipsImage *out, int vips__png_header_buffer( char *buffer, size_t length, VipsImage *out ); int vips__png_write( VipsImage *in, const char *filename, - int compress, int interlace, const char *profile ); + int compress, int interlace, const char *profile, + VipsForeignPngFilter filter ); int vips__png_write_buf( VipsImage *in, void **obuf, size_t *olen, int compression, int interlace, - const char *profile ); + const char *profile, VipsForeignPngFilter filter ); #ifdef __cplusplus } diff --git a/libvips/include/vips/enumtypes.h b/libvips/include/vips/enumtypes.h index 970596d1..251d387f 100644 --- a/libvips/include/vips/enumtypes.h +++ b/libvips/include/vips/enumtypes.h @@ -17,6 +17,8 @@ GType vips_foreign_tiff_predictor_get_type (void) G_GNUC_CONST; #define VIPS_TYPE_FOREIGN_TIFF_PREDICTOR (vips_foreign_tiff_predictor_get_type()) GType vips_foreign_tiff_resunit_get_type (void) G_GNUC_CONST; #define VIPS_TYPE_FOREIGN_TIFF_RESUNIT (vips_foreign_tiff_resunit_get_type()) +GType vips_foreign_png_filter_get_type (void) G_GNUC_CONST; +#define VIPS_TYPE_FOREIGN_PNG_FILTER (vips_foreign_png_filter_get_type()) GType vips_foreign_dz_layout_get_type (void) G_GNUC_CONST; #define VIPS_TYPE_FOREIGN_DZ_LAYOUT (vips_foreign_dz_layout_get_type()) GType vips_foreign_dz_depth_get_type (void) G_GNUC_CONST; diff --git a/libvips/include/vips/foreign.h b/libvips/include/vips/foreign.h index ed096075..0e9e3665 100644 --- a/libvips/include/vips/foreign.h +++ b/libvips/include/vips/foreign.h @@ -436,6 +436,28 @@ int vips_matrixprint( VipsImage *in, ... ) int vips_magickload( const char *filename, VipsImage **out, ... ) __attribute__((sentinel)); +/** + * VipsForeignPngFilter: + * @VIPS_FOREIGN_PNG_FILTER_NONE + * @VIPS_FOREIGN_PNG_FILTER_SUB + * @VIPS_FOREIGN_PNG_FILTER_UP + * @VIPS_FOREIGN_PNG_FILTER_AVG + * @VIPS_FOREIGN_PNG_FILTER_PAETH + * @VIPS_FOREIGN_PNG_FILTER_ALL + * + * http://www.w3.org/TR/PNG-Filters.html + * The values mirror those of png.h in libpng. + */ +typedef enum /*< flags >*/ { + VIPS_FOREIGN_PNG_FILTER_NONE = 0x08, + VIPS_FOREIGN_PNG_FILTER_SUB = 0x10, + VIPS_FOREIGN_PNG_FILTER_UP = 0x20, + VIPS_FOREIGN_PNG_FILTER_AVG = 0x40, + VIPS_FOREIGN_PNG_FILTER_PAETH = 0x80, + VIPS_FOREIGN_PNG_FILTER_ALL = 0xEA, + VIPS_FOREIGN_PNG_FILTER_LAST = 0xFF +} VipsForeignPngFilter; + int vips_pngload( const char *filename, VipsImage **out, ... ) __attribute__((sentinel)); int vips_pngload_buffer( void *buf, size_t len, VipsImage **out, ... ) diff --git a/libvips/iofuncs/enumtypes.c b/libvips/iofuncs/enumtypes.c index 5e091590..3f2c8e74 100644 --- a/libvips/iofuncs/enumtypes.c +++ b/libvips/iofuncs/enumtypes.c @@ -106,6 +106,28 @@ vips_foreign_tiff_resunit_get_type( void ) return( etype ); } GType +vips_foreign_png_filter_get_type( void ) +{ + static GType etype = 0; + + if( etype == 0 ) { + static const GFlagsValue values[] = { + {VIPS_FOREIGN_PNG_FILTER_NONE, "VIPS_FOREIGN_PNG_FILTER_NONE", "none"}, + {VIPS_FOREIGN_PNG_FILTER_SUB, "VIPS_FOREIGN_PNG_FILTER_SUB", "sub"}, + {VIPS_FOREIGN_PNG_FILTER_UP, "VIPS_FOREIGN_PNG_FILTER_UP", "up"}, + {VIPS_FOREIGN_PNG_FILTER_AVG, "VIPS_FOREIGN_PNG_FILTER_AVG", "avg"}, + {VIPS_FOREIGN_PNG_FILTER_PAETH, "VIPS_FOREIGN_PNG_FILTER_PAETH", "paeth"}, + {VIPS_FOREIGN_PNG_FILTER_ALL, "VIPS_FOREIGN_PNG_FILTER_ALL", "all"}, + {VIPS_FOREIGN_PNG_FILTER_LAST, "VIPS_FOREIGN_PNG_FILTER_LAST", "last"}, + {0, NULL, NULL} + }; + + etype = g_flags_register_static( "VipsForeignPngFilter", values ); + } + + return( etype ); +} +GType vips_foreign_dz_layout_get_type( void ) { static GType etype = 0;