diff --git a/__tests__/fixtures/imageInfoV2.json b/__tests__/fixtures/imageInfoV2.json new file mode 100644 index 0000000..db1bf6e --- /dev/null +++ b/__tests__/fixtures/imageInfoV2.json @@ -0,0 +1,24 @@ +{ + "@context": "http://iiif.io/api/image/2/context.json", + "@id": "https://stacks.stanford.edu/image/iiif/fv114zn4386/LD3047_Q4_v090_1985_0001", + "protocol": "http://iiif.io/api/image", + "width": 4056, + "height": 5182, + "sizes": [ + { "width": 127, "height": 162 }, + { "width": 254, "height": 324 }, + { "width": 507, "height": 648 }, + { "width": 1014, "height": 1296 }, + { "width": 2028, "height": 2591 }, + { "width": 4056, "height": 5182 }, + { "width": 4056, "height": 5182 } + ], + "tiles": [ + { + "width": 1024, + "height": 1024, + "scaleFactors": [1, 2, 4, 8, 16, 32] + } + ], + "profile": ["http://iiif.io/api/image/2/level2.json"] +} diff --git a/__tests__/fixtures/imageInfoV3.json b/__tests__/fixtures/imageInfoV3.json new file mode 100644 index 0000000..477a077 --- /dev/null +++ b/__tests__/fixtures/imageInfoV3.json @@ -0,0 +1,45 @@ +{ + "@context": "http://iiif.io/api/image/3/context.json", + "id": "https://ndhadeliver.natlib.govt.nz/iiif/3/IE18987210:FL91807985.jp2", + "type": "ImageService3", + "protocol": "http://iiif.io/api/image", + "profile": "level2", + "width": 4145, + "height": 5389, + "sizes": [ + { "width": 65, "height": 84 }, + { "width": 130, "height": 168 }, + { "width": 259, "height": 337 }, + { "width": 518, "height": 674 }, + { "width": 1036, "height": 1347 }, + { "width": 2073, "height": 2695 }, + { "width": 4145, "height": 5389 } + ], + "tiles": [ + { + "width": 1024, + "height": 1024, + "scaleFactors": [1, 2, 4, 8, 16, 32, 64] + } + ], + "extraQualities": ["bitonal", "color", "gray"], + "extraFormats": ["tif", "gif"], + "extraFeatures": [ + "baseUriRedirect", + "canonicalLinkHeader", + "cors", + "jsonldMediaType", + "mirroring", + "profileLinkHeader", + "regionByPct", + "regionByPx", + "regionSquare", + "rotationArbitrary", + "rotationBy90s", + "sizeByConfinedWh", + "sizeByH", + "sizeByPct", + "sizeByW", + "sizeByWh" + ] +} diff --git a/__tests__/iiifImageFunctions.test.js b/__tests__/iiifImageFunctions.test.js new file mode 100644 index 0000000..d6dd0ae --- /dev/null +++ b/__tests__/iiifImageFunctions.test.js @@ -0,0 +1,68 @@ +import { requestExceedsMaximum } from '../src/iiifImageFunctions'; +import v2ImageInfo from './fixtures/imageInfoV2.json'; +import v3ImageInfo from './fixtures/imageInfoV3.json'; + +const v2ImageInfoWithLimits = { + ...v2ImageInfo, + profile: [ + 'http://iiif.io/api/image/2/level2.json', + { + maxWidth: 3000, + maxHeight: 3500, + maxArea: 8000000, + }, + ], +}; + +const v3ImageInfoWithLimits = { + ...v3ImageInfo, + maxWidth: 3000, + maxHeight: 3500, + maxArea: 8000000, +}; + +describe('requestExceedsMaximum', () => { + describe('IIIF Image API 2 (stacks.stanford.edu fixture)', () => { + it('does not throw and returns false when the profile has no size limits', () => { + expect(requestExceedsMaximum(v2ImageInfo, 8000, 8000)).toBe(false); + }); + + it('returns true when the requested area exceeds profile[1].maxArea', () => { + expect(requestExceedsMaximum(v2ImageInfoWithLimits, 3000, 3000)).toBe(true); + }); + + it('returns true when the requested width exceeds profile[1].maxWidth', () => { + expect(requestExceedsMaximum(v2ImageInfoWithLimits, 3500, 100)).toBe(true); + }); + + it('returns true when the requested height exceeds profile[1].maxHeight', () => { + expect(requestExceedsMaximum(v2ImageInfoWithLimits, 100, 4000)).toBe(true); + }); + + it('returns false when the request is within all declared limits', () => { + expect(requestExceedsMaximum(v2ImageInfoWithLimits, 1000, 1000)).toBe(false); + }); + }); + + describe('IIIF Image API 3 (ndhadeliver.natlib.govt.nz fixture)', () => { + it('does not throw and returns false when the profile has no size limits', () => { + expect(requestExceedsMaximum(v3ImageInfo, 8000, 8000)).toBe(false); + }); + + it('returns true when the requested area exceeds maxArea', () => { + expect(requestExceedsMaximum(v3ImageInfoWithLimits, 3000, 3000)).toBe(true); + }); + + it('returns true when the requested width exceeds maxWidth', () => { + expect(requestExceedsMaximum(v3ImageInfoWithLimits, 3500, 100)).toBe(true); + }); + + it('returns true when the requested height exceeds maxHeight', () => { + expect(requestExceedsMaximum(v3ImageInfoWithLimits, 100, 4000)).toBe(true); + }); + + it('returns false when the request is within all declared limits', () => { + expect(requestExceedsMaximum(v3ImageInfoWithLimits, 1000, 1000)).toBe(false); + }); + }); +}); diff --git a/src/iiifImageFunctions.js b/src/iiifImageFunctions.js index 7561dd4..1507f74 100644 --- a/src/iiifImageFunctions.js +++ b/src/iiifImageFunctions.js @@ -50,15 +50,19 @@ export function getImageApiVersion(imageInfo) { return undefined; } +function getProfileCapabilities(imageInfo) { + const profile = getArrayFromInfoResponse(imageInfo, 'profile'); + return profile && profile.length > 1 && profile[1]; +} + function supportsAdditonalFeature(imageInfo, feature) { const version = getImageApiVersion(imageInfo); switch (version) { case 2: { - const profile = getArrayFromInfoResponse(imageInfo, 'profile'); - return profile - && profile.length > 1 - && profile[1].supports - && profile[1].supports.indexOf(feature) > -1; + const capabilities = getProfileCapabilities(imageInfo); + return capabilities + && capabilities.supports + && capabilities.supports.indexOf(feature) > -1; } case 3: return imageInfo.extraFeatures && imageInfo.extraFeatures.indexOf(feature) > -1; @@ -71,15 +75,19 @@ export function requestExceedsMaximum(imageInfo, width, height) { const version = getImageApiVersion(imageInfo); switch (version) { case 2: { - const profile = getArrayFromInfoResponse(imageInfo, 'profile'); - return (profile.maxWidth && profile.maxWidth < width) - || (profile.maxHeight && profile.maxHeight < height) - || (profile.maxArea && profile.maxArea < width * height); + const capabilities = getProfileCapabilities(imageInfo); + return Boolean(capabilities && ( + (capabilities.maxWidth && capabilities.maxWidth < width) + || (capabilities.maxHeight && capabilities.maxHeight < height) + || (capabilities.maxArea && capabilities.maxArea < width * height) + )); } case 3: { - return (imageInfo.maxWidth && imageInfo.maxWidth < width) + return Boolean( + (imageInfo.maxWidth && imageInfo.maxWidth < width) || (imageInfo.maxHeight && imageInfo.maxHeight < height) - || (imageInfo.maxArea && imageInfo.maxArea < width * height); + || (imageInfo.maxArea && imageInfo.maxArea < width * height), + ); } default: return false;