diff --git a/src/ol/source/IIIF.js b/src/ol/source/IIIF.js index 6da518cb57..1dfa88dd31 100644 --- a/src/ol/source/IIIF.js +++ b/src/ol/source/IIIF.js @@ -66,7 +66,7 @@ class IIIF extends TileImage { const sizes = options.sizes || []; const size = options.size; assert(size != undefined && Array.isArray(size) && size.length == 2 && - !isNaN(size[0]) && size[0] > 0 && !isNaN(size[1] && size[1] > 0), 60); + !isNaN(size[0]) && size[0] > 0 && !isNaN(size[1]) && size[1] > 0, 60); const width = size[0]; const height = size[1]; const tileSize = options.tileSize; @@ -142,10 +142,21 @@ class IIIF extends TileImage { sizes.sort(function(a, b) { return a[0] - b[0]; }); + maxZoom = -1; + const ignoredSizesIndex = []; for (let i = 0; i < sizes.length; i++) { const resolution = width / sizes[i][0]; + if (resolutions.length > 0 && resolutions[resolutions.length - 1] == resolution) { + ignoredSizesIndex.push(i); + continue; + } resolutions.push(resolution); - maxZoom = i; + maxZoom++; + } + if (ignoredSizesIndex.length > 0) { + for (let i = 0; i < ignoredSizesIndex.length; i++) { + sizes.splice(ignoredSizesIndex[i] - i, 1); + } } } else { // No useful image information at all. Try pseudo tile with full image. @@ -166,13 +177,14 @@ class IIIF extends TileImage { let regionParam, sizeParam; const zoom = tileCoord[0]; - if (maxZoom < zoom) { + if (zoom > maxZoom) { return; } const tileX = tileCoord[1], tileY = tileCoord[2], scale = resolutions[zoom]; - if (tileX < 0 || Math.ceil(width / scale / tileWidth) <= tileX || + if (tileX === undefined || tileY === undefined || scale === undefined || + tileX < 0 || Math.ceil(width / scale / tileWidth) <= tileX || tileY < 0 || Math.ceil(height / scale / tileHeight) <= tileY) { return; } @@ -221,7 +233,21 @@ class IIIF extends TileImage { } else { regionParam = 'full'; if (supportsListedSizes) { - sizeParam = sizes[zoom][0] + ',' + (version == Versions.VERSION3 ? sizes[zoom][1] : ''); + const regionWidth = sizes[zoom][0], + regionHeight = sizes[zoom][1]; + if (version == Versions.VERSION3) { + if (regionWidth == width && regionHeight == height) { + sizeParam = 'max'; + } else { + sizeParam = regionWidth + ',' + regionHeight; + } + } else { + if (regionWidth == width) { + sizeParam = 'full'; + } else { + sizeParam = regionWidth + ','; + } + } } else { sizeParam = version == Versions.VERSION3 ? 'max' : 'full'; } diff --git a/test/spec/ol/source/iiif.test.js b/test/spec/ol/source/iiif.test.js new file mode 100644 index 0000000000..2fdd37a026 --- /dev/null +++ b/test/spec/ol/source/iiif.test.js @@ -0,0 +1,271 @@ +// import {DEFAULT_TILE_SIZE} from '../../../../src/ol/tilegrid/common.js'; +import IIIF from '../../../../src/ol/source/IIIF.js'; +import {Versions} from '../../../../src/ol/format/IIIFInfo.js'; +// import {CustomTile} from '../../../../src/ol/source/Zoomify.js'; +// import TileGrid from '../../../../src/ol/tilegrid/TileGrid.js'; + + +describe('ol.source.IIIF', function() { + const width = 2000, + height = 1500, + size = [width, height], + url = 'http://iiif.test/image-id'; + + function getMinimalSource() { + return new IIIF({ + size: size + }); + } + + function getSource(additionalOptions) { + const options = Object.assign({}, { + size: size, + url: url + }, additionalOptions === undefined ? {} : additionalOptions); + return new IIIF(options); + } + + describe('constructor', function() { + + it('requires valid size option', function() { + + expect(function() { + new IIIF(); + }).to.throwException(); + + expect(function() { + new IIIF({}); + }).to.throwException(); + + expect(function() { + new IIIF({ + size: [] + }); + }).to.throwException(); + + expect(function() { + new IIIF({ + size: 100 + }); + }).to.throwException(); + + expect(function() { + new IIIF({ + size: [100] + }); + }).to.throwException(); + + expect(function() { + new IIIF({ + size: [null, 100] + }); + }).to.throwException(); + + expect(function() { + new IIIF({ + size: ['very wide', 100] + }); + }).to.throwException(); + + expect(function() { + new IIIF({ + size: [0, 100] + }); + }).to.throwException(); + + expect(function() { + new IIIF({ + size: [100, null] + }); + }).to.throwException(); + + expect(function() { + new IIIF({ + size: [100, 0] + }); + }).to.throwException(); + + expect(function() { + new IIIF({ + size: [100, 'not that high'] + }); + }).to.throwException(); + + expect(function() { + new IIIF({ + size: [100, 200, 300] + }); + }).to.throwException(); + + let source; + + expect(function() { + source = new IIIF({ + size: [100, 200] + }); + }).to.not.throwException(); + + expect(source).to.be.a(IIIF); + + expect(function() { + getMinimalSource(); + }).to.not.throwException(); + + }); + + it('uses empty base URL, default quality, jpg format as default', function() { + + const tileUrlFunction = getMinimalSource().getTileUrlFunction(); + expect(tileUrlFunction([0, 0, 0])).to.be('full/full/0/default.jpg'); + + }); + + it('uses native as default quality for version 1', function() { + + const tileUrlFunction = new IIIF({ + size: size, + version: Versions.VERSION1 + }).getTileUrlFunction(); + expect(tileUrlFunction([0, 0, 0])).to.be('full/full/0/native.jpg'); + + }); + + it('corrects non empty base URL if trailing slash is missing', function() { + + // missing trailing slash is added + let tileUrlFunction = getSource().getTileUrlFunction(); + expect(tileUrlFunction([0, 0, 0])).to.be('http://iiif.test/image-id/full/full/0/default.jpg'); + + // existent trailing slash isn't doubled + tileUrlFunction = getSource({ + url: 'http://iiif.test/other-image-id/' + }).getTileUrlFunction(); + expect(tileUrlFunction([0, 0, 0])).to.be('http://iiif.test/other-image-id/full/full/0/default.jpg'); + + }); + + }); + + describe('tileUrlFunction', function() { + + it('has only one resolution and one tile if no tiles, resolutions, sizes and supported features are given', function() { + + let tileUrlFunction = getSource().getTileUrlFunction(); + expect(tileUrlFunction([0, 0, 0])).to.be('http://iiif.test/image-id/full/full/0/default.jpg'); + expect(tileUrlFunction([-1, 0, 0])).to.be(undefined); + expect(tileUrlFunction([1, 0, 0])).to.be(undefined); + expect(tileUrlFunction([0, 1, 0])).to.be(undefined); + expect(tileUrlFunction([0, 0, 1])).to.be(undefined); + + tileUrlFunction = getSource({ + version: Versions.VERSION1 + }).getTileUrlFunction(); + expect(tileUrlFunction([0, 0, 0])).to.be('http://iiif.test/image-id/full/full/0/native.jpg'); + + tileUrlFunction = getSource({ + version: Versions.VERSION3 + }).getTileUrlFunction(); + expect(tileUrlFunction([0, 0, 0])).to.be('http://iiif.test/image-id/full/max/0/default.jpg'); + + }); + + it('constructs the same number of resolutions as sizes are given', function() { + + let tileUrlFunction = getSource({ + sizes: [[2000, 1500], [1000, 750], [500, 375]] + }).getTileUrlFunction(); + + expect(tileUrlFunction([0, 0, 0])).to.be('http://iiif.test/image-id/full/500,/0/default.jpg'); + expect(tileUrlFunction([1, 0, 0])).to.be('http://iiif.test/image-id/full/1000,/0/default.jpg'); + expect(tileUrlFunction([2, 0, 0])).to.be('http://iiif.test/image-id/full/full/0/default.jpg'); + expect(tileUrlFunction([3, 0, 0])).to.be(undefined); + expect(tileUrlFunction([-1, 0, 0])).to.be(undefined); + expect(tileUrlFunction([0, 1, 0])).to.be(undefined); + expect(tileUrlFunction([0, 0, 1])).to.be(undefined); + expect(tileUrlFunction([1, 1, 0])).to.be(undefined); + expect(tileUrlFunction([1, 0, 1])).to.be(undefined); + + tileUrlFunction = getSource({ + sizes: [[2000, 1500], [1000, 750], [500, 375]], + version: Versions.VERSION3 + }).getTileUrlFunction(); + + expect(tileUrlFunction([0, 0, 0])).to.be('http://iiif.test/image-id/full/500,375/0/default.jpg'); + expect(tileUrlFunction([1, 0, 0])).to.be('http://iiif.test/image-id/full/1000,750/0/default.jpg'); + expect(tileUrlFunction([2, 0, 0])).to.be('http://iiif.test/image-id/full/max/0/default.jpg'); + + tileUrlFunction = getSource({ + sizes: [[2000, 1500], [1000, 749], [1000, 750], [500, 375], [500, 374]] + }).getTileUrlFunction(); + + expect(tileUrlFunction([0, 0, 0])).to.be('http://iiif.test/image-id/full/500,/0/default.jpg'); + expect(tileUrlFunction([1, 0, 0])).to.be('http://iiif.test/image-id/full/1000,/0/default.jpg'); + expect(tileUrlFunction([2, 0, 0])).to.be('http://iiif.test/image-id/full/full/0/default.jpg'); + expect(tileUrlFunction([3, 0, 0])).to.be(undefined); + + }); + + it('given resolutions without tilesize or supported features do not result in tiling', function() { + + const tileUrlFunction = getSource({ + resolutions: [16, 8, 4, 2, 1] + }).getTileUrlFunction(); + + expect(tileUrlFunction([0, 0, 0])).to.be('http://iiif.test/image-id/full/full/0/default.jpg'); + expect(tileUrlFunction([-1, 0, 0])).to.be(undefined); + expect(tileUrlFunction([1, 0, 0])).to.be(undefined); + expect(tileUrlFunction([0, 1, 0])).to.be(undefined); + expect(tileUrlFunction([0, 0, 1])).to.be(undefined); + + }); + + it('given tilesize results in tiling with minimal resolutions set and canonical URLs', function() { + + let tileUrlFunction = getSource({ + tileSize: 512 + }).getTileUrlFunction(); + + expect(tileUrlFunction([0, 0, 0])).to.be('http://iiif.test/image-id/full/500,/0/default.jpg'); + expect(tileUrlFunction([-1, 0, 0])).to.be(undefined); + expect(tileUrlFunction([0, 1, 0])).to.be(undefined); + expect(tileUrlFunction([0, 0, 1])).to.be(undefined); + expect(tileUrlFunction([1, 0, 0])).to.be('http://iiif.test/image-id/0,0,1024,1024/512,/0/default.jpg'); + expect(tileUrlFunction([1, 1, 0])).to.be('http://iiif.test/image-id/1024,0,976,1024/488,/0/default.jpg'); + expect(tileUrlFunction([1, 0, 1])).to.be('http://iiif.test/image-id/0,1024,1024,476/512,/0/default.jpg'); + expect(tileUrlFunction([1, 1, 1])).to.be('http://iiif.test/image-id/1024,1024,976,476/488,/0/default.jpg'); + expect(tileUrlFunction([2, 0, 0])).to.be('http://iiif.test/image-id/0,0,512,512/512,/0/default.jpg'); + expect(tileUrlFunction([2, 3, 0])).to.be('http://iiif.test/image-id/1536,0,464,512/464,/0/default.jpg'); + expect(tileUrlFunction([2, 0, 2])).to.be('http://iiif.test/image-id/0,1024,512,476/512,/0/default.jpg'); + expect(tileUrlFunction([2, 3, 2])).to.be('http://iiif.test/image-id/1536,1024,464,476/464,/0/default.jpg'); + expect(tileUrlFunction([3, 0, 0])).to.be(undefined); + + tileUrlFunction = getSource({ + tileSize: 512, + version: Versions.VERSION3 + }).getTileUrlFunction(); + + expect(tileUrlFunction([0, 0, 0])).to.be('http://iiif.test/image-id/full/500,375/0/default.jpg'); + expect(tileUrlFunction([1, 0, 0])).to.be('http://iiif.test/image-id/0,0,1024,1024/512,512/0/default.jpg'); + expect(tileUrlFunction([1, 1, 0])).to.be('http://iiif.test/image-id/1024,0,976,1024/488,512/0/default.jpg'); + expect(tileUrlFunction([1, 0, 1])).to.be('http://iiif.test/image-id/0,1024,1024,476/512,238/0/default.jpg'); + expect(tileUrlFunction([1, 1, 1])).to.be('http://iiif.test/image-id/1024,1024,976,476/488,238/0/default.jpg'); + expect(tileUrlFunction([2, 0, 0])).to.be('http://iiif.test/image-id/0,0,512,512/512,512/0/default.jpg'); + expect(tileUrlFunction([2, 3, 0])).to.be('http://iiif.test/image-id/1536,0,464,512/464,512/0/default.jpg'); + expect(tileUrlFunction([2, 0, 2])).to.be('http://iiif.test/image-id/0,1024,512,476/512,476/0/default.jpg'); + expect(tileUrlFunction([2, 3, 2])).to.be('http://iiif.test/image-id/1536,1024,464,476/464,476/0/default.jpg'); + + }); + + it('', function() { + //expect(tileUrlFunction([])); + }); + + // canonical tiles + // unsufficient features, no tilesize, but resolution given: static + // sufficient features, no tilesize: default tilesize + // sufficient features, tilesize: this one + // sufficient features, all teh combinations + + }); + +});