diff --git a/ChangeLog b/ChangeLog
index 9a79527e..83bb4614 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,7 @@
23/12/17 started 8.7.0
- add magicksave, save image with libMagick [dlemstra]
- dzsave to szi sets suffix correctly [martinweihrauch]
+- dzsave szi writes "scan-properties.xml"
5/1/18 started 8.6.2
- vips_sink_screen() keeps a ref to the input image ... stops a rare race
diff --git a/libvips/foreign/dzsave.c b/libvips/foreign/dzsave.c
index 98f4c014..efc325dc 100644
--- a/libvips/foreign/dzsave.c
+++ b/libvips/foreign/dzsave.c
@@ -76,6 +76,8 @@
* 24/11/17
* - output overlap-only tiles on edges for better deepzoom spec
* compliance
+ * 6/1/18
+ * - add scan-properties.xml for szi output
*/
/*
@@ -858,6 +860,81 @@ write_vips_meta( VipsForeignSaveDz *dz )
return( 0 );
}
+static void
+build_scan_property( VipsDbuf *dbuf, VipsImage *image,
+ const char *vips_name, const char *szi_name )
+{
+ const char *str;
+
+ if( vips_image_get_typeof( image, vips_name ) &&
+ !vips_image_get_string( image, vips_name, &str ) ) {
+ vips_dbuf_writef( dbuf, " \n" );
+ vips_dbuf_writef( dbuf, " " );
+ vips_dbuf_write_amp( dbuf, szi_name );
+ vips_dbuf_writef( dbuf, "\n" );
+ vips_dbuf_writef( dbuf, " " );
+ vips_dbuf_write_amp( dbuf, str );
+ vips_dbuf_writef( dbuf, "\n" );
+ vips_dbuf_writef( dbuf, " \n" );
+ }
+}
+
+/* Make the xml we write to scan-properties.xml in szi write.
+ * Free with g_free().
+ */
+char *
+build_scan_properties( VipsImage *image )
+{
+ VipsDbuf dbuf;
+ GTimeVal now;
+ char *date;
+
+ vips_dbuf_init( &dbuf );
+
+ g_get_current_time( &now );
+ date = g_time_val_to_iso8601( &now );
+ vips_dbuf_writef( &dbuf, "\n" );
+ vips_dbuf_writef( &dbuf, "\n", date );
+ g_free( date );
+ vips_dbuf_writef( &dbuf, " \n" );
+
+ build_scan_property( &dbuf, image,
+ "openslide.vendor", "Vendor" );
+ build_scan_property( &dbuf, image,
+ "openslide.objective-power", "ObjectiveMagnification" );
+ build_scan_property( &dbuf, image,
+ "openslide.mpp-x", "MicronsPerPixelX" );
+ build_scan_property( &dbuf, image,
+ "openslide.mpp-y", "MicronsPerPixelY" );
+
+ vips_dbuf_writef( &dbuf, " \n" );
+ vips_dbuf_writef( &dbuf, "\n" );
+
+ return( (char *) vips_dbuf_steal( &dbuf, NULL ) );
+}
+
+static int
+write_scan_properties( VipsForeignSaveDz *dz )
+{
+ VipsForeignSave *save = (VipsForeignSave *) dz;
+
+ char *dump;
+ GsfOutput *out;
+
+ if( !(dump = build_scan_properties( save->ready )) )
+ return( -1 );
+
+ out = vips_gsf_path( dz->tree, "scan-properties.xml", NULL );
+ gsf_output_write( out, strlen( dump ), (guchar *) dump );
+ (void) gsf_output_close( out );
+ g_object_unref( out );
+
+ g_free( dump );
+
+ return( 0 );
+}
+
/* Our state during a threaded write of a strip.
*/
typedef struct _Strip {
@@ -1936,6 +2013,10 @@ vips_foreign_save_dz_build( VipsObject *object )
write_vips_meta( dz ) )
return( -1 );
+ if( dz->write_szi &&
+ write_scan_properties( dz ) )
+ return( -1 );
+
/* This is so ugly. In earlier versions of dzsave, we wrote x.dzi and
* x_files. Now we write x/x.dzi and x/x_files to make it possible to
* create zip files.
diff --git a/libvips/include/vips/dbuf.h b/libvips/include/vips/dbuf.h
index 8f0835a7..787b505d 100644
--- a/libvips/include/vips/dbuf.h
+++ b/libvips/include/vips/dbuf.h
@@ -69,6 +69,7 @@ unsigned char *vips_dbuf_get_write( VipsDbuf *dbuf, size_t *size );
gboolean vips_dbuf_write( VipsDbuf *dbuf,
const unsigned char *data, size_t size );
gboolean vips_dbuf_writef( VipsDbuf *dbuf, const char *fmt, ... );
+gboolean vips_dbuf_write_amp( VipsDbuf *dbuf, const char *str );
void vips_dbuf_reset( VipsDbuf *dbuf );
void vips_dbuf_destroy( VipsDbuf *dbuf );
gboolean vips_dbuf_seek( VipsDbuf *dbuf, off_t offset, int whence );
diff --git a/libvips/iofuncs/dbuf.c b/libvips/iofuncs/dbuf.c
index aa7c023f..e9b71417 100644
--- a/libvips/iofuncs/dbuf.c
+++ b/libvips/iofuncs/dbuf.c
@@ -206,6 +206,52 @@ vips_dbuf_writef( VipsDbuf *dbuf, const char *fmt, ... )
return( TRUE );
}
+/**
+ * vips_dbuf_write_amp:
+ * @dbuf: the buffer
+ * @str: string to write
+ *
+ * Write @str to @dbuf, but escape <>&.
+ *
+ * Returns: %FALSE on out of memory, %TRUE otherwise.
+ */
+gboolean
+vips_dbuf_write_amp( VipsDbuf *dbuf, const char *str )
+{
+ const char *p;
+ size_t len;
+
+ for( p = str; *p; p += len ) {
+ len = strcspn( p, "&<>" );
+
+ vips_dbuf_write( dbuf, (unsigned char *) p, len );
+ switch( p[len] ) {
+ case '&':
+ if( vips_dbuf_writef( dbuf, "&" ) )
+ return( FALSE );
+ len += 1;
+ break;
+
+ case '<':
+ if( vips_dbuf_writef( dbuf, "<" ) )
+ return( FALSE );
+ len += 1;
+ break;
+
+ case '>':
+ if( vips_dbuf_writef( dbuf, ">" ) )
+ return( FALSE );
+ len += 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return( TRUE );
+}
+
/**
* vips_dbuf_reset:
* @dbuf: the buffer
diff --git a/libvips/iofuncs/vips.c b/libvips/iofuncs/vips.c
index 50ed9d58..c770c4f2 100644
--- a/libvips/iofuncs/vips.c
+++ b/libvips/iofuncs/vips.c
@@ -743,40 +743,6 @@ dbuf_write_quotes( VipsDbuf *dbuf, const char *str )
}
}
-/* Append a string to a buffer, but escape &<>.
- */
-static void
-dbuf_write_amp( VipsDbuf *dbuf, const char *str )
-{
- const char *p;
- size_t len;
-
- for( p = str; *p; p += len ) {
- len = strcspn( p, "&<>" );
-
- vips_dbuf_write( dbuf, (unsigned char *) p, len );
- switch( p[len] ) {
- case '&':
- vips_dbuf_writef( dbuf, "&" );
- len += 1;
- break;
-
- case '<':
- vips_dbuf_writef( dbuf, "<" );
- len += 1;
- break;
-
- case '>':
- vips_dbuf_writef( dbuf, ">" );
- len += 1;
- break;
-
- default:
- break;
- }
- }
-}
-
static void *
build_xml_meta( VipsMeta *meta, VipsDbuf *dbuf )
{
@@ -808,7 +774,7 @@ build_xml_meta( VipsMeta *meta, VipsDbuf *dbuf )
g_type_name( type ) );
dbuf_write_quotes( dbuf, meta->name );
vips_dbuf_writef( dbuf, "\">" );
- dbuf_write_amp( dbuf, str );
+ vips_dbuf_write_amp( dbuf, str );
vips_dbuf_writef( dbuf, "\n" );
}
@@ -839,7 +805,7 @@ build_xml( VipsImage *image )
vips_dbuf_writef( &dbuf,
" ",
g_type_name( VIPS_TYPE_REF_STRING ) );
- dbuf_write_amp( &dbuf, str );
+ vips_dbuf_write_amp( &dbuf, str );
vips_dbuf_writef( &dbuf, "\n" );
}
@@ -884,11 +850,11 @@ vips__xml_properties_meta( VipsImage *image,
vips_dbuf_writef( dbuf, " \n" );
vips_dbuf_writef( dbuf, " " );
- dbuf_write_amp( dbuf, field );
+ vips_dbuf_write_amp( dbuf, field );
vips_dbuf_writef( dbuf, "\n" );
vips_dbuf_writef( dbuf, " ",
g_type_name( type ) );
- dbuf_write_amp( dbuf, str );
+ vips_dbuf_write_amp( dbuf, str );
vips_dbuf_writef( dbuf, "\n" );
vips_dbuf_writef( dbuf, " \n" );