From 42930e8d87a6bb9106051821e8a93d38e003d41c Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sun, 26 Jan 2020 18:39:47 +0000 Subject: [PATCH] add "depth" param to tiffsave Add a "depth" param to tiffsave to set pyramid depth, just like the "depth" param on dzsave. See https://github.com/libvips/libvips/issues/1485 --- ChangeLog | 1 + libvips/foreign/pforeign.h | 8 +++++-- libvips/foreign/tiffsave.c | 23 ++++++++++++++++-- libvips/foreign/vips2tiff.c | 48 ++++++++++++++++++++++++++++++------- 4 files changed, 68 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6608763a..9fb6a081 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ - add @id to dzsave to set IIIF id property [regisrob] - add max and min to region shrink [rgluskin] - allow \ as an escape character in vips_break_token() [akemrir] +- tiffsave has a "depth" param to set max pyr depth 20/6/19 started 8.9.1 - don't use the new source loaders for new_from_file or new_from_buffer, it diff --git a/libvips/foreign/pforeign.h b/libvips/foreign/pforeign.h index b19ec78e..77381f47 100644 --- a/libvips/foreign/pforeign.h +++ b/libvips/foreign/pforeign.h @@ -61,7 +61,9 @@ int vips__tiff_write( VipsImage *in, const char *filename, gboolean properties, gboolean strip, VipsRegionShrink region_shrink, - int level, gboolean lossless ); + int level, + gboolean lossless, + VipsForeignDzDepth depth ); int vips__tiff_write_buf( VipsImage *in, void **obuf, size_t *olen, @@ -77,7 +79,9 @@ int vips__tiff_write_buf( VipsImage *in, gboolean rgbjpeg, gboolean properties, gboolean strip, VipsRegionShrink region_shrink, - int level, gboolean lossless ); + int level, + gboolean lossless, + VipsForeignDzDepth depth ); gboolean vips__istiff_source( VipsSource *source ); gboolean vips__istifftiled_source( VipsSource *source ); diff --git a/libvips/foreign/tiffsave.c b/libvips/foreign/tiffsave.c index 2447e2d9..281d486a 100644 --- a/libvips/foreign/tiffsave.c +++ b/libvips/foreign/tiffsave.c @@ -19,6 +19,8 @@ * - add @level and @lossless * 4/9/18 [f--f] * - xres/yres params were in pixels/cm + * 26/1/20 + * - add "depth" to set pyr depth */ /* @@ -95,6 +97,7 @@ typedef struct _VipsForeignSaveTiff { VipsRegionShrink region_shrink; int level; gboolean lossless; + VipsForeignDzDepth depth; } VipsForeignSaveTiff; typedef VipsForeignSaveClass VipsForeignSaveTiffClass; @@ -330,6 +333,13 @@ vips_foreign_save_tiff_class_init( VipsForeignSaveTiffClass *class ) G_STRUCT_OFFSET( VipsForeignSaveTiff, lossless ), FALSE ); + VIPS_ARG_ENUM( class, "depth", 25, + _( "Depth" ), + _( "Pyramid depth" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsForeignSaveTiff, depth ), + VIPS_TYPE_FOREIGN_DZ_DEPTH, VIPS_FOREIGN_DZ_DEPTH_ONETILE ); + } static void @@ -346,6 +356,7 @@ vips_foreign_save_tiff_init( VipsForeignSaveTiff *tiff ) tiff->region_shrink = VIPS_REGION_SHRINK_MEAN; tiff->level = 10; tiff->lossless = FALSE; + tiff->depth = VIPS_FOREIGN_DZ_DEPTH_ONETILE; } typedef struct _VipsForeignSaveTiffFile { @@ -384,7 +395,8 @@ vips_foreign_save_tiff_file_build( VipsObject *object ) save->strip, tiff->region_shrink, tiff->level, - tiff->lossless ) ) + tiff->lossless, + tiff->depth ) ) return( -1 ); return( 0 ); @@ -455,7 +467,8 @@ vips_foreign_save_tiff_buffer_build( VipsObject *object ) save->strip, tiff->region_shrink, tiff->level, - tiff->lossless ) ) + tiff->lossless, + tiff->depth ) ) return( -1 ); /* vips__tiff_write_buf() makes a buffer that needs g_free(), not @@ -523,6 +536,7 @@ vips_foreign_save_tiff_buffer_init( VipsForeignSaveTiffBuffer *buffer ) * * @region_shrink: #VipsRegionShrink How to shrink each 2x2 region. * * @level: %gint, Zstd compression level * * @lossless: %gboolean, WebP losssless mode + * * @depth: #VipsForeignDzDepth how deep to make the pyramid * * Write a VIPS image to a file as TIFF. * @@ -564,6 +578,10 @@ vips_foreign_save_tiff_buffer_init( VipsForeignSaveTiffBuffer *buffer ) * default each 2x2 block is just averaged, but you can set MODE or MEDIAN as * well. * + * By default, the pyramid stops when the image is small enough to fit in one + * tile. Use @depth to stop when the image fits in one pixel, or to only write + * a single layer. + * * Set @squash to make 8-bit uchar images write as 1-bit TIFFs. Values >128 * are written as white, values <=128 as black. Normally vips will write * MINISBLACK TIFFs where black is a 0 bit, but if you set @miniswhite, it @@ -642,6 +660,7 @@ vips_tiffsave( VipsImage *in, const char *filename, ... ) * * @region_shrink: #VipsRegionShrink How to shrink each 2x2 region. * * @level: %gint, Zstd compression level * * @lossless: %gboolean, WebP losssless mode + * * @depth: #VipsForeignDzDepth how deep to make the pyramid * * As vips_tiffsave(), but save to a memory buffer. * diff --git a/libvips/foreign/vips2tiff.c b/libvips/foreign/vips2tiff.c index c7afbc7f..63e338ac 100644 --- a/libvips/foreign/vips2tiff.c +++ b/libvips/foreign/vips2tiff.c @@ -187,6 +187,8 @@ * - add @level and @lossless * 18/12/19 * - "squash" now squashes 3-band float LAB down to LABQ + * 26/1/20 + * - add "depth" to set pyr depth */ /* @@ -327,6 +329,7 @@ struct _Wtiff { VipsRegionShrink region_shrink; /* How to shrink regions */ int level; /* zstd compression level */ gboolean lossless; /* webp lossless mode */ + VipsForeignDzDepth depth; /* Pyr depth */ /* True if we've detected a toilet-roll image, plus the page height, * which has been checked to be a factor of im->Ysize. @@ -420,19 +423,41 @@ wtiff_layer_new( Wtiff *wtiff, Layer *above, int width, int height ) layer->sub, width, height ); */ - if( wtiff->pyramid ) + if( wtiff->pyramid ) { + int limitw, limith; + + switch( wtiff->depth ) { + case VIPS_FOREIGN_DZ_DEPTH_ONEPIXEL: + limitw = limith = 1; + break; + + case VIPS_FOREIGN_DZ_DEPTH_ONETILE: + limitw = wtiff->tilew; + limith = wtiff->tileh; + break; + + case VIPS_FOREIGN_DZ_DEPTH_ONE: + limitw = wtiff->ready->Xsize; + limith = wtiff->ready->Ysize; + break; + + default: + g_assert_not_reached(); + } + /* We make another layer if the image is too large to fit in a * single tile, and if neither axis is greater than 1. * * Very tall or wide images might end up with a smallest layer * larger than one tile. */ - if( (layer->width > wtiff->tilew || - layer->height > wtiff->tileh) && + if( (layer->width > limitw || + layer->height > limith) && layer->width > 1 && layer->height > 1 ) layer->below = wtiff_layer_new( wtiff, layer, width / 2, height / 2 ); + } /* The name for the top layer is the output filename. * @@ -969,7 +994,9 @@ wtiff_new( VipsImage *input, const char *filename, gboolean properties, gboolean strip, VipsRegionShrink region_shrink, - int level, gboolean lossless ) + int level, + gboolean lossless, + VipsForeignDzDepth depth ) { Wtiff *wtiff; @@ -1000,6 +1027,7 @@ wtiff_new( VipsImage *input, const char *filename, wtiff->region_shrink = region_shrink; wtiff->level = level; wtiff->lossless = lossless; + wtiff->depth = depth; wtiff->toilet_roll = FALSE; wtiff->page_height = vips_image_get_page_height( input ); wtiff->image_height = input->Ysize; @@ -1889,7 +1917,9 @@ vips__tiff_write( VipsImage *input, const char *filename, gboolean rgbjpeg, gboolean properties, gboolean strip, VipsRegionShrink region_shrink, - int level, gboolean lossless ) + int level, + gboolean lossless, + VipsForeignDzDepth depth ) { Wtiff *wtiff; @@ -1903,7 +1933,7 @@ vips__tiff_write( VipsImage *input, const char *filename, compression, Q, predictor, profile, tile, tile_width, tile_height, pyramid, squash, miniswhite, resunit, xres, yres, bigtiff, rgbjpeg, - properties, strip, region_shrink, level, lossless )) ) + properties, strip, region_shrink, level, lossless, depth )) ) return( -1 ); if( wtiff_write_image( wtiff ) ) { @@ -1931,7 +1961,9 @@ vips__tiff_write_buf( VipsImage *input, gboolean rgbjpeg, gboolean properties, gboolean strip, VipsRegionShrink region_shrink, - int level, gboolean lossless ) + int level, + gboolean lossless, + VipsForeignDzDepth depth ) { Wtiff *wtiff; @@ -1941,7 +1973,7 @@ vips__tiff_write_buf( VipsImage *input, compression, Q, predictor, profile, tile, tile_width, tile_height, pyramid, squash, miniswhite, resunit, xres, yres, bigtiff, rgbjpeg, - properties, strip, region_shrink, level, lossless )) ) + properties, strip, region_shrink, level, lossless, depth )) ) return( -1 ); wtiff->obuf = obuf;