Skip to content
Snippets Groups Projects
Unverified Commit ef2bfe58 authored by Jack Reed's avatar Jack Reed Committed by GitHub
Browse files

Merge pull request #3196 from ProjectMirador/level0-thumb

Try a little harder to find a good level 0 thumbnail image
parents ba575555 0c3647b0
No related branches found
No related tags found
No related merge requests found
......@@ -84,6 +84,23 @@ describe('getThumbnail', () => {
type: 'Image',
})).toMatchObject({ url: 'xyz' });
});
it('uses embedded sizes to find an appropriate size', () => {
const sizes = [
{ height: 25, width: 25 },
{ height: 100, width: 100 },
{ height: 125, width: 125 },
{ height: 1000, width: 1000 },
];
const obj = {
...(iiifService('some-url', {}, { profile: 'level0', sizes })),
id: 'xyz',
type: 'Image',
};
expect(createImageSubject(obj, { maxHeight: 120, maxWidth: 120 }))
.toMatchObject({ height: 125, width: 125 });
});
});
describe('with a IIIF service', () => {
......
......@@ -2,6 +2,12 @@ import { Utils } from 'manifesto.js';
import MiradorManifest from './MiradorManifest';
import MiradorCanvas from './MiradorCanvas';
/** */
function asArray(value) {
if (value === undefined) return [];
return Array.isArray(value) ? value : [value];
}
/** */
function isLevel0ImageProfile(service) {
const profile = service.getProfile();
......@@ -32,7 +38,7 @@ function isLevel2ImageProfile(service) {
function iiifv3ImageServiceType(service) {
const type = service.getProperty('type') || [];
return (Array.isArray(type) ? type : [type]).some(v => v.startsWith('ImageService'));
return asArray(type).some(v => v.startsWith('ImageService'));
}
/** */
......@@ -68,9 +74,9 @@ class ThumbnailFactory {
let size;
let width;
let height;
let maxHeight;
let maxWidth;
const minDimension = 120;
let maxHeight = minDimension;
let maxWidth = minDimension;
const { maxHeight: requestedMaxHeight, maxWidth: requestedMaxWidth } = this.iiifOpts;
if (requestedMaxHeight) maxHeight = Math.max(requestedMaxHeight, minDimension);
......@@ -80,16 +86,62 @@ class ThumbnailFactory {
if (!service) return undefined;
const aspectRatio = resource.getWidth()
&& resource.getHeight()
&& (resource.getWidth() / resource.getHeight());
// just bail to a static image, even though sizes might provide something better
if (isLevel0ImageProfile(service)) {
return ThumbnailFactory.staticImageUrl(resource);
const sizes = asArray(service.getProperty('sizes'));
const serviceHeight = service.getProperty('height');
const serviceWidth = service.getProperty('width');
const target = (requestedMaxWidth && requestedMaxHeight)
? requestedMaxWidth * requestedMaxHeight
: maxHeight * maxWidth;
let closestSize = {
default: true,
height: serviceHeight || Number.MAX_SAFE_INTEGER,
width: serviceWidth || Number.MAX_SAFE_INTEGER,
};
/** Compare the total image area to our target */
const imageFitness = (test) => test.width * test.height - target;
/** Look for the size that's just bigger than we prefer... */
closestSize = sizes.reduce(
(best, test) => {
const score = imageFitness(test);
if (score < 0) return best;
return Math.abs(score) < Math.abs(imageFitness(best))
? test
: best;
}, closestSize,
);
/** .... but not "too" big; we'd rather scale up an image than download too much */
if (closestSize.width * closestSize.height > target * 6) {
closestSize = sizes.reduce(
(best, test) => (
Math.abs(imageFitness(test)) < Math.abs(imageFitness(best))
? test
: best
), closestSize,
);
}
const aspectRatio = resource.getWidth()
&& resource.getHeight()
&& (resource.getWidth() / resource.getHeight());
/** Bail if the best available size is the full size.. maybe we'll get lucky with the @id */
if (closestSize.default && !serviceHeight && !serviceWidth) {
return ThumbnailFactory.staticImageUrl(resource);
}
if (maxHeight && maxWidth) {
width = closestSize.width;
height = closestSize.height;
size = `${width},${height}`;
} else if (requestedMaxHeight && requestedMaxWidth) {
// IIIF level 2, no problem.
if (isLevel2ImageProfile(service)) {
size = `!${maxWidth},${maxHeight}`;
......@@ -107,11 +159,11 @@ class ThumbnailFactory {
height = maxHeight;
if (aspectRatio) width = Math.round(maxHeight * aspectRatio);
}
} else if (maxHeight && !maxWidth) {
} else if (requestedMaxHeight && !requestedMaxWidth) {
size = `,${maxHeight}`;
height = maxHeight;
if (aspectRatio) width = Math.round(maxHeight * aspectRatio);
} else if (!maxHeight && maxWidth) {
} else if (!requestedMaxHeight && requestedMaxWidth) {
size = `${maxWidth},`;
width = maxWidth;
if (aspectRatio) height = Math.round(maxWidth / aspectRatio);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment