write scan-properties.xml to szi

see https://github.com/jcupitt/libvips/issues/853
This commit is contained in:
John Cupitt 2018-01-26 17:20:58 +00:00
parent c46f4b15e0
commit 21e1e68771
5 changed files with 133 additions and 38 deletions

View File

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

View File

@ -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, " <property>\n" );
vips_dbuf_writef( dbuf, " <name>" );
vips_dbuf_write_amp( dbuf, szi_name );
vips_dbuf_writef( dbuf, "</name>\n" );
vips_dbuf_writef( dbuf, " <value type=\"str\">" );
vips_dbuf_write_amp( dbuf, str );
vips_dbuf_writef( dbuf, "</value>\n" );
vips_dbuf_writef( dbuf, " </property>\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, "<?xml version=\"1.0\"?>\n" );
vips_dbuf_writef( &dbuf, "<image xmlns=\"http://www.pathozoom.com/szi\""
" date=\"%s\" version=\"1.0\">\n", date );
g_free( date );
vips_dbuf_writef( &dbuf, " <properties>\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, " </properties>\n" );
vips_dbuf_writef( &dbuf, "</image>\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.

View File

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

View File

@ -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, "&amp;" ) )
return( FALSE );
len += 1;
break;
case '<':
if( vips_dbuf_writef( dbuf, "&lt;" ) )
return( FALSE );
len += 1;
break;
case '>':
if( vips_dbuf_writef( dbuf, "&gt;" ) )
return( FALSE );
len += 1;
break;
default:
break;
}
}
return( TRUE );
}
/**
* vips_dbuf_reset:
* @dbuf: the buffer

View File

@ -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, "&amp;" );
len += 1;
break;
case '<':
vips_dbuf_writef( dbuf, "&lt;" );
len += 1;
break;
case '>':
vips_dbuf_writef( dbuf, "&gt;" );
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, "</field>\n" );
}
@ -839,7 +805,7 @@ build_xml( VipsImage *image )
vips_dbuf_writef( &dbuf,
" <field type=\"%s\" name=\"Hist\">",
g_type_name( VIPS_TYPE_REF_STRING ) );
dbuf_write_amp( &dbuf, str );
vips_dbuf_write_amp( &dbuf, str );
vips_dbuf_writef( &dbuf, "</field>\n" );
}
@ -884,11 +850,11 @@ vips__xml_properties_meta( VipsImage *image,
vips_dbuf_writef( dbuf, " <property>\n" );
vips_dbuf_writef( dbuf, " <name>" );
dbuf_write_amp( dbuf, field );
vips_dbuf_write_amp( dbuf, field );
vips_dbuf_writef( dbuf, "</name>\n" );
vips_dbuf_writef( dbuf, " <value type=\"%s\">",
g_type_name( type ) );
dbuf_write_amp( dbuf, str );
vips_dbuf_write_amp( dbuf, str );
vips_dbuf_writef( dbuf, "</value>\n" );
vips_dbuf_writef( dbuf, " </property>\n" );