Merge branch 'fix-dzsave-overlap'
This commit is contained in:
commit
96796d3202
@ -1,4 +1,4 @@
|
||||
7/5/15 started 8.1.0
|
||||
7/5/15 starteld 8.1.0
|
||||
- add vips_premultiply(), vips_unpremultiply()
|
||||
- change the alpha range rules for vips_flatten() to match vips_premultiply()
|
||||
- vipsthumbnail uses vips_resize() rather than its own code
|
||||
@ -17,6 +17,7 @@
|
||||
- can now set any jpeg exif tag, not just modify existing tags
|
||||
- add vips_hist_entropy()
|
||||
- vips_log(), vips_log10() are zero-avoiding
|
||||
- better overlap handling for dzsave, thanks robclouth
|
||||
|
||||
7/5/15 started 8.0.3
|
||||
- dzsave and tif pyr write could fail for some image dimensions, thanks Jonas
|
||||
|
@ -53,6 +53,8 @@
|
||||
* - use a better temp dir name for fs dz output
|
||||
* 8/8/15
|
||||
* - allow zip > 4gb if we have a recent libgsf
|
||||
* 9/9/15
|
||||
* - better overlap handling, thanks robclouth
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -375,8 +377,7 @@ struct _Layer {
|
||||
*/
|
||||
VipsImage *image;
|
||||
|
||||
/* The top of this strip of tiles, excluding the overlap. Go up from
|
||||
* this to get to the top pixel we write in each one.
|
||||
/* The top of this strip of tiles.
|
||||
*/
|
||||
int y;
|
||||
|
||||
@ -414,6 +415,11 @@ struct _VipsForeignSaveDz {
|
||||
|
||||
Layer *layer; /* x2 shrink pyr layer */
|
||||
|
||||
/* We step by tile_size - overlap as we move across the image ...
|
||||
* make a note of it.
|
||||
*/
|
||||
int tile_step;
|
||||
|
||||
/* Count zoomify tiles we write.
|
||||
*/
|
||||
int tile_count;
|
||||
@ -481,7 +487,8 @@ vips_foreign_save_dz_dispose( GObject *gobject )
|
||||
VIPS_FREE( dz->root_name );
|
||||
VIPS_FREE( dz->file_suffix );
|
||||
|
||||
G_OBJECT_CLASS( vips_foreign_save_dz_parent_class )->dispose( gobject );
|
||||
G_OBJECT_CLASS( vips_foreign_save_dz_parent_class )->
|
||||
dispose( gobject );
|
||||
}
|
||||
|
||||
/* Build a pyramid.
|
||||
@ -503,8 +510,8 @@ pyramid_build( VipsForeignSaveDz *dz, Layer *above,
|
||||
layer->width = width;
|
||||
layer->height = height;
|
||||
|
||||
layer->tiles_across = ROUND_UP( width, dz->tile_size ) / dz->tile_size;
|
||||
layer->tiles_down = ROUND_UP( height, dz->tile_size ) / dz->tile_size;
|
||||
layer->tiles_across = ROUND_UP( width, dz->tile_step ) / dz->tile_step;
|
||||
layer->tiles_down = ROUND_UP( height, dz->tile_step ) / dz->tile_step;
|
||||
|
||||
layer->real_pixels = *real_pixels;
|
||||
|
||||
@ -543,8 +550,7 @@ pyramid_build( VipsForeignSaveDz *dz, Layer *above,
|
||||
vips__region_no_ownership( layer->strip );
|
||||
vips__region_no_ownership( layer->copy );
|
||||
|
||||
/* Build a line of tiles here. Normally strips are height + 2 *
|
||||
* overlap, but the first row is missing the top edge.
|
||||
/* Build a line of tiles here.
|
||||
*
|
||||
* Expand the strip if necessary to make sure we have an even
|
||||
* number of lines.
|
||||
@ -554,7 +560,7 @@ pyramid_build( VipsForeignSaveDz *dz, Layer *above,
|
||||
strip.left = 0;
|
||||
strip.top = 0;
|
||||
strip.width = layer->image->Xsize;
|
||||
strip.height = dz->tile_size + dz->overlap;
|
||||
strip.height = dz->tile_size;
|
||||
if( (strip.height & 1) == 1 )
|
||||
strip.height += 1;
|
||||
if( vips_region_buffer( layer->strip, &strip ) ) {
|
||||
@ -638,7 +644,8 @@ write_dzi( VipsForeignSaveDz *dz )
|
||||
if( (p = (char *) vips__find_rightmost_brackets( buf )) )
|
||||
*p = '\0';
|
||||
|
||||
gsf_output_printf( out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" );
|
||||
gsf_output_printf( out, "<?xml "
|
||||
"version=\"1.0\" encoding=\"UTF-8\"?>\n" );
|
||||
gsf_output_printf( out, "<Image "
|
||||
"xmlns=\"http://schemas.microsoft.com/deepzoom/2008\"\n" );
|
||||
gsf_output_printf( out, " Format=\"%s\"\n", buf );
|
||||
@ -923,9 +930,9 @@ strip_init( Strip *strip, Layer *layer )
|
||||
image.height = layer->height;
|
||||
|
||||
line.left = 0;
|
||||
line.top = layer->y - dz->overlap;
|
||||
line.top = layer->y;
|
||||
line.width = image.width;
|
||||
line.height = dz->tile_size + 2 * dz->overlap;
|
||||
line.height = dz->tile_size;
|
||||
|
||||
vips_rect_intersectrect( &image, &line, &line );
|
||||
|
||||
@ -963,16 +970,16 @@ strip_allocate( VipsThreadState *state, void *a, gboolean *stop )
|
||||
|
||||
/* Position this tile.
|
||||
*/
|
||||
state->pos.left = strip->x - dz->overlap;
|
||||
state->pos.top = 0;
|
||||
state->pos.width = dz->tile_size + 2 * dz->overlap;
|
||||
state->pos.height = state->im->Ysize;
|
||||
state->pos.left = strip->x;
|
||||
state->pos.top = layer->y;
|
||||
state->pos.width = dz->tile_size;
|
||||
state->pos.height = dz->tile_size;
|
||||
|
||||
vips_rect_intersectrect( &image, &state->pos, &state->pos );
|
||||
state->x = strip->x;
|
||||
state->y = layer->y;
|
||||
|
||||
strip->x += dz->tile_size;
|
||||
strip->x += dz->tile_step;
|
||||
|
||||
if( vips_rect_isempty( &state->pos ) ) {
|
||||
*stop = TRUE;
|
||||
@ -1055,6 +1062,10 @@ tile_name( Layer *layer, int x, int y )
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf( "tile_name: writing to %s\n", name );
|
||||
#endif /*DEBUG_VERBOSE*/
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
@ -1124,10 +1135,6 @@ strip_work( VipsThreadState *state, void *a )
|
||||
x = t;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf( "strip_work: writing to %s\n", buf );
|
||||
#endif /*DEBUG_VERBOSE*/
|
||||
|
||||
vips_image_set_int( x, "hide-progress", 1 );
|
||||
if( vips_image_write_to_buffer( x, dz->suffix, &buf, &len, NULL ) ) {
|
||||
g_object_unref( x );
|
||||
@ -1140,7 +1147,7 @@ strip_work( VipsThreadState *state, void *a )
|
||||
g_mutex_lock( vips__global_lock );
|
||||
|
||||
out = tile_name( layer,
|
||||
state->x / dz->tile_size, state->y / dz->tile_size );
|
||||
state->x / dz->tile_step, state->y / dz->tile_step );
|
||||
|
||||
status = gsf_output_write( out, len, buf );
|
||||
dz->bytes_written += len;
|
||||
@ -1201,6 +1208,10 @@ strip_save( Layer *layer )
|
||||
}
|
||||
strip_free( &strip );
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "strip_save: success\n" );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
@ -1272,6 +1283,11 @@ strip_shrink( Layer *layer )
|
||||
VipsRect target;
|
||||
VipsRect source;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "strip_shrink: %d lines in layer %d to layer %d\n",
|
||||
from->valid.height, layer->n, below->n );
|
||||
#endif/*DEBUG*/
|
||||
|
||||
/* We may have an extra column of pixels on the right or
|
||||
* bottom that need filling: generate them.
|
||||
*/
|
||||
@ -1336,7 +1352,7 @@ strip_shrink( Layer *layer )
|
||||
*
|
||||
* - write a line of tiles
|
||||
* - shrink what we can to the layer below
|
||||
* - move our strip down by the tile height
|
||||
* - move our strip down by the tile step
|
||||
* - copy the overlap with the previous strip
|
||||
*/
|
||||
static int
|
||||
@ -1348,6 +1364,11 @@ strip_arrived( Layer *layer )
|
||||
VipsRect overlap;
|
||||
VipsRect image_area;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "strip_arrived: layer %d, strip at %d, height %d\n",
|
||||
layer->n, layer->y, layer->strip->valid.height );
|
||||
#endif/*DEBUG*/
|
||||
|
||||
if( strip_save( layer ) )
|
||||
return( -1 );
|
||||
|
||||
@ -1360,11 +1381,11 @@ strip_arrived( Layer *layer )
|
||||
* Expand the strip if necessary to make sure we have an even
|
||||
* number of lines.
|
||||
*/
|
||||
layer->y += dz->tile_size;
|
||||
layer->y += dz->tile_step;
|
||||
new_strip.left = 0;
|
||||
new_strip.top = layer->y - dz->overlap;
|
||||
new_strip.top = layer->y;
|
||||
new_strip.width = layer->image->Xsize;
|
||||
new_strip.height = dz->tile_size + 2 * dz->overlap;
|
||||
new_strip.height = dz->tile_size;
|
||||
|
||||
image_area.left = 0;
|
||||
image_area.top = 0;
|
||||
@ -1534,6 +1555,9 @@ vips_foreign_save_dz_build( VipsObject *object )
|
||||
save->ready = z;
|
||||
}
|
||||
|
||||
/* How much we step by as we write tiles.
|
||||
*/
|
||||
dz->tile_step = dz->tile_size - dz->overlap;
|
||||
|
||||
/* The real pixels we have from our input. This is about to get
|
||||
* expanded with background.
|
||||
|
@ -4,6 +4,7 @@ from __future__ import division
|
||||
import unittest
|
||||
import math
|
||||
import os
|
||||
import shutil
|
||||
|
||||
#import logging
|
||||
#logging.basicConfig(level = logging.DEBUG)
|
||||
@ -345,6 +346,115 @@ class TestForeign(unittest.TestCase):
|
||||
def test_rad(self):
|
||||
self.save_load("%s.hdr", self.colour)
|
||||
|
||||
def test_dzsave(self):
|
||||
x = Vips.type_find("VipsForeign", "dzsave")
|
||||
if not x.is_instantiatable():
|
||||
print("no dzsave support in this vips, skipping test")
|
||||
return
|
||||
|
||||
# dzsave is hard to test, there are so many options
|
||||
# test each option separately and hope they all function together
|
||||
# correctly
|
||||
|
||||
# default deepzoom layout
|
||||
self.colour.dzsave("test")
|
||||
|
||||
# test right edge ... default is 256x256 tiles, overlap 1
|
||||
x = Vips.Image.new_from_file("test_files/10/3_2.jpeg")
|
||||
self.assertEqual(x.width, 256)
|
||||
y = Vips.Image.new_from_file("test_files/10/4_2.jpeg")
|
||||
self.assertEqual(y.width,
|
||||
self.colour.width - 255 * int(self.colour.width / 255))
|
||||
|
||||
# test bottom edge
|
||||
x = Vips.Image.new_from_file("test_files/10/3_2.jpeg")
|
||||
self.assertEqual(x.height, 256)
|
||||
y = Vips.Image.new_from_file("test_files/10/3_3.jpeg")
|
||||
self.assertEqual(y.height,
|
||||
self.colour.height - 255 * int(self.colour.height / 255))
|
||||
|
||||
# there should be a bottom layer
|
||||
x = Vips.Image.new_from_file("test_files/0/0_0.jpeg")
|
||||
self.assertEqual(x.width, 1)
|
||||
self.assertEqual(x.height, 1)
|
||||
|
||||
# 10 should be the final layer
|
||||
self.assertFalse(os.path.isdir("test_files/11"))
|
||||
|
||||
shutil.rmtree("test_files")
|
||||
os.unlink("test.dzi")
|
||||
|
||||
# default google layout
|
||||
self.colour.dzsave("test", layout = "google")
|
||||
|
||||
# test bottom-right tile ... default is 256x256 tiles, overlap 0
|
||||
x = Vips.Image.new_from_file("test/2/2/3.jpg")
|
||||
self.assertEqual(x.width, 256)
|
||||
self.assertEqual(x.height, 256)
|
||||
self.assertFalse(os.path.exists("test/2/2/4.jpg"))
|
||||
self.assertFalse(os.path.exists("test/3"))
|
||||
x = Vips.Image.new_from_file("test/blank.png")
|
||||
self.assertEqual(x.width, 256)
|
||||
self.assertEqual(x.height, 256)
|
||||
|
||||
shutil.rmtree("test")
|
||||
|
||||
# default zoomify layout
|
||||
self.colour.dzsave("test", layout = "zoomify")
|
||||
|
||||
# 256x256 tiles, no overlap
|
||||
self.assertTrue(os.path.exists("test/ImageProperties.xml"))
|
||||
x = Vips.Image.new_from_file("test/TileGroup0/2-3-2.jpg")
|
||||
self.assertEqual(x.width, 256)
|
||||
self.assertEqual(x.height, 256)
|
||||
|
||||
shutil.rmtree("test")
|
||||
|
||||
# test zip output
|
||||
self.colour.dzsave("test.zip")
|
||||
self.assertFalse(os.path.exists("test_files"))
|
||||
self.assertFalse(os.path.exists("test.dzi"))
|
||||
os.unlink("test.zip")
|
||||
|
||||
# test suffix
|
||||
self.colour.dzsave("test", suffix = ".png")
|
||||
|
||||
x = Vips.Image.new_from_file("test_files/10/3_2.png")
|
||||
self.assertEqual(x.width, 256)
|
||||
|
||||
shutil.rmtree("test_files")
|
||||
os.unlink("test.dzi")
|
||||
|
||||
# test overlap
|
||||
self.colour.dzsave("test", overlap = 200)
|
||||
|
||||
y = Vips.Image.new_from_file("test_files/10/18_6.jpeg")
|
||||
self.assertEqual(y.width,
|
||||
self.colour.width - 56 * int(self.colour.width / 56))
|
||||
|
||||
shutil.rmtree("test_files")
|
||||
os.unlink("test.dzi")
|
||||
|
||||
# test tile-size
|
||||
self.colour.dzsave("test", tile_size = 512)
|
||||
|
||||
y = Vips.Image.new_from_file("test_files/10/2_1.jpeg")
|
||||
self.assertEqual(y.width,
|
||||
self.colour.width - 511 * int(self.colour.width / 511))
|
||||
|
||||
shutil.rmtree("test_files")
|
||||
os.unlink("test.dzi")
|
||||
|
||||
# test tile-size
|
||||
self.colour.dzsave("test", tile_size = 512)
|
||||
|
||||
y = Vips.Image.new_from_file("test_files/10/2_1.jpeg")
|
||||
self.assertEqual(y.width,
|
||||
self.colour.width - 511 * int(self.colour.width / 511))
|
||||
|
||||
shutil.rmtree("test_files")
|
||||
os.unlink("test.dzi")
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user