Merge pull request #461 from felixbuenemann/dzsave-zip-compression
Vips dzsave zip compression support
This commit is contained in:
commit
88acc23e2b
@ -147,6 +147,14 @@
|
|||||||
#include <vips/vips.h>
|
#include <vips/vips.h>
|
||||||
#include <vips/internal.h>
|
#include <vips/internal.h>
|
||||||
|
|
||||||
|
#define VIPS_ZIP_STORE 0
|
||||||
|
#define VIPS_ZIP_DEFLATE 8
|
||||||
|
#define VIPS_ZIP_DEFAULT_COMPRESSION -1
|
||||||
|
|
||||||
|
/* libgsf before 1.14.31 did not support deflate-level.
|
||||||
|
*/
|
||||||
|
#define vips_gsf_has_zip64 vips_gsf_has_deflate_level
|
||||||
|
|
||||||
/* Track this during property save.
|
/* Track this during property save.
|
||||||
*/
|
*/
|
||||||
typedef struct _WriteInfo {
|
typedef struct _WriteInfo {
|
||||||
@ -319,13 +327,17 @@ typedef struct _VipsGsfDirectory {
|
|||||||
|
|
||||||
/* If we need to turn off compression for this container.
|
/* If we need to turn off compression for this container.
|
||||||
*/
|
*/
|
||||||
gboolean no_compression;
|
gboolean is_zip;
|
||||||
|
|
||||||
/* The root node holds the enclosing zip file or FS root ... finish
|
/* The root node holds the enclosing zip file or FS root ... finish
|
||||||
* this on cleanup.
|
* this on cleanup.
|
||||||
*/
|
*/
|
||||||
GsfOutput *container;
|
GsfOutput *container;
|
||||||
|
|
||||||
|
/* Set deflate compression level for zip container.
|
||||||
|
*/
|
||||||
|
gint compression_level;
|
||||||
|
|
||||||
} VipsGsfDirectory;
|
} VipsGsfDirectory;
|
||||||
|
|
||||||
/* Close all dirs, non-NULL on error.
|
/* Close all dirs, non-NULL on error.
|
||||||
@ -383,7 +395,7 @@ vips_gsf_tree_free( VipsGsfDirectory *tree )
|
|||||||
/* Make a new tree root.
|
/* Make a new tree root.
|
||||||
*/
|
*/
|
||||||
static VipsGsfDirectory *
|
static VipsGsfDirectory *
|
||||||
vips_gsf_tree_new( GsfOutput *out, gboolean no_compression )
|
vips_gsf_tree_new( GsfOutput *out, gboolean is_zip, gint compression_level )
|
||||||
{
|
{
|
||||||
VipsGsfDirectory *tree = g_new( VipsGsfDirectory, 1 );
|
VipsGsfDirectory *tree = g_new( VipsGsfDirectory, 1 );
|
||||||
|
|
||||||
@ -391,8 +403,9 @@ vips_gsf_tree_new( GsfOutput *out, gboolean no_compression )
|
|||||||
tree->name = NULL;
|
tree->name = NULL;
|
||||||
tree->children = NULL;
|
tree->children = NULL;
|
||||||
tree->out = out;
|
tree->out = out;
|
||||||
tree->no_compression = no_compression;
|
tree->is_zip = is_zip;
|
||||||
tree->container = NULL;
|
tree->container = NULL;
|
||||||
|
tree->compression_level = compression_level;
|
||||||
|
|
||||||
return( tree );
|
return( tree );
|
||||||
}
|
}
|
||||||
@ -428,14 +441,15 @@ vips_gsf_dir_new( VipsGsfDirectory *parent, const char *name )
|
|||||||
dir->parent = parent;
|
dir->parent = parent;
|
||||||
dir->name = g_strdup( name );
|
dir->name = g_strdup( name );
|
||||||
dir->children = NULL;
|
dir->children = NULL;
|
||||||
dir->no_compression = parent->no_compression;
|
dir->is_zip = parent->is_zip;
|
||||||
dir->container = NULL;
|
dir->container = NULL;
|
||||||
|
dir->compression_level = parent->compression_level;
|
||||||
|
|
||||||
if( dir->no_compression )
|
if( dir->is_zip )
|
||||||
dir->out = gsf_outfile_new_child_full(
|
dir->out = gsf_outfile_new_child_full(
|
||||||
(GsfOutfile *) parent->out,
|
(GsfOutfile *) parent->out,
|
||||||
name, TRUE,
|
name, TRUE,
|
||||||
"compression-level", 0,
|
"compression-level", VIPS_ZIP_STORE,
|
||||||
NULL );
|
NULL );
|
||||||
else
|
else
|
||||||
dir->out = gsf_outfile_new_child(
|
dir->out = gsf_outfile_new_child(
|
||||||
@ -474,11 +488,26 @@ vips_gsf_path( VipsGsfDirectory *tree, const char *name, ... )
|
|||||||
dir = vips_gsf_dir_new( dir, dir_name );
|
dir = vips_gsf_dir_new( dir, dir_name );
|
||||||
va_end( ap );
|
va_end( ap );
|
||||||
|
|
||||||
if( dir->no_compression )
|
if( dir->is_zip )
|
||||||
obj = gsf_outfile_new_child_full( (GsfOutfile *) dir->out,
|
if( dir->compression_level == 0 )
|
||||||
name, FALSE,
|
obj = gsf_outfile_new_child_full(
|
||||||
"compression-level", 0,
|
(GsfOutfile *) dir->out,
|
||||||
NULL );
|
name, FALSE,
|
||||||
|
"compression-level", VIPS_ZIP_STORE,
|
||||||
|
NULL );
|
||||||
|
else if( dir->compression_level == VIPS_ZIP_DEFAULT_COMPRESSION )
|
||||||
|
obj = gsf_outfile_new_child_full(
|
||||||
|
(GsfOutfile *) dir->out,
|
||||||
|
name, FALSE,
|
||||||
|
"compression-level", VIPS_ZIP_DEFLATE,
|
||||||
|
NULL );
|
||||||
|
else
|
||||||
|
obj = gsf_outfile_new_child_full(
|
||||||
|
(GsfOutfile *) dir->out,
|
||||||
|
name, FALSE,
|
||||||
|
"compression-level", VIPS_ZIP_DEFLATE,
|
||||||
|
"deflate-level", dir->compression_level,
|
||||||
|
NULL );
|
||||||
else
|
else
|
||||||
obj = gsf_outfile_new_child( (GsfOutfile *) dir->out,
|
obj = gsf_outfile_new_child( (GsfOutfile *) dir->out,
|
||||||
name, FALSE );
|
name, FALSE );
|
||||||
@ -560,6 +589,7 @@ struct _VipsForeignSaveDz {
|
|||||||
gboolean properties;
|
gboolean properties;
|
||||||
VipsAngle angle;
|
VipsAngle angle;
|
||||||
VipsForeignDzContainer container;
|
VipsForeignDzContainer container;
|
||||||
|
int compression;
|
||||||
|
|
||||||
Layer *layer; /* x2 shrink pyr layer */
|
Layer *layer; /* x2 shrink pyr layer */
|
||||||
|
|
||||||
@ -1827,7 +1857,7 @@ vips_foreign_save_dz_build( VipsObject *object )
|
|||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
dz->tree = vips_gsf_tree_new( out, FALSE );
|
dz->tree = vips_gsf_tree_new( out, FALSE, 0 );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
GsfOutput *out;
|
GsfOutput *out;
|
||||||
@ -1842,7 +1872,7 @@ vips_foreign_save_dz_build( VipsObject *object )
|
|||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
dz->tree = vips_gsf_tree_new( out, FALSE );
|
dz->tree = vips_gsf_tree_new( out, FALSE, 0 );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1878,10 +1908,16 @@ vips_foreign_save_dz_build( VipsObject *object )
|
|||||||
*/
|
*/
|
||||||
out2 = gsf_outfile_new_child_full( (GsfOutfile *) zip,
|
out2 = gsf_outfile_new_child_full( (GsfOutfile *) zip,
|
||||||
dz->basename, TRUE,
|
dz->basename, TRUE,
|
||||||
"compression-level", 0,
|
"compression-level", VIPS_ZIP_STORE,
|
||||||
NULL );
|
NULL );
|
||||||
|
|
||||||
dz->tree = vips_gsf_tree_new( out2, TRUE );
|
if( dz->compression > 0 && !vips_gsf_has_deflate_level() ) {
|
||||||
|
vips_warn( "VipsDzSave",
|
||||||
|
"%s",
|
||||||
|
_( "libgsf too old, using default compression" ) );
|
||||||
|
dz->compression = VIPS_ZIP_DEFAULT_COMPRESSION;
|
||||||
|
}
|
||||||
|
dz->tree = vips_gsf_tree_new( out2, TRUE, dz->compression );
|
||||||
|
|
||||||
/* Note the thing that will need closing up on exit.
|
/* Note the thing that will need closing up on exit.
|
||||||
*/
|
*/
|
||||||
@ -2072,6 +2108,13 @@ vips_foreign_save_dz_class_init( VipsForeignSaveDzClass *class )
|
|||||||
G_STRUCT_OFFSET( VipsForeignSaveDz, properties ),
|
G_STRUCT_OFFSET( VipsForeignSaveDz, properties ),
|
||||||
FALSE );
|
FALSE );
|
||||||
|
|
||||||
|
VIPS_ARG_INT( class, "compression", 17,
|
||||||
|
_( "Compression" ),
|
||||||
|
_( "ZIP deflate compression level" ),
|
||||||
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||||
|
G_STRUCT_OFFSET( VipsForeignSaveDz, compression ),
|
||||||
|
-1, 9, 0 );
|
||||||
|
|
||||||
/* How annoying. We stupidly had these in earlier versions.
|
/* How annoying. We stupidly had these in earlier versions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -2116,6 +2159,7 @@ vips_foreign_save_dz_init( VipsForeignSaveDz *dz )
|
|||||||
dz->depth = VIPS_FOREIGN_DZ_DEPTH_ONEPIXEL;
|
dz->depth = VIPS_FOREIGN_DZ_DEPTH_ONEPIXEL;
|
||||||
dz->angle = VIPS_ANGLE_D0;
|
dz->angle = VIPS_ANGLE_D0;
|
||||||
dz->container = VIPS_FOREIGN_DZ_CONTAINER_FS;
|
dz->container = VIPS_FOREIGN_DZ_CONTAINER_FS;
|
||||||
|
dz->compression = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /*HAVE_GSF*/
|
#endif /*HAVE_GSF*/
|
||||||
@ -2138,6 +2182,7 @@ vips_foreign_save_dz_init( VipsForeignSaveDz *dz )
|
|||||||
* * @angle: rotate the image by this much
|
* * @angle: rotate the image by this much
|
||||||
* * @container: set container type
|
* * @container: set container type
|
||||||
* * @properties: write a properties file
|
* * @properties: write a properties file
|
||||||
|
* * @compression: zip deflate compression level
|
||||||
*
|
*
|
||||||
* Save an image as a set of tiles at various resolutions. By default dzsave
|
* Save an image as a set of tiles at various resolutions. By default dzsave
|
||||||
* uses DeepZoom layout -- use @layout to pick other conventions.
|
* uses DeepZoom layout -- use @layout to pick other conventions.
|
||||||
@ -2168,6 +2213,10 @@ vips_foreign_save_dz_init( VipsForeignSaveDz *dz )
|
|||||||
* programs which wish to use fields from source files loaded via
|
* programs which wish to use fields from source files loaded via
|
||||||
* vips_openslideload().
|
* vips_openslideload().
|
||||||
*
|
*
|
||||||
|
* If @container is set to `zip`, you can set a compression level from -1
|
||||||
|
* (use zlib default), 0 (store, compression disabled) to 9 (max compression).
|
||||||
|
* If no value is given, the default is to store files without compression.
|
||||||
|
*
|
||||||
* See also: vips_tiffsave().
|
* See also: vips_tiffsave().
|
||||||
*
|
*
|
||||||
* Returns: 0 on success, -1 on error.
|
* Returns: 0 on success, -1 on error.
|
||||||
|
@ -609,7 +609,13 @@ class TestForeign(unittest.TestCase):
|
|||||||
self.colour.dzsave("test.zip")
|
self.colour.dzsave("test.zip")
|
||||||
self.assertFalse(os.path.exists("test_files"))
|
self.assertFalse(os.path.exists("test_files"))
|
||||||
self.assertFalse(os.path.exists("test.dzi"))
|
self.assertFalse(os.path.exists("test.dzi"))
|
||||||
|
|
||||||
|
# test compressed zip output
|
||||||
|
self.colour.dzsave("test_compressed.zip", compression = -1)
|
||||||
|
self.assertLess(os.path.getsize("test_compressed.zip"),
|
||||||
|
os.path.getsize("test.zip"))
|
||||||
os.unlink("test.zip")
|
os.unlink("test.zip")
|
||||||
|
os.unlink("test_compressed.zip")
|
||||||
|
|
||||||
# test suffix
|
# test suffix
|
||||||
self.colour.dzsave("test", suffix = ".png")
|
self.colour.dzsave("test", suffix = ".png")
|
||||||
|
Loading…
Reference in New Issue
Block a user