/* * OpenSeadragon - IIIFTileSource * * Copyright (C) 2009 CodePlex Foundation * Copyright (C) 2010-2013 OpenSeadragon contributors * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of CodePlex Foundation nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ (function( $ ){ /** * @class IIIFTileSource * @classdesc A client implementation of the International Image Interoperability Framework * Format: Image API 1.0 - 2.1 * * @memberof OpenSeadragon * @extends OpenSeadragon.TileSource * @see http://iiif.io/api/image/ */ $.IIIFTileSource = function( options ){ $.extend( true, this, options ); if ( !( this.height && this.width && this['@id'] ) ) { throw new Error( 'IIIF required parameters not provided.' ); } options.tileSizePerScaleFactor = {}; // N.B. 2.0 renamed scale_factors to scaleFactors if ( this.tile_width && this.tile_height ) { options.tileWidth = this.tile_width; options.tileHeight = this.tile_height; } else if ( this.tile_width ) { options.tileSize = this.tile_width; } else if ( this.tile_height ) { options.tileSize = this.tile_height; } else if ( this.tiles ) { // Version 2.0 forwards if ( this.tiles.length == 1 ) { options.tileWidth = this.tiles[0].width; // Use height if provided, otherwise assume square tiles and use width. options.tileHeight = this.tiles[0].height || this.tiles[0].width; this.scale_factors = this.tiles[0].scaleFactors; } else { // Multiple tile sizes at different levels this.scale_factors = []; for (var t = 0; t < this.tiles.length; t++ ) { for (var sf = 0; sf < this.tiles[t].scaleFactors.length; sf++) { var scaleFactor = this.tiles[t].scaleFactors[sf]; this.scale_factors.push(scaleFactor); options.tileSizePerScaleFactor[scaleFactor] = { width: this.tiles[t].width, height: this.tiles[t].height || this.tiles[t].width }; } } } } else if ( canBeTiled(options.profile) ) { // use the largest of tileOptions that is smaller than the short dimension var shortDim = Math.min( this.height, this.width ), tileOptions = [256,512,1024], smallerTiles = []; for ( var c = 0; c < tileOptions.length; c++ ) { if ( tileOptions[c] <= shortDim ) { smallerTiles.push( tileOptions[c] ); } } if ( smallerTiles.length > 0 ) { options.tileSize = Math.max.apply( null, smallerTiles ); } else { // If we're smaller than 256, just use the short side. options.tileSize = shortDim; } } else if (this.sizes && this.sizes.length > 0) { // This info.json can't be tiled, but we can still construct a legacy pyramid from the sizes array. // In this mode, IIIFTileSource will call functions from the abstract baseTileSource or the // LegacyTileSource instead of performing IIIF tiling. this.emulateLegacyImagePyramid = true; options.levels = constructLevels( this ); // use the largest available size to define tiles $.extend( true, options, { width: options.levels[ options.levels.length - 1 ].width, height: options.levels[ options.levels.length - 1 ].height, tileSize: Math.max( options.height, options.width ), tileOverlap: 0, minLevel: 0, maxLevel: options.levels.length - 1 }); this.levels = options.levels; } else { $.console.error("Nothing in the info.json to construct image pyramids from"); } if (!options.maxLevel && !this.emulateLegacyImagePyramid) { if (!this.scale_factors) { options.maxLevel = Number(Math.ceil(Math.log(Math.max(this.width, this.height), 2))); } else { options.maxLevel = Math.floor(Math.pow(Math.max.apply(null, this.scale_factors), 0.5)); } } $.TileSource.apply( this, [ options ] ); }; $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.IIIFTileSource.prototype */{ /** * Determine if the data and/or url imply the image service is supported by * this tile source. * @function * @param {Object|Array} data * @param {String} optional - url */ supports: function( data, url ) { // Version 2.0 and forwards if (data.protocol && data.protocol == 'http://iiif.io/api/image') { return true; // Version 1.1 } else if ( data['@context'] && ( data['@context'] == "http://library.stanford.edu/iiif/image-api/1.1/context.json" || data['@context'] == "http://iiif.io/api/image/1/context.json") ) { // N.B. the iiif.io context is wrong, but where the representation lives so likely to be used return true; // Version 1.0 } else if ( data.profile && data.profile.indexOf("http://library.stanford.edu/iiif/image-api/compliance.html") === 0) { return true; } else if ( data.identifier && data.width && data.height ) { return true; } else if ( data.documentElement && "info" == data.documentElement.tagName && "http://library.stanford.edu/iiif/image-api/ns/" == data.documentElement.namespaceURI) { return true; // Not IIIF } else { return false; } }, /** * * @function * @param {Object} data - the raw configuration * @example