Expose ability to control libpng's row filter

Disabling adaptive filters can improve image size
This commit is contained in:
Lovell Fuller 2014-10-25 15:42:10 +01:00
parent 66445c359d
commit 45d90b68f1
7 changed files with 76 additions and 9 deletions

View File

@ -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.
*

View File

@ -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 );

View File

@ -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" ) );

View File

@ -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
}

View File

@ -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;

View File

@ -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, ... )

View File

@ -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;