mirror of
https://github.com/openseadragon/openseadragon.git
synced 2025-02-16 14:53:14 +03:00
Merge pull request #673 from ConnerMan/master
Add support for non-square tiles (#670)
This commit is contained in:
commit
c7b66b3e0a
@ -12,6 +12,10 @@ OPENSEADRAGON CHANGELOG
|
||||
* Added `preserveImageSizeOnResize` option (#666)
|
||||
* Better error reporting for tile load failures (#679)
|
||||
* Added collectionColumns as a configuration parameter (#680)
|
||||
* Added support for non-square tiles (#673)
|
||||
* TileSource.Options objects can now optionally provide tileWidth/tileHeight instead of tileSize for non-square tile support.
|
||||
* IIIFTileSources will now respect non-square tiles if available.
|
||||
* DEPRECATION: TileSource.getTileSize is deprecated use TileSource.getTileWidth and TileSource.getTileHeight instead.
|
||||
|
||||
2.0.0:
|
||||
|
||||
|
@ -55,14 +55,19 @@ $.IIIFTileSource = function( options ){
|
||||
options.tileSizePerScaleFactor = {};
|
||||
|
||||
// N.B. 2.0 renamed scale_factors to scaleFactors
|
||||
if ( this.tile_width ) {
|
||||
if ( this.tile_width && this.tile_height ) {
|
||||
options.tileWidth = this.tile_width;
|
||||
options.tileHeight = this.tile_height;
|
||||
} else if ( this.tile_width ) {
|
||||
options.tileSize = this.tile_width;
|
||||
} else if ( this.tile_height ) {
|
||||
options.tileSize = this.tile_height;
|
||||
} else if ( this.tiles ) {
|
||||
// Version 2.0 forwards
|
||||
if ( this.tiles.length == 1 ) {
|
||||
options.tileSize = this.tiles[0].width;
|
||||
options.tileWidth = this.tiles[0].width;
|
||||
// Use height if provided, otherwise assume square tiles and use width.
|
||||
options.tileHeight = this.tiles[0].height || this.tiles[0].width;
|
||||
this.scale_factors = this.tiles[0].scaleFactors;
|
||||
} else {
|
||||
// Multiple tile sizes at different levels
|
||||
@ -71,13 +76,15 @@ $.IIIFTileSource = function( options ){
|
||||
for (var sf = 0; sf < this.tiles[t].scaleFactors.length; sf++) {
|
||||
var scaleFactor = this.tiles[t].scaleFactors[sf];
|
||||
this.scale_factors.push(scaleFactor);
|
||||
options.tileSizePerScaleFactor[scaleFactor] = this.tiles[t].width;
|
||||
options.tileSizePerScaleFactor[scaleFactor] = {
|
||||
width: this.tiles[t].width,
|
||||
height: this.tiles[t].height || this.tiles[t].width
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// use the largest of tileOptions that is smaller than the short dimension
|
||||
|
||||
var shortDim = Math.min( this.height, this.width ),
|
||||
tileOptions = [256,512,1024],
|
||||
smallerTiles = [];
|
||||
@ -94,8 +101,6 @@ $.IIIFTileSource = function( options ){
|
||||
// If we're smaller than 256, just use the short side.
|
||||
options.tileSize = shortDim;
|
||||
}
|
||||
this.tile_width = options.tileSize; // So that 'full' gets used for
|
||||
this.tile_height = options.tileSize; // the region below
|
||||
}
|
||||
|
||||
if ( !options.maxLevel ) {
|
||||
@ -117,6 +122,7 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
* @param {Object|Array} data
|
||||
* @param {String} optional - url
|
||||
*/
|
||||
|
||||
supports: function( data, url ) {
|
||||
// Version 2.0 and forwards
|
||||
if (data.protocol && data.protocol == 'http://iiif.io/api/image') {
|
||||
@ -181,20 +187,34 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the tileSize for the given level.
|
||||
* Return the tileWidth for the given level.
|
||||
* @function
|
||||
* @param {Number} level
|
||||
*/
|
||||
|
||||
getTileSize: function( level ){
|
||||
*/
|
||||
getTileWidth: function( level ) {
|
||||
var scaleFactor = Math.pow(2, this.maxLevel - level);
|
||||
// cache it in case any external code is going to read it directly
|
||||
|
||||
if (this.tileSizePerScaleFactor && this.tileSizePerScaleFactor[scaleFactor]) {
|
||||
this.tileSize = this.tileSizePerScaleFactor[scaleFactor];
|
||||
return this.tileSizePerScaleFactor[scaleFactor].width;
|
||||
}
|
||||
return this.tileSize;
|
||||
return this._tileWidth;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the tileHeight for the given level.
|
||||
* @function
|
||||
* @param {Number} level
|
||||
*/
|
||||
getTileHeight: function( level ) {
|
||||
var scaleFactor = Math.pow(2, this.maxLevel - level);
|
||||
|
||||
if (this.tileSizePerScaleFactor && this.tileSizePerScaleFactor[scaleFactor]) {
|
||||
return this.tileSizePerScaleFactor[scaleFactor].height;
|
||||
}
|
||||
return this._tileHeight;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Responsible for retreiving the url which will return an image for the
|
||||
* region specified by the given x, y, and level components.
|
||||
@ -216,7 +236,8 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
levelHeight = Math.ceil( this.height * scale ),
|
||||
|
||||
//## iiif region
|
||||
tileSize,
|
||||
tileWidth,
|
||||
tileHeight,
|
||||
iiifTileSizeWidth,
|
||||
iiifTileSizeHeight,
|
||||
iiifRegion,
|
||||
@ -228,9 +249,10 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
iiifQuality,
|
||||
uri;
|
||||
|
||||
tileSize = this.getTileSize(level);
|
||||
iiifTileSizeWidth = Math.ceil( tileSize / scale );
|
||||
iiifTileSizeHeight = iiifTileSizeWidth;
|
||||
tileWidth = this.getTileWidth(level);
|
||||
tileHeight = this.getTileHeight(level);
|
||||
iiifTileSizeWidth = Math.ceil( tileWidth / scale );
|
||||
iiifTileSizeHeight = Math.ceil( tileHeight / scale );
|
||||
|
||||
if ( this['@context'].indexOf('/1.0/context.json') > -1 ||
|
||||
this['@context'].indexOf('/1.1/context.json') > -1 ||
|
||||
@ -240,7 +262,7 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
iiifQuality = "default.jpg";
|
||||
}
|
||||
|
||||
if ( levelWidth < tileSize && levelHeight < tileSize ){
|
||||
if ( levelWidth < tileWidth && levelHeight < tileHeight ){
|
||||
iiifSize = levelWidth + ",";
|
||||
iiifRegion = 'full';
|
||||
} else {
|
||||
|
@ -1036,7 +1036,7 @@ function onTileLoad( tiledImage, tile, time, image, errorMsg ) {
|
||||
|
||||
var finish = function() {
|
||||
var cutoff = Math.ceil( Math.log(
|
||||
tiledImage.source.getTileSize(tile.level) ) / Math.log( 2 ) );
|
||||
tiledImage.source.getTileWidth(tile.level) ) / Math.log( 2 ) );
|
||||
setTileLoaded(tiledImage, tile, image, cutoff);
|
||||
};
|
||||
|
||||
|
@ -73,6 +73,11 @@
|
||||
* The size of the tiles to assumed to make up each pyramid layer in pixels.
|
||||
* Tile size determines the point at which the image pyramid must be
|
||||
* divided into a matrix of smaller images.
|
||||
* Use options.tileWidth and options.tileHeight to support non-square tiles.
|
||||
* @param {Number} [options.tileWidth]
|
||||
* The width of the tiles to assumed to make up each pyramid layer in pixels.
|
||||
* @param {Number} [options.tileHeight]
|
||||
* The height of the tiles to assumed to make up each pyramid layer in pixels.
|
||||
* @param {Number} [options.tileOverlap]
|
||||
* The number of pixels each tile is expected to overlap touching tiles.
|
||||
* @param {Number} [options.minLevel]
|
||||
@ -137,13 +142,6 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
|
||||
* @member {OpenSeadragon.Point} dimensions
|
||||
* @memberof OpenSeadragon.TileSource#
|
||||
*/
|
||||
/**
|
||||
* The size of the image tiles used to compose the image.
|
||||
* Please note that tileSize may be deprecated in a future release.
|
||||
* Instead the getTileSize(level) function should be used.
|
||||
* @member {Number} tileSize
|
||||
* @memberof OpenSeadragon.TileSource#
|
||||
*/
|
||||
/**
|
||||
* The overlap in pixels each tile shares with its adjacent neighbors.
|
||||
* @member {Number} tileOverlap
|
||||
@ -174,7 +172,8 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
|
||||
//async mechanism set some safe defaults first
|
||||
this.aspectRatio = 1;
|
||||
this.dimensions = new $.Point( 10, 10 );
|
||||
this.tileSize = 0;
|
||||
this._tileWidth = 0;
|
||||
this._tileHeight = 0;
|
||||
this.tileOverlap = 0;
|
||||
this.minLevel = 0;
|
||||
this.maxLevel = 0;
|
||||
@ -191,7 +190,29 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
|
||||
this.aspectRatio = ( options.width && options.height ) ?
|
||||
( options.width / options.height ) : 1;
|
||||
this.dimensions = new $.Point( options.width, options.height );
|
||||
this.tileSize = options.tileSize ? options.tileSize : 0;
|
||||
|
||||
if ( this.tileSize ){
|
||||
this._tileWidth = this._tileHeight = this.tileSize;
|
||||
delete this.tileSize;
|
||||
} else {
|
||||
if( this.tileWidth ){
|
||||
// We were passed tileWidth in options, but we want to rename it
|
||||
// with a leading underscore to make clear that it is not safe to directly modify it
|
||||
this._tileWidth = this.tileWidth;
|
||||
delete this.tileWidth;
|
||||
} else {
|
||||
this._tileWidth = 0;
|
||||
}
|
||||
|
||||
if( this.tileHeight ){
|
||||
// See note above about renaming this.tileWidth
|
||||
this._tileHeight = this.tileHeight;
|
||||
delete this.tileHeight;
|
||||
} else {
|
||||
this._tileHeight = 0;
|
||||
}
|
||||
}
|
||||
|
||||
this.tileOverlap = options.tileOverlap ? options.tileOverlap : 0;
|
||||
this.minLevel = options.minLevel ? options.minLevel : 0;
|
||||
this.maxLevel = ( undefined !== options.maxLevel && null !== options.maxLevel ) ?
|
||||
@ -212,16 +233,42 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
|
||||
|
||||
$.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{
|
||||
|
||||
getTileSize: function( level ) {
|
||||
$.console.error(
|
||||
"[TileSource.getTileSize] is deprecated." +
|
||||
"Use TileSource.getTileWidth() and TileSource.getTileHeight() instead"
|
||||
);
|
||||
return this._tileWidth;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the tileSize for a given level.
|
||||
* Subclasses should override this if tileSizes can be different at different levels
|
||||
* Return the tileWidth for a given level.
|
||||
* Subclasses should override this if tileWidth can be different at different levels
|
||||
* such as in IIIFTileSource. Code should use this function rather than reading
|
||||
* from .tileSize directly. tileSize may be deprecated in a future release.
|
||||
* from ._tileWidth directly.
|
||||
* @function
|
||||
* @param {Number} level
|
||||
*/
|
||||
getTileSize: function( level ) {
|
||||
return this.tileSize;
|
||||
getTileWidth: function( level ) {
|
||||
if (!this._tileWidth) {
|
||||
return this.getTileSize(level);
|
||||
}
|
||||
return this._tileWidth;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the tileHeight for a given level.
|
||||
* Subclasses should override this if tileHeight can be different at different levels
|
||||
* such as in IIIFTileSource. Code should use this function rather than reading
|
||||
* from ._tileHeight directly.
|
||||
* @function
|
||||
* @param {Number} level
|
||||
*/
|
||||
getTileHeight: function( level ) {
|
||||
if (!this._tileHeight) {
|
||||
return this.getTileSize(level);
|
||||
}
|
||||
return this._tileHeight;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -250,8 +297,8 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{
|
||||
*/
|
||||
getNumTiles: function( level ) {
|
||||
var scale = this.getLevelScale( level ),
|
||||
x = Math.ceil( scale * this.dimensions.x / this.getTileSize(level) ),
|
||||
y = Math.ceil( scale * this.dimensions.y / this.getTileSize(level) );
|
||||
x = Math.ceil( scale * this.dimensions.x / this.getTileWidth(level) ),
|
||||
y = Math.ceil( scale * this.dimensions.y / this.getTileHeight(level) );
|
||||
|
||||
return new $.Point( x, y );
|
||||
},
|
||||
@ -277,10 +324,15 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{
|
||||
var i,
|
||||
tilesPerSide,
|
||||
tiles;
|
||||
|
||||
for( i = this.minLevel; i < this.maxLevel; i++ ){
|
||||
tiles = this.getNumTiles( i );
|
||||
tilesPerSide = Math.floor( Math.max( rect.x, rect.y ) / this.getTileSize(i) );
|
||||
if( Math.max( tiles.x, tiles.y ) + 1 >= tilesPerSide ){
|
||||
tilesPerSide = new $.Point(
|
||||
Math.floor( rect.x / this.getTileWidth(i) ),
|
||||
Math.floor( rect.y / this.getTileHeight(i) )
|
||||
);
|
||||
|
||||
if( tiles.x + 1 >= tilesPerSide.x || tiles.y + 1 >= tilesPerSide.y ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -293,9 +345,9 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{
|
||||
* @param {OpenSeadragon.Point} point
|
||||
*/
|
||||
getTileAtPoint: function( level, point ) {
|
||||
var pixel = point.times( this.dimensions.x ).times( this.getLevelScale(level ) ),
|
||||
tx = Math.floor( pixel.x / this.getTileSize(level) ),
|
||||
ty = Math.floor( pixel.y / this.getTileSize(level) );
|
||||
var pixel = point.times( this.dimensions.x ).times( this.getLevelScale(level) ),
|
||||
tx = Math.floor( pixel.x / this.getTileWidth(level) ),
|
||||
ty = Math.floor( pixel.y / this.getTileHeight(level) );
|
||||
|
||||
return new $.Point( tx, ty );
|
||||
},
|
||||
@ -308,11 +360,12 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{
|
||||
*/
|
||||
getTileBounds: function( level, x, y ) {
|
||||
var dimensionsScaled = this.dimensions.times( this.getLevelScale( level ) ),
|
||||
tileSize = this.getTileSize(level),
|
||||
px = ( x === 0 ) ? 0 : tileSize * x - this.tileOverlap,
|
||||
py = ( y === 0 ) ? 0 : tileSize * y - this.tileOverlap,
|
||||
sx = tileSize + ( x === 0 ? 1 : 2 ) * this.tileOverlap,
|
||||
sy = tileSize + ( y === 0 ? 1 : 2 ) * this.tileOverlap,
|
||||
tileWidth = this.getTileWidth(level),
|
||||
tileHeight = this.getTileHeight(level),
|
||||
px = ( x === 0 ) ? 0 : tileWidth * x - this.tileOverlap,
|
||||
py = ( y === 0 ) ? 0 : tileHeight * y - this.tileOverlap,
|
||||
sx = tileWidth + ( x === 0 ? 1 : 2 ) * this.tileOverlap,
|
||||
sy = tileHeight + ( y === 0 ? 1 : 2 ) * this.tileOverlap,
|
||||
scale = 1.0 / dimensionsScaled.x;
|
||||
|
||||
sx = Math.min( sx, dimensionsScaled.x - px );
|
||||
|
51
test/modules/tilesource.js
Normal file
51
test/modules/tilesource.js
Normal file
@ -0,0 +1,51 @@
|
||||
/* global module, ok, equal, start, test, testLog, Util */
|
||||
(function() {
|
||||
|
||||
module('TileSource', {
|
||||
setup: function() {
|
||||
testLog.reset();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
test("should set sane tile size defaults", function() {
|
||||
var source = new OpenSeadragon.TileSource();
|
||||
|
||||
equal(source.getTileWidth(), 0, "getTileWidth() should return 0 if not provided a size");
|
||||
equal(source.getTileHeight(), 0, "getTileHeight() should return 0 if not provided a size");
|
||||
});
|
||||
|
||||
test("providing tileSize", function(){
|
||||
var tileSize = 256,
|
||||
source = new OpenSeadragon.TileSource({
|
||||
tileSize: tileSize
|
||||
});
|
||||
|
||||
equal(source.tileSize, undefined, "tileSize should not be set on the tileSource");
|
||||
equal(source.getTileWidth(), tileSize, "getTileWidth() should equal tileSize");
|
||||
equal(source.getTileHeight(), tileSize, "getTileHeight() should equal tileSize");
|
||||
});
|
||||
|
||||
|
||||
test("providing tileWidth and tileHeight", function(){
|
||||
var tileWidth = 256,
|
||||
tileHeight = 512,
|
||||
source = new OpenSeadragon.TileSource({
|
||||
tileWidth: tileWidth,
|
||||
tileHeight: tileHeight
|
||||
});
|
||||
|
||||
equal(source._tileWidth, tileWidth, "tileWidth option should set _tileWidth");
|
||||
equal(source._tileHeight, tileHeight, "tileHeight option should set _tileHeight");
|
||||
equal(source.tileWidth, undefined, "tileWidth should be renamed _tileWidth");
|
||||
equal(source.tileHeight, undefined, "tileHeight should be renamed _tileHeight");
|
||||
equal(source.getTileWidth(), tileWidth, "getTileWidth() should equal tileWidth");
|
||||
equal(source.getTileHeight(), tileHeight, "getTileHeight() should equal tileHeight");
|
||||
});
|
||||
|
||||
test('getTileSize() deprecation', function() {
|
||||
var source = new OpenSeadragon.TileSource();
|
||||
Util.testDeprecation(source, 'getTileSize');
|
||||
});
|
||||
|
||||
}());
|
@ -36,6 +36,7 @@
|
||||
<script src="/test/modules/tiledimage.js"></script>
|
||||
<script src="/test/modules/tilecache.js"></script>
|
||||
<script src="/test/modules/referencestrip.js"></script>
|
||||
<script src="/test/modules/tilesource.js"></script>
|
||||
<script src="/test/modules/tilesourcecollection.js"></script>
|
||||
<script src="/test/modules/spring.js"></script>
|
||||
<!-- The navigator tests are the slowest (for now; hopefully they can be sped up)
|
||||
|
Loading…
x
Reference in New Issue
Block a user