diff --git a/examples/iiif.js b/examples/iiif.js index 3c9439166a..23b6ce2822 100644 --- a/examples/iiif.js +++ b/examples/iiif.js @@ -16,7 +16,7 @@ const layer = new TileLayer(), function refreshMap(imageInfoUrl) { fetch(imageInfoUrl).then(function(response) { response.json().then(function(imageInfo) { - const options = new IIIFInfo().readOptionsFromJson(imageInfo); + const options = new IIIFInfo(imageInfo).getTileSourceOptions(); if (options === undefined || options.version === undefined) { notifyDiv.textContent = 'Data seems to be no valid IIIF image information.'; return; diff --git a/src/ol/format/IIIFInfo.js b/src/ol/format/IIIFInfo.js index cb5e4ccbd8..8b865a2def 100644 --- a/src/ol/format/IIIFInfo.js +++ b/src/ol/format/IIIFInfo.js @@ -13,11 +13,19 @@ import {assert} from '../asserts.js'; * indicates support for that quality. */ +/** + * @typedef {Object} SupportedFeatures + * @property {Array} [supports] Supported IIIF image size and region + * calculation features. + * @property {Array} [formats] Supported image formats. + * @property {Array} [qualities] Supported IIIF image qualities. + */ + /** * Supported image formats, qualities and supported region / size calculation features * for different image API versions and compliance levels * @const - * @type {Object>>} + * @type {Object} */ const IIIF_PROFILE_VALUES = { version1: { @@ -90,178 +98,9 @@ export const Versions = { VERSION3: 'version3' }; -function getComplianceLevelOfImageInfoForVersion(imageInfo, version) { - switch (version) { - case Versions.VERSION1: - case Versions.VERSION3: - return imageInfo.profile; - case Versions.VERSION2: - if (typeof imageInfo.profile === 'string') { - return imageInfo.profile; - } - if (Array.isArray(imageInfo.profile) && imageInfo.profile.length > 0 - && typeof imageInfo.profile[0] === 'string') { - return imageInfo.profile[0]; - } - return; - default: - } -} - -function getVersionOfImageInfo(imageInfo) { - const context = imageInfo['@context'] || undefined; - switch (context) { - case 'http://library.stanford.edu/iiif/image-api/1.1/context.json': - case 'http://iiif.io/api/image/1/context.json': - return Versions.VERSION1; - case 'http://iiif.io/api/image/2/context.json': - return Versions.VERSION2; - case 'http://iiif.io/api/image/3/context.json': - return Versions.VERSION3; - case undefined: - // Image API 1.0 has no '@context' - if (getComplianceLevelOfImageInfoForVersion(imageInfo, Versions.VERSION1)) { - return Versions.VERSION1; - } - break; - default: - } - assert(false, 61); -} - -function getLevelProfileForImageInfo(imageInfo) { - const version = getVersionOfImageInfo(imageInfo), - complianceLevel = getComplianceLevelOfImageInfoForVersion(imageInfo, version); - let level; - if (version === undefined || complianceLevel === undefined) { - return IIIF_PROFILE_VALUES.none; - } - level = complianceLevel.match(/level[0-2](\.json)?$/g); - level = Array.isArray(level) ? level[0].replace('.json', '') : 'none'; - return IIIF_PROFILE_VALUES[version][level]; -} - -function generateVersion1Options(imageInfo) { - const levelProfile = getLevelProfileForImageInfo(imageInfo); - return { - url: imageInfo['@id'].replace(/\/?(info.json)?$/g, ''), - supports: levelProfile.supports, - formats: [...levelProfile.formats, imageInfo.formats === undefined ? - [] : imageInfo.formats - ], - qualities: [...levelProfile.qualities, imageInfo.qualities === undefined ? - [] : imageInfo.qualities - ], - resolutions: imageInfo.scale_factors, - tileSize: imageInfo.tile_width !== undefined ? imageInfo.tile_height != undefined ? - [imageInfo.tile_width, imageInfo.tile_height] : [imageInfo.tile_width, imageInfo.tile_width] : - imageInfo.tile_height != undefined ? [imageInfo.tile_height, imageInfo.tile_height] : undefined - }; -} - -function generateVersion2Options(imageInfo) { - const levelProfile = getLevelProfileForImageInfo(imageInfo), - additionalProfile = Array.isArray(imageInfo.profile) && imageInfo.profile.length > 1, - profileSupports = additionalProfile && imageInfo.profile[1].supports ? imageInfo.profile[1].supports : [], - profileFormats = additionalProfile && imageInfo.profile[1].formats ? imageInfo.profile[1].formats : [], - profileQualities = additionalProfile && imageInfo.profile[1].qualities ? imageInfo.profile[1].qualities : [], - attributions = []; - if (imageInfo.attribution !== undefined) { - // TODO potentially dangerous - attributions.push(imageInfo.attribution); - } - if (imageInfo.license !== undefined) { - let license = imageInfo.license; - if (license.match(/^http(s)?:\/\//g)) { - license = '' + encodeURI(license) + ''; - } - // TODO potentially dangerous - attributions.push(license); - } - return { - url: imageInfo['@id'].replace(/\/?(info.json)?$/g, ''), - sizes: imageInfo.sizes === undefined ? undefined : imageInfo.sizes.map(function(size) { - return [size.width, size.height]; - }), - tileSize: imageInfo.tiles === undefined ? undefined : [ - imageInfo.tiles.map(function(tile) { - return tile.width; - })[0], - imageInfo.tiles.map(function(tile) { - return tile.height; - })[0] - ], - resolutions: imageInfo.tiles === undefined ? undefined : - imageInfo.tiles.map(function(tile) { - return tile.scaleFactors; - })[0], - supports: [...levelProfile.supports, ...profileSupports], - formats: [...levelProfile.formats, ...profileFormats], - qualities: [...levelProfile.qualities, ...profileQualities], - attributions: attributions.length == 0 ? undefined : attributions - }; -} - -function generateVersion3Options(imageInfo) { - const levelProfile = getLevelProfileForImageInfo(imageInfo); - return { - url: imageInfo['id'], - sizes: imageInfo.sizes === undefined ? undefined : imageInfo.sizes.map(function(size) { - return [size.width, size.height]; - }), - tileSize: imageInfo.tiles === undefined ? undefined : [ - imageInfo.tiles.map(function(tile) { - return tile.width; - })[0], - imageInfo.tiles.map(function(tile) { - return tile.height; - })[0] - ], - resolutions: imageInfo.tiles === undefined ? undefined : - imageInfo.tiles.map(function(tile) { - return tile.scaleFactors; - })[0], - supports: imageInfo.extraFeatures === undefined ? levelProfile.supports : - [...levelProfile.supports, ...imageInfo.extraFeatures], - formats: imageInfo.extraFormats === undefined ? levelProfile.formats : - [...levelProfile.formats, ...imageInfo.extraFormats], - qualities: imageInfo.extraQualities === undefined ? levelProfile.qualities : - [...levelProfile.extraQualities, ...imageInfo.extraQualities], - maxWidth: undefined, - maxHeight: undefined, - maxArea: undefined, - attributions: undefined - }; -} - -const versionFunctions = {}; -versionFunctions[Versions.VERSION1] = generateVersion1Options; -versionFunctions[Versions.VERSION2] = generateVersion2Options; -versionFunctions[Versions.VERSION3] = generateVersion3Options; - -function getOptionsForImageInformation(imageInfo, preferredOptions) { - const options = preferredOptions || {}, - version = getVersionOfImageInfo(imageInfo), - imageOptions = version === undefined ? undefined : versionFunctions[version](imageInfo); - if (imageOptions === undefined) { - return; - } - return { - url: imageOptions.url, - version: version, - size: [imageInfo.width, imageInfo.height], - sizes: imageOptions.sizes, - format: imageOptions.formats.includes(options.format) ? options.format : 'jpg', - supports: imageOptions.supports, - quality: options.quality && imageOptions.qualities.includes(options.quality) ? - options.quality : imageOptions.qualities.includes('native') ? 'native' : 'default', - resolutions: Array.isArray(imageOptions.resolutions) ? imageOptions.resolutions.sort(function(a, b) { - return b - a; - }) : undefined, - tileSize: imageOptions.tileSize, - attributions: imageOptions.attributions - }; -} +const COMPLIANCE_VERSION1 = new RegExp('^https?\:\/\/library\.stanford\.edu\/iiif\/image-api\/(1\.1\/)?compliance\.html#level[0-2]$'); +const COMPLIANCE_VERSION2 = new RegExp('^https?\:\/\/iiif\.io\/api\/image\/2\/level[0-2](\.json)?$'); +const COMPLIANCE_VERSION3 = new RegExp('(^https?\:\/\/iiif\.io\/api\/image\/3\/level[0-2](\.json)?$)|(^level[0-2]$)'); /** * @classdesc @@ -270,25 +109,263 @@ function getOptionsForImageInformation(imageInfo, preferredOptions) { * * @api */ -// TODO at the moment, this does not need to be a class. class IIIFInfo { /** - * @param {Object} imageInfo Deserialized image information JSON response object - * @param {PreferredOptions} opt_preferredOptions Optional options for preferred format and quality. - * @returns {import("../source/IIIF.js").Options} IIIF tile source ready constructor options. + * @param {Object|string} imageInfo Deserialized image information JSON response + * object or JSON response as string */ - readOptionsFromJson(imageInfo, opt_preferredOptions) { - return getOptionsForImageInformation(imageInfo, opt_preferredOptions); + constructor(imageInfo) { + this.setImageInfo(imageInfo); + this.versionFunctions = {}; + this.versionFunctions[Versions.VERSION1] = this.generateVersion1Options.bind(this); + this.versionFunctions[Versions.VERSION2] = this.generateVersion2Options.bind(this); + this.versionFunctions[Versions.VERSION3] = this.generateVersion3Options.bind(this); + } + + /** + * @param {Object|string} imageInfo Deserialized image information JSON response + * object or JSON response as string + */ + setImageInfo(imageInfo) { + if (typeof imageInfo == 'string') { + this.imageInfo = JSON.parse(imageInfo); + } else { + this.imageInfo = imageInfo; + } + } + + /** + * @returns {Versions} Major IIIF version. + */ + getImageApiVersion() { + if (this.imageInfo === undefined) { + return; + } + const context = this.imageInfo['@context'] || undefined; + switch (context) { + case 'http://library.stanford.edu/iiif/image-api/1.1/context.json': + case 'http://iiif.io/api/image/1/context.json': + return Versions.VERSION1; + case 'http://iiif.io/api/image/2/context.json': + return Versions.VERSION2; + case 'http://iiif.io/api/image/3/context.json': + return Versions.VERSION3; + case undefined: + // Image API 1.0 has no '@context' + if (this.getComplianceLevelEntryFromProfile(Versions.VERSION1) && this.imageInfo.identifier) { + return Versions.VERSION1; + } + break; + default: + } + assert(false, 61); + } + + /** + * @param {Versions} version Optional IIIF image API version + * @returns {string} Compliance level as it appears in the IIIF image information + * response. + */ + getComplianceLevelEntryFromProfile(version) { + if (this.imageInfo === undefined || this.imageInfo.profile === undefined) { + return; + } + if (version === undefined) { + version = this.getImageApiVersion(); + } + switch (version) { + case Versions.VERSION1: + if (COMPLIANCE_VERSION1.test(this.imageInfo.profile)) { + return this.imageInfo.profile; + } + break; + case Versions.VERSION3: + if (COMPLIANCE_VERSION3.test(this.imageInfo.profile)) { + return this.imageInfo.profile; + } + break; + case Versions.VERSION2: + if (typeof this.imageInfo.profile === 'string' && COMPLIANCE_VERSION2.test(this.imageInfo.profile)) { + return this.imageInfo.profile; + } + if (Array.isArray(this.imageInfo.profile) && this.imageInfo.profile.length > 0 + && typeof this.imageInfo.profile[0] === 'string' && COMPLIANCE_VERSION2.test(this.imageInfo.profile[0])) { + return this.imageInfo.profile[0]; + } + break; + default: + } + } + + /** + * @param {Versions} version Optional IIIF image API version + * @returns {string} Compliance level, on of 'level0', 'level1' or 'level2' or undefined + */ + getComplianceLevelFromProfile(version) { + const complianceLevel = this.getComplianceLevelEntryFromProfile(version); + if (complianceLevel === undefined) { + return undefined; + } + const level = complianceLevel.match(/level[0-2](\.json)?$/g); + return Array.isArray(level) ? level[0].replace('.json', '') : 'none'; + } + + /** + * @returns {SupportedFeatures} Image formats, qualities and region / size calculation + * methods that are supported by the IIIF service. + */ + getComplianceLevelSupportedFeatures() { + if (this.imageInfo === undefined) { + return; + } + const version = this.getImageApiVersion(); + const level = this.getComplianceLevelFromProfile(version); + if (level === undefined) { + return IIIF_PROFILE_VALUES.none; + } + return IIIF_PROFILE_VALUES[version][level]; } /** - * @param {string} imageInfo Image information JSON response as string serialization. * @param {PreferredOptions} opt_preferredOptions Optional options for preferred format and quality. * @returns {import("../source/IIIF.js").Options} IIIF tile source ready constructor options. */ - readOptionsFromJsonString(imageInfo, opt_preferredOptions) { - return getOptionsForImageInformation(JSON.parse(imageInfo), opt_preferredOptions); + getTileSourceOptions(opt_preferredOptions) { + const options = opt_preferredOptions || {}, + version = this.getImageApiVersion(); + if (version === undefined) { + return; + } + const imageOptions = version === undefined ? undefined : this.versionFunctions[version](); + if (imageOptions === undefined) { + return; + } + return { + url: imageOptions.url, + version: version, + size: [this.imageInfo.width, this.imageInfo.height], + sizes: imageOptions.sizes, + format: imageOptions.formats.includes(options.format) ? options.format : 'jpg', + supports: imageOptions.supports, + quality: options.quality && imageOptions.qualities.includes(options.quality) ? + options.quality : imageOptions.qualities.includes('native') ? 'native' : 'default', + resolutions: Array.isArray(imageOptions.resolutions) ? imageOptions.resolutions.sort(function(a, b) { + return b - a; + }) : undefined, + tileSize: imageOptions.tileSize, + attributions: imageOptions.attributions + }; + } + + /** + * @private + * @returns {object} Available options + */ + generateVersion1Options() { + let levelProfile = this.getComplianceLevelSupportedFeatures(); + // Version 1.0 and 1.1 do not require a profile. + if (levelProfile === undefined) { + levelProfile = IIIF_PROFILE_VALUES.version1.level0; + } + return { + url: this.imageInfo['@id'] === undefined ? undefined : this.imageInfo['@id'].replace(/\/?(info.json)?$/g, ''), + supports: levelProfile.supports, + formats: [...levelProfile.formats, this.imageInfo.formats === undefined ? + [] : this.imageInfo.formats + ], + qualities: [...levelProfile.qualities, this.imageInfo.qualities === undefined ? + [] : this.imageInfo.qualities + ], + resolutions: this.imageInfo.scale_factors, + tileSize: this.imageInfo.tile_width !== undefined ? this.imageInfo.tile_height != undefined ? + [this.imageInfo.tile_width, this.imageInfo.tile_height] : [this.imageInfo.tile_width, this.imageInfo.tile_width] : + this.imageInfo.tile_height != undefined ? [this.imageInfo.tile_height, this.imageInfo.tile_height] : undefined + }; + } + + /** + * @private + * @returns {object} Available options + */ + generateVersion2Options() { + const levelProfile = this.getComplianceLevelSupportedFeatures(), + additionalProfile = Array.isArray(this.imageInfo.profile) && this.imageInfo.profile.length > 1, + profileSupports = additionalProfile && this.imageInfo.profile[1].supports ? this.imageInfo.profile[1].supports : [], + profileFormats = additionalProfile && this.imageInfo.profile[1].formats ? this.imageInfo.profile[1].formats : [], + profileQualities = additionalProfile && this.imageInfo.profile[1].qualities ? this.imageInfo.profile[1].qualities : [], + attributions = []; + if (this.imageInfo.attribution !== undefined) { + // TODO potentially dangerous + attributions.push(this.imageInfo.attribution); + } + if (this.imageInfo.license !== undefined) { + let license = this.imageInfo.license; + if (license.match(/^http(s)?:\/\//g)) { + license = '' + encodeURI(license) + ''; + } + // TODO potentially dangerous + attributions.push(license); + } + return { + url: this.imageInfo['@id'].replace(/\/?(info.json)?$/g, ''), + sizes: this.imageInfo.sizes === undefined ? undefined : this.imageInfo.sizes.map(function(size) { + return [size.width, size.height]; + }), + tileSize: this.imageInfo.tiles === undefined ? undefined : [ + this.imageInfo.tiles.map(function(tile) { + return tile.width; + })[0], + this.imageInfo.tiles.map(function(tile) { + return tile.height; + })[0] + ], + resolutions: this.imageInfo.tiles === undefined ? undefined : + this.imageInfo.tiles.map(function(tile) { + return tile.scaleFactors; + })[0], + supports: [...levelProfile.supports, ...profileSupports], + formats: [...levelProfile.formats, ...profileFormats], + qualities: [...levelProfile.qualities, ...profileQualities], + attributions: attributions.length == 0 ? undefined : attributions + }; + } + + /** + * @ignore + * @private + * @returns {object} Available options + */ + generateVersion3Options() { + const levelProfile = this.getComplianceLevelSupportedFeatures(); + return { + url: this.imageInfo['id'], + sizes: this.imageInfo.sizes === undefined ? undefined : this.imageInfo.sizes.map(function(size) { + return [size.width, size.height]; + }), + tileSize: this.imageInfo.tiles === undefined ? undefined : [ + this.imageInfo.tiles.map(function(tile) { + return tile.width; + })[0], + this.imageInfo.tiles.map(function(tile) { + return tile.height; + })[0] + ], + resolutions: this.imageInfo.tiles === undefined ? undefined : + this.imageInfo.tiles.map(function(tile) { + return tile.scaleFactors; + })[0], + supports: this.imageInfo.extraFeatures === undefined ? levelProfile.supports : + [...levelProfile.supports, ...this.imageInfo.extraFeatures], + formats: this.imageInfo.extraFormats === undefined ? levelProfile.formats : + [...levelProfile.formats, ...this.imageInfo.extraFormats], + qualities: this.imageInfo.extraQualities === undefined ? levelProfile.qualities : + [...levelProfile.extraQualities, ...this.imageInfo.extraQualities], + maxWidth: undefined, + maxHeight: undefined, + maxArea: undefined, + attributions: undefined + }; } } diff --git a/test/spec/ol/format/iiif.test.js b/test/spec/ol/format/iiif.test.js new file mode 100644 index 0000000000..ff5759d8c1 --- /dev/null +++ b/test/spec/ol/format/iiif.test.js @@ -0,0 +1,278 @@ +import IIIFInfo from '../../../../src/ol/format/IIIFInfo.js'; +import {Versions} from '../../../../src/ol/format/IIIFInfo.js'; + +describe('ol.format.IIIF', function() { + + const iiifInfo = new IIIFInfo(), + imageInfoVersion1_0Level0 = { + identifier: 'identifier-version-1.0', + width: 2000, + height: 1500, + profile: 'http://library.stanford.edu/iiif/image-api/compliance.html#level0' + }, + imageInfoVersion2Level1 = { + '@context': 'http://iiif.io/api/image/2/context.json', + '@id': 'http://iiif.test/version2/id', + width: 2000, + height: 1500, + profile: [ + 'http://iiif.io/api/image/2/level1.json' + ] + }, + imageInfoVersion2Level2 = { + '@context': 'http://iiif.io/api/image/2/context.json', + '@id': 'http://iiif.test/version2/id', + width: 2000, + height: 1500, + profile: [ + 'http://iiif.io/api/image/2/level2.json' + ] + }; + + describe('constructor', function() { + + }); + + describe('setImageInfo', function() { + + it('can handle image info JSON as object or as string serialization', function() { + + iiifInfo.setImageInfo({ + '@context': 'http://iiif.io/api/image/3/context.json', + '@id': 'http://iiif.test/id' + }); + expect(iiifInfo.getImageApiVersion()).to.be(Versions.VERSION3); + + iiifInfo.setImageInfo('{"@context": "http://iiif.io/api/image/2/context.json","@id":"http://iiif.test/id"}'); + expect(iiifInfo.getImageApiVersion()).to.be(Versions.VERSION2); + + }); + + }); + + describe('getImageApiVersion', function() { + + it('provides the correct Image API version', function() { + + iiifInfo.setImageInfo({ + '@id': 'http://iiif.test/id' + }); + expect(function() { + iiifInfo.getImageApiVersion(); + }).to.throwException(); + + iiifInfo.setImageInfo({ + 'identifier': 'http://iiif.test/id', + 'profile': 'this is no valid profile' + }); + expect(function() { + iiifInfo.getImageApiVersion(); + }).to.throwException(); + + iiifInfo.setImageInfo({ + '@context': 'this is no valid context', + '@id': 'http://iiif.test/id' + }); + expect(function() { + iiifInfo.getImageApiVersion(); + }).to.throwException(); + + iiifInfo.setImageInfo({ + 'identifier': 'http://iiif.test/id', + profile: 'http://library.stanford.edu/iiif/image-api/compliance.html#level0' + }); + expect(iiifInfo.getImageApiVersion()).to.be(Versions.VERSION1); + + iiifInfo.setImageInfo({ + '@context': 'http://library.stanford.edu/iiif/image-api/1.1/context.json', + '@id': 'http://iiif.test/id' + }); + expect(iiifInfo.getImageApiVersion()).to.be(Versions.VERSION1); + + iiifInfo.setImageInfo({ + '@context': 'http://iiif.io/api/image/1/context.json', + 'identifier': 'http://iiif.test/id' + }); + expect(iiifInfo.getImageApiVersion()).to.be(Versions.VERSION1); + + iiifInfo.setImageInfo({ + '@context': 'http://iiif.io/api/image/2/context.json', + '@id': 'http://iiif.test/id' + }); + expect(iiifInfo.getImageApiVersion()).to.be(Versions.VERSION2); + + iiifInfo.setImageInfo({ + '@context': 'http://iiif.io/api/image/3/context.json', + 'id': 'http://iiif.test/id' + }); + expect(iiifInfo.getImageApiVersion()).to.be(Versions.VERSION3); + + }); + + }); + + describe('getComplianceLevelFromProfile', function() { + + it('detects the correct compliance level', function() { + + iiifInfo.setImageInfo({ + '@context': 'http://iiif.io/api/image/2/context.json', + 'profile': 'level0' + }); + expect(iiifInfo.getComplianceLevelFromProfile()).to.be(undefined); + + iiifInfo.setImageInfo({ + '@context': 'http://iiif.io/api/image/2/context.json', + 'profile': 'http://iiif.io/api/image/level3.json' + }); + expect(iiifInfo.getComplianceLevelFromProfile()).to.be(undefined); + + iiifInfo.setImageInfo({ + '@context': 'http://iiif.io/api/image/2/context.json', + 'profile': 'level1' + }); + expect(iiifInfo.getComplianceLevelFromProfile()).to.be(undefined); + + iiifInfo.setImageInfo({ + '@context': 'http://iiif.io/api/image/2/context.json', + 'profile': 'http://iiif.io/api/image/2/level2.json' + }); + expect(iiifInfo.getComplianceLevelFromProfile()).to.be('level2'); + + iiifInfo.setImageInfo({ + '@context': 'http://iiif.io/api/image/2/context.json', + 'profile': ['http://iiif.io/api/image/2/level1.json'] + }); + expect(iiifInfo.getComplianceLevelFromProfile()).to.be('level1'); + + iiifInfo.setImageInfo({ + '@context': 'http://iiif.io/api/image/3/context.json', + 'profile': 'level4' + }); + expect(iiifInfo.getComplianceLevelFromProfile()).to.be(undefined); + + iiifInfo.setImageInfo({ + '@context': 'http://iiif.io/api/image/3/context.json', + 'profile': 'http://iiif.io/api/image/3/level3.json' + }); + expect(iiifInfo.getComplianceLevelFromProfile()).to.be(undefined); + + iiifInfo.setImageInfo({ + '@context': 'http://iiif.io/api/image/3/context.json', + 'profile': 'http://iiif.io/api/image/2/level1.json' + }); + expect(iiifInfo.getComplianceLevelFromProfile()).to.be(undefined); + + iiifInfo.setImageInfo({ + '@context': 'http://iiif.io/api/image/3/context.json', + 'profile': 'level2' + }); + expect(iiifInfo.getComplianceLevelFromProfile()).to.be('level2'); + + iiifInfo.setImageInfo({ + '@context': 'http://iiif.io/api/image/3/context.json', + 'profile': 'http://iiif.io/api/image/3/level1.json' + }); + expect(iiifInfo.getComplianceLevelFromProfile()).to.be('level1'); + }); + + }); + + describe('getComplianceLevelSupportedFeatures', function() { + + it('provides the correct features for given versions and compliance levels', function() { + + iiifInfo.setImageInfo({ + '@context': 'http://library.stanford.edu/iiif/image-api/1.1/context.json', + 'profile': 'http://library.stanford.edu/iiif/image-api/compliance.html#level0' + }); + expect(); + + }); + + }); + + describe('getTileSourceOptions', function() { + + it('produces options from minimal information responses', function() { + + let imageInfo = { + width: 2000, + height: 1500 + }; + + expect(function() { + iiifInfo.setImageInfo(imageInfo); + iiifInfo.getTileSourceOptions(); + }).to.throwException(); + + imageInfo = { + identifier: 'id', + profile: 'http://library.stanford.edu/iiif/image-api/compliance.html#level0' + }; + + iiifInfo.setImageInfo(imageInfo); + let options = iiifInfo.getTileSourceOptions(imageInfo); + + expect(options).to.be.an('object'); + expect(options).to.have.property('version', Versions.VERSION1); + + iiifInfo.setImageInfo(imageInfoVersion1_0Level0); + options = iiifInfo.getTileSourceOptions(); + + expect(options).to.not.be(undefined); + expect(options).to.not.be(null); + expect(options).to.have.property('version', Versions.VERSION1); + expect(options).to.have.property('size'); + expect(options.size).to.be.an('array'); + expect(options.size.length).to.be(2); + expect(options.size[0]).to.be(2000); + expect(options.size[1]).to.be(1500); + expect(options.quality).to.be('native'); + expect(options.url).to.be(undefined); + expect(options.sizes).to.be(undefined); + expect(options.tileSize).to.be(undefined); + expect(options.format).to.be('jpg'); + expect(options.supports).to.be.empty(); + + imageInfo = { + '@context': 'http://iiif.io/api/image/2/context.json', + '@id': 'http://iiif.test/version2/id' + }; + iiifInfo.setImageInfo(imageInfo); + options = iiifInfo.getTileSourceOptions(); + + expect(options).to.be.an('object'); + expect(options).to.have.property('version', Versions.VERSION2); + expect(options).to.have.property('url', 'http://iiif.test/version2/id'); + expect(options).to.have.property('format', 'jpg'); + + }); + + it('uses preferred options if applicable', function() { + + iiifInfo.setImageInfo(imageInfoVersion2Level2); + const options = iiifInfo.getTileSourceOptions({ + quality: 'bitonal', + format: 'png' + }); + expect(options).to.have.property('quality', 'bitonal'); + expect(options).to.have.property('format', 'png'); + + }); + + it('ignores preferred options that are not supported', function() { + + iiifInfo.setImageInfo(imageInfoVersion2Level1); + const options = iiifInfo.getTileSourceOptions({ + quality: 'bitonal', + format: 'png' + }); + expect(options).to.have.property('quality', 'default'); + expect(options).to.have.property('format', 'jpg'); + + }); + + }); + +});