From 620bff2d78104c3b492ff9c537517d754e003b47 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 27 Oct 2014 11:40:43 +0000 Subject: [PATCH] allow symbolic names for flags you can now use numbers or names for GFlags values, eg.: $ vips copy 50020484-00001.png x.png[filter=avg] $ vips copy 50020484-00001.png x.png[filter=64] was numbers only before --- ChangeLog | 1 + libvips/foreign/foreign.c | 5 +++-- libvips/foreign/vipspng.c | 2 ++ libvips/include/vips/foreign.h | 15 +++++++-------- libvips/include/vips/util.h | 1 + libvips/iofuncs/enumtypes.c | 3 +-- libvips/iofuncs/object.c | 6 ++++-- libvips/iofuncs/util.c | 34 ++++++++++++++++++++++++++++++++++ 8 files changed, 53 insertions(+), 14 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1b9f39e5..8f6444c5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18,6 +18,7 @@ - add support for vips8 plugins - added "autorotate" option to jpeg load - added autorot operator +- added @filter option to pngsave (Lovell) 8/10/14 started 7.40.11 - rework extra band handling for colour functions diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index b3723eee..7b1a1b81 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -2487,7 +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) + * @filter: #VipsForeignPngFilter row filter flag(s) * * Write a VIPS image to a file as PNG. * @@ -2507,7 +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). + * Use @filter to specify one or more filters (instead of adaptive filtering), + * see #VipsForeignPngFilter. * * The image is automatically converted to RGB, RGBA, Monochrome or Mono + * alpha before saving. Images with more than one byte per band element are diff --git a/libvips/foreign/vipspng.c b/libvips/foreign/vipspng.c index 171d0541..e5cad2a7 100644 --- a/libvips/foreign/vipspng.c +++ b/libvips/foreign/vipspng.c @@ -50,6 +50,8 @@ * - more robust error handling from libpng * 9/8/14 * - don't check profiles, helps with libpng >=1.6.11 + * 27/10/14 Lovell + * - add @filter option */ /* diff --git a/libvips/include/vips/foreign.h b/libvips/include/vips/foreign.h index 0e9e3665..4a2418d7 100644 --- a/libvips/include/vips/foreign.h +++ b/libvips/include/vips/foreign.h @@ -438,12 +438,12 @@ int vips_magickload( const char *filename, VipsImage **out, ... ) /** * 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 + * @VIPS_FOREIGN_PNG_FILTER_NONE: no filtering + * @VIPS_FOREIGN_PNG_FILTER_SUB: difference to the left + * @VIPS_FOREIGN_PNG_FILTER_UP: difference up + * @VIPS_FOREIGN_PNG_FILTER_AVG: average of left and up + * @VIPS_FOREIGN_PNG_FILTER_PAETH: pick best neighbor predictor automatically + * @VIPS_FOREIGN_PNG_FILTER_ALL: adaptive * * http://www.w3.org/TR/PNG-Filters.html * The values mirror those of png.h in libpng. @@ -454,8 +454,7 @@ typedef enum /*< flags >*/ { 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 + VIPS_FOREIGN_PNG_FILTER_ALL = 0xEA } VipsForeignPngFilter; int vips_pngload( const char *filename, VipsImage **out, ... ) diff --git a/libvips/include/vips/util.h b/libvips/include/vips/util.h index 4043dd10..38c0499d 100644 --- a/libvips/include/vips/util.h +++ b/libvips/include/vips/util.h @@ -165,6 +165,7 @@ G_STMT_START { \ const char *vips_enum_string( GType enm, int value ); const char *vips_enum_nick( GType enm, int value ); int vips_enum_from_nick( const char *domain, GType type, const char *str ); +int vips_flags_from_nick( const char *domain, GType type, const char *nick ); gboolean vips_slist_equal( GSList *l1, GSList *l2 ); void *vips_slist_map2( GSList *list, VipsSListMap2Fn fn, void *a, void *b ); diff --git a/libvips/iofuncs/enumtypes.c b/libvips/iofuncs/enumtypes.c index 3f2c8e74..e182bfc8 100644 --- a/libvips/iofuncs/enumtypes.c +++ b/libvips/iofuncs/enumtypes.c @@ -118,10 +118,9 @@ vips_foreign_png_filter_get_type( void ) {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 ); } diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index 492f5e95..b120dc59 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -1961,7 +1961,7 @@ vips_object_set_argument_from_string( VipsObject *object, g_value_set_enum( &gvalue, i ); } else if( G_IS_PARAM_SPEC_FLAGS( pspec ) ) { - /* Hard to set from a symbolic name. Just take an int. + /* Allow a symbolic name, or an int. */ int i; @@ -1970,7 +1970,9 @@ vips_object_set_argument_from_string( VipsObject *object, return( -1 ); } - if( sscanf( value, "%d", &i ) != 1 ) { + if( sscanf( value, "%d", &i ) != 1 && + (i = vips_flags_from_nick( class->nickname, + otype, value )) < 0 ) { vips_error( class->nickname, _( "'%s' is not an integer" ), value ); return( -1 ); diff --git a/libvips/iofuncs/util.c b/libvips/iofuncs/util.c index 1942dd1a..fd1d07dd 100644 --- a/libvips/iofuncs/util.c +++ b/libvips/iofuncs/util.c @@ -1597,6 +1597,40 @@ vips_enum_from_nick( const char *domain, GType type, const char *nick ) return( -1 ); } +int +vips_flags_from_nick( const char *domain, GType type, const char *nick ) +{ + GTypeClass *class; + GFlagsClass *gflags; + GFlagsValue *flags_value; + int i; + char str[1000]; + VipsBuf buf = VIPS_BUF_STATIC( str ); + + if( !(class = g_type_class_ref( type )) ) { + vips_error( domain, "%s", _( "no such flag type" ) ); + return( -1 ); + } + gflags = G_FLAGS_CLASS( class ); + + if( (flags_value = g_flags_get_value_by_name( gflags, nick )) ) + return( flags_value->value ); + if( (flags_value = g_flags_get_value_by_nick( gflags, nick )) ) + return( flags_value->value ); + + for( i = 0; i < gflags->n_values; i++ ) { + if( i > 0 ) + vips_buf_appends( &buf, ", " ); + vips_buf_appends( &buf, gflags->values[i].value_nick ); + } + + vips_error( domain, _( "flags '%s' has no member '%s', " + "should be one of: %s" ), + g_type_name( type ), nick, vips_buf_all( &buf ) ); + + return( -1 ); +} + /* Scan @buf for the first "%ns" (eg. "%12s") and substitute the * lowest-numbered one for @sub. @buf is @len bytes in size. *