remove libxml from xml save

just some printfs now
This commit is contained in:
John Cupitt 2017-02-25 18:10:42 +00:00
parent e87654fcd9
commit 5614330cc4
7 changed files with 198 additions and 187 deletions

149
TODO
View File

@ -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
<?xml version="1.0"?>
<root xmlns="http://www.vips.ecs.soton.ac.uk/vips/7.39.0">
<header>
<field type="VipsRefString" name="Hist"/>
</header>
<meta>
<field type="VipsRefString" name="vips-loader">jpegload</field>
<field type="gint" name="jpeg-multiscan">0</field>
<field type="VipsRefString" name="exif-ifd0-X-Resolution">4294966289/169093161 (25.399999998, Rational, 1 components, 8 bytes)</field>
<field type="VipsRefString" name="exif-ifd0-Y-Resolution">4294966289/169093161 (25.399999998, Rational, 1 components, 8 bytes)</field>
<field type="VipsRefString" name="exif-ifd0-Resolution Unit">2 (Inch, Short, 1 components, 2 bytes)</field>
<field type="VipsRefString" name="exif-ifd2-Exif Version">Exif Version 2.1 (Exif Version 2.1, Undefined, 4 components, 4 bytes)</field>
<field type="VipsRefString" name="exif-ifd2-FlashPixVersion">FlashPix Version 1.0 (FlashPix Version 1.0, Undefined, 4 components, 4 bytes)</field>
<field type="VipsRefString" name="exif-ifd2-Colour Space">65535 (Internal error (unknown value 65535), Short, 1 components, 2 bytes)</field>
<field type="VipsRefString" name="resolution-unit">in</field><field type="VipsBlob" name="exif-data">
RXhpZgAATU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUAAAABAAAARgEoAAMAAAABAAIAAIdpAAQA
AAABAAAATgAAAAD///wRChQoKf///BEKFCgpAAOQAAAHAAAABDAyMTCgAAAHAAAABDAxMDCgAQAD
AAAAAf//AAAAAAAA
</field>
</meta>
</root>
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
<?xml version="1.0"?>
<image xmlns="http://www.vips.ecs.soton.ac.uk/dzsave" date="2017-02-25T17:32:07.565137Z" version="8.5.0">
<properties>
<property>
<name>width</name>
<value type="gint">1450</value>
</property>
<property>
<name>height</name>
<value type="gint">2048</value>
</property>
<property>
<name>bands</name>
<value type="gint">3</value>
</property>
<property>
<name>xoffset</name>
<value type="gint">0</value>
</property>
<property>
<name>yoffset</name>
<value type="gint">0</value>
</property>
<property>
<name>xres</name>
<value type="gdouble">0.99999999990686772</value>
</property>
<property>
<name>yres</name>
<value type="gdouble">0.99999999990686772</value>
</property>
<property>
<name>vips-loader</name>
<value type="VipsRefString">jpegload</value>
</property>
<property>
<name>jpeg-multiscan</name>
<value type="gint">0</value>
</property>
<property>
<name>exif-data</name>
<value type="VipsBlob">
RXhpZgAASUkqAAgAAAAGABIBAwABAAAAAQAAABoBBQABAAAAVgAAABsBBQABAAAAXgAAACgBAwAB
AAAAAgAAABMCAwABAAAAAQAAAGmHBAABAAAAZgAAAAAAAAAR/P//KSgUChH8//8pKBQKBgAAkAcA
BAAAADAyMTABkQcABAAAAAECAwAAoAcABAAAADAxMDABoAMAAQAAAP//AAACoAQAAQAAAKoFAAAD
oAQAAQAAAAAIAAAAAAAA
</value>
</property>
<property>
<name>resolution-unit</name>
<value type="VipsRefString">in</value>
</property>
<property>
<name>exif-ifd0-Orientation</name>
<value type="VipsRefString">1 (Top-left, Short, 1 components, 2 bytes)</value>
</property>
<property>
<name>exif-ifd0-XResolution</name>
<value type="VipsRefString">4294966289/169093161 (25.399999998, Rational, 1 components, 8 bytes)</value>
</property>
<property>
<name>exif-ifd0-YResolution</name>
<value type="VipsRefString">4294966289/169093161 (25.399999998, Rational, 1 components, 8 bytes)</value>
</property>
<property>
<name>exif-ifd0-ResolutionUnit</name>
<value type="VipsRefString">2 (Inch, Short, 1 components, 2 bytes)</value>
</property>
<property>
<name>exif-ifd0-YCbCrPositioning</name>
<value type="VipsRefString">1 (Centred, Short, 1 components, 2 bytes)</value>
</property>
<property>
<name>exif-ifd2-ExifVersion</name>
<value type="VipsRefString">Exif Version 2.1 (Exif Version 2.1, Undefined, 4 components, 4 bytes)</value>
</property>
<property>
<name>exif-ifd2-ComponentsConfiguration</name>
<value type="VipsRefString">Y Cb Cr - (Y Cb Cr -, Undefined, 4 components, 4 bytes)</value>
</property>
<property>
<name>exif-ifd2-FlashPixVersion</name>
<value type="VipsRefString">FlashPix Version 1.0 (FlashPix Version 1.0, Undefined, 4 components, 4 bytes)</value>
</property>
<property>
<name>exif-ifd2-ColorSpace</name>
<value type="VipsRefString">65535 (Internal error (unknown value 65535), Short, 1 components, 2 bytes)</value>
</property>
<property>
<name>exif-ifd2-PixelXDimension</name>
<value type="VipsRefString">1450 (1450, Long, 1 components, 4 bytes)</value>
</property>
<property>
<name>exif-ifd2-PixelYDimension</name>
<value type="VipsRefString">2048 (2048, Long, 1 components, 4 bytes)</value>
</property>
<property>
<name>orientation</name>
<value type="gint">1</value>
</property>
</properties>
</image>
- vips linecache has access there twice!

View File

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

View File

@ -152,144 +152,9 @@
#include <stdlib.h>
#include <string.h>
#include <libxml/parser.h>
#include <vips/vips.h>
#include <vips/internal.h>
/* 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 <gsf/gsf.h>
@ -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 );
}

View File

@ -48,7 +48,6 @@
#include <unistd.h>
#endif /*HAVE_UNISTD_H*/
#include <string.h>
#include <libxml/parser.h>
#include <vips/vips.h>
#include <vips/internal.h>

View File

@ -218,7 +218,6 @@
#include <unistd.h>
#endif /*HAVE_UNISTD_H*/
#include <string.h>
#include <libxml/parser.h>
#include <vips/vips.h>
#include <vips/internal.h>
@ -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;

View File

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

View File

@ -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, "<?xml version=\"1.0\"?>\n" );
buffer_appendf( &buffer, "<root xmlns=\"%s/%d.%d.%d\">\n",
NAMESPACE,
buffer_appendf( &buffer, "<root xmlns=\"%s/vips/%d.%d.%d\">\n",
NAMESPACE_URI,
VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION, VIPS_MICRO_VERSION );
buffer_appendf( &buffer, " <header>\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, " <property>\n" );
buffer_appendf( buffer, " <name>%s</name>\n", field );
buffer_appendf( buffer, " <value type=\"%s\">",
g_type_name( type ) );
buffer_append( buffer, str, strlen( str ) );
buffer_appendf( buffer, "</value>\n" );
buffer_appendf( buffer, " </property>\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, "<?xml version=\"1.0\"?>\n" );
buffer_appendf( &buffer, "<image xmlns=\"%s/dzsave\" "
"date=\"%s\" version=\"%d.%d.%d\">\n",
NAMESPACE_URI,
date,
VIPS_MAJOR_VERSION, VIPS_MINOR_VERSION, VIPS_MICRO_VERSION );
g_free( date );
buffer_appendf( &buffer, " <properties>\n" );
if( vips_image_map( image, vips__xml_properties_meta, &buffer ) ) {
buffer_destroy( &buffer );
return( NULL );
}
buffer_appendf( &buffer, " </properties>\n" );
buffer_appendf( &buffer, "</image>\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 ) ) ) {