-
-
Save bdunnette/9675483 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// hacked together aperio support | |
(function( $ ){ | |
/** | |
* A client implementation of the Aperio ImageServer Format | |
* | |
* @class | |
* @extends OpenSeadragon.TileSource | |
* @param {Number|Object} width - the pixel width of the image or the idiomatic | |
* options object which is used instead of positional arguments. | |
* @param {Number} height | |
* @param {Number} tileSize | |
* @param {String} tilesUrl | |
*/ | |
$.AperioTileSource = function( width, height, tileSize, tilesUrl ) { | |
var options; | |
if( $.isPlainObject( width ) ){ | |
options = width; | |
}else{ | |
options = { | |
width: arguments[0], | |
height: arguments[1], | |
tileSize: arguments[2], | |
tilesUrl: arguments[3] | |
}; | |
} | |
if( !options.width || !options.height || !options.tilesUrl ){ | |
throw new Error('width, height, and tilesUrl parameters are required.'); | |
} | |
if( !options.tileSize ){ | |
options.tileSize = 256; | |
} | |
console.log(options); | |
// Initialization stuff | |
var imageSize = new $.Point(options.width, options.height); | |
var tiles = new $.Point( | |
Math.ceil(options.width / options.tileSize), | |
Math.ceil(options.height / options.tileSize) | |
); | |
// Create an arrays showing tier dimensions (in pixels and tiles) | |
// A tier is essentially a zoom level | |
this.tierSizeInTiles = [tiles]; | |
this.tierImageSize = [imageSize]; | |
while (imageSize.x > options.tileSize || | |
imageSize.y > options.tileSize ) { | |
imageSize = new $.Point( | |
Math.floor( imageSize.x / 2 ), | |
Math.floor( imageSize.y / 2 ) | |
); | |
tiles = new $.Point( | |
Math.ceil( imageSize.x / options.tileSize ), | |
Math.ceil( imageSize.y / options.tileSize ) | |
); | |
this.tierSizeInTiles.push( tiles ); | |
this.tierImageSize.push( imageSize ); | |
} | |
this.tierSizeInTiles.reverse(); | |
this.tierImageSize.reverse(); | |
this.numberOfTiers = this.tierSizeInTiles.length; | |
options.maxLevel = this.numberOfTiers; | |
// In order to calculate the TileGroup, we need to have an index of the | |
// number of tiles in each tier | |
this.tileCountUpToTier = [0]; | |
for (var i = 1; i < this.numberOfTiers; i++) { | |
this.tileCountUpToTier.push( | |
this.tierSizeInTiles[i-1].x * this.tierSizeInTiles[i-1].y + | |
this.tileCountUpToTier[i-1] | |
); | |
} | |
$.TileSource.apply( this, [ options ] ); | |
}; | |
$.extend( $.AperioTileSource.prototype, $.TileSource.prototype, { | |
/** | |
* Determine if the data and/or url imply the image service is supported by | |
* this tile source. | |
* @function | |
* @name OpenSeadragon.AperioTileSource.prototype.supports | |
* @param {Object|Array} data | |
* @param {String} optional - url | |
*/ | |
supports: function( data, url ){ | |
return ( | |
data.type && | |
"zoomify" == data.type | |
) || ( | |
data.documentElement && | |
"IMAGE_PROPERTIES" == data.documentElement.tagName | |
); | |
}, | |
/** | |
* | |
* @function | |
* @name OpenSeadragon.AperioTileSource.prototype.configure | |
* @param {Object|XMLDocument} data - the raw configuration | |
* @param {String} url - the url the data was retreived from if any. | |
* @return {Object} options - A dictionary of keyword arguments sufficient | |
* to configure this tile source via it's constructor. | |
*/ | |
configure: function( data, url ){ | |
if( !$.isPlainObject(data) ){ | |
options = configureFromXml( this, data ); | |
} else { | |
options = configureFromObject( this, data ); | |
} | |
var tilesurl = url || data.tilesUrl; | |
service = tilesurl.split('/'); | |
service.pop(); //ImageProperties.json or ImageProperties.xml, or "" if slash-terminated | |
service = service.join('/') + "/"; | |
if( 'http' !== tilesurl.substring( 0, 4 ) ){ | |
host = location.protocol + '//' + location.host; | |
service = host + service; | |
} | |
options.tilesUrl = service; | |
return options; | |
}, | |
// getLevelScale: function( level ) { | |
// var levelScale = NaN; | |
// if ( level >= this.minLevel && level <= this.maxLevel ){ | |
// levelScale = | |
// this.levels[ level ].width / | |
// this.levels[ this.maxLevel ].width; | |
// } | |
// return levelScale; | |
// }, | |
/** | |
* Responsible for retreiving the url which will return an image for the | |
* region speified by the given x, y, and level components. | |
* @function | |
* @name OpenSeadragon.AperioTileSource.prototype.getTileUrl | |
* @param {Number} level - z index | |
* @param {Number} x | |
* @param {Number} y | |
* @throws {Error} | |
*/ | |
getTileUrl: function( level, x, y ){ | |
//zoomify implementation | |
// level = Math.max(0, level - 1); | |
// var tileIndex = x + y * this.tierSizeInTiles[level].x + this.tileCountUpToTier[level]; | |
// var tileGroup = Math.floor( (tileIndex) / 256 ); | |
// var urlstring = "TileGroup" + tileGroup + "/" + level + "-" + x + "-" + y + ".jpg"; | |
// return this.tilesUrl + urlstring; | |
// aperio via leaflet implementation | |
// var tileGroup, x, y, z; | |
// x = tilePoint.x; | |
// y = tilePoint.y; | |
// z = this._getZoomForUrl(); | |
// tileGroup = this._tileGroupNumber(x, y, z); | |
// var scale = Math.pow(2, this.numOfTiers() - z - 1); | |
// var x_pos = x * 256 | |
// var y_pos = y * 256 | |
// var tileurl = this.baseUrl + "?" + x_pos + "+" + y_pos + "+" + 256 + "+" + 256 + "+" + scale + "+" + "80+s"; | |
// aperio for openseadragon | |
var x_pos = x * this.tileSize; | |
var y_pos = y * this.tileSize; | |
var scale = Math.pow(2, this.numberOfTiers - level); | |
var urlString = "?" + x_pos + "+" + y_pos + "+" + this.tileSize + "+" + this.tileSize + "+" + scale + "+" + "80+s"; | |
// console.log(urlString); | |
return this.tilesUrl + urlString; | |
} | |
}); | |
/** | |
* @private | |
* @inner | |
* @function | |
* | |
<IMAGE_PROPERTIES WIDTH="5569" HEIGHT="7938" NUMTILES="945" NUMIMAGES="1" VERSION="1.8" TILESIZE="256"/> | |
*/ | |
function configureFromXML( tileSource, xmlDoc ){ | |
//parse the xml | |
if ( !xmlDoc || !xmlDoc.documentElement ) { | |
throw new Error( $.getString( "Errors.Xml" ) ); | |
} | |
var root = xmlDoc.documentElement, | |
rootName = root.tagName, | |
configuration = null; | |
if ( rootName == "IMAGE_PROPERTIES" ) { | |
try { | |
configuration = { | |
"width": root.getAttribute("WIDTH"), | |
"height": root.getAttribute("HEIGHT"), | |
"tileSize": root.getAttribute("TILESIZE") | |
}; | |
return configureFromObject( tileSource, configuration ); | |
} catch ( e ) { | |
throw (e instanceof Error) ? | |
e : | |
new Error( $.getString("Errors.Aperio") ); | |
} | |
} | |
throw new Error( $.getString( "Errors.Aperio" ) ); | |
} | |
/** | |
* @private | |
* @inner | |
* @function | |
* | |
{ | |
"width" : 6000, | |
"height" : 4000, | |
"tileSize" : 256 | |
} | |
*/ | |
function configureFromObject( tileSource, configuration ){ | |
return configuration; | |
} | |
}( OpenSeadragon )); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// code for openseadragon aperio layer | |
// Generated by CoffeeScript 1.3.3 | |
(function() { | |
var AperioLayer, | |
__hasProp = {}.hasOwnProperty, | |
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; | |
AperioLayer = (function(_super) { | |
__extends(AperioLayer, _super); | |
'Implement AperioLayer layer for Cloudmade\'s Leaflet library'; | |
function AperioLayer(url, imageProperties, options) { | |
var i, t; | |
if (options == null) { | |
options = {}; | |
} | |
this.options = options; | |
console.log(this.options); | |
this.baseUrl = url; | |
if (!((imageProperties.width != null) && (imageProperties.height != null))) { | |
throw 'width and height must be defined'; | |
} | |
this.imageProperties = { | |
width: imageProperties.width, | |
height: imageProperties.height, | |
tilesize: imageProperties.tilesize || 256 | |
}; | |
t = this.numOfTiers(); | |
this._tiers = (function() { | |
var _i, _results; | |
_results = []; | |
for (i = _i = 1; 1 <= t ? _i <= t : _i >= t; i = 1 <= t ? ++_i : --_i) { | |
_results.push(Math.ceil(this.imageProperties.width / this.imageProperties.tilesize / Math.pow(2, t - i)) * Math.ceil(this.imageProperties.height / this.imageProperties.tilesize / Math.pow(2, t - i))); | |
} | |
return _results; | |
}).call(this); | |
this.options.minZoom = 0; | |
this.options.maxZoom = t - 1; | |
} | |
AperioLayer.prototype._getTierForResolution = function(resolution) { | |
var lambda; | |
lambda = function(x, r) { | |
if (r < resolution) { | |
return lambda(x + 1, r * 2); | |
} | |
return x; | |
}; | |
return this.numOfTiers() - lambda(0, 1) - 1; | |
}; | |
AperioLayer.prototype._getSizeForTier = function(tier) { | |
var r; | |
r = Math.pow(2, this.numOfTiers() - tier - 1); | |
return [Math.ceil(this.imageProperties.width / r), Math.ceil(this.imageProperties.height / r)]; | |
}; | |
AperioLayer.prototype.onAdd = function(map) { | |
var layerSize, offset, r, size, tier; | |
AperioLayer.__super__.onAdd.call(this, map); | |
size = map.getSize(); | |
r = Math.max(Math.ceil(this.imageProperties.width / size.x), Math.ceil(this.imageProperties.height / size.y)); | |
tier = this._getTierForResolution(r); | |
layerSize = this._getSizeForTier(tier); | |
offset = [(size.x - layerSize[0]) / 2, (size.y - layerSize[1]) / 2]; | |
window.ll = map.options.crs.pointToLatLng(new L.Point(size.x / 2 - offset[0], size.y / 2 - offset[1]), tier); | |
return map.setView(ll, tier); | |
}; | |
AperioLayer.prototype._createTile = function() { | |
var tile; | |
tile = document.createElement('img'); | |
tile.setAttribute('class', 'leaflet-tile'); | |
tile.onselectstart = tile.onmousemove = L.Util.falseFn; | |
return tile; | |
}; | |
AperioLayer.prototype._addTilesFromCenterOut = function(bounds) { | |
var center, fragment, i, j, point, queue, tilesToLoad, _i, _j, _k, _ref, _ref1, _ref2, _ref3; | |
queue = []; | |
center = bounds.getCenter(); | |
for (j = _i = _ref = bounds.min.y, _ref1 = bounds.max.y; _ref <= _ref1 ? _i <= _ref1 : _i >= _ref1; j = _ref <= _ref1 ? ++_i : --_i) { | |
for (i = _j = _ref2 = bounds.min.x, _ref3 = bounds.max.x; _ref2 <= _ref3 ? _j <= _ref3 : _j >= _ref3; i = _ref2 <= _ref3 ? ++_j : --_j) { | |
point = new L.Point(i, j); | |
if (this._tileShouldBeLoaded(point)) { | |
queue.push(point); | |
} | |
} | |
} | |
tilesToLoad = queue.length; | |
if (tilesToLoad === 0) { | |
return; | |
} | |
queue.sort(function(a, b) { | |
return a.distanceTo(center) - b.distanceTo(center); | |
}); | |
fragment = document.createDocumentFragment(); | |
if (!this._tilesToLoad) { | |
this.fire('loading'); | |
} | |
this._tilesToLoad += tilesToLoad; | |
for (i = _k = 0; 0 <= tilesToLoad ? _k < tilesToLoad : _k > tilesToLoad; i = 0 <= tilesToLoad ? ++_k : --_k) { | |
this._addTile(queue[i], fragment); | |
} | |
return this._container.appendChild(fragment); | |
}; | |
AperioLayer.prototype._reset = function() { | |
return AperioLayer.__super__._reset.call(this); | |
}; | |
AperioLayer.prototype._tileShouldBeLoaded = function(point) { | |
var limitX, limitY, tier; | |
if (point.x >= 0 && point.y >= 0) { | |
tier = this._getZoomForUrl(); | |
limitX = Math.pow(2, this.numOfTiers() - tier - 1) * this.imageProperties.tilesize * point.x; | |
limitY = Math.pow(2, this.numOfTiers() - tier - 1) * this.imageProperties.tilesize * point.y; | |
return limitX <= this.imageProperties.width && limitY <= this.imageProperties.height; | |
} | |
return false; | |
}; | |
AperioLayer.prototype._getTilePos = function(tilePoint) { | |
var origin; | |
origin = this._map.getPixelOrigin(); | |
return tilePoint.multiplyBy(this.imageProperties.tilesize).subtract(origin); | |
}; | |
AperioLayer.prototype._update = function(e) { | |
var bounds, nwTilePoint, seTilePoint, tileBounds, tileSize, zoom; | |
if (!(this._map != null)) { | |
return; | |
} | |
bounds = this._map.getPixelBounds(); | |
zoom = this._map.getZoom(); | |
tileSize = this.imageProperties.tilesize; | |
if (zoom > this.options.maxZoom || zoom < this.options.minZoom) { | |
return; | |
} | |
nwTilePoint = new L.Point(Math.floor(bounds.min.x / tileSize), Math.floor(bounds.min.y / tileSize)); | |
seTilePoint = new L.Point(Math.floor(bounds.max.x / tileSize), Math.floor(bounds.max.y / tileSize)); | |
tileBounds = new L.Bounds(nwTilePoint, seTilePoint); | |
this._addTilesFromCenterOut(tileBounds); | |
if (this.options.unloadInvisibleTiles || this.options.reuseTiles) { | |
return this._removeOtherTiles(tileBounds); | |
} | |
}; | |
AperioLayer.prototype.numOfTiers = function() { | |
var a, i; | |
if (!(this._numOfTiers != null)) { | |
i = 0; | |
a = Math.ceil(Math.max(this.imageProperties.width, this.imageProperties.height) / this.imageProperties.tilesize); | |
while (a > 1) { | |
i += 1; | |
a = Math.ceil(a / 2); | |
} | |
this._numOfTiers = i + 1; | |
} | |
return this._numOfTiers; | |
}; | |
AperioLayer.prototype._tileGroupNumber = function(x, y, tier) { | |
var height, i, idx, numOfTiers, tileSize, width, _i; | |
numOfTiers = this.numOfTiers(); | |
width = this.imageProperties.width; | |
height = this.imageProperties.height; | |
tileSize = this.imageProperties.tilesize; | |
idx = 0; | |
for (i = _i = 0; 0 <= tier ? _i < tier : _i > tier; i = 0 <= tier ? ++_i : --_i) { | |
idx += this._tiers[i]; | |
} | |
idx += y * Math.ceil(this.imageProperties.width / this.imageProperties.tilesize / Math.pow(2, numOfTiers - tier - 1)); | |
idx += x; | |
return Math.floor(idx / 256); | |
}; | |
AperioLayer.prototype._getZoomForUrl = function() { | |
var zoom; | |
if (this.imageProperties != null) { | |
zoom = this._map.getZoom(); | |
return zoom; | |
} | |
return 0; | |
}; | |
AperioLayer.prototype.getTileUrl = function(tilePoint, zoom) { | |
var tileGroup, x, y, z; | |
x = tilePoint.x; | |
y = tilePoint.y; | |
z = this._getZoomForUrl(); | |
tileGroup = this._tileGroupNumber(x, y, z); | |
var scale = Math.pow(2, this.numOfTiers() - z - 1); | |
var x_pos = x * this.imageProperties.tilesize; | |
var y_pos = y * this.imageProperties.tilesize; | |
var tileurl = this.baseUrl + "?" + x_pos + "+" + y_pos + "+" + this.imageProperties.tilesize + "+" + this.imageProperties.tilesize + "+" + scale + "+" + "80+s"; | |
// return this.baseUrl + ("TileGroup" + tileGroup + "/" + z + "-" + x + "-" + y + ".jpg" + rangeString); | |
return tileurl; | |
}; | |
return AperioLayer; | |
})(L.TileLayer); | |
window.AperioLayer = AperioLayer; | |
}).call(this); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
if(annotation_type == 'freehand'){ | |
var points = new Array(); | |
var annotation_points = $(annotationXML).find('point'); | |
$(annotation_points).each(function(index, point){ | |
var x_base = parseInt($(point).find('x').text()); | |
var y_base = parseInt($(point).find('y').text()); | |
// converts hamamatsu annotation to aperio coordinate system | |
var new_point = self.convertPointToAperio(x_base, y_base); | |
// if valid point, push point in leaflet coordinate system (latlng) to point array (via native point unproject) | |
if (new_point) { | |
points.push(_activeViewer.unproject(new L.Point(new_point.x, new_point.y), _activeViewer.getMaxZoom())); | |
} | |
}); | |
// native overlays! | |
var polygon = L.polygon(points, { | |
color : "#0000FF", | |
weight : 2, | |
opacity : 0.5, | |
fillOpacity: 0.0 | |
}) | |
// .addTo(_activeViewer); | |
// uncomment the above line to load the annotation immediately into the map | |
all_annotations.push(polygon); | |
// after exiting this scope, push all_annotations to a master annotation object | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
if(annotation_type == 'freehand'){ | |
console.log('processing' + annotation_type) | |
var points = new Array(); | |
var annotation_points = $(annotationXML).find('point'); | |
$(annotation_points).each(function(index, point){ | |
console.log(point); | |
var x_base = parseInt($(point).find('x').text()); | |
var y_base = parseInt($(point).find('y').text()); | |
var new_point = self.convertPointToAperio(x_base, y_base); | |
if (new_point) { | |
console.log(new_point); | |
points.push(new Seadragon.Point(new_point.x, new_point.y)); | |
} | |
}); | |
var svg = new OpenSeajax.Shapes.Polygon(points); | |
svg.getElement().attr({"stroke": lineColor, "stroke-width": "10px"}); | |
svg.getElement().attr({"fill": "none"}); | |
svg.attachTo(_activeViewer); | |
_annotations.push({path: svg, index: id }); | |
console.log(points); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Leaflet loading aperio metadata | |
var metadata_url = _basePath + '?INFO3'; | |
var self = this; | |
$.ajax({ | |
url: metadata_url, | |
success: function (data) { | |
var metadata_array = data.split('|'); | |
_imageMetaData = { | |
width: parseInt(metadata_array[0]), | |
height: parseInt(metadata_array[1]), | |
tilex: parseInt(metadata_array[3]), | |
tiley: parseInt(metadata_array[4]), | |
appmag: metadata_array[7], | |
mpp: metadata_array[8] | |
} | |
// ((1./x+1./y)/2)*self.GetSourceLens()*10**7 | |
// var conversionfactor = ((1.0/_imageMetaData.width) + (1.0/_imageMetaData.height)) * (20.) * Math.pow(10,7) | |
image_size = {width:_imageMetaData.width, height:_imageMetaData.height }; | |
var aperioImageSource = new AperioLayer(_basePath, image_size, {tilesize:_imageMetaData.tilex*2}); | |
var miniMap = new L.Control.MiniMap(aperioImageSource,{ | |
toggleDisplay:true | |
}).addTo(_activeViewer); | |
_activeViewer.addLayer(aperioImageSource); | |
_annotationLayerGroup = L.layerGroup(); | |
_activeViewer.addLayer(_annotationLayerGroup); | |
// example info3 response: | |
// ["55296", "38912", "1", "256", "256", "", "NanoZoomer Digital Pathology Image", "AppMag = 20", "MPP = 0.4526↵"] | |
// now load annotations (from Hamamatsu ndpa source) after short delay | |
self.loadNDPA(); | |
} | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Openseadragon loading aperio metadata | |
var metadata_url = _basePath + '?INFO3'; | |
var self = this; | |
$.ajax({ | |
url: metadata_url, | |
success: function (data) { | |
var metadata_array = data.split('|'); | |
_imageMetaData = { | |
width: parseInt(metadata_array[0]), | |
height: parseInt(metadata_array[1]), | |
tilex: parseInt(metadata_array[3]), | |
tiley: parseInt(metadata_array[4]), | |
appmag: metadata_array[7], | |
mpp: metadata_array[8] | |
} | |
// example info3 response: | |
// ["55296", "38912", "1", "256", "256", "", "NanoZoomer Digital Pathology Image", "AppMag = 20", "MPP = 0.4526↵"] | |
var aperioTileSource = new OpenSeadragon.AperioTileSource(_imageMetaData.width, _imageMetaData.height, _imageMetaData.tilex, _basePath); | |
aperioTileSource.minLevel = 3; | |
_activeViewer.open(aperioTileSource); | |
// now load annotations from Aperio xml after short delay | |
self.loadAperioAnnotations(); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment