2012-02-23 08:02:54 +04:00
|
|
|
|
|
|
|
(function( $ ){
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The LegacyTileSource allows simple, traditional image pyramids to be loaded
|
|
|
|
* into an OpenSeadragon Viewer. Basically, this translates to the historically
|
|
|
|
* common practice of starting with a 'master' image, maybe a tiff for example,
|
|
|
|
* and generating a set of 'service' images like one or more thumbnails, a medium
|
|
|
|
* resolution image and a high resolution image in standard web formats like
|
|
|
|
* png or jpg.
|
|
|
|
* @class
|
2012-06-05 15:52:00 +04:00
|
|
|
* @param {Array} levels An array of file descriptions, each is an object with
|
2012-02-23 08:02:54 +04:00
|
|
|
* a 'url', a 'width', and a 'height'. Overriding classes can expect more
|
|
|
|
* properties but these properties are sufficient for this implementation.
|
2012-06-05 15:52:00 +04:00
|
|
|
* Additionally, the levels are required to be listed in order from
|
2012-02-23 08:02:54 +04:00
|
|
|
* smallest to largest.
|
|
|
|
* @property {Number} aspectRatio
|
|
|
|
* @property {Number} dimensions
|
|
|
|
* @property {Number} tileSize
|
|
|
|
* @property {Number} tileOverlap
|
|
|
|
* @property {Number} minLevel
|
|
|
|
* @property {Number} maxLevel
|
2012-06-05 15:52:00 +04:00
|
|
|
* @property {Array} levels
|
2012-02-23 08:02:54 +04:00
|
|
|
*/
|
2012-06-05 15:52:00 +04:00
|
|
|
$.LegacyTileSource = function( levels ) {
|
|
|
|
|
|
|
|
var options,
|
|
|
|
width,
|
|
|
|
height;
|
|
|
|
|
|
|
|
if( $.isArray( levels ) ){
|
|
|
|
options = {
|
|
|
|
type: 'legacy-image-pyramid',
|
|
|
|
levels: levels
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
//clean up the levels to make sure we support all formats
|
|
|
|
options.levels = filterFiles( options.levels );
|
|
|
|
width = options.levels[ options.levels.length - 1 ].width;
|
|
|
|
height = options.levels[ options.levels.length - 1 ].height;
|
|
|
|
|
|
|
|
$.extend( true, options, {
|
|
|
|
width: width,
|
|
|
|
height: height,
|
|
|
|
tileSize: Math.max( height, width ),
|
|
|
|
tileOverlap: 0,
|
|
|
|
minLevel: 0,
|
|
|
|
maxLevel: options.levels.length - 1
|
|
|
|
});
|
|
|
|
|
|
|
|
$.TileSource.apply( this, [ options ] );
|
|
|
|
|
|
|
|
this.levels = options.levels;
|
2012-02-23 08:02:54 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
$.LegacyTileSource.prototype = {
|
2012-06-05 15:52:00 +04:00
|
|
|
/**
|
|
|
|
* Determine if the data and/or url imply the image service is supported by
|
|
|
|
* this tile source.
|
|
|
|
* @function
|
|
|
|
* @name OpenSeadragon.DziTileSource.prototype.supports
|
|
|
|
* @param {Object|Array} data
|
|
|
|
* @param {String} optional - url
|
|
|
|
*/
|
|
|
|
supports: function( data, url ){
|
|
|
|
return (
|
|
|
|
data.type &&
|
|
|
|
"legacy-image-pyramid" == data.type
|
|
|
|
) || (
|
|
|
|
data.documentElement &&
|
|
|
|
"legacy-image-pyramid" == data.documentElement.getAttribute('type')
|
|
|
|
);
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @function
|
|
|
|
* @name OpenSeadragon.DziTileSource.prototype.configure
|
|
|
|
* @param {Object|XMLDocument} configuration - the raw configuration
|
|
|
|
* @param {String} dataUrl - the url the data was retreived from if any.
|
|
|
|
* @return {Array} args - positional arguments required and/or optional
|
|
|
|
* for this tile sources constructor
|
|
|
|
*/
|
|
|
|
configure: function( configuration, dataUrl ){
|
|
|
|
|
|
|
|
var options;
|
|
|
|
|
|
|
|
if( configuration instanceof XMLDocument ){
|
|
|
|
|
|
|
|
options = configureFromXML( this, configuration );
|
|
|
|
|
|
|
|
}else if( 'object' == $.type( configuration) ){
|
|
|
|
|
|
|
|
options = configureFromObject( this, configuration );
|
|
|
|
}
|
|
|
|
|
|
|
|
return options;
|
|
|
|
|
|
|
|
},
|
2012-02-23 08:02:54 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @function
|
|
|
|
* @param {Number} level
|
|
|
|
*/
|
|
|
|
getLevelScale: function( level ) {
|
|
|
|
var levelScale = NaN;
|
|
|
|
if ( level >= this.minLevel && level <= this.maxLevel ){
|
|
|
|
levelScale =
|
2012-06-05 15:52:00 +04:00
|
|
|
this.levels[ level ].width /
|
|
|
|
this.levels[ this.maxLevel ].width;
|
2012-02-23 08:02:54 +04:00
|
|
|
}
|
|
|
|
return levelScale;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function
|
|
|
|
* @param {Number} level
|
|
|
|
*/
|
|
|
|
getNumTiles: function( level ) {
|
|
|
|
var scale = this.getLevelScale( level );
|
|
|
|
if ( scale ){
|
|
|
|
return new $.Point( 1, 1 );
|
|
|
|
} else {
|
|
|
|
return new $.Point( 0, 0 );
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function
|
|
|
|
* @param {Number} level
|
|
|
|
*/
|
|
|
|
getPixelRatio: function( level ) {
|
|
|
|
var imageSizeScaled = this.dimensions.times( this.getLevelScale( level ) ),
|
|
|
|
rx = 1.0 / imageSizeScaled.x,
|
|
|
|
ry = 1.0 / imageSizeScaled.y;
|
|
|
|
|
|
|
|
return new $.Point(rx, ry);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function
|
|
|
|
* @param {Number} level
|
|
|
|
* @param {OpenSeadragon.Point} point
|
|
|
|
*/
|
|
|
|
getTileAtPoint: function( level, point ) {
|
|
|
|
return new $.Point( 0, 0 );
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function
|
|
|
|
* @param {Number} level
|
|
|
|
* @param {Number} x
|
|
|
|
* @param {Number} y
|
|
|
|
*/
|
|
|
|
getTileBounds: function( level, x, y ) {
|
|
|
|
var dimensionsScaled = this.dimensions.times( this.getLevelScale( level ) ),
|
2012-06-05 15:52:00 +04:00
|
|
|
px = ( x === 0 ) ? 0 : this.levels[ level ].width,
|
|
|
|
py = ( y === 0 ) ? 0 : this.levels[ level ].height,
|
|
|
|
sx = this.levels[ level ].width,
|
|
|
|
sy = this.levels[ level ].height,
|
2012-04-03 11:08:27 +04:00
|
|
|
scale = 1.0 / ( this.width >= this.height ?
|
|
|
|
dimensionsScaled.y :
|
|
|
|
dimensionsScaled.x
|
2012-02-23 08:02:54 +04:00
|
|
|
);
|
|
|
|
|
|
|
|
sx = Math.min( sx, dimensionsScaled.x - px );
|
|
|
|
sy = Math.min( sy, dimensionsScaled.y - py );
|
|
|
|
|
|
|
|
return new $.Rect( px * scale, py * scale, sx * scale, sy * scale );
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method is not implemented by this class other than to throw an Error
|
|
|
|
* announcing you have to implement it. Because of the variety of tile
|
|
|
|
* server technologies, and various specifications for building image
|
|
|
|
* pyramids, this method is here to allow easy integration.
|
|
|
|
* @function
|
|
|
|
* @param {Number} level
|
|
|
|
* @param {Number} x
|
|
|
|
* @param {Number} y
|
|
|
|
* @throws {Error}
|
|
|
|
*/
|
|
|
|
getTileUrl: function( level, x, y ) {
|
|
|
|
var url = null;
|
|
|
|
if( level >= this.minLevel && level <= this.maxLevel ){
|
2012-06-05 15:52:00 +04:00
|
|
|
url = this.levels[ level ].url;
|
2012-02-23 08:02:54 +04:00
|
|
|
}
|
|
|
|
return url;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function
|
|
|
|
* @param {Number} level
|
|
|
|
* @param {Number} x
|
|
|
|
* @param {Number} y
|
|
|
|
*/
|
|
|
|
tileExists: function( level, x, y ) {
|
|
|
|
var numTiles = this.getNumTiles( level );
|
|
|
|
return level >= this.minLevel &&
|
|
|
|
level <= this.maxLevel &&
|
|
|
|
x >= 0 &&
|
|
|
|
y >= 0 &&
|
|
|
|
x < numTiles.x &&
|
|
|
|
y < numTiles.y;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-06-05 15:52:00 +04:00
|
|
|
/**
|
|
|
|
* This method removes any files from the Array which dont conform to our
|
|
|
|
* basic requirements for a 'level' in the LegacyTileSource.
|
|
|
|
* @private
|
|
|
|
* @inner
|
|
|
|
* @function
|
|
|
|
*/
|
|
|
|
function filterFiles( files ){
|
|
|
|
var filtered = [],
|
|
|
|
file,
|
|
|
|
i;
|
|
|
|
for( i = 0; i < files.length; i++ ){
|
|
|
|
file = files[ i ];
|
|
|
|
if( file.height &&
|
|
|
|
file.width &&
|
|
|
|
file.url && (
|
|
|
|
file.url.toLowerCase().match(/^.*\.(png|jpg|jpeg|gif)$/) || (
|
|
|
|
file.mimetype &&
|
|
|
|
file.mimetype.toLowerCase().match(/^.*\/(png|jpg|jpeg|gif)$/)
|
|
|
|
)
|
|
|
|
) ){
|
|
|
|
//This is sufficient to serve as a level
|
|
|
|
filtered.push({
|
|
|
|
url: file.url,
|
|
|
|
width: Number( file.width ),
|
|
|
|
height: Number( file.height )
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return filtered.sort(function(a,b){
|
|
|
|
return a.height - b.height;
|
|
|
|
});
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
* @inner
|
|
|
|
* @function
|
|
|
|
*/
|
|
|
|
function configureFromXML( tileSource, xmlDoc ){
|
|
|
|
|
|
|
|
if ( !xmlDoc || !xmlDoc.documentElement ) {
|
|
|
|
throw new Error( $.getString( "Errors.Xml" ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
var root = xmlDoc.documentElement,
|
|
|
|
rootName = root.tagName,
|
|
|
|
conf = null,
|
|
|
|
levels = [],
|
|
|
|
level,
|
|
|
|
i;
|
|
|
|
|
|
|
|
if ( rootName == "image" ) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
conf = {
|
|
|
|
type: root.getAttribute( "type" ),
|
|
|
|
levels: []
|
|
|
|
};
|
|
|
|
|
|
|
|
levels = root.getElementsByTagName( "level" );
|
|
|
|
for ( i = 0; i < levels.length; i++ ) {
|
|
|
|
level = levels[ i ];
|
|
|
|
|
|
|
|
conf.levels .push({
|
|
|
|
url: level.getAttribute( "url" ),
|
|
|
|
width: parseInt( level.getAttribute( "width" ) ),
|
|
|
|
height: parseInt( level.getAttribute( "height" ) )
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return configureFromObject( tileSource, conf );
|
|
|
|
|
|
|
|
} catch ( e ) {
|
|
|
|
throw (e instanceof Error) ?
|
|
|
|
e :
|
|
|
|
new Error( 'Unknown error parsing Legacy Image Pyramid XML.' );
|
|
|
|
}
|
|
|
|
} else if ( rootName == "collection" ) {
|
|
|
|
throw new Error( 'Legacy Image Pyramid Collections not yet supported.' );
|
|
|
|
} else if ( rootName == "error" ) {
|
|
|
|
throw new Error( 'Error: ' + xmlDoc );
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new Error( 'Unknown element ' + rootName );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
* @inner
|
|
|
|
* @function
|
|
|
|
*/
|
|
|
|
function configureFromObject( tileSource, configuration ){
|
|
|
|
|
|
|
|
return configuration.levels;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
2012-02-23 08:02:54 +04:00
|
|
|
}( OpenSeadragon ));
|