Added Layer.Zoomify. This is a late follow-up on the FOSS4G 2009 sprint

in Sydney. Thanks Petr for the hard work on this. p=klokan, r=me (closes 
#1285)


git-svn-id: http://svn.openlayers.org/trunk/openlayers@10086 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
ahocevar
2010-03-04 08:41:18 +00:00
parent 8adcc155fb
commit 22f0f933fb
3 changed files with 377 additions and 0 deletions

70
examples/zoomify.html Normal file
View File

@@ -0,0 +1,70 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>OpenLayers Zoomify Example</title>
<link rel="stylesheet" href="../theme/default/style.css" type="text/css" />
<link rel="stylesheet" href="style.css" type="text/css" />
<script src="../lib/OpenLayers.js"></script>
<script type="text/javascript">
var zoomify_width = 8001;
var zoomify_height = 6943;
var zoomify_url = "http://almor.mzk.cz/moll/AA22/0103/";
var map, zoomify;
function init(){
/* First we initialize the zoomify pyramid (to get number of tiers) */
var zoomify = new OpenLayers.Layer.Zoomify( "Zoomify", zoomify_url,
new OpenLayers.Size( zoomify_width, zoomify_height ) );
/* Map with raster coordinates (pixels) from Zoomify image */
var options = {
controls: [],
maxExtent: new OpenLayers.Bounds(0, 0, zoomify_width, zoomify_height),
maxResolution: Math.pow(2, zoomify.numberOfTiers-1 ),
numZoomLevels: zoomify.numberOfTiers,
units: 'pixels'
};
map = new OpenLayers.Map("map", options);
map.addLayer(zoomify);
map.addControl(new OpenLayers.Control.MousePosition());
map.addControl(new OpenLayers.Control.PanZoomBar());
map.addControl(new OpenLayers.Control.MouseDefaults());
map.addControl(new OpenLayers.Control.KeyboardDefaults());
map.setBaseLayer(zoomify);
map.zoomToMaxExtent();
};
</script>
</head>
<body onload="init()">
<h1 id="title">Zoomify Layer Example</h1>
<div id="tags"></div>
<p id="shortdesc">
Demo of a layer with Zoomify tiles.
</p>
<div id="map" class="smallmap"></div>
<div id="docs">
<p>
Demonstration of the Zoomify layer in OpenLayers.<br />
You can have a look at <a href="http://almor.mzk.cz/moll/AA22/103.html">Zoomify viewer for this picture</a>, which is using the same <a href="http://almor.mzk.cz/moll/AA22/0103/">tiles</a>.
</p>
<p>
For change to our own image you have to specify 'url' (zoomifyImagePath in Zoomify terminology) and 'size' ('width' and 'height' from ImageProperty.xml file).<br />
Custom tiles can be easily generated with original <a href="http://www.zoomify.com/">Zoomify software</a> like with freely available <a href="http://www.zoomify.com/express.htm">ZoomifyerEZ</a> or with Adobe PhotoShop CS3 (it has built in support for export into Zoomify tiles).<br />
There is also a <a href="http://sourceforge.net/projects/zoomifyimage/">ZoomifyImage SourceForge Project</a>, a tile cutter available under GPL license.<br />
Zoomify tiles can be also served dynamically on the server side from JPEG2000 masters using <a href="http://dltj.org/article/introducing-j2ktilerenderer/">J2KTileRender</a> with available integration for DSpace and soon for Fedora Digital Repository.<br/>
<a href="http://iipimage.sourceforge.net/">IIPImage server</a> can serve Zoomify tiles dynamically from TIFF files.
</p>
<p>
Development of the Zoomify support for OpenLayers was supported from the grant <a href="http://www.oldmapsonline.org/">Old Maps Online</a>.
</p>
</div>
</body>
</html>

View File

@@ -130,6 +130,7 @@
"OpenLayers/Layer/XYZ.js",
"OpenLayers/Layer/TMS.js",
"OpenLayers/Layer/TileCache.js",
"OpenLayers/Layer/Zoomify.js",
"OpenLayers/Popup/Anchored.js",
"OpenLayers/Popup/AnchoredBubble.js",
"OpenLayers/Popup/Framed.js",

View File

@@ -0,0 +1,306 @@
/* Copyright (c) 2008 Klokan Petr Pridal, published under the Clear BSD
* licence. See http://svn.openlayers.org/trunk/openlayers/license.txt for the
* full text of the license. */
/*
* Development supported by a R&D grant DC08P02OUK006 - Old Maps Online
* (www.oldmapsonline.org) from Ministry of Culture of the Czech Republic.
*/
/**
* @requires OpenLayers/Layer/Grid.js
*/
/**
* Class: OpenLayers.Layer.Zoomify
*
* Inherits from:
* - <OpenLayers.Layer.Grid>
*/
OpenLayers.Layer.Zoomify = OpenLayers.Class(OpenLayers.Layer.Grid, {
/**
* Property: url
* {String} URL for root directory with TileGroupX subdirectories.
*/
url: null,
/**
* Property: size
* {<OpenLayers.Size>} The Zoomify image size in pixels.
*/
size: null,
/**
* APIProperty: isBaseLayer
* {Boolean}
*/
isBaseLayer: true,
/**
* Property: standardTileSize
* {Integer} The size of a standard (non-border) square tile in pixels.
*/
standardTileSize: 256,
/**
* Property: numberOfTiers
* {Integer} Depth of the Zoomify pyramid, number of tiers (zoom levels)
* - filled during Zoomify pyramid initialization.
*/
numberOfTiers: 0,
/**
* Property: tileCountUpToTier
* {Array(Integer)} Number of tiles up to the given tier of pyramid.
* - filled during Zoomify pyramid initialization.
*/
tileCountUpToTier: new Array(),
/**
* Property: tierSizeInTiles
* {Array(<OpenLayers.Size>)} Size (in tiles) for each tier of pyramid.
* - filled during Zoomify pyramid initialization.
*/
tierSizeInTiles: new Array(),
/**
* Property: tierImageSize
* {Array(<OpenLayers.Size>)} Image size in pixels for each pyramid tier.
* - filled during Zoomify pyramid initialization.
*/
tierImageSize: new Array(),
/**
* Constructor: OpenLayers.Layer.Zoomify
*
* Parameters:
* name - {String} A name for the layer.
* url - {String} - Relative or absolute path to the image or more
* precisly to the TileGroup[X] directories root.
* Flash plugin use the variable name "zoomifyImagePath" for this.
* size - {<OpenLayers.Size>} The size (in pixels) of the image.
* options - {Object} Hashtable of extra options to tag onto the layer
*/
initialize: function(name, url, size, options) {
// initilize the Zoomify pyramid for given size
this.initializeZoomify( size );
var newArguments = [];
newArguments.push(name, url, size, {}, options);
OpenLayers.Layer.Grid.prototype.initialize.apply(this, newArguments);
},
/**
* Method: initializeZoomify
* It generates constants for all tiers of the Zoomify pyramid
*
* Parameters:
* size - {<OpenLayers.Size>} The size of the image in pixels
*
*/
initializeZoomify: function( size ) {
var imageSize = size.clone()
var tiles = new OpenLayers.Size(
Math.ceil( imageSize.w / this.standardTileSize ),
Math.ceil( imageSize.h / this.standardTileSize )
);
this.tierSizeInTiles.push( tiles );
this.tierImageSize.push( imageSize );
while (imageSize.w > this.standardTileSize ||
imageSize.h > this.standardTileSize ) {
imageSize = new OpenLayers.Size(
Math.floor( imageSize.w / 2 ),
Math.floor( imageSize.h / 2 )
);
tiles = new OpenLayers.Size(
Math.ceil( imageSize.w / this.standardTileSize ),
Math.ceil( imageSize.h / this.standardTileSize )
);
this.tierSizeInTiles.push( tiles );
this.tierImageSize.push( imageSize );
}
this.tierSizeInTiles.reverse();
this.tierImageSize.reverse();
this.numberOfTiers = this.tierSizeInTiles.length;
this.tileCountUpToTier[0] = 0;
for (var i = 1; i < this.numberOfTiers; i++) {
this.tileCountUpToTier.push(
this.tierSizeInTiles[i-1].w * this.tierSizeInTiles[i-1].h +
this.tileCountUpToTier[i-1]
);
}
},
/**
* APIMethod:destroy
*/
destroy: function() {
// for now, nothing special to do here.
OpenLayers.Layer.Grid.prototype.destroy.apply(this, arguments);
// Remove from memory the Zoomify pyramid - is that enough?
this.tileCountUpToTier.length = 0
this.tierSizeInTiles.length = 0
this.tierImageSize.length = 0
},
/**
* APIMethod: clone
*
* Parameters:
* obj - {Object}
*
* Returns:
* {<OpenLayers.Layer.Zoomify>} An exact clone of this <OpenLayers.Layer.Zoomify>
*/
clone: function (obj) {
if (obj == null) {
obj = new OpenLayers.Layer.Zoomify(this.name,
this.url,
this.size,
this.options);
}
//get all additions from superclasses
obj = OpenLayers.Layer.Grid.prototype.clone.apply(this, [obj]);
// copy/set any non-init, non-simple values here
return obj;
},
/**
* Method: getURL
*
* Parameters:
* bounds - {<OpenLayers.Bounds>}
*
* Returns:
* {String} A string with the layer's url and parameters and also the
* passed-in bounds and appropriate tile size specified as
* parameters
*/
getURL: function (bounds) {
bounds = this.adjustBounds(bounds);
var res = this.map.getResolution();
var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w));
var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h));
var z = this.map.getZoom();
var tileIndex = x + y * this.tierSizeInTiles[z].w + this.tileCountUpToTier[z];
var path = "TileGroup" + Math.floor( (tileIndex) / 256 ) +
"/" + z + "-" + x + "-" + y + ".jpg";
var url = this.url;
if (url instanceof Array) {
url = this.selectUrl(path, url);
}
return url + path;
},
/**
* Method: getImageSize
* getImageSize returns size for a particular tile. If bounds are given as
* first argument, size is calculated (bottom-right tiles are non square).
*
*/
getImageSize: function() {
if (arguments.length > 0) {
bounds = this.adjustBounds(arguments[0]);
var res = this.map.getResolution();
var x = Math.round((bounds.left - this.tileOrigin.lon) / (res * this.tileSize.w));
var y = Math.round((this.tileOrigin.lat - bounds.top) / (res * this.tileSize.h));
var z = this.map.getZoom();
var w = this.standardTileSize;
var h = this.standardTileSize;
if (x == this.tierSizeInTiles[z].w -1 ) {
var w = this.tierImageSize[z].w % this.standardTileSize;
};
if (y == this.tierSizeInTiles[z].h -1 ) {
var h = this.tierImageSize[z].h % this.standardTileSize;
};
return (new OpenLayers.Size(w, h));
} else {
return this.tileSize;
}
},
/**
* Method: addTile
* addTile creates a tile, initializes it, and adds it to the layer div.
*
* Parameters:
* bounds - {<OpenLayers.Bounds>}
* position - {<OpenLayers.Pixel>}
*
* Returns:
* {<OpenLayers.Tile.Image>} The added OpenLayers.Tile.Image
*/
addTile:function(bounds,position) {
return new OpenLayers.Tile.Image(this, position, bounds,
null, this.tileSize);
},
/**
* APIMethod: setMap
* When the layer is added to a map, then we can fetch our origin
* (if we don't have one.)
*
* Parameters:
* map - {<OpenLayers.Map>}
*/
setMap: function(map) {
OpenLayers.Layer.Grid.prototype.setMap.apply(this, arguments);
this.tileOrigin = new OpenLayers.LonLat(this.map.maxExtent.left,
this.map.maxExtent.top);
},
/**
* Method: calculateGridLayout
* Generate parameters for the grid layout. This
*
* Parameters:
* bounds - {<OpenLayers.Bound>}
* extent - {<OpenLayers.Bounds>}
* resolution - {Number}
*
* Returns:
* Object containing properties tilelon, tilelat, tileoffsetlat,
* tileoffsetlat, tileoffsetx, tileoffsety
*/
calculateGridLayout: function(bounds, extent, resolution) {
var tilelon = resolution * this.tileSize.w;
var tilelat = resolution * this.tileSize.h;
var offsetlon = bounds.left - extent.left;
var tilecol = Math.floor(offsetlon/tilelon) - this.buffer;
var tilecolremain = offsetlon/tilelon - tilecol;
var tileoffsetx = -tilecolremain * this.tileSize.w;
var tileoffsetlon = extent.left + tilecol * tilelon;
var offsetlat = extent.top - bounds.top + tilelat;
var tilerow = Math.floor(offsetlat/tilelat) - this.buffer;
var tilerowremain = tilerow - offsetlat/tilelat;
var tileoffsety = tilerowremain * this.tileSize.h;
var tileoffsetlat = extent.top - tilelat*tilerow;
return {
tilelon: tilelon, tilelat: tilelat,
tileoffsetlon: tileoffsetlon, tileoffsetlat: tileoffsetlat,
tileoffsetx: tileoffsetx, tileoffsety: tileoffsety
};
},
CLASS_NAME: "OpenLayers.Layer.Zoomify"
});