diff --git a/TODO b/TODO index 468b151b..e8841b03 100644 --- a/TODO +++ b/TODO @@ -1,47 +1,124 @@ -- added expat to required packages in configure.ac +- remove libxml from configure.ac + + we don't escape " inside xml attr strings, or < > inside xml content - try moving iofuncs/vips.c to expat + break Buffer out into a separate class that does this? VipsDbuf, for dynamic + buffer? or can it be a mode for VipsBuf? - sample XML for us to parse + buffer should expand by 30% on each fill to avoid lots of tiny realloc - $ vipsheader -f getext babe.v - - -
- -
- - jpegload - 0 - 4294966289/169093161 (25.399999998, Rational, 1 components, 8 bytes) - 4294966289/169093161 (25.399999998, Rational, 1 components, 8 bytes) - 2 (Inch, Short, 1 components, 2 bytes) - Exif Version 2.1 (Exif Version 2.1, Undefined, 4 components, 4 bytes) - FlashPix Version 1.0 (FlashPix Version 1.0, Undefined, 4 components, 4 bytes) - 65535 (Internal error (unknown value 65535), Short, 1 components, 2 bytes) - in - RXhpZgAATU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAIdpAAQA - AAABAAAATgAAAAD///wRChQoKf///BEKFCgpAAOQAAAHAAAABDAyMTCgAAAHAAAABDAxMDCgAQAD - AAAAAf//AAAAAAAA - - -
+ use for tiffsave_buffer etc. - currently works like this + have things like write-escaped-string as extra append operations - read_xml is called on image load - - loads extension bytes into memory - - calls libxml to parse it to an xmlDoc - - saves xmlDoc to VIPS_META_XML in header + need one that escapes ", a separate one that escapes < > - rebuild_header called next - - gets xmlDoc from header - - gets "header" node - calls rebuild_header_builtin() for every field node - - gets "meta" field - calls rebuild_header_meta() for every field node +- dzsave vips.properties is currently + + + + + width + 1450 + + + height + 2048 + + + bands + 3 + + + xoffset + 0 + + + yoffset + 0 + + + xres + 0.99999999990686772 + + + yres + 0.99999999990686772 + + + vips-loader + jpegload + + + jpeg-multiscan + 0 + + + exif-data + +RXhpZgAASUkqAAgAAAAGABIBAwABAAAAAQAAABoBBQABAAAAVgAAABsBBQABAAAAXgAAACgBAwAB +AAAAAgAAABMCAwABAAAAAQAAAGmHBAABAAAAZgAAAAAAAAAR/P//KSgUChH8//8pKBQKBgAAkAcA +BAAAADAyMTABkQcABAAAAAECAwAAoAcABAAAADAxMDABoAMAAQAAAP//AAACoAQAAQAAAKoFAAAD +oAQAAQAAAAAIAAAAAAAA + + + + resolution-unit + in + + + exif-ifd0-Orientation + 1 (Top-left, Short, 1 components, 2 bytes) + + + exif-ifd0-XResolution + 4294966289/169093161 (25.399999998, Rational, 1 components, 8 bytes) + + + exif-ifd0-YResolution + 4294966289/169093161 (25.399999998, Rational, 1 components, 8 bytes) + + + exif-ifd0-ResolutionUnit + 2 (Inch, Short, 1 components, 2 bytes) + + + exif-ifd0-YCbCrPositioning + 1 (Centred, Short, 1 components, 2 bytes) + + + exif-ifd2-ExifVersion + Exif Version 2.1 (Exif Version 2.1, Undefined, 4 components, 4 bytes) + + + exif-ifd2-ComponentsConfiguration + Y Cb Cr - (Y Cb Cr -, Undefined, 4 components, 4 bytes) + + + exif-ifd2-FlashPixVersion + FlashPix Version 1.0 (FlashPix Version 1.0, Undefined, 4 components, 4 bytes) + + + exif-ifd2-ColorSpace + 65535 (Internal error (unknown value 65535), Short, 1 components, 2 bytes) + + + exif-ifd2-PixelXDimension + 1450 (1450, Long, 1 components, 4 bytes) + + + exif-ifd2-PixelYDimension + 2048 (2048, Long, 1 components, 4 bytes) + + + orientation + 1 + + + + - vips linecache has access there twice! diff --git a/configure.ac b/configure.ac index b7a7cd8c..d81fd6bd 100644 --- a/configure.ac +++ b/configure.ac @@ -348,9 +348,8 @@ AC_CHECK_LIB(m,atan2,[AC_DEFINE(HAVE_ATAN2,1,[have atan2() in libm.])]) # have to have these # need glib 2.6 for GOption -PKG_CHECK_MODULES(REQUIRED, glib-2.0 >= 2.6 gmodule-2.0 gobject-2.0 - libxml-2.0 expat) -PACKAGES_USED="$PACKAGES_USED glib-2.0 gmodule-2.0 gobject-2.0 libxml-2.0 expat" +PKG_CHECK_MODULES(REQUIRED, glib-2.0 >= 2.6 gmodule-2.0 gobject-2.0 expat) +PACKAGES_USED="$PACKAGES_USED glib-2.0 gmodule-2.0 gobject-2.0 expat" # after 2.28 we have a monotonic timer PKG_CHECK_MODULES(MONOTONIC, glib-2.0 >= 2.28, diff --git a/libvips/foreign/dzsave.c b/libvips/foreign/dzsave.c index 46696af2..4beeeb31 100644 --- a/libvips/foreign/dzsave.c +++ b/libvips/foreign/dzsave.c @@ -152,144 +152,9 @@ #include #include -#include - #include #include -/* Track this during property save. - */ -typedef struct _WriteInfo { - const char *domain; - VipsImage *image; - xmlNode *node; -} WriteInfo; - -static int -set_prop( WriteInfo *info, - xmlNode *node, const char *name, const char *fmt, ... ) -{ - va_list ap; - char value[1024]; - - va_start( ap, fmt ); - (void) vips_vsnprintf( value, 1024, fmt, ap ); - va_end( ap ); - - if( !xmlSetProp( node, (xmlChar *) name, (xmlChar *) value ) ) { - vips_error( info->domain, - _( "unable to set property \"%s\" to value \"%s\"." ), - name, value ); - return( -1 ); - } - - return( 0 ); -} - -static xmlNode * -new_child( WriteInfo *info, xmlNode *parent, const char *name ) -{ - xmlNode *child; - - if( !(child = xmlNewChild( parent, NULL, (xmlChar *) name, NULL )) ) { - vips_error( info->domain, - _( "unable to set create node \"%s\"" ), name ); - return( NULL ); - } - - return( child ); -} - -static void * -write_vips_property( VipsImage *image, - const char *field, GValue *value, void *a ) -{ - WriteInfo *info = (WriteInfo *) a; - GType type = G_VALUE_TYPE( value ); - - if( g_value_type_transformable( type, VIPS_TYPE_SAVE_STRING ) ) { - GValue save_value = { 0 }; - xmlNode *property; - xmlNode *child; - - g_value_init( &save_value, VIPS_TYPE_SAVE_STRING ); - if( !g_value_transform( value, &save_value ) ) - return( image ); - - if( !(property = new_child( info, info->node, "property" )) ) - return( image ); - - if( !(child = new_child( info, property, "name" )) ) - return( image ); - xmlNodeSetContent( child, (xmlChar *) field ); - - if( !(child = new_child( info, property, "value" )) || - set_prop( info, child, "type", g_type_name( type ) ) ) - return( image ); - xmlNodeSetContent( child, - (xmlChar *) vips_value_get_save_string( &save_value ) ); - } - - return( NULL ); -} - -/* Pack up all the metadata from an image as XML. This called from vips2tiff - * as well. - * - * Free the result with xmlFree(). - */ -char * -vips__make_xml_metadata( const char *domain, VipsImage *image ) -{ - xmlDoc *doc; - GTimeVal now; - char *date; - WriteInfo info; - char *dump; - int dump_size; - - if( !(doc = xmlNewDoc( (xmlChar *) "1.0" )) ) { - vips_error( domain, "%s", _( "xml save error" ) ); - return( NULL ); - } - if( !(doc->children = xmlNewDocNode( doc, NULL, - (xmlChar *) "image", NULL )) ) { - vips_error( domain, "%s", _( "xml save error" ) ); - xmlFreeDoc( doc ); - return( NULL ); - } - - info.domain = domain; - info.image = image; - g_get_current_time( &now ); - date = g_time_val_to_iso8601( &now ); - if( set_prop( &info, doc->children, "xmlns", - "http://www.vips.ecs.soton.ac.uk/dzsave" ) || - set_prop( &info, doc->children, "date", date ) || - set_prop( &info, doc->children, "version", VIPS_VERSION ) ) { - g_free( date ); - xmlFreeDoc( doc ); - return( NULL ); - } - g_free( date ); - - if( !(info.node = new_child( &info, doc->children, "properties" )) || - vips_image_map( image, write_vips_property, &info ) ) { - xmlFreeDoc( doc ); - return( NULL ); - } - - xmlDocDumpFormatMemory( doc, (xmlChar **) &dump, &dump_size, 1 ); - if( !dump ) { - vips_error( domain, "%s", _( "xml save error" ) ); - xmlFreeDoc( doc ); - return( NULL ); - } - xmlFreeDoc( doc ); - - return( dump ); -} - #ifdef HAVE_GSF #include @@ -980,12 +845,11 @@ static int write_vips_meta( VipsForeignSaveDz *dz ) { VipsForeignSave *save = (VipsForeignSave *) dz; - VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( dz ); char *dump; GsfOutput *out; - if( !(dump = vips__make_xml_metadata( class->nickname, save->ready )) ) + if( !(dump = vips__xml_properties( save->ready )) ) return( -1 ); /* For deepzom the props must go inside the ${name}_files subdir, for @@ -1001,7 +865,7 @@ write_vips_meta( VipsForeignSaveDz *dz ) (void) gsf_output_close( out ); g_object_unref( out ); - xmlFree( dump ); + g_free( dump ); return( 0 ); } diff --git a/libvips/foreign/tiff.c b/libvips/foreign/tiff.c index dd9bdcd2..b083adc2 100644 --- a/libvips/foreign/tiff.c +++ b/libvips/foreign/tiff.c @@ -48,7 +48,6 @@ #include #endif /*HAVE_UNISTD_H*/ #include -#include #include #include diff --git a/libvips/foreign/vips2tiff.c b/libvips/foreign/vips2tiff.c index 8f344380..621e092a 100644 --- a/libvips/foreign/vips2tiff.c +++ b/libvips/foreign/vips2tiff.c @@ -218,7 +218,6 @@ #include #endif /*HAVE_UNISTD_H*/ #include -#include #include #include @@ -512,10 +511,10 @@ wtiff_embed_imagedescription( Wtiff *wtiff, TIFF *tif ) if( wtiff->properties ) { char *doc; - if( !(doc = vips__make_xml_metadata( "vips2tiff", wtiff->im )) ) + if( !(doc = vips__xml_properties( wtiff->im )) ) return( -1 ); TIFFSetField( tif, TIFFTAG_IMAGEDESCRIPTION, doc ); - xmlFree( doc ); + g_free( doc ); } else { const char *imagedescription; diff --git a/libvips/include/vips/internal.h b/libvips/include/vips/internal.h index 8329cf87..858bd11a 100644 --- a/libvips/include/vips/internal.h +++ b/libvips/include/vips/internal.h @@ -227,7 +227,7 @@ int vips_check_bands_3ormore( const char *domain, VipsImage *im ); int vips__byteswap_bool( VipsImage *in, VipsImage **out, gboolean swap ); -char *vips__make_xml_metadata( const char *domain, VipsImage *image ); +char *vips__xml_properties( VipsImage *image ); void vips__cairo2rgba( guint32 *buf, int n ); diff --git a/libvips/iofuncs/vips.c b/libvips/iofuncs/vips.c index 5244aa04..970be1ef 100644 --- a/libvips/iofuncs/vips.c +++ b/libvips/iofuncs/vips.c @@ -141,7 +141,7 @@ /* Our XML namespace. */ -#define NAMESPACE "http://www.vips.ecs.soton.ac.uk/vips" +#define NAMESPACE_URI "http://www.vips.ecs.soton.ac.uk/" /* Open for read for image files. */ @@ -595,7 +595,7 @@ parser_element_start_handler( void *user_data, else if( strcmp( name, "root" ) == 0 ) { for( p = atts; *p; p += 2 ) if( strcmp( p[0], "xmlns" ) == 0 && - !vips_isprefix( NAMESPACE, p[1] ) ) { + !vips_isprefix( NAMESPACE_URI "/vips", p[1] ) ) { vips_error( "VipsImage", "%s", _( "incorrect namespace in XML" ) ); vep->error = TRUE; @@ -801,6 +801,8 @@ build_xml_meta( VipsMeta *meta, Buffer *buffer ) return( NULL ); } +/* Make the xml we append to vips images after the pixel data. + */ static char * build_xml( VipsImage *image ) { @@ -810,8 +812,8 @@ build_xml( VipsImage *image ) buffer_init( &buffer ); buffer_appendf( &buffer, "\n" ); - buffer_appendf( &buffer, "\n", - NAMESPACE, + buffer_appendf( &buffer, "\n", + NAMESPACE_URI, VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION, VIPS_MICRO_VERSION ); buffer_appendf( &buffer, "
\n" ); @@ -836,6 +838,77 @@ build_xml( VipsImage *image ) return( buffer.data ); } +static void * +vips__xml_properties_meta( VipsImage *image, + const char *field, GValue *value, void *a ) +{ + Buffer *buffer = (Buffer *) a; + GType type = G_VALUE_TYPE( value ); + + const char *str; + + /* If we can transform to VIPS_TYPE_SAVE_STRING and back, we can save + * and restore. + */ + if( g_value_type_transformable( type, VIPS_TYPE_SAVE_STRING ) && + g_value_type_transformable( VIPS_TYPE_SAVE_STRING, type ) ) { + GValue save_value = { 0 }; + + g_value_init( &save_value, VIPS_TYPE_SAVE_STRING ); + if( !g_value_transform( value, &save_value ) ) { + vips_error( "VipsImage", "%s", + _( "error transforming to save format" ) ); + return( buffer ); + } + str = vips_value_get_save_string( &save_value ); + g_value_unset( &save_value ); + + buffer_appendf( buffer, " \n" ); + buffer_appendf( buffer, " %s\n", field ); + buffer_appendf( buffer, " ", + g_type_name( type ) ); + buffer_append( buffer, str, strlen( str ) ); + buffer_appendf( buffer, "\n" ); + buffer_appendf( buffer, " \n" ); + } + + return( NULL ); +} + +/* Make the xml we write to vips-properties in dzsave, or to TIFF. A simple + * dump of all vips metadata. Free with g_free(). + */ +char * +vips__xml_properties( VipsImage *image ) +{ + Buffer buffer; + GTimeVal now; + char *date; + + buffer_init( &buffer ); + + g_get_current_time( &now ); + date = g_time_val_to_iso8601( &now ); + buffer_appendf( &buffer, "\n" ); + buffer_appendf( &buffer, "\n", + NAMESPACE_URI, + date, + VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION, VIPS_MICRO_VERSION ); + g_free( date ); + buffer_appendf( &buffer, " \n" ); + + if( vips_image_map( image, vips__xml_properties_meta, &buffer ) ) { + buffer_destroy( &buffer ); + return( NULL ); + } + + buffer_appendf( &buffer, " \n" ); + buffer_appendf( &buffer, "\n" ); + + return( buffer.data ); +} + /* Append XML to output fd. */ int @@ -846,7 +919,7 @@ vips__writehist( VipsImage *image ) assert( image->dtype == VIPS_IMAGE_OPENOUT ); assert( image->fd != -1 ); - if( !(xml = build_xml( im )) ) + if( !(xml = build_xml( image )) ) return( -1 ); if( vips__write_extension_block( image, xml, strlen( xml ) ) ) {