diff --git a/examples/zoomify.html b/examples/zoomify.html index 0af0930288..919b7ceea3 100644 --- a/examples/zoomify.html +++ b/examples/zoomify.html @@ -3,7 +3,13 @@ layout: example.html title: Zoomify shortdesc: Example of a Zoomify source. docs: > - Zoomify is a format for deep-zooming into high resolution images. This example shows how to use the Zoomify source with a pixel projection. -tags: "zoomify, deep zoom, pixel, projection" + Zoomify is a format for deep-zooming into high resolution images. This example shows how to use the Zoomify source with a pixel projection. Internet Imaging Protocol (IIP) with JTL extension is also handled. +tags: "zoomify, deep zoom, IIP, pixel, projection" ---
+
+ +
diff --git a/examples/zoomify.js b/examples/zoomify.js index 5c388b9b9d..ebc0814483 100644 --- a/examples/zoomify.js +++ b/examples/zoomify.js @@ -6,26 +6,47 @@ goog.require('ol.source.Zoomify'); var imgWidth = 9911; var imgHeight = 6100; -var source = new ol.source.Zoomify({ - url: 'http://vips.vtech.fr/cgi-bin/iipsrv.fcgi?zoomify=' + - '/mnt/MD1/AD00/plan_CHU-4HD-01/FOND.TIF/', - size: [imgWidth, imgHeight], - crossOrigin: 'anonymous' +var zoomifyUrl = 'http://vips.vtech.fr/cgi-bin/iipsrv.fcgi?zoomify=' + + '/mnt/MD1/AD00/plan_CHU-4HD-01/FOND.TIF/'; +var iipUrl = 'http://vips.vtech.fr/cgi-bin/iipsrv.fcgi?FIF=' + '/mnt/MD1/AD00/plan_CHU-4HD-01/FOND.TIF' + '&JTL={z},{tileIndex}'; + +var layer = new ol.layer.Tile({ + source: new ol.source.Zoomify({ + url: zoomifyUrl, + size: [imgWidth, imgHeight], + crossOrigin: 'anonymous' + }) }); + var extent = [0, -imgHeight, imgWidth, 0]; var map = new ol.Map({ - layers: [ - new ol.layer.Tile({ - source: source - }) - ], + layers: [layer], target: 'map', view: new ol.View({ // adjust zoom levels to those provided by the source - resolutions: source.getTileGrid().getResolutions(), + resolutions: layer.getSource().getTileGrid().getResolutions(), // constrain the center: center cannot be set outside this extent extent: extent }) }); map.getView().fit(extent); + +var control = document.getElementById('zoomifyProtocol'); +control.addEventListener('change', function(event) { + var value = event.currentTarget.value; + if (value === 'iip') { + layer.setSource(new ol.source.Zoomify({ + url: iipUrl, + size: [imgWidth, imgHeight], + crossOrigin: 'anonymous' + })); + } else if (value === 'zoomify') { + layer.setSource(new ol.source.Zoomify({ + url: zoomifyUrl, + size: [imgWidth, imgHeight], + crossOrigin: 'anonymous' + })); + } + +}); diff --git a/externs/olx.js b/externs/olx.js index d2c8c06a7b..22dcd4c472 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -7175,6 +7175,9 @@ olx.source.ZoomifyOptions.prototype.reprojectionErrorThreshold; * `http://my.zoomify.info/IMAGE.TIF/`. A URL template must include * `{TileGroup}`, `{x}`, `{y}`, and `{z}` placeholders, e.g. * `http://my.zoomify.info/IMAGE.TIF/{TileGroup}/{z}-{x}-{y}.jpg`. + * Internet Imaging Protocol (IIP) with JTL extension can be also used with + * `{tileIndex}` and `{z}` placeholders, e.g. + * `http://my.zoomify.info?FIF=IMAGE.TIF&JTL={z},{tileIndex}`. * A `{?-?}` template pattern, for example `subdomain{a-f}.domain.com`, may be * used instead of defining each one separately in the `urls` option. * @type {!string} diff --git a/src/ol/source/zoomify.js b/src/ol/source/zoomify.js index ba448efffc..f0c0ffed47 100644 --- a/src/ol/source/zoomify.js +++ b/src/ol/source/zoomify.js @@ -13,7 +13,8 @@ goog.require('ol.tilegrid.TileGrid'); /** * @classdesc - * Layer source for tile data in Zoomify format. + * Layer source for tile data in Zoomify format (both Zoomify and Internet + * Imaging Protocol are supported). * * @constructor * @extends {ol.source.TileImage} @@ -84,7 +85,7 @@ ol.source.Zoomify = function(opt_options) { }); var url = options.url; - if (url && url.indexOf('{TileGroup}') == -1) { + if (url && url.indexOf('{TileGroup}') == -1 && url.indexOf('{tileIndex}') == -1) { url += '{TileGroup}/{z}-{x}-{y}.jpg'; } var urls = ol.TileUrlFunction.expandUrl(url); @@ -111,13 +112,13 @@ ol.source.Zoomify = function(opt_options) { var tileCoordY = -tileCoord[2] - 1; var tileIndex = tileCoordX + - tileCoordY * tierSizeInTiles[tileCoordZ][0] + - tileCountUpToTier[tileCoordZ]; - var tileGroup = (tileIndex / ol.DEFAULT_TILE_SIZE) | 0; + tileCoordY * tierSizeInTiles[tileCoordZ][0]; + var tileGroup = ((tileIndex + tileCountUpToTier[tileCoordZ]) / ol.DEFAULT_TILE_SIZE) | 0; var localContext = { 'z': tileCoordZ, 'x': tileCoordX, 'y': tileCoordY, + 'tileIndex': tileIndex, 'TileGroup': 'TileGroup' + tileGroup }; return template.replace(/\{(\w+?)\}/g, function(m, p) { diff --git a/test/spec/ol/source/zoomify.test.js b/test/spec/ol/source/zoomify.test.js index c3f9f40e1c..cb39adab88 100644 --- a/test/spec/ol/source/zoomify.test.js +++ b/test/spec/ol/source/zoomify.test.js @@ -11,7 +11,8 @@ describe('ol.source.Zoomify', function() { var w = 1024; var h = 512; var size = [w, h]; - var url = 'spec/ol/source/images/zoomify/{TileGroup}/{z}-{x}-{y}.jpg'; + var zoomifyUrl = 'spec/ol/source/images/zoomify/{TileGroup}/{z}-{x}-{y}.jpg'; + var iipUrl = 'spec/ol/source/images/zoomify?JTL={z},{tileIndex}'; var proj = new ol.proj.Projection({ code: 'ZOOMIFY', units: 'pixels', @@ -19,7 +20,13 @@ describe('ol.source.Zoomify', function() { }); function getZoomifySource() { return new ol.source.Zoomify({ - url: url, + url: zoomifyUrl, + size: size + }); + } + function getIIPSource() { + return new ol.source.Zoomify({ + url: iipUrl, size: size }); } @@ -55,10 +62,13 @@ describe('ol.source.Zoomify', function() { // we got a source expect(source).to.be.a(ol.source.Zoomify); - // also test our helper method from above + // also test our helper methods from above expect(function() { source = getZoomifySource(); }).to.not.throwException(); + expect(function() { + source = getIIPSource(); + }).to.not.throwException(); // we got a source expect(source).to.be.a(ol.source.Zoomify); }); @@ -99,10 +109,12 @@ describe('ol.source.Zoomify', function() { }).to.throwException(); }); - it('creates a tileGrid', function() { - var source = getZoomifySource(); - var tileGrid = source.getTileGrid(); - expect(tileGrid).to.be.a(ol.tilegrid.TileGrid); + it('creates a tileGrid for both protocols', function() { + var sources = [getZoomifySource(), getIIPSource()]; + for (var i = 0; i < sources.length; i++) { + var tileGrid = sources[i].getTileGrid(); + expect(tileGrid).to.be.a(ol.tilegrid.TileGrid); + } }); }); @@ -110,24 +122,30 @@ describe('ol.source.Zoomify', function() { describe('generated tileGrid', function() { it('has expected extent', function() { - var source = getZoomifySource(); - var tileGrid = source.getTileGrid(); - var expectedExtent = [0, -h, w, 0]; - expect(tileGrid.getExtent()).to.eql(expectedExtent); + var sources = [getZoomifySource(), getIIPSource()]; + for (var i = 0; i < sources.length; i++) { + var tileGrid = sources[i].getTileGrid(); + var expectedExtent = [0, -h, w, 0]; + expect(tileGrid.getExtent()).to.eql(expectedExtent); + } }); it('has expected origin', function() { - var source = getZoomifySource(); - var tileGrid = source.getTileGrid(); - var expectedOrigin = [0, 0]; - expect(tileGrid.getOrigin()).to.eql(expectedOrigin); + var sources = [getZoomifySource(), getIIPSource()]; + for (var i = 0; i < sources.length; i++) { + var tileGrid = sources[i].getTileGrid(); + var expectedOrigin = [0, 0]; + expect(tileGrid.getOrigin()).to.eql(expectedOrigin); + } }); it('has expected resolutions', function() { - var source = getZoomifySource(); - var tileGrid = source.getTileGrid(); - var expectedResolutions = [4, 2, 1]; - expect(tileGrid.getResolutions()).to.eql(expectedResolutions); + var sources = [getZoomifySource(), getIIPSource()]; + for (var i = 0; i < sources.length; i++) { + var tileGrid = sources[i].getTileGrid(); + var expectedResolutions = [4, 2, 1]; + expect(tileGrid.getResolutions()).to.eql(expectedResolutions); + } }); }); @@ -137,14 +155,14 @@ describe('ol.source.Zoomify', function() { it('influences resolutions', function() { // not configured at all var source = new ol.source.Zoomify({ - url: url, + url: zoomifyUrl, size: [513, 256] }); var tileGrid = source.getTileGrid(); // explicitly set as 'default' var sourceDefault = new ol.source.Zoomify({ - url: url, + url: zoomifyUrl, size: [513, 256], tierSizeCalculation: 'default' }); @@ -152,7 +170,7 @@ describe('ol.source.Zoomify', function() { // explicitly set to 'truncated' var sourceTruncated = new ol.source.Zoomify({ - url: url, + url: zoomifyUrl, size: [513, 256], tierSizeCalculation: 'truncated' }); @@ -165,9 +183,9 @@ describe('ol.source.Zoomify', function() { }); - describe('generated tileUrlFunction', function() { + describe('generated tileUrlFunction for zoomify protocol', function() { - it('creates an expected tileUrlFunction with template', function() { + it('creates an expected tileUrlFunction with zoomify template', function() { var source = getZoomifySource(); var tileUrlFunction = source.getTileUrlFunction(); // zoomlevel 0 @@ -178,6 +196,17 @@ describe('ol.source.Zoomify', function() { expect(tileUrlFunction([1, 0, -2])).to.eql('spec/ol/source/images/zoomify/TileGroup0/1-0-1.jpg'); expect(tileUrlFunction([1, 1, -2])).to.eql('spec/ol/source/images/zoomify/TileGroup0/1-1-1.jpg'); }); + it('creates an expected tileUrlFunction with IIP template', function() { + var source = getIIPSource(); + var tileUrlFunction = source.getTileUrlFunction(); + // zoomlevel 0 + expect(tileUrlFunction([0, 0, -1])).to.eql('spec/ol/source/images/zoomify?JTL=0,0'); + // zoomlevel 1 + expect(tileUrlFunction([1, 0, -1])).to.eql('spec/ol/source/images/zoomify?JTL=1,0'); + expect(tileUrlFunction([1, 1, -1])).to.eql('spec/ol/source/images/zoomify?JTL=1,1'); + expect(tileUrlFunction([1, 0, -2])).to.eql('spec/ol/source/images/zoomify?JTL=1,2'); + expect(tileUrlFunction([1, 1, -2])).to.eql('spec/ol/source/images/zoomify?JTL=1,3'); + }); it('creates an expected tileUrlFunction without template', function() { var source = new ol.source.Zoomify({