From 18baedcd1e7e762c8b279e92e880a401cbffc7da Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sun, 28 Jan 2018 15:56:08 +0000 Subject: [PATCH] write associated images to szi --- libvips/foreign/dzsave.c | 123 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/libvips/foreign/dzsave.c b/libvips/foreign/dzsave.c index 13b2ece4..5e43d2c9 100644 --- a/libvips/foreign/dzsave.c +++ b/libvips/foreign/dzsave.c @@ -551,6 +551,73 @@ iszip( VipsForeignDzContainer container ) } } +static int +write_image( VipsForeignSaveDz *dz, + GsfOutput *out, VipsImage *image, const char *format ) +{ + VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( dz ); + + void *buf; + size_t len; + + /* Hopefully, no one will want the same metadata on all the images. + * Strip them. + */ + vips_image_set_int( image, "hide-progress", 1 ); + if( vips_image_write_to_buffer( image, format, &buf, &len, + "strip", TRUE, + NULL ) ) + return( -1 ); + + /* gsf doesn't like more than one write active at once. + */ + g_mutex_lock( vips__global_lock ); + + if( !gsf_output_write( out, len, buf ) ) { + gsf_output_close( out ); + g_mutex_unlock( vips__global_lock ); + g_free( buf ); + vips_error( class->nickname, + "%s", gsf_output_error( out )->message ); + + return( -1 ); + } + + dz->bytes_written += len; + + gsf_output_close( out ); + +#ifndef HAVE_GSF_ZIP64 + if( iszip( dz->container ) ) { + /* Leave 3 entry headroom for blank.png and metadata files. + */ + if( dz->tree->file_count + 3 >= (unsigned int) USHRT_MAX ) { + g_mutex_unlock( vips__global_lock ); + + vips_error( class->nickname, + "%s", _( "too many files in zip" ) ); + return( -1 ); + } + + /* Leave 16k headroom for blank.png and metadata files. + */ + if( estimate_zip_size( dz ) > (size_t) UINT_MAX - 16384) { + g_mutex_unlock( vips__global_lock ); + + vips_error( class->nickname, + "%s", _( "output file too large" ) ); + return( -1 ); + } + } +#endif /*HAVE_GSF_ZIP64*/ + + g_mutex_unlock( vips__global_lock ); + + g_free( buf ); + + return( 0 ); +} + /* Free a pyramid. */ static void @@ -983,6 +1050,58 @@ write_scan_properties( VipsForeignSaveDz *dz ) return( 0 ); } +static void * +write_associated_properties( VipsImage *image, + const char *field, GValue *value, void *a ) +{ + VipsForeignSaveDz *dz = (VipsForeignSaveDz *) a; + + if( vips_isprefix( "openslide.associated.", field ) ) { + VipsImage *associated; + const char *p; + const char *q; + GsfOutput *out; + char buf[VIPS_PATH_MAX]; + + p = field + strlen( "openslide.associated." ); + + /* Make sure there are no '/' in the filename. + */ + if( (q = strrchr( p, '/' )) ) + p = q + 1; + + if( vips_image_get_image( image, field, &associated ) ) + return( image ); + + vips_snprintf( buf, VIPS_PATH_MAX, "%s.jpg", p ); + out = vips_gsf_path( dz->tree, buf, "associated_images", NULL ); + + if( write_image( dz, out, associated, ".jpg" ) ) { + g_object_unref( out ); + g_object_unref( associated ); + + return( image ); + } + + g_object_unref( out ); + + g_object_unref( associated ); + } + + return( NULL ); +} + +static int +write_associated( VipsForeignSaveDz *dz ) +{ + VipsForeignSave *save = (VipsForeignSave *) dz; + + if( vips_image_map( save->ready, write_associated_properties, dz ) ) + return( -1 ); + + return( 0 ); +} + /* Our state during a threaded write of a strip. */ typedef struct _Strip { @@ -2069,6 +2188,10 @@ vips_foreign_save_dz_build( VipsObject *object ) write_scan_properties( dz ) ) return( -1 ); + if( dz->container == VIPS_FOREIGN_DZ_CONTAINER_SZI && + write_associated( 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.