@allmaps/iiif-parser
Version:
Allmaps IIIF parser
93 lines (92 loc) • 3.55 kB
JavaScript
import { getTileImageRequest } from './tiles.js';
function getImageRequestSize(imageSize, containerSize, mode = 'cover') {
if (mode === 'cover' || mode === 'contain') {
const widthRatio = containerSize.width / imageSize.width;
const heightRatio = containerSize.height / imageSize.height;
const ratio = mode === 'cover'
? Math.max(widthRatio, heightRatio)
: Math.min(widthRatio, heightRatio);
const width = imageSize.width * ratio;
const height = imageSize.height * ratio;
return {
width,
height
};
}
else {
throw new Error('Mode must be either "cover" or "contain"');
}
}
const maxThumbnailDownscale = 0.8;
const maxThumbnailUpscale = 1.5;
export function getImageRequest(imageSize, containerSize, mode = 'cover', { sizes, tileZoomLevels, supportsAnyRegionAndSize, maxWidth, maxHeight, maxArea }) {
let { width, height } = getImageRequestSize(imageSize, containerSize, mode);
if (maxWidth && width > maxWidth) {
height = (height / width) * maxWidth;
width = maxWidth;
}
if (maxHeight && height > maxHeight) {
width = (width / height) * maxHeight;
height = maxHeight;
}
if (maxArea && width * height > maxArea) {
const aspectRatio = height / width;
const thumbnailMaxWidth = Math.floor(Math.sqrt(maxArea / aspectRatio));
const thumbnailMaxHeight = thumbnailMaxWidth * aspectRatio;
width = Math.floor(thumbnailMaxHeight) / aspectRatio;
height = width * aspectRatio;
}
const aspectRatio = imageSize.width / imageSize.height;
width = Math.floor(width);
height = Math.round(width / aspectRatio);
if (sizes) {
let matchingSize;
for (const size of sizes) {
const scaleFactor = size.width / width;
if (scaleFactor >= maxThumbnailDownscale &&
scaleFactor <= maxThumbnailUpscale) {
matchingSize = size;
break;
}
}
if (matchingSize) {
return {
size: matchingSize
};
}
}
if (supportsAnyRegionAndSize) {
// TODO: can request smaller region than full
return {
size: {
width: Math.round(width),
height: Math.round(height)
}
};
}
if (tileZoomLevels) {
// TODO: take maxThumbnailDownscale and maxThumbnailUpscale into account
const ratio = imageSize.width / width;
const nearestZoomLevels = tileZoomLevels
.map(({ scaleFactor }, index) => ({
index,
scaleFactor,
diff: Math.abs(scaleFactor - ratio)
}))
.sort((a, b) => a.diff - b.diff);
const zoomLevel = tileZoomLevels[nearestZoomLevels[0].index];
const tilesX = Math.ceil(imageSize.width / (zoomLevel.scaleFactor * tileZoomLevels[0].width));
const tilesY = Math.ceil(imageSize.height / (zoomLevel.scaleFactor * tileZoomLevels[0].height));
const thumbnailTiles = [];
for (let y = 0; y < tilesY; y++) {
const thumbnailRow = [];
for (let x = 0; x < tilesX; x++) {
const thumbnailTile = getTileImageRequest(imageSize, zoomLevel, x, y);
thumbnailRow.push(thumbnailTile);
}
thumbnailTiles.push(thumbnailRow);
}
return thumbnailTiles;
}
throw new Error('Unable to create thumbnail');
}