From 30808f70a5a4cc86230f12e974164ada04ec2516 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 6 May 2014 14:28:41 +0100 Subject: [PATCH 1/3] sort out dzsave paths, auto-enable zip rationalised output paths for dzsave enable zip automatically if output name ends in .zip --- TODO | 13 ++++++- libvips/foreign/dzsave.c | 83 ++++++++++++++++++++++++---------------- libvips/iofuncs/system.c | 4 -- 3 files changed, 61 insertions(+), 39 deletions(-) diff --git a/TODO b/TODO index c0790304..45cc07b5 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,14 @@ +- argh oh dear sort out zip / non-zip paths + + container FS zip + layout + + deepzoom x/x_files/ x.zip/x/x_files/ + google x/0 x.zip/x/0 + zoomify x/Imag.. x.zip/x/Imag.. + + + - how do we keep compat with old behaviour? gsf won't let us write to "." @@ -5,8 +16,6 @@ -- auto-enable zip output? - - try vips vips diff --git a/libvips/foreign/dzsave.c b/libvips/foreign/dzsave.c index 662db30f..84db3a2a 100644 --- a/libvips/foreign/dzsave.c +++ b/libvips/foreign/dzsave.c @@ -41,28 +41,6 @@ * filesystem */ -/* - - TODO - - - need some way to pass save options to the jpeg tile writer - - - and to pick a tile writer! - - - need some way to select a container format - - - are the rules for naming objects correct? eg. - - vips dzsave fred.tif /my/output/file.zip - - will create file.zip containing - - file.zip:file_files - file.zip:file_files/0/0_0.jpg - file.zip:file.dzi - - */ - /* This file is part of VIPS. @@ -176,6 +154,10 @@ typedef struct _VipsGsfDirectory { */ gboolean no_compression; + /* The root node holds the enclosing zip file or FS root ... finish + * this on cleanup. + */ + GsfOutput *container; } VipsGsfDirectory; /* Close all dirs, non-NULL on error. @@ -185,12 +167,19 @@ vips_gsf_tree_close( VipsGsfDirectory *tree ) { vips_slist_map2( tree->children, (VipsSListMap2Fn) vips_gsf_tree_close, NULL, NULL ); + if( tree->out && !gsf_output_is_closed( tree->out ) && !gsf_output_close( tree->out ) ) { vips_error( "vips_gsf", "%s", _( "unable to close stream" ) ); return( tree ); } + if( tree->container && + !gsf_output_is_closed( tree->container ) && + !gsf_output_close( tree->container ) ) { + vips_error( "vips_gsf", "%s", _( "unable to close stream" ) ); + return( tree ); + } return( NULL ); } @@ -205,11 +194,19 @@ vips_gsf_tree_free( VipsGsfDirectory *tree ) (VipsSListMap2Fn) vips_gsf_tree_free, NULL, NULL ); g_slist_free( tree->children ); g_free( (char *) tree->name ); + if( tree->out ) { if( !gsf_output_is_closed( tree->out ) ) (void) gsf_output_close( tree->out ); g_object_unref( tree->out ); } + + if( tree->container ) { + if( !gsf_output_is_closed( tree->container ) ) + (void) gsf_output_close( tree->container ); + g_object_unref( tree->container ); + } + g_free( tree ); return( NULL ); @@ -227,6 +224,7 @@ vips_gsf_tree_new( GsfOutput *out, gboolean no_compression ) tree->children = NULL; tree->out = out; tree->no_compression = no_compression; + tree->container = NULL; return( tree ); } @@ -263,6 +261,7 @@ vips_gsf_dir_new( VipsGsfDirectory *parent, const char *name ) dir->name = g_strdup( name ); dir->children = NULL; dir->no_compression = parent->no_compression; + dir->container = NULL; if( dir->no_compression ) dir->out = gsf_outfile_new_child_full( @@ -404,8 +403,8 @@ struct _VipsForeignSaveDz { */ char *dirname; - /* The root directory name ... used to form - * $(root_name)_files, $(root_name), etc. + /* The root directory name ... $basename with perhaps some extra + * stuff, eg. $(basename)_files, etc. */ char *root_name; }; @@ -588,7 +587,7 @@ write_dzi( VipsForeignSaveDz *dz ) char buf[VIPS_PATH_MAX]; char *p; - vips_snprintf( buf, VIPS_PATH_MAX, "%s.dzi", dz->name ); + vips_snprintf( buf, VIPS_PATH_MAX, "%s.dzi", dz->basename ); out = vips_gsf_path( dz->tree, buf, NULL ); vips_snprintf( buf, VIPS_PATH_MAX, "%s", dz->suffix + 1 ); @@ -675,7 +674,7 @@ write_blank( VipsForeignSaveDz *dz ) } g_object_unref( x ); - out = vips_gsf_path( dz->tree, "blank.png", dz->root_name, NULL ); + out = vips_gsf_path( dz->tree, "blank.png", NULL ); gsf_output_write( out, len, buf ); gsf_output_close( out ); g_object_unref( out ); @@ -955,8 +954,7 @@ tile_name( Layer *layer, int x, int y ) */ dz->tile_count += 1; - out = vips_gsf_path( dz->tree, name, - dz->root_name, dirname, NULL ); + out = vips_gsf_path( dz->tree, name, dirname, NULL ); break; @@ -965,8 +963,7 @@ tile_name( Layer *layer, int x, int y ) vips_snprintf( dirname2, VIPS_PATH_MAX, "%d", y ); vips_snprintf( name, VIPS_PATH_MAX, "%d%s", x, dz->suffix ); - out = vips_gsf_path( dz->tree, name, - dz->root_name, dirname, dirname2, NULL ); + out = vips_gsf_path( dz->tree, name, dirname, dirname2, NULL ); break; @@ -1490,10 +1487,17 @@ vips_foreign_save_dz_build( VipsObject *object ) char *p; dz->basename = g_path_get_basename( dz->name ); - if( (p = (char *) vips__find_rightmost_brackets( dz->name )) ) + if( (p = (char *) vips__find_rightmost_brackets( dz->basename )) ) *p = '\0'; - if( (p = strrchr( dz->name, '.' )) ) + if( (p = strrchr( dz->basename, '.' )) ) { *p = '\0'; + + /* If we're writing to thing.zip, default to zip container. + */ + if( strcasecmp( p + 1, "zip" ) == 0 && + !vips_object_argument_isset( object, "container" ) ) + dz->container = VIPS_FOREIGN_DZ_CONTAINER_ZIP; + } } dz->dirname = g_path_get_dirname( dz->name ); @@ -1528,6 +1532,7 @@ vips_foreign_save_dz_build( VipsObject *object ) { GsfOutput *out; GsfOutput *zip; + GsfOutput *out2; GError *error = NULL; /* This is the zip we are building. @@ -1547,7 +1552,19 @@ vips_foreign_save_dz_build( VipsObject *object ) */ g_object_unref( out ); - dz->tree = vips_gsf_tree_new( zip, TRUE ); + /* Make the base directory inside the zip. All stuff goes into + * this. + */ + out2 = gsf_outfile_new_child_full( (GsfOutfile *) zip, + dz->basename, TRUE, + "compression-level", 0, + NULL ); + + dz->tree = vips_gsf_tree_new( out2, TRUE ); + + /* Note the thing that will need closing up on exit. + */ + dz->tree->container = zip; } break; diff --git a/libvips/iofuncs/system.c b/libvips/iofuncs/system.c index 15b34ff6..ec3df1ce 100644 --- a/libvips/iofuncs/system.c +++ b/libvips/iofuncs/system.c @@ -118,10 +118,6 @@ vips_system_build( VipsObject *object ) char cmd[VIPS_PATH_MAX]; - FILE *fp; - char line[VIPS_PATH_MAX]; - char txt[VIPS_PATH_MAX]; - VipsBuf buf = VIPS_BUF_STATIC( txt ); char *p; char *std_output; char *std_error; From 249c87906afeecdc31365a8f00b0d14495cf83ca Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 6 May 2014 14:30:28 +0100 Subject: [PATCH 2/3] TODO notes --- TODO | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/TODO b/TODO index 45cc07b5..c52780ee 100644 --- a/TODO +++ b/TODO @@ -1,18 +1,5 @@ -- argh oh dear sort out zip / non-zip paths +- sort out dzsave docs ... note auto-zip and new path system - container FS zip - layout - - deepzoom x/x_files/ x.zip/x/x_files/ - google x/0 x.zip/x/0 - zoomify x/Imag.. x.zip/x/Imag.. - - - - -- how do we keep compat with old behaviour? gsf won't let us write to "." - - looks like we need to break compatibility :-( From 5478a9bb8173369dfd72011c9208a55e1038f07b Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 6 May 2014 14:38:24 +0100 Subject: [PATCH 3/3] update dzsave docs --- TODO | 4 ---- libvips/foreign/dzsave.c | 22 ++++------------------ 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/TODO b/TODO index c52780ee..defdf266 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,3 @@ -- sort out dzsave docs ... note auto-zip and new path system - - - - try diff --git a/libvips/foreign/dzsave.c b/libvips/foreign/dzsave.c index 84db3a2a..16f27149 100644 --- a/libvips/foreign/dzsave.c +++ b/libvips/foreign/dzsave.c @@ -1780,21 +1780,14 @@ vips_foreign_save_dz_init( VipsForeignSaveDz *dz ) * @depth: how deep to make the pyramid * @centre: centre the tiles * @angle: rotate the image by this much - * @container: container format + * @container: set container type * * Save an image as a set of tiles at various resolutions. By default dzsave * uses DeepZoom layout -- use @layout to pick other conventions. * - * @name is split into three parts: $(dirname) (everything before the - * last '/'), $(basename) (everything after the last '/') and $(rootname) - * ($(basename) minus any extensions). - * - * In DeepZoom layout a directory in $(dirname) called - * "$(basename)_files" is created to hold the tiles, and an XML file called - * "$(basename).dzi" is written with the image metadata, - * - * In Zoomify and Google layout, a directory called @name is created to - * hold the tile structure. + * vips_dzsave() creates a directory called @name to hold the tiles. If @name + * ends ".zip", vips_dzsave() will create a zip file called @name to hold the + * tiles. You can use @container to force zip file output. * * You can set @suffix to something like ".jpg[Q=85]" to control the tile write * options. @@ -1810,13 +1803,6 @@ vips_foreign_save_dz_init( VipsForeignSaveDz *dz ) * Use @depth to control how low the pyramid goes. This defaults to the * correct setting for the @layout you select. * - * Use @container to set where to write the zoom structure. By default it - * writes to the filesystem, but set this to #VIPS_FOREIGN_DZ_CONTAINER_ZIP - * and dzsave will create a zip file called @name to hold the pyramid. - * - * Using #VIPS_FOREIGN_DZ_CONTAINER_ZIP can save a separate zip stage, - * which will be very slow on some platforms. - * * See also: vips_tiffsave(). * * Returns: 0 on success, -1 on error.