From 3681ce0e776b0512beb269174d47b31aa14db129 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 1 Nov 2016 10:14:12 +0000 Subject: [PATCH 1/2] fix vipsheader with new get/set system --- TODO | 6 ++ libvips/iofuncs/buf.c | 142 +++++++++++++++++++++++++++++++++++++++-- libvips/iofuncs/util.c | 1 + tools/vipsheader.c | 37 ++++------- 4 files changed, 155 insertions(+), 31 deletions(-) diff --git a/TODO b/TODO index 715f4c8f..78b50f08 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,9 @@ +- look at vips_image_get_as_string() vs. vips_buf_appendgv() + + should Hist and getext be true header fields? + + vipsheader is not displaying filename correctly + - not sure about utf8 error messages on win - strange: diff --git a/libvips/iofuncs/buf.c b/libvips/iofuncs/buf.c index a067c158..3b2e104e 100644 --- a/libvips/iofuncs/buf.c +++ b/libvips/iofuncs/buf.c @@ -493,19 +493,151 @@ vips_buf_appendd( VipsBuf *buf, int d ) * @buf: the buffer * @value: #GValue to format and append * - * Format and append a #GValue with g_strdup_value_contents(). + * Format and append a #GValue. This doesn't use g_strdup_value_contents(): + * that doesn't do what we want for some types and can change too much between + * glib versions. * * Returns: %FALSE on overflow, %TRUE otherwise. */ gboolean vips_buf_appendgv( VipsBuf *buf, GValue *value ) { - char *str_value; + GType type = G_VALUE_TYPE( value ); + GType fundamental = g_type_fundamental( type ); + + gboolean handled; gboolean result; - str_value = g_strdup_value_contents( value ); - result = vips_buf_appends( buf, str_value ); - g_free( str_value ); + result = FALSE; + handled = FALSE; + + switch( fundamental ) { + case G_TYPE_STRING: + /* These are GStrings, vips refstrings are handled by boxed, see + * below. + */ + result = vips_buf_appends( buf, g_value_get_string( value ) ); + handled = TRUE; + break; + + case G_TYPE_OBJECT: +{ + GObject *object; + + object = g_value_get_object( value ); + if( VIPS_IS_OBJECT( object ) ) { + vips_object_summary( VIPS_OBJECT( object ), buf ); + result = TRUE; + handled = TRUE; + } +} + break; + + case G_TYPE_INT: + result = vips_buf_appendf( buf, + "%d", g_value_get_int( value ) ); + handled = TRUE; + break; + + case G_TYPE_UINT64: + result = vips_buf_appendf( buf, + "%zd", g_value_get_uint64( value ) ); + handled = TRUE; + break; + + case G_TYPE_DOUBLE: + result = vips_buf_appendf( buf, + "%g", g_value_get_double( value ) ); + handled = TRUE; + break; + + case G_TYPE_BOOLEAN: + result = vips_buf_appends( buf, + g_value_get_boolean( value ) ? "true" : "false" ); + handled = TRUE; + break; + + case G_TYPE_ENUM: + result = vips_buf_appends( buf, + vips_enum_nick( type, g_value_get_enum( value ) ) ); + handled = TRUE; + break; + + case G_TYPE_FLAGS: +{ + GFlagsClass *flags_class = g_type_class_ref( type ); + + GFlagsValue *v; + int flags; + + flags = g_value_get_flags( value ); + + while( flags && + (v = g_flags_get_first_value( flags_class, flags )) ) { + result = vips_buf_appendf( buf, "%s ", v->value_nick ); + flags &= ~v->value; + } + + handled = TRUE; +} + break; + + case G_TYPE_BOXED: + if( type == VIPS_TYPE_REF_STRING || + type == VIPS_TYPE_BLOB ) { + const char *str; + size_t str_len; + + str = vips_value_get_ref_string( value, &str_len ); + result = vips_buf_appends( buf, str ); + handled = TRUE; + } + else if( type == VIPS_TYPE_ARRAY_DOUBLE ) { + double *arr; + int n; + int i; + + arr = vips_value_get_array_double( value, &n ); + for( i = 0; i < n; i++ ) + result = vips_buf_appendf( buf, "%g ", arr[i] ); + handled = TRUE; + } + else if( type == VIPS_TYPE_ARRAY_INT ) { + int *arr; + int n; + int i; + + arr = vips_value_get_array_int( value, &n ); + for( i = 0; i < n; i++ ) + result = vips_buf_appendf( buf, "%d ", arr[i] ); + handled = TRUE; + } + else if( type == VIPS_TYPE_ARRAY_IMAGE ) { + VipsImage **arr; + int n; + int i; + + arr = vips_value_get_array_image( value, &n ); + for( i = 0; i < n; i++ ) { + vips_object_summary( VIPS_OBJECT( arr[i] ), + buf ); + result = vips_buf_appends( buf, " " ); + } + handled = TRUE; + } + break; + + default: + break; + } + + if( !handled ) { + char *str_value; + + str_value = g_strdup_value_contents( value ); + result = vips_buf_appends( buf, str_value ); + g_free( str_value ); + } return( result ); } diff --git a/libvips/iofuncs/util.c b/libvips/iofuncs/util.c index 7ed1a332..3842dbf7 100644 --- a/libvips/iofuncs/util.c +++ b/libvips/iofuncs/util.c @@ -1806,6 +1806,7 @@ vips_flags_from_nick( const char *domain, GType type, const char *nick ) return( -1 ); } + /* Scan @buf for the first "%ns" (eg. "%12s") and substitute the * lowest-numbered one for @sub. @buf is @len bytes in size. * diff --git a/tools/vipsheader.c b/tools/vipsheader.c index 23373998..41756088 100644 --- a/tools/vipsheader.c +++ b/tools/vipsheader.c @@ -106,33 +106,16 @@ static void * print_field_fn( VipsImage *image, const char *field, GValue *value, void *a ) { gboolean *many = (gboolean *) a; - const char *extra; - char *str_value; - - /* Look for known enums and decode them. - */ - extra = NULL; - if( strcmp( field, "coding" ) == 0 ) - extra = vips_enum_nick( - VIPS_TYPE_CODING, g_value_get_int( value ) ); - else if( strcmp( field, "format" ) == 0 ) - extra = vips_enum_nick( - VIPS_TYPE_BAND_FORMAT, g_value_get_int( value ) ); - else if( strcmp( field, "interpretation" ) == 0 ) - extra = vips_enum_nick( - VIPS_TYPE_INTERPRETATION, g_value_get_int( value ) ); + char str[256]; + VipsBuf buf = VIPS_BUF_STATIC( str ); if( *many ) printf( "%s: ", image->filename ); - str_value = g_strdup_value_contents( value ); - printf( "%s: %s", field, str_value ); - g_free( str_value ); + printf( "%s: ", field ); - if( extra ) - printf( " - %s", extra ); - - printf( "\n" ); + vips_buf_appendgv( &buf, value ); + printf( "%s\n", vips_buf_all( &buf ) ); return( NULL ); } @@ -164,12 +147,14 @@ print_header( VipsImage *im, gboolean many ) else if( strcmp( main_option_field, "Hist" ) == 0 ) printf( "%s", vips_image_get_history( im ) ); else { - char *str; + GValue value = { 0 }; + char str[256]; + VipsBuf buf = VIPS_BUF_STATIC( str ); - if( vips_image_get_as_string( im, main_option_field, &str ) ) - return( -1 ); + vips_image_get( im, main_option_field, &value ); + vips_buf_appendgv( &buf, &value ); printf( "%s\n", str ); - g_free( str ); + g_value_unset( &value ); } return( 0 ); From a96d851ff25165188a17288cc3a10d0d651b4af6 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 1 Nov 2016 11:51:20 +0000 Subject: [PATCH 2/2] fix up vipsheader with complex field types "-f name" displays a detailed form, "-a" displays a summary of each field fix a problem with string fields as well --- ChangeLog | 1 + TODO | 6 ------ libvips/iofuncs/buf.c | 36 +++++++++++++++++++++++++++--------- libvips/iofuncs/header.c | 7 +++++-- man/vipsheader.1 | 25 +++++++++++++++---------- tools/vipsheader.c | 9 +++------ 6 files changed, 51 insertions(+), 33 deletions(-) diff --git a/ChangeLog b/ChangeLog index 40377268..da65cdf8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ - added tiff save to buffer - added dzsave save to buffer (zip only) - revise header get/set functions +- better vipsheader behaviour with complex field types - added vips_image_hasalpha() 18/10/16 started 8.4.3 diff --git a/TODO b/TODO index 78b50f08..715f4c8f 100644 --- a/TODO +++ b/TODO @@ -1,9 +1,3 @@ -- look at vips_image_get_as_string() vs. vips_buf_appendgv() - - should Hist and getext be true header fields? - - vipsheader is not displaying filename correctly - - not sure about utf8 error messages on win - strange: diff --git a/libvips/iofuncs/buf.c b/libvips/iofuncs/buf.c index 3b2e104e..9cb83bfc 100644 --- a/libvips/iofuncs/buf.c +++ b/libvips/iofuncs/buf.c @@ -493,10 +493,12 @@ vips_buf_appendd( VipsBuf *buf, int d ) * @buf: the buffer * @value: #GValue to format and append * - * Format and append a #GValue. This doesn't use g_strdup_value_contents(): - * that doesn't do what we want for some types and can change too much between - * glib versions. - * + * Format and append a #GValue as a printable thing. We display text line "3144 + * bytes of binary data" for BLOBs like icc-profile-data. + * + * Use vips_image_get_as_string() to make a text representation of a field. + * That will base64-encode blobs, for example. + * * Returns: %FALSE on overflow, %TRUE otherwise. */ gboolean @@ -513,11 +515,16 @@ vips_buf_appendgv( VipsBuf *buf, GValue *value ) switch( fundamental ) { case G_TYPE_STRING: - /* These are GStrings, vips refstrings are handled by boxed, see - * below. +{ + const char *str; + + /* These are GStrings (gchararray). vips refstrings are + * handled by boxed, see below. */ - result = vips_buf_appends( buf, g_value_get_string( value ) ); + str = g_value_get_string( value ); + result = vips_buf_appends( buf, str ); handled = TRUE; +} break; case G_TYPE_OBJECT: @@ -583,15 +590,26 @@ vips_buf_appendgv( VipsBuf *buf, GValue *value ) break; case G_TYPE_BOXED: - if( type == VIPS_TYPE_REF_STRING || - type == VIPS_TYPE_BLOB ) { + if( type == VIPS_TYPE_REF_STRING ) { const char *str; size_t str_len; + /* These should be printable. + */ str = vips_value_get_ref_string( value, &str_len ); result = vips_buf_appends( buf, str ); handled = TRUE; } + else if( type == VIPS_TYPE_BLOB ) { + size_t str_len; + + /* Binary data and not printable. + */ + (void) vips_value_get_ref_string( value, &str_len ); + result = vips_buf_appendf( buf, + _( "%zd bytes of binary data" ), str_len ); + handled = TRUE; + } else if( type == VIPS_TYPE_ARRAY_DOUBLE ) { double *arr; int n; diff --git a/libvips/iofuncs/header.c b/libvips/iofuncs/header.c index e0376526..78757617 100644 --- a/libvips/iofuncs/header.c +++ b/libvips/iofuncs/header.c @@ -966,7 +966,7 @@ vips_set_value_from_pointer( GValue *value, void *data ) else if( fundamental == G_TYPE_ENUM ) g_value_set_enum( value, *((int *) data) ); else if( fundamental == G_TYPE_STRING ) - g_value_set_string( value, ((char *) data) ); + g_value_set_string( value, *((char **) data) ); else g_warning( "%s: unimplemented vips_set_value_from_pointer() " "type %s", @@ -1486,7 +1486,10 @@ vips_image_set_string( VipsImage *image, const char *field, const char *str ) * This function will read any field, returning it as a printable string. * You need to free the string with g_free() when you are done with it. * - * See also: vips_image_get(), vips_image_get_typeof(). + * This will base64-encode BLOBs, for example. Use vips_buf_appendgv() to + * make a string that's for humans. + * + * See also: vips_image_get(), vips_image_get_typeof(), vips_buf_appendgv(). * * Returns: 0 on success, -1 otherwise. */ diff --git a/man/vipsheader.1 b/man/vipsheader.1 index 8de4ecc4..578f55d2 100644 --- a/man/vipsheader.1 +++ b/man/vipsheader.1 @@ -5,23 +5,28 @@ vipsheader \- prints information about an image file vipsheader [OPTIONS ...] files ... .SH DESCRIPTION .B vipsheader(1) -prints image header fields to stdout. +prints image header fields to stdout. .SH OPTIONS + +.TP +.B -a, --all +Show all fields. Fields are displayed to be convenient for humans to read, so +binary data, for example, is summarized rather than simply copied. + .TP .B -f FIELD, --field=FIELD Print value of .B FIELD -from image header. The special field name getext prints -the VIPS extension block: the XML defining the image metadata. You can alter -this, then reattach with -.B vipsedit(1). +from image header. Fields are printed in a way suitable for programs to +understand, so, for example, binary data is base64-encoded and printed as a +stream of characters. -.TP -.B -a, --all -Show all fields. Normally -.B vipsheader -just shows a one-line summary. +The special field name +.B getext +prints the VIPS extension block: the XML defining the image metadata. You can +alter this, then reattach with +.B vipsedit(1). .SH EXAMPLES $ vipsheader -f Xsize ~/pics/*.v diff --git a/tools/vipsheader.c b/tools/vipsheader.c index 41756088..5d2892c4 100644 --- a/tools/vipsheader.c +++ b/tools/vipsheader.c @@ -147,14 +147,11 @@ print_header( VipsImage *im, gboolean many ) else if( strcmp( main_option_field, "Hist" ) == 0 ) printf( "%s", vips_image_get_history( im ) ); else { - GValue value = { 0 }; - char str[256]; - VipsBuf buf = VIPS_BUF_STATIC( str ); + char *str; - vips_image_get( im, main_option_field, &value ); - vips_buf_appendgv( &buf, &value ); + vips_image_get_as_string( im, main_option_field, &str ); printf( "%s\n", str ); - g_value_unset( &value ); + g_free( str ); } return( 0 );