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