Merge pull request #10562 from crubier/master
Zoomify: Separate the service pixel ratio and the device pixel ratio
This commit is contained in:
@@ -10,7 +10,6 @@ tags: "zoomify, deep zoom, IIP, pixel, projection"
|
|||||||
<div class="controls">
|
<div class="controls">
|
||||||
<select id="zoomifyProtocol">
|
<select id="zoomifyProtocol">
|
||||||
<option value="zoomify">Zoomify</option>
|
<option value="zoomify">Zoomify</option>
|
||||||
<option value="iip">IIP</option>
|
|
||||||
<option value="zoomifyretina">Zoomify Retina</option>
|
<option value="zoomifyretina">Zoomify Retina</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+30
-87
@@ -3,36 +3,42 @@ import View from '../src/ol/View.js';
|
|||||||
import TileLayer from '../src/ol/layer/Tile.js';
|
import TileLayer from '../src/ol/layer/Tile.js';
|
||||||
import Zoomify from '../src/ol/source/Zoomify.js';
|
import Zoomify from '../src/ol/source/Zoomify.js';
|
||||||
|
|
||||||
const imgWidth = 9911;
|
const imgWidth = 4000;
|
||||||
const imgHeight = 6100;
|
const imgHeight = 3000;
|
||||||
|
|
||||||
const zoomifyUrl = 'http://vips.vtech.fr/cgi-bin/iipsrv.fcgi?zoomify=' +
|
const zoomifyUrl = 'https://ol-zoomify.surge.sh/zoomify/';
|
||||||
'/mnt/MD1/AD00/plan_CHU-4HD-01/FOND.TIF/';
|
|
||||||
const iipUrl = 'http://vips.vtech.fr/cgi-bin/iipsrv.fcgi?FIF=' + '/mnt/MD1/AD00/plan_CHU-4HD-01/FOND.TIF' + '&JTL={z},{tileIndex}';
|
|
||||||
|
|
||||||
const layer = new TileLayer({
|
const source = new Zoomify({
|
||||||
source: new Zoomify({
|
url: zoomifyUrl,
|
||||||
tileSize: 256,
|
size: [imgWidth, imgHeight],
|
||||||
tilePixelRatio: 1,
|
crossOrigin: 'anonymous',
|
||||||
url: zoomifyUrl,
|
zDirection: -1 // Ensure we get a tile with the screen resolution or higher
|
||||||
size: [imgWidth, imgHeight],
|
});
|
||||||
crossOrigin: 'anonymous'
|
const extent = source.getTileGrid().getExtent();
|
||||||
})
|
|
||||||
|
const retinaPixelRatio = 2;
|
||||||
|
const retinaSource = new Zoomify({
|
||||||
|
url: zoomifyUrl,
|
||||||
|
size: [imgWidth, imgHeight],
|
||||||
|
crossOrigin: 'anonymous',
|
||||||
|
zDirection: -1, // Ensure we get a tile with the screen resolution or higher
|
||||||
|
tilePixelRatio: retinaPixelRatio, // Display retina tiles
|
||||||
|
tileSize: 256 / retinaPixelRatio // from a higher zoom level
|
||||||
});
|
});
|
||||||
|
|
||||||
const extent = [0, -imgHeight, imgWidth, 0];
|
const layer = new TileLayer({
|
||||||
|
source: source
|
||||||
const resolutions = layer.getSource().getTileGrid().getResolutions();
|
});
|
||||||
|
|
||||||
const map = new Map({
|
const map = new Map({
|
||||||
layers: [layer],
|
layers: [layer],
|
||||||
target: 'map',
|
target: 'map',
|
||||||
view: new View({
|
view: new View({
|
||||||
// adjust zoom levels to those provided by the source
|
// adjust zoom levels to those provided by the source
|
||||||
minResolution: resolutions[resolutions.length - 1],
|
resolutions: layer.getSource().getTileGrid().getResolutions(),
|
||||||
maxResolution: resolutions[0],
|
|
||||||
// constrain the center: center cannot be set outside this extent
|
// constrain the center: center cannot be set outside this extent
|
||||||
extent: extent
|
extent: extent,
|
||||||
|
constrainOnlyCenter: true
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
map.getView().fit(extent);
|
map.getView().fit(extent);
|
||||||
@@ -40,74 +46,11 @@ map.getView().fit(extent);
|
|||||||
const control = document.getElementById('zoomifyProtocol');
|
const control = document.getElementById('zoomifyProtocol');
|
||||||
control.addEventListener('change', function(event) {
|
control.addEventListener('change', function(event) {
|
||||||
const value = event.currentTarget.value;
|
const value = event.currentTarget.value;
|
||||||
if (value === 'iip') {
|
if (value === 'zoomify') {
|
||||||
const extent = [0, -imgHeight, imgWidth, 0];
|
layer.setSource(source);
|
||||||
layer.setSource(
|
|
||||||
new Zoomify({
|
|
||||||
tileSize: 256,
|
|
||||||
tilePixelRatio: 1,
|
|
||||||
url: iipUrl,
|
|
||||||
size: [imgWidth, imgHeight],
|
|
||||||
crossOrigin: 'anonymous'
|
|
||||||
})
|
|
||||||
);
|
|
||||||
const resolutions = layer.getSource().getTileGrid().getResolutions();
|
|
||||||
map.setView(
|
|
||||||
new View({
|
|
||||||
// adjust zoom levels to those provided by the source
|
|
||||||
minResolution: resolutions[resolutions.length - 1],
|
|
||||||
maxResolution: resolutions[0],
|
|
||||||
// constrain the center: center cannot be set outside this extent
|
|
||||||
extent: extent
|
|
||||||
})
|
|
||||||
);
|
|
||||||
map.getView().fit(extent);
|
|
||||||
} else if (value === 'zoomify') {
|
|
||||||
const extent = [0, -imgHeight, imgWidth, 0];
|
|
||||||
layer.setSource(
|
|
||||||
new Zoomify({
|
|
||||||
tileSize: 256,
|
|
||||||
tilePixelRatio: 1,
|
|
||||||
url: zoomifyUrl,
|
|
||||||
size: [imgWidth, imgHeight],
|
|
||||||
crossOrigin: 'anonymous'
|
|
||||||
})
|
|
||||||
);
|
|
||||||
const resolutions = layer.getSource().getTileGrid().getResolutions();
|
|
||||||
map.setView(
|
|
||||||
new View({
|
|
||||||
// adjust zoom levels to those provided by the source
|
|
||||||
minResolution: resolutions[resolutions.length - 1],
|
|
||||||
maxResolution: resolutions[0],
|
|
||||||
// constrain the center: center cannot be set outside this extent
|
|
||||||
extent: extent
|
|
||||||
})
|
|
||||||
);
|
|
||||||
map.getView().fit(extent);
|
|
||||||
} else if (value === 'zoomifyretina') {
|
} else if (value === 'zoomifyretina') {
|
||||||
const pixelRatio = 4;
|
layer.setSource(retinaSource);
|
||||||
// Be careful! Image extent will be modified by pixel ratio
|
|
||||||
const extent = [0, -imgHeight / pixelRatio, imgWidth / pixelRatio, 0];
|
|
||||||
layer.setSource(
|
|
||||||
new Zoomify({
|
|
||||||
tileSize: 256 / pixelRatio,
|
|
||||||
tilePixelRatio: pixelRatio,
|
|
||||||
url: zoomifyUrl,
|
|
||||||
size: [imgWidth / pixelRatio, imgHeight / pixelRatio],
|
|
||||||
crossOrigin: 'anonymous'
|
|
||||||
})
|
|
||||||
);
|
|
||||||
const resolutions = layer.getSource().getTileGrid().getResolutions();
|
|
||||||
map.setView(
|
|
||||||
new View({
|
|
||||||
// adjust zoom levels to those provided by the source
|
|
||||||
minResolution: resolutions[resolutions.length - 1] / pixelRatio,
|
|
||||||
maxResolution: resolutions[0],
|
|
||||||
// constrain the center: center cannot be set outside this extent
|
|
||||||
extent: extent
|
|
||||||
})
|
|
||||||
);
|
|
||||||
map.getView().fit(extent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {Versions} from '../format/IIIFInfo.js';
|
|||||||
import {assert} from '../asserts.js';
|
import {assert} from '../asserts.js';
|
||||||
import TileGrid from '../tilegrid/TileGrid.js';
|
import TileGrid from '../tilegrid/TileGrid.js';
|
||||||
import TileImage from './TileImage.js';
|
import TileImage from './TileImage.js';
|
||||||
|
import {toSize} from '../size.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} Options
|
* @typedef {Object} Options
|
||||||
@@ -87,7 +88,7 @@ class IIIF extends TileImage {
|
|||||||
const extent = options.extent || [0, -height, width, 0];
|
const extent = options.extent || [0, -height, width, 0];
|
||||||
|
|
||||||
const supportsListedSizes = sizes != undefined && Array.isArray(sizes) && sizes.length > 0;
|
const supportsListedSizes = sizes != undefined && Array.isArray(sizes) && sizes.length > 0;
|
||||||
const supportsListedTiles = tileSize != undefined && (typeof tileSize === 'number' && Number.isInteger(tileSize) && tileSize > 0 || Array.isArray(tileSize) && tileSize.length > 0);
|
const supportsListedTiles = tileSize !== undefined && (typeof tileSize === 'number' && Number.isInteger(tileSize) && tileSize > 0 || Array.isArray(tileSize) && tileSize.length > 0);
|
||||||
const supportsArbitraryTiling = supports != undefined && Array.isArray(supports) &&
|
const supportsArbitraryTiling = supports != undefined && Array.isArray(supports) &&
|
||||||
(supports.includes('regionByPx') || supports.includes('regionByPct')) &&
|
(supports.includes('regionByPx') || supports.includes('regionByPct')) &&
|
||||||
(supports.includes('sizeByWh') || supports.includes('sizeByH') ||
|
(supports.includes('sizeByWh') || supports.includes('sizeByH') ||
|
||||||
@@ -265,7 +266,9 @@ class IIIF extends TileImage {
|
|||||||
return baseUrl + regionParam + '/' + sizeParam + '/0/' + quality + '.' + format;
|
return baseUrl + regionParam + '/' + sizeParam + '/0/' + quality + '.' + format;
|
||||||
};
|
};
|
||||||
|
|
||||||
const IiifTileClass = CustomTile.bind(null, tilePixelRatio, tileGrid);
|
const IiifTileClass = CustomTile.bind(null, toSize(tileSize || 256).map(function(size) {
|
||||||
|
return size * tilePixelRatio;
|
||||||
|
}));
|
||||||
|
|
||||||
super({
|
super({
|
||||||
attributions: options.attributions,
|
attributions: options.attributions,
|
||||||
|
|||||||
+15
-22
@@ -8,7 +8,6 @@ import TileState from '../TileState.js';
|
|||||||
import {expandUrl, createFromTileUrlFunctions} from '../tileurlfunction.js';
|
import {expandUrl, createFromTileUrlFunctions} from '../tileurlfunction.js';
|
||||||
import {assert} from '../asserts.js';
|
import {assert} from '../asserts.js';
|
||||||
import {createCanvasContext2D} from '../dom.js';
|
import {createCanvasContext2D} from '../dom.js';
|
||||||
import {getTopLeft} from '../extent.js';
|
|
||||||
import {toSize} from '../size.js';
|
import {toSize} from '../size.js';
|
||||||
import TileImage from './TileImage.js';
|
import TileImage from './TileImage.js';
|
||||||
import TileGrid from '../tilegrid/TileGrid.js';
|
import TileGrid from '../tilegrid/TileGrid.js';
|
||||||
@@ -26,8 +25,7 @@ const TierSizeCalculation = {
|
|||||||
export class CustomTile extends ImageTile {
|
export class CustomTile extends ImageTile {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {number} tilePixelRatio Tile pixel ratio to display the tile
|
* @param {import("../size.js").Size} tileSize Full tile size.
|
||||||
* @param {import("../tilegrid/TileGrid.js").default} tileGrid TileGrid that the tile belongs to.
|
|
||||||
* @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
|
* @param {import("../tilecoord.js").TileCoord} tileCoord Tile coordinate.
|
||||||
* @param {TileState} state State.
|
* @param {TileState} state State.
|
||||||
* @param {string} src Image source URI.
|
* @param {string} src Image source URI.
|
||||||
@@ -35,7 +33,8 @@ export class CustomTile extends ImageTile {
|
|||||||
* @param {import("../Tile.js").LoadFunction} tileLoadFunction Tile load function.
|
* @param {import("../Tile.js").LoadFunction} tileLoadFunction Tile load function.
|
||||||
* @param {import("../Tile.js").Options=} opt_options Tile options.
|
* @param {import("../Tile.js").Options=} opt_options Tile options.
|
||||||
*/
|
*/
|
||||||
constructor(tilePixelRatio, tileGrid, tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options) {
|
constructor(tileSize, tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options) {
|
||||||
|
|
||||||
super(tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options);
|
super(tileCoord, state, src, crossOrigin, tileLoadFunction, opt_options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -45,14 +44,10 @@ export class CustomTile extends ImageTile {
|
|||||||
this.zoomifyImage_ = null;
|
this.zoomifyImage_ = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
|
||||||
* @type {import("../size.js").Size}
|
* @type {import("../size.js").Size}
|
||||||
*/
|
*/
|
||||||
this.tileSize_ = toSize(tileGrid.getTileSize(tileCoord[0])).map(
|
this.tileSize_ = tileSize;
|
||||||
function(x) {
|
|
||||||
return x * tilePixelRatio;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -114,8 +109,8 @@ export class CustomTile extends ImageTile {
|
|||||||
* @property {number} [transition] Duration of the opacity transition for rendering.
|
* @property {number} [transition] Duration of the opacity transition for rendering.
|
||||||
* To disable the opacity transition, pass `transition: 0`.
|
* To disable the opacity transition, pass `transition: 0`.
|
||||||
* @property {number} [tileSize=256] Tile size. Same tile size is used for all zoom levels.
|
* @property {number} [tileSize=256] Tile size. Same tile size is used for all zoom levels.
|
||||||
* @property {number} [zDirection=0] Indicate which resolution should be used
|
* @property {number} [zDirection] Indicate which resolution should be used
|
||||||
* by a renderer if the view resolution does not match any resolution of the tile source.
|
* by a renderer if the views resolution does not match any resolution of the tile source.
|
||||||
* If 0, the nearest resolution will be used. If 1, the nearest lower resolution
|
* If 0, the nearest resolution will be used. If 1, the nearest lower resolution
|
||||||
* will be used. If -1, the nearest higher resolution will be used.
|
* will be used. If -1, the nearest higher resolution will be used.
|
||||||
*/
|
*/
|
||||||
@@ -141,13 +136,12 @@ class Zoomify extends TileImage {
|
|||||||
options.tierSizeCalculation :
|
options.tierSizeCalculation :
|
||||||
TierSizeCalculation.DEFAULT;
|
TierSizeCalculation.DEFAULT;
|
||||||
|
|
||||||
|
const tilePixelRatio = options.tilePixelRatio || 1;
|
||||||
const imageWidth = size[0];
|
const imageWidth = size[0];
|
||||||
const imageHeight = size[1];
|
const imageHeight = size[1];
|
||||||
const extent = options.extent || [0, -size[1], size[0], 0];
|
|
||||||
const tierSizeInTiles = [];
|
const tierSizeInTiles = [];
|
||||||
const tileSize = options.tileSize || DEFAULT_TILE_SIZE;
|
const tileSize = options.tileSize || DEFAULT_TILE_SIZE;
|
||||||
const tilePixelRatio = options.tilePixelRatio || 1;
|
let tileSizeForTierSizeCalculation = tileSize * tilePixelRatio;
|
||||||
let tileSizeForTierSizeCalculation = tileSize;
|
|
||||||
|
|
||||||
switch (tierSizeCalculation) {
|
switch (tierSizeCalculation) {
|
||||||
case TierSizeCalculation.DEFAULT:
|
case TierSizeCalculation.DEFAULT:
|
||||||
@@ -179,10 +173,10 @@ class Zoomify extends TileImage {
|
|||||||
tierSizeInTiles.push([1, 1]);
|
tierSizeInTiles.push([1, 1]);
|
||||||
tierSizeInTiles.reverse();
|
tierSizeInTiles.reverse();
|
||||||
|
|
||||||
const resolutions = [1];
|
const resolutions = [tilePixelRatio];
|
||||||
const tileCountUpToTier = [0];
|
const tileCountUpToTier = [0];
|
||||||
for (let i = 1, ii = tierSizeInTiles.length; i < ii; i++) {
|
for (let i = 1, ii = tierSizeInTiles.length; i < ii; i++) {
|
||||||
resolutions.push(1 << i);
|
resolutions.push(tilePixelRatio << i);
|
||||||
tileCountUpToTier.push(
|
tileCountUpToTier.push(
|
||||||
tierSizeInTiles[i - 1][0] * tierSizeInTiles[i - 1][1] +
|
tierSizeInTiles[i - 1][0] * tierSizeInTiles[i - 1][1] +
|
||||||
tileCountUpToTier[i - 1]
|
tileCountUpToTier[i - 1]
|
||||||
@@ -192,8 +186,7 @@ class Zoomify extends TileImage {
|
|||||||
|
|
||||||
const tileGrid = new TileGrid({
|
const tileGrid = new TileGrid({
|
||||||
tileSize: tileSize,
|
tileSize: tileSize,
|
||||||
extent: extent,
|
extent: options.extent || [0, -imageHeight, imageWidth, 0],
|
||||||
origin: getTopLeft(extent),
|
|
||||||
resolutions: resolutions
|
resolutions: resolutions
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -203,6 +196,8 @@ class Zoomify extends TileImage {
|
|||||||
}
|
}
|
||||||
const urls = expandUrl(url);
|
const urls = expandUrl(url);
|
||||||
|
|
||||||
|
const tileWidth = tileSize * tilePixelRatio;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} template Template.
|
* @param {string} template Template.
|
||||||
* @return {import("../Tile.js").UrlFunction} Tile URL function.
|
* @return {import("../Tile.js").UrlFunction} Tile URL function.
|
||||||
@@ -226,8 +221,6 @@ class Zoomify extends TileImage {
|
|||||||
const tileIndex =
|
const tileIndex =
|
||||||
tileCoordX +
|
tileCoordX +
|
||||||
tileCoordY * tierSizeInTiles[tileCoordZ][0];
|
tileCoordY * tierSizeInTiles[tileCoordZ][0];
|
||||||
const tileSize = tileGrid.getTileSize(tileCoordZ);
|
|
||||||
const tileWidth = Array.isArray(tileSize) ? tileSize[0] : tileSize;
|
|
||||||
const tileGroup = ((tileIndex + tileCountUpToTier[tileCoordZ]) / tileWidth) | 0;
|
const tileGroup = ((tileIndex + tileCountUpToTier[tileCoordZ]) / tileWidth) | 0;
|
||||||
const localContext = {
|
const localContext = {
|
||||||
'z': tileCoordZ,
|
'z': tileCoordZ,
|
||||||
@@ -246,7 +239,7 @@ class Zoomify extends TileImage {
|
|||||||
|
|
||||||
const tileUrlFunction = createFromTileUrlFunctions(urls.map(createFromTemplate));
|
const tileUrlFunction = createFromTileUrlFunctions(urls.map(createFromTemplate));
|
||||||
|
|
||||||
const ZoomifyTileClass = CustomTile.bind(null, tilePixelRatio, tileGrid);
|
const ZoomifyTileClass = CustomTile.bind(null, toSize(tileSize * tilePixelRatio));
|
||||||
|
|
||||||
super({
|
super({
|
||||||
attributions: options.attributions,
|
attributions: options.attributions,
|
||||||
|
|||||||
Reference in New Issue
Block a user