Support tile-less IIIF as per LegacyTileSource: Fix #737

This commit is contained in:
Tom Crane 2015-12-13 21:32:21 +00:00
parent 0d43f7e01a
commit f7c9585003
11 changed files with 326 additions and 8 deletions

View File

@ -36,8 +36,8 @@
/**
* @class IIIFTileSource
* @classdesc A client implementation of the International Image Interoperability
* Format: Image API 1.0 - 2.0
* @classdesc A client implementation of the International Image Interoperability Framework
* Format: Image API 1.0 - 2.1
*
* @memberof OpenSeadragon
* @extends OpenSeadragon.TileSource
@ -83,7 +83,7 @@ $.IIIFTileSource = function( options ){
}
}
}
} else {
} else if ( canBeTiled(options.profile) ) {
// use the largest of tileOptions that is smaller than the short dimension
var shortDim = Math.min( this.height, this.width ),
tileOptions = [256,512,1024],
@ -101,13 +101,32 @@ $.IIIFTileSource = function( options ){
// If we're smaller than 256, just use the short side.
options.tileSize = shortDim;
}
} else if (this.sizes && this.sizes.length > 0) {
// This info.json can't be tiled, but we can still construct a legacy pyramid from the sizes array.
// In this mode, IIIFTileSource will call functions from the abstract baseTileSource or the
// LegacyTileSource instead of performing IIIF tiling.
this.emulateLegacyImagePyramid = true;
options.levels = constructLevels( this );
// use the largest available size to define tiles
$.extend( true, options, {
width: options.levels[ options.levels.length - 1 ].width,
height: options.levels[ options.levels.length - 1 ].height,
tileSize: Math.max( options.height, options.width ),
tileOverlap: 0,
minLevel: 0,
maxLevel: options.levels.length - 1
});
this.levels = options.levels;
} else {
$.console.error("Nothing in the info.json to construct image pyramids from");
}
if ( !options.maxLevel ) {
if ( !this.scale_factors ) {
options.maxLevel = Number( Math.ceil( Math.log( Math.max( this.width, this.height ), 2 ) ) );
if (!options.maxLevel && !this.emulateLegacyImagePyramid) {
if (!this.scale_factors) {
options.maxLevel = Number(Math.ceil(Math.log(Math.max(this.width, this.height), 2)));
} else {
options.maxLevel = Math.floor( Math.pow( Math.max.apply(null, this.scale_factors), 0.5) );
options.maxLevel = Math.floor(Math.pow(Math.max.apply(null, this.scale_factors), 0.5));
}
}
@ -192,6 +211,11 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
* @param {Number} level
*/
getTileWidth: function( level ) {
if(this.emulateLegacyImagePyramid) {
return $.TileSource.prototype.getTileWidth.call(this, level);
}
var scaleFactor = Math.pow(2, this.maxLevel - level);
if (this.tileSizePerScaleFactor && this.tileSizePerScaleFactor[scaleFactor]) {
@ -206,6 +230,11 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
* @param {Number} level
*/
getTileHeight: function( level ) {
if(this.emulateLegacyImagePyramid) {
return $.TileSource.prototype.getTileHeight.call(this, level);
}
var scaleFactor = Math.pow(2, this.maxLevel - level);
if (this.tileSizePerScaleFactor && this.tileSizePerScaleFactor[scaleFactor]) {
@ -214,9 +243,61 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
return this._tileHeight;
},
/**
* @function
* @param {Number} level
*/
getLevelScale: function ( level ) {
if(this.emulateLegacyImagePyramid) {
var levelScale = NaN;
if (this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel) {
levelScale =
this.levels[level].width /
this.levels[this.maxLevel].width;
}
return levelScale;
}
return $.TileSource.prototype.getLevelScale.call(this, level);
},
/**
* Responsible for retreiving the url which will return an image for the
* @function
* @param {Number} level
*/
getNumTiles: function( level ) {
if(this.emulateLegacyImagePyramid) {
var scale = this.getLevelScale(level);
if (scale) {
return new $.Point(1, 1);
} else {
return new $.Point(0, 0);
}
}
return $.TileSource.prototype.getNumTiles.call(this, level);
},
/**
* @function
* @param {Number} level
* @param {OpenSeadragon.Point} point
*/
getTileAtPoint: function( level, point ) {
if(this.emulateLegacyImagePyramid) {
return new $.Point(0, 0);
}
return $.TileSource.prototype.getTileAtPoint.call(this, level, point);
},
/**
* Responsible for retrieving the url which will return an image for the
* region specified by the given x, y, and level components.
* @function
* @param {Number} level - z index
@ -226,6 +307,14 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
*/
getTileUrl: function( level, x, y ){
if(this.emulateLegacyImagePyramid) {
var url = null;
if ( this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel ) {
url = this.levels[ level ].url;
}
return url;
}
//# constants
var IIIF_ROTATION = '0',
//## get the scale (level as a decimal)
@ -280,6 +369,40 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
});
/**
* Determine whether arbitrary tile requests can be made against a service with the given profile
* @function
* @param {object} profile - IIIF profile object
* @throws {Error}
*/
function canBeTiled (profile ) {
var level0Profiles = [
"http://library.stanford.edu/iiif/image-api/compliance.html#level0",
"http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0",
"http://iiif.io/api/image/2/level0.json"
];
var isLevel0 = (level0Profiles.indexOf(profile[0]) != -1);
return !isLevel0 || (profile.indexOf("sizeByW") != -1);
}
/**
* Build the legacy pyramid URLs (one tile per level)
* @function
* @param {object} options - infoJson
* @throws {Error}
*/
function constructLevels(options) {
var levels = [];
for(var i=0; i<options.sizes.length; i++) {
levels.push({
url: options['@id'] + '/full/' + options.sizes[i].width + ',/0/default.jpg',
width: options.sizes[i].width,
height: options.sizes[i].height
});
}
return levels.sort(function(a,b){return a.width - b.width;});
}
function configureFromXml10(xmlDoc) {
//parse the xml
@ -330,4 +453,5 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
}
}( OpenSeadragon ));

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 678 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View File

@ -0,0 +1,15 @@
{
"@context": "http://iiif.io/api/image/2/context.json",
"@id": "http://localhost:8000/test/data/iiif_2_0_sizes",
"protocol": "http://iiif.io/api/image",
"width": 6976,
"height": 5074,
"profile": ["http://iiif.io/api/image/2/level0.json"],
"sizes" : [
{"width" : 400, "height" : 291},
{"width" : 800, "height" : 582},
{"width" : 1600, "height" : 1164},
{"width" : 3200, "height": 2328},
{"width" : 6976, "height": 5074}
]
}

51
test/demo/iiif-sizes.html Normal file
View File

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<title>OpenSeadragon Demo - IIIF emulation of legacy image pyramid</title>
<script type="text/javascript" src='../../build/openseadragon/openseadragon.js'></script>
<script type="text/javascript" src='../lib/jquery-1.9.1.min.js'></script>
<style type="text/css">
.openseadragon1 {
width: 800px;
height: 600px;
}
</style>
</head>
<body>
<div>
<p>Default OpenSeadragon viewer from IIIF Source</p>
<p>This allows IIIF even if you only have a handful of static image sizes.</p>
</div>
<!--
Notes:
legacy iiif
supports
configure
getTileWidth
getTileHeight
getLevelScale
getNumTiles
getTileAtPoint
getTileUrl getTileUrl
-->
<div id="contentDiv" class="openseadragon1"></div>
<script type="text/javascript">
var viewer = OpenSeadragon({
// debugMode: true,
id: "contentDiv",
prefixUrl: "../../build/openseadragon/images/",
tileSources: "../data/iiif_2_0_sizes/info.json",
showNavigator:true
});
</script>
</body>
</html>

34
test/demo/iiif.html Normal file
View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
<title>OpenSeadragon Demo - IIIF Tiled</title>
<script type="text/javascript" src='../../build/openseadragon/openseadragon.js'></script>
<script type="text/javascript" src='../lib/jquery-1.9.1.min.js'></script>
<style type="text/css">
.openseadragon1 {
width: 800px;
height: 600px;
}
</style>
</head>
<body>
<div>
<p>Default OpenSeadragon viewer from IIIF Tile Source.</p>
<p>This depends on a remote server providing a IIIF Image API endpoint.</p>
</div>
<div id="contentDiv" class="openseadragon1"></div>
<script type="text/javascript">
var viewer = OpenSeadragon({
// debugMode: true,
id: "contentDiv",
prefixUrl: "../../build/openseadragon/images/",
tileSources: "http://wellcomelibrary.org/iiif-img/b11768265-0/a6801943-b8b4-4674-908c-7d5b27e70569/info.json",
showNavigator:true
});
</script>
</body>
</html>

56
test/demo/legacy.html Normal file
View File

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html>
<head>
<title>OpenSeadragon Demo - Legacy image pyramid</title>
<script type="text/javascript" src='../../build/openseadragon/openseadragon.js'></script>
<script type="text/javascript" src='../lib/jquery-1.9.1.min.js'></script>
<style type="text/css">
.openseadragon1 {
width: 800px;
height: 600px;
}
</style>
</head>
<body>
<div>
Use an array of full images at different sizes.
</div>
<div id="contentDiv" class="openseadragon1"></div>
<script type="text/javascript">
var viewer = OpenSeadragon({
// debugMode: true,
id: "contentDiv",
prefixUrl: "../../build/openseadragon/images/",
tileSources: {
type: 'legacy-image-pyramid',
levels:[{
url: '/test/data/iiif_2_0_sizes/full/400,/0/default.jpg',
height: 291,
width: 400
},{
url: '/test/data/iiif_2_0_sizes/full/800,/0/default.jpg',
height: 582,
width: 800
},{
url: '/test/data/iiif_2_0_sizes/full/1600,/0/default.jpg',
height: 1164,
width: 1600
},{
url: '/test/data/iiif_2_0_sizes/full/3200,/0/default.jpg',
height: 2328,
width: 3200
},{
url: '/test/data/iiif_2_0_sizes/full/6976,/0/default.jpg',
height: 5074,
width: 6976
}]
},
showNavigator:true
});
</script>
</body>
</html>

View File

@ -114,6 +114,11 @@
testOpenUrl('iiif_2_0_tiled/info.json');
});
// ----------
asyncTest('IIIF 2.0 JSON, sizes array only', function() {
testOpenUrl('iiif_2_0_sizes/info.json');
});
// ----------
asyncTest('IIIF 2.0 JSON String', function() {
testOpen(
@ -149,5 +154,38 @@
url: "/test/data/A.png"
});
});
// ----------
asyncTest('Legacy Image Pyramid', function() {
// Although it is using image paths that happen to be in IIIF format, this is not a IIIFTileSource.
// The url values are opaque, just image locations.
// When emulating a legacy pyramid, IIIFTileSource calls functions from LegacyTileSource, so this
// adds a test for the legacy functionality too.
testOpen({
type: 'legacy-image-pyramid',
levels:[{
url: '/test/data/iiif_2_0_sizes/full/400,/0/default.jpg',
height: 291,
width: 400
},{
url: '/test/data/iiif_2_0_sizes/full/800,/0/default.jpg',
height: 582,
width: 800
},{
url: '/test/data/iiif_2_0_sizes/full/1600,/0/default.jpg',
height: 1164,
width: 1600
},{
url: '/test/data/iiif_2_0_sizes/full/3200,/0/default.jpg',
height: 2328,
width: 3200
},{
url: '/test/data/iiif_2_0_sizes/full/6976,/0/default.jpg',
height: 5074,
width: 6976
}]
});
});
})();