Add external execution pipeline (proof of concept implementation, needs polishing). Add filtering plugin live demo for testing. Fix issues with tile cache access outside its lifespan. Add custom css for the static page renderer and differentiate folder icons. Remove some old deprecations.

This commit is contained in:
Aiosa 2023-12-10 16:34:42 +01:00
parent 90ce0669c5
commit a690b50eee
16 changed files with 1816 additions and 82 deletions

View File

@ -192,7 +192,12 @@ module.exports = function(grunt) {
server: {
options: {
port: 8000,
base: "."
base: {
path: ".",
options: {
stylesheet: 'style.css'
}
}
}
}
},

View File

@ -194,12 +194,8 @@ $.Control.prototype = {
* @param {Number} opactiy - a value between 1 and 0 inclusively.
*/
setOpacity: function( opacity ) {
if ( this.element[ $.SIGNAL ] && $.Browser.vendor === $.BROWSERS.IE ) {
$.setElementOpacity( this.element, opacity, true );
} else {
$.setElementOpacity( this.wrapper, opacity, true );
}
}
};
}( OpenSeadragon ));

View File

@ -231,6 +231,13 @@ $.ImageLoader.prototype = {
}
},
/**
* @returns {boolean} true if a job can be submitted
*/
canAcceptNewJob() {
return !this.jobLimit || this.jobsInProgress < this.jobLimit;
},
/**
* Clear any unstarted image loading jobs from the queue.
* @method
@ -264,14 +271,14 @@ function completeJob(loader, job, callback) {
loader.jobsInProgress--;
if ((!loader.jobLimit || loader.jobsInProgress < loader.jobLimit) && loader.jobQueue.length > 0) {
if (loader.canAcceptNewJob() && loader.jobQueue.length > 0) {
nextJob = loader.jobQueue.shift();
nextJob.start();
loader.jobsInProgress++;
}
if (loader.tileRetryMax > 0 && loader.jobQueue.length === 0) {
if ((!loader.jobLimit || loader.jobsInProgress < loader.jobLimit) && loader.failedTiles.length > 0) {
if (loader.canAcceptNewJob() && loader.failedTiles.length > 0) {
nextJob = loader.failedTiles.shift();
setTimeout(function () {
nextJob.start();

View File

@ -1450,12 +1450,14 @@ function OpenSeadragon( options ){
/**
* TODO: get rid of this. I can't see how it's required at all. Looks
* like an early legacy code artifact.
* @static
* TODO: remove soon
* @deprecated
* @ignore
*/
SIGNAL: "----seadragon----",
get SIGNAL() {
$.console.error("OpenSeadragon.SIGNAL is deprecated and should not be used.");
return "----seadragon----";
},
/**
@ -2269,29 +2271,6 @@ function OpenSeadragon( options ){
event.stopPropagation();
},
// Deprecated
createCallback: function( object, method ) {
//TODO: This pattern is painful to use and debug. It's much cleaner
// to use pinning plus anonymous functions. Get rid of this
// pattern!
console.error('The createCallback function is deprecated and will be removed in future versions. Please use alternativeFunction instead.');
var initialArgs = [],
i;
for ( i = 2; i < arguments.length; i++ ) {
initialArgs.push( arguments[ i ] );
}
return function() {
var args = initialArgs.concat( [] ),
i;
for ( i = 0; i < arguments.length; i++ ) {
args.push( arguments[ i ] );
}
return method.apply( object, args );
};
},
/**
* Retrieves the value of a url parameter from the window.location string.
@ -2632,8 +2611,72 @@ function OpenSeadragon( options ){
setImageFormatsSupported: function(formats) {
// eslint-disable-next-line no-use-before-define
$.extend(FILEFORMATS, formats);
},
//@private, runs non-invasive update of all tiles given in the list
invalidateTilesLater: function(tileList, tStamp, viewer, batch = 999) {
let i = 0;
let interval = setInterval(() => {
let tile = tileList[i];
while (tile && !tile.loaded) {
tile = tileList[i++];
}
if (i >= tileList.length) {
console.log(":::::::::::::::::::::::::::::end");
clearInterval(interval);
return;
}
const tiledImage = tile.tiledImage;
if (tiledImage.invalidatedAt > tStamp) {
console.log(":::::::::::::::::::::::::::::end");
clearInterval(interval);
return;
}
let count = 1;
for (; i < tileList.length; i++) {
const tile = tileList[i];
if (!tile.loaded) {
console.log("skipping tile: not loaded", tile);
continue;
}
const tileCache = tile.getCache();
if (tileCache._updateStamp >= tStamp) {
continue;
}
// prevents other tiles sharing the cache (~the key) from event
//todo works unless the cache key CHANGES by plugins
// - either prevent
// - or ...?
tileCache._updateStamp = tStamp;
$.invalidateTile(tile, tile.tiledImage, tStamp, viewer, i);
if (++count > batch) {
break;
}
}
}, 5); //how to select the delay...?? todo: just try out
},
//@private, runs tile update event
invalidateTile: function(tile, image, tStamp, viewer, i = -1) {
console.log(i, "tile: process", tile);
//todo consider also ability to cut execution of ongoing event if outdated by providing comparison timestamp
viewer.raiseEventAwaiting('tile-needs-update', {
tile: tile,
tiledImage: image,
}).then(() => {
//TODO IF NOT CACHE ERRO
const newCache = tile.getCache();
if (newCache) {
newCache._updateStamp = tStamp;
} else {
$.console.error("After an update, the tile %s has not cache data! Check handlers on 'tile-needs-update' evemt!", tile);
}
});
}
});
@ -2903,13 +2946,10 @@ function OpenSeadragon( options ){
}
const promise = function () {};
//TODO consider supplying promise API via callbacks/polyfill
promise.prototype.then = function () {
throw "OpenSeadragon needs promises API. Your browser do not support promises. You can add polyfill.js to import promises.";
};
promise.prototype.catch = function () {
throw "OpenSeadragon needs promises API. Your browser do not support promises. You can add polyfill.js to import promises.";
};
promise.prototype.finally = function () {
promise.prototype.then =
promise.prototype.catch =
promise.prototype.finally =
promise.all = promise.race = function () {
throw "OpenSeadragon needs promises API. Your browser do not support promises. You can add polyfill.js to import promises.";
};
return promise;

View File

@ -266,18 +266,13 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, aja
* @memberof OpenSeadragon.Tile#
*/
this.isBottomMost = false;
/**
* FIXME: I would like to remove this reference but there is no way
* to remove it since tile-unloaded event requires the tiledImage reference.
* And, unloadTilesFor(tiledImage) in cache uses it too. Storing the
* reference on a tile level rather than cache level is more efficient.
*
* Owner of this tile.
* Owner of this tile. Do not change this property manually.
* @member {OpenSeadragon.TiledImage}
* @memberof OpenSeadragon.Tile#
*/
this.tiledImage = null;
/**
* Array of cached tile data associated with the tile.
* @member {Object} _caches
@ -385,7 +380,7 @@ $.Tile.prototype = {
* @returns {?Image}
*/
getImage: function() {
//TODO: after merge $.console.error("[Tile.getImage] property has been deprecated. Use [Tile.getData] instead.");
//TODO: after-merge-aiosa $.console.error("[Tile.getImage] property has been deprecated. Use [Tile.getData] instead.");
//this method used to ensure the underlying data model conformed to given type - convert instead of getData()
const cache = this.getCache(this.cacheKey);
if (!cache) {
@ -413,7 +408,7 @@ $.Tile.prototype = {
* @returns {?CanvasRenderingContext2D}
*/
getCanvasContext: function() {
//TODO: after merge $.console.error("[Tile.getCanvasContext] property has been deprecated. Use [Tile.getData] instead.");
//TODO: after-merge-aiosa $.console.error("[Tile.getCanvasContext] property has been deprecated. Use [Tile.getData] instead.");
//this method used to ensure the underlying data model conformed to given type - convert instead of getData()
const cache = this.getCache(this.cacheKey);
if (!cache) {
@ -471,10 +466,14 @@ $.Tile.prototype = {
/**
* Get the data to render for this tile
* @param {string} type data type to require
* @param {boolean?} [copy=this.loaded] whether to force copy retrieval
* @param {boolean?} [copy=true] whether to force copy retrieval
* @return {*|undefined} data in the desired type, or undefined if a conversion is ongoing
*/
getData: function(type, copy = this.loaded) {
getData: function(type, copy = true) {
if (!this.tiledImage) {
return null; //async can access outside its lifetime
}
//we return the data synchronously immediatelly (undefined if conversion happens)
const cache = this.getCache(this.cacheKey);
if (!cache) {
@ -491,6 +490,10 @@ $.Tile.prototype = {
* @return {*|undefined} data in the desired type, or undefined if a conversion is ongoing
*/
getOriginalData: function(type, copy = true) {
if (!this.tiledImage) {
return null; //async can access outside its lifetime
}
//we return the data synchronously immediatelly (undefined if conversion happens)
const cache = this.getCache(this.originalCacheKey);
if (!cache) {
@ -509,6 +512,10 @@ $.Tile.prototype = {
* to a new data. This makes the Tile assigned to two cache objects.
*/
setData: function(value, type, preserveOriginalData = true) {
if (!this.tiledImage) {
return null; //async can access outside its lifetime
}
if (preserveOriginalData && this.cacheKey === this.originalCacheKey) {
//caches equality means we have only one cache:
// change current pointer to a new cache and create it: new tiles will
@ -542,10 +549,13 @@ $.Tile.prototype = {
* @param {*} data data to cache - this data will be sent to the TileSource API for refinement.
* @param {?string} type data type, will be guessed if not provided
* @param [_safely=true] private
* @param [_cutoff=0] private
* @returns {OpenSeadragon.CacheRecord} - The cache record the tile was attached to.
* @returns {OpenSeadragon.CacheRecord|null} - The cache record the tile was attached to.
*/
setCache: function(key, data, type = undefined, _safely = true, _cutoff = 0) {
setCache: function(key, data, type = undefined, _safely = true) {
if (!this.tiledImage) {
return null; //async can access outside its lifetime
}
if (!type) {
if (this.tiledImage && !this.tiledImage.__typeWarningReported) {
$.console.warn(this, "[Tile.setCache] called without type specification. " +
@ -557,20 +567,22 @@ $.Tile.prototype = {
const writesToRenderingCache = key === this.cacheKey;
if (writesToRenderingCache && _safely) {
//todo later, we could have drawers register their supported rendering type
// and OpenSeadragon would check compatibility automatically, now we render
// using two main types so we check their ability
//todo after-merge-aiosa decide dynamically
const conversion = $.convertor.getConversionPath(type, "context2d");
$.console.assert(conversion, "[Tile.setCache] data was set for the default tile cache we are unable" +
"to render. Make sure OpenSeadragon.convertor was taught to convert type: " + type);
}
if (!this.__cutoff) {
//todo consider caching this on a tiled image level..
this.__cutoff = this.tiledImage.source.getClosestLevel();
}
const cachedItem = this.tiledImage._tileCache.cacheTile({
data: data,
dataType: type,
tile: this,
cacheKey: key,
cutoff: _cutoff
cutoff: this.__cutoff,
});
const havingRecord = this._caches[key];
if (havingRecord !== cachedItem) {
@ -631,8 +643,13 @@ $.Tile.prototype = {
const _this = this;
// This gives the application a chance to make image manipulation
// changes as we are rendering the image
drawingHandler({context: context, tile: this, get rendered() {
$.console.warn("[tile-drawing rendered] property is deprecated. Use Tile data API.");
drawingHandler({context: context, get tile() {
$.console.warn("[tile-drawing] event is deprecated. " +
"Use 'tile-drawn' event instead.");
return _this;
}, get rendered() {
$.console.warn("[tile-drawing] rendered property and this event itself are deprecated. " +
"Use Tile data API and `tile-drawn` event instead.");
const context = _this.getCanvasContext();
if (!context) {
$.console.warn(

View File

@ -581,6 +581,18 @@ $.TileCache = class {
}
}
/**
* Returns reference to all tiles loaded by a particular
* tiled image item
* @param {OpenSeadragon.TiledImage|Boolean} tiledImage true for all, reference for selection
*/
getLoadedTilesFor(tiledImage) {
if (tiledImage === true) {
return [...this._tilesLoaded];
}
return this._tilesLoaded.filter(tile => tile.tiledImage === tiledImage);
}
/**
* Get cache record (might be a unattached record, i.e. a zombie)
* @param cacheKey

View File

@ -241,6 +241,7 @@ $.TiledImage = function( options ) {
* @property {OpenSeadragon.Tile} context - The HTML canvas context being drawn into.
* @property {OpenSeadragon.Tile} rendered - The HTML canvas context containing the tile imagery.
* @property {?Object} userData - Arbitrary subscriber-defined object.
* @deprecated
*/
_this.viewer.raiseEvent('tile-drawing', $.extend({
tiledImage: _this
@ -290,6 +291,32 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
});
},
/**
* Forces the system consider all tiles in this tiled image
* as outdated, and fire tile update event on relevant tiles
* Detailed description is available within the 'tile-needs-update'
* event. TODO: consider re-using update function instead?
* @param {boolean} [viewportOnly=false] optionally invalidate only viewport-visible tiles if true
* @param {number} [tStamp=OpenSeadragon.now()] optionally provide tStamp of the update event
*/
invalidate: function (viewportOnly, tStamp) {
tStamp = tStamp || $.now();
this.invalidatedAt = tStamp; //todo document, or remove by something nicer
//always invalidate active tiles
for (let tile of this.lastDrawn) {
$.invalidateTile(tile, this, tStamp, this.viewer);
}
//if not called from world or not desired, avoid update of offscreen data
if (viewportOnly) {
return;
}
//else update all tiles at some point, but by priority of access time
const tiles = this.tileCache.getLoadedTilesFor(this);
tiles.sort((a, b) => a.lastTouchTime - b.lastTouchTime);
$.invalidateTilesLater(tiles, tStamp, this.viewer);
},
/**
* Clears all tiles and triggers an update on the next call to
* {@link OpenSeadragon.TiledImage#update}.
@ -1575,14 +1602,13 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
}
let record = this._tileCache.getCacheRecord(tile.cacheKey);
const cutoff = this.source.getClosestLevel();
if (record) {
//setup without calling tile loaded event! tile cache is ready for usage,
tile.loading = true;
tile.loaded = false;
//set data as null, cache already has data, it does not overwrite
this._setTileLoaded(tile, null, cutoff, null, record.type,
this._setTileLoaded(tile, null, null, null, record.type,
this.callTileLoadedWithCachedData);
return true;
}
@ -1594,7 +1620,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
tile.loading = true;
tile.loaded = false;
//set data as null, cache already has data, it does not overwrite
this._setTileLoaded(tile, null, cutoff, null, record.type);
this._setTileLoaded(tile, null, null, null, record.type);
return true;
}
}
@ -1673,8 +1699,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
ajaxHeaders,
sourceBounds,
post,
tileSource.getTileHashKey(level, xMod, yMod, urlOrGetter, ajaxHeaders, post),
this
tileSource.getTileHashKey(level, xMod, yMod, urlOrGetter, ajaxHeaders, post)
);
if (this.getFlip()) {
@ -1779,9 +1804,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
var _this = this,
finish = function() {
var ccc = _this.source;
var cutoff = ccc.getClosestLevel();
_this._setTileLoaded(tile, data, cutoff, tileRequest, dataType);
_this._setTileLoaded(tile, data, null, tileRequest, dataType);
};
// Check if we're mid-update; this can happen on IE8 because image load events for
@ -1800,7 +1823,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
* @param {OpenSeadragon.Tile} tile
* @param {*} data image data, the data sent to ImageJob.prototype.finish(), by default an Image object,
* can be null: in that case, cache is assigned to a tile without further processing
* @param {?Number} cutoff
* @param {?Number} cutoff ignored, @deprecated
* @param {?XMLHttpRequest} tileRequest
* @param {?String} [dataType=undefined] data type, derived automatically if not set
* @param {?Boolean} [withEvent=true] do not trigger event if true
@ -1808,7 +1831,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
_setTileLoaded: function(tile, data, cutoff, tileRequest, dataType, withEvent = true) {
tile.tiledImage = this; //unloaded with tile.unload(), so we need to set it back
// -> reason why it is not in the constructor
tile.setCache(tile.cacheKey, data, dataType, false, cutoff);
tile.setCache(tile.cacheKey, data, dataType, false);
let resolver = null,
increment = 0,
@ -1829,7 +1852,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
);
//make sure cache data is ready for drawing, if not, request the desired format
const cache = tile.getCache(tile.cacheKey),
// TODO: dynamic type declaration from the drawer base class interface from v5.0 onwards
// TODO: after-merge-aiosa dynamic type declaration from the drawer base class interface
requiredType = _this._drawer.useCanvas ? "context2d" : "image";
if (!cache) {
$.console.warn("Tile %s not cached at the end of tile-loaded event: tile will not be drawn - it has no data!", tile);
@ -1866,9 +1889,9 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
/**
* Triggered when a tile has just been loaded in memory. That means that the
* image has been downloaded and can be modified before being drawn to the canvas.
* This event awaits its handlers - they can return promises, or be async functions.
* This event is _awaiting_, it supports asynchronous functions or functions that return a promise.
*
* @event tile-loaded awaiting event
* @event tile-loaded
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {Image|*} image - The image (data) of the tile. Deprecated.
@ -2213,15 +2236,26 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
shouldRoundPositionAndSize = !isAnimating;
}
for (var i = lastDrawn.length - 1; i >= 0; i--) {
for (let i = lastDrawn.length - 1; i >= 0; i--) {
tile = lastDrawn[ i ];
if (tile.loaded) {
const cache = tile.getCache();
if (cache._updateStamp && cache._updateStamp !== $.__updated) {
console.warn("Tile not updated", cache);
}
}
this._drawer.drawTile( tile, this._drawingHandler, useSketch, sketchScale,
sketchTranslate, shouldRoundPositionAndSize, this.source );
tile.beingDrawn = true;
if( this.viewer ){
const targetTile = tile;
/**
* <em>- Needs documentation -</em>
* This event is fired after a tile has been drawn on the viewport. You can
* use this event to modify the tile data if necessary.
* This event is _awaiting_, it supports asynchronous functions or functions that return a promise.
*
* @event tile-drawn
* @memberof OpenSeadragon.Viewer
@ -2231,9 +2265,19 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
* @property {OpenSeadragon.Tile} tile
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.viewer.raiseEvent( 'tile-drawn', {
this.viewer.raiseEventAwaiting( 'tile-drawn', {
tiledImage: this,
tile: tile
tile: targetTile
}).then(() => {
const cache = targetTile.getCache(targetTile.cacheKey),
// TODO: after-merge-aiosa dynamic type declaration from the drawer base class interface
requiredType = this._drawer.useCanvas ? "context2d" : "image";
if (!cache) {
$.console.warn("Tile %s not cached at the end of tile-drawn event: tile will not be drawn - it has no data!", targetTile);
} else if (cache.type !== requiredType) {
//initiate conversion as soon as possible if incompatible with the drawer
cache.transformTo(requiredType);
}
});
}
}

View File

@ -354,9 +354,24 @@ $.Viewer = function( options ) {
THIS[ _this.hash ].forceRedraw = true;
//if we are not throttling
if (_this.imageLoader.canAcceptNewJob()) {
//todo small hack, we could make this builtin speedup more sophisticated
const item = event.item;
const origOpacity = item.opacity;
const origMaxTiles = item.maxTilesPerFrame;
//update tiles
item.opacity = 0; //prevent draw
item.maxTilesPerFrame = 50; //todo based on image size and also number of images!
item._updateViewport();
item._needsDraw = true; //we did not draw
item.opacity = origOpacity;
item.maxTilesPerFrame = origMaxTiles;
if (!_this._updateRequestId) {
_this._updateRequestId = scheduleUpdate( _this, updateMulti );
}
}
});
this.world.addHandler('remove-item', function(event) {

View File

@ -232,6 +232,28 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W
}
},
/**
* Forces the system consider all tiles across all tiled images
* as outdated, and fire tile update event on relevant tiles
* Detailed description is available within the 'tile-needs-update'
* event.
*/
invalidateItems: function () {
const updatedAt = $.now();
$.__updated = updatedAt;
for ( let i = 0; i < this._items.length; i++ ) {
console.log("Refreshing ", this._items[i].lastDrawn);
this._items[i].invalidate(true, updatedAt);
}
//update all tiles at some point, but by priority of access time
const tiles = this.viewer.tileCache.getLoadedTilesFor(true);
tiles.sort((a, b) => a.lastTouchTime - b.lastTouchTime);
console.log("Refreshing with late update: ", tiles);
$.invalidateTilesLater(tiles, updatedAt, this.viewer);
},
/**
* Clears all tiles and triggers updates for all items.
*/

300
style.css Normal file
View File

@ -0,0 +1,300 @@
* {
margin: 0;
padding: 0;
outline: 0;
}
body {
padding: 80px 100px;
font: 13px "Helvetica Neue", "Lucida Grande", "Arial";
background: #ECE9E9 -webkit-gradient(linear, 0% 0%, 0% 100%, from(#fff), to(#ECE9E9));
background: #ECE9E9 -moz-linear-gradient(top, #fff, #ECE9E9);
background-repeat: no-repeat;
color: #555;
-webkit-font-smoothing: antialiased;
}
h1, h2, h3 {
font-size: 22px;
color: #343434;
}
h1 em, h2 em {
padding: 0 5px;
font-weight: normal;
}
h1 {
font-size: 60px;
}
h2 {
margin-top: 10px;
}
h3 {
margin: 5px 0 10px 0;
padding-bottom: 5px;
border-bottom: 1px solid #eee;
font-size: 18px;
}
ul li {
list-style: none;
}
ul li:hover {
cursor: pointer;
color: #2e2e2e;
}
ul li .path {
padding-left: 5px;
font-weight: bold;
}
ul li .line {
padding-right: 5px;
font-style: italic;
}
ul li:first-child .path {
padding-left: 0;
}
p {
line-height: 1.5;
}
a {
color: #555;
text-decoration: none;
}
a:hover {
color: #303030;
}
#stacktrace {
margin-top: 15px;
}
.directory h1 {
margin-bottom: 15px;
font-size: 18px;
}
ul#files {
width: 100%;
height: 100%;
overflow: hidden;
}
ul#files li {
float: left;
width: 30%;
line-height: 25px;
margin: 1px;
}
ul#files li a {
display: block;
height: 25px;
border: 1px solid transparent;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
overflow: hidden;
white-space: nowrap;
}
ul#files li a:focus,
ul#files li a:hover {
background: rgba(255,255,255,0.65);
border: 1px solid #ececec;
}
ul#files li a.highlight {
-webkit-transition: background .4s ease-in-out;
background: #ffff4f;
border-color: #E9DC51;
}
#search {
display: block;
position: fixed;
top: 20px;
right: 20px;
width: 90px;
-webkit-transition: width ease 0.2s, opacity ease 0.4s;
-moz-transition: width ease 0.2s, opacity ease 0.4s;
-webkit-border-radius: 32px;
-moz-border-radius: 32px;
-webkit-box-shadow: inset 0px 0px 3px rgba(0, 0, 0, 0.25), inset 0px 1px 3px rgba(0, 0, 0, 0.7), 0px 1px 0px rgba(255, 255, 255, 0.03);
-moz-box-shadow: inset 0px 0px 3px rgba(0, 0, 0, 0.25), inset 0px 1px 3px rgba(0, 0, 0, 0.7), 0px 1px 0px rgba(255, 255, 255, 0.03);
-webkit-font-smoothing: antialiased;
text-align: left;
font: 13px "Helvetica Neue", Arial, sans-serif;
padding: 4px 10px;
border: none;
background: transparent;
margin-bottom: 0;
outline: none;
opacity: 0.7;
color: #888;
}
#search:focus {
width: 120px;
opacity: 1.0;
}
/*views*/
#files span {
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
text-indent: 10px;
}
#files .name {
background-repeat: no-repeat;
}
#files .icon .name {
text-indent: 28px;
}
/*tiles*/
.view-tiles .name {
width: 100%;
background-position: 8px 5px;
margin-left: 30px;
}
.view-tiles .size,
.view-tiles .date {
display: none;
}
.view-tiles a {
position: relative;
}
/*hack: reuse empty to find folders*/
#files .size:empty {
width: 20px;
height: 14px;
background-color: #f9d342; /* Folder color */
position: absolute;
border-radius: 4px;
box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.1); /* Optional shadow for effect */
display: block !important;
float: left;
left: 13px;
top: 5px;
}
#files .size:empty:before {
content: '';
position: absolute;
top: -2px;
left: 2px;
width: 12px;
height: 4px;
background-color: #f9d342;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
#files .size:empty:after {
content: '';
position: absolute;
top: 0;
left: 0;
width: 8px;
height: 4px;
background-color: #e8c233; /* Slightly darker shade for the tab */
border-top-left-radius: 2px;
border-bottom-right-radius: 2px;
}
/*details*/
ul#files.view-details li {
float: none;
display: block;
width: 90%;
}
ul#files.view-details li.header {
height: 25px;
background: #000;
color: #fff;
font-weight: bold;
}
.view-details .header {
border-radius: 5px;
}
.view-details .name {
width: 60%;
background-position: 8px 5px;
}
.view-details .size {
width: 10%;
}
.view-details .date {
width: 30%;
}
.view-details .size,
.view-details .date {
text-align: right;
direction: rtl;
}
/*mobile*/
@media (max-width: 768px) {
body {
font-size: 13px;
line-height: 16px;
padding: 0;
}
#search {
position: static;
width: 100%;
font-size: 2em;
line-height: 1.8em;
text-indent: 10px;
border: 0;
border-radius: 0;
padding: 10px 0;
margin: 0;
}
#search:focus {
width: 100%;
border: 0;
opacity: 1;
}
.directory h1 {
font-size: 2em;
line-height: 1.5em;
color: #fff;
background: #000;
padding: 15px 10px;
margin: 0;
}
ul#files {
border-top: 1px solid #cacaca;
}
ul#files li {
float: none;
width: auto !important;
display: block;
border-bottom: 1px solid #cacaca;
font-size: 2em;
line-height: 1.2em;
text-indent: 0;
margin: 0;
}
ul#files li:nth-child(odd) {
background: #e0e0e0;
}
ul#files li a {
height: auto;
border: 0;
border-radius: 0;
padding: 15px 10px;
}
ul#files li a:focus,
ul#files li a:hover {
border: 0;
}
#files .header,
#files .size,
#files .date {
display: none !important;
}
#files .name {
float: none;
display: inline-block;
width: 100%;
text-indent: 0;
background-position: 0 50%;
}
#files .icon .name {
text-indent: 41px;
}
#files .size:empty {
top: 23px;
left: 5px;
}
}

View File

@ -0,0 +1,750 @@
/*
* Modified and maintained by the OpenSeadragon Community.
*
* This software was orignally developed at the National Institute of Standards and
* Technology by employees of the Federal Government. NIST assumes
* no responsibility whatsoever for its use by other parties, and makes no
* guarantees, expressed or implied, about its quality, reliability, or
* any other characteristic.
* @author Antoine Vandecreme <antoine.vandecreme@nist.gov>
*/
/**
* This class is an improvement over the basic jQuery spinner to support
* 'Enter' to update the value (with validity checks).
* @param {Object} options Options object
* @return {Spinner} A spinner object
*/
class Spinner {
constructor(options) {
options.$element.html('<input type="text" size="1" ' +
'class="ui-widget-content ui-corner-all"/>');
const self = this,
$spinner = options.$element.find('input');
this.value = options.init;
$spinner.spinner({
min: options.min,
max: options.max,
step: options.step,
spin: function(event, ui) {
/*jshint unused:true */
self.value = ui.value;
options.updateCallback(self.value);
}
});
$spinner.val(this.value);
$spinner.keyup(function(e) {
if (e.which === 13) {
if (!this.value.match(/^-?\d?\.?\d*$/)) {
this.value = options.init;
} else if (options.min !== undefined &&
this.value < options.min) {
this.value = options.min;
} else if (options.max !== undefined &&
this.value > options.max) {
this.value = options.max;
}
self.value = this.value;
options.updateCallback(self.value);
}
});
}
getValue() {
return this.value;
}
}
class SpinnerSlider {
constructor(options) {
let idIncrement = 0;
this.hash = idIncrement++;
const spinnerId = 'wdzt-spinner-slider-spinner-' + this.hash;
const sliderId = 'wdzt-spinner-slider-slider-' + this.hash;
this.value = options.init;
const self = this;
options.$element.html(`
<div class="wdzt-table-layout wdzt-full-width">
<div class="wdzt-row-layout">
<div class="wdzt-cell-layout">
<input id="${spinnerId}" type="text" size="1"
class="ui-widget-content ui-corner-all"/>
</div>
<div class="wdzt-cell-layout wdzt-full-width">
<div id="${sliderId}" class="wdzt-menu-slider">
</div>
</div>
</div>
</div>
`);
const $slider = options.$element.find('#' + sliderId)
.slider({
min: options.min,
max: options.sliderMax !== undefined ?
options.sliderMax : options.max,
step: options.step,
value: this.value,
slide: function (event, ui) {
/*jshint unused:true */
self.value = ui.value;
$spinner.spinner('value', self.value);
options.updateCallback(self.value);
}
});
const $spinner = options.$element.find('#' + spinnerId)
.spinner({
min: options.min,
max: options.max,
step: options.step,
spin: function (event, ui) {
/*jshint unused:true */
self.value = ui.value;
$slider.slider('value', self.value);
options.updateCallback(self.value);
}
});
$spinner.val(this.value);
$spinner.keyup(function (e) {
if (e.which === 13) {
self.value = $spinner.spinner('value');
$slider.slider('value', self.value);
options.updateCallback(self.value);
}
});
}
getValue () {
return this.value;
};
}
const viewer = window.viewer = new OpenSeadragon({
id: 'openseadragon',
prefixUrl: '/build/openseadragon/images/',
tileSources: 'https://openseadragon.github.io/example-images/highsmith/highsmith.dzi',
crossOriginPolicy: 'Anonymous'
});
// Prevent Caman from caching the canvas because without this:
// 1. We have a memory leak
// 2. Non-caman filters in between 2 camans filters get ignored.
Caman.Store.put = function() {};
// List of filters with their templates.
const availableFilters = [
{
name: 'Invert',
generate: function() {
return {
html: '',
getParams: function() {
return '';
},
getFilter: function() {
/*eslint new-cap: 0*/
return OpenSeadragon.Filters.INVERT();
}
};
}
}, {
name: 'Colormap',
generate: function(updateCallback) {
const cmaps = {
aCm: [ [0,0,0], [0,4,0], [0,8,0], [0,12,0], [0,16,0], [0,20,0], [0,24,0], [0,28,0], [0,32,0], [0,36,0], [0,40,0], [0,44,0], [0,48,0], [0,52,0], [0,56,0], [0,60,0], [0,64,0], [0,68,0], [0,72,0], [0,76,0], [0,80,0], [0,85,0], [0,89,0], [0,93,0], [0,97,0], [0,101,0], [0,105,0], [0,109,0], [0,113,0], [0,117,0], [0,121,0], [0,125,0], [0,129,2], [0,133,5], [0,137,7], [0,141,10], [0,145,13], [0,149,15], [0,153,18], [0,157,21], [0,161,23], [0,165,26], [0,170,29], [0,174,31], [0,178,34], [0,182,37], [0,186,39], [0,190,42], [0,194,45], [0,198,47], [0,202,50], [0,206,53], [0,210,55], [0,214,58], [0,218,61], [0,222,63], [0,226,66], [0,230,69], [0,234,71], [0,238,74], [0,242,77], [0,246,79], [0,250,82], [0,255,85], [3,251,87], [7,247,90], [11,243,92], [15,239,95], [19,235,98], [23,231,100], [27,227,103], [31,223,106], [35,219,108], [39,215,111], [43,211,114], [47,207,116], [51,203,119], [55,199,122], [59,195,124], [63,191,127], [67,187,130], [71,183,132], [75,179,135], [79,175,138], [83,171,140], [87,167,143], [91,163,146], [95,159,148], [99,155,151], [103,151,154], [107,147,156], [111,143,159], [115,139,162], [119,135,164], [123,131,167], [127,127,170], [131,123,172], [135,119,175], [139,115,177], [143,111,180], [147,107,183], [151,103,185], [155,99,188], [159,95,191], [163,91,193], [167,87,196], [171,83,199], [175,79,201], [179,75,204], [183,71,207], [187,67,209], [191,63,212], [195,59,215], [199,55,217], [203,51,220], [207,47,223], [211,43,225], [215,39,228], [219,35,231], [223,31,233], [227,27,236], [231,23,239], [235,19,241], [239,15,244], [243,11,247], [247,7,249], [251,3,252], [255,0,255], [255,0,251], [255,0,247], [255,0,244], [255,0,240], [255,0,237], [255,0,233], [255,0,230], [255,0,226], [255,0,223], [255,0,219], [255,0,216], [255,0,212], [255,0,208], [255,0,205], [255,0,201], [255,0,198], [255,0,194], [255,0,191], [255,0,187], [255,0,184], [255,0,180], [255,0,177], [255,0,173], [255,0,170], [255,0,166], [255,0,162], [255,0,159], [255,0,155], [255,0,152], [255,0,148], [255,0,145], [255,0,141], [255,0,138], [255,0,134], [255,0,131], [255,0,127], [255,0,123], [255,0,119], [255,0,115], [255,0,112], [255,0,108], [255,0,104], [255,0,100], [255,0,96], [255,0,92], [255,0,88], [255,0,85], [255,0,81], [255,0,77], [255,0,73], [255,0,69], [255,0,65], [255,0,61], [255,0,57], [255,0,54], [255,0,50], [255,0,46], [255,0,42], [255,0,38], [255,0,34], [255,0,30], [255,0,27], [255,0,23], [255,0,19], [255,0,15], [255,0,11], [255,0,7], [255,0,3], [255,0,0], [255,4,0], [255,8,0], [255,12,0], [255,17,0], [255,21,0], [255,25,0], [255,30,0], [255,34,0], [255,38,0], [255,43,0], [255,47,0], [255,51,0], [255,56,0], [255,60,0], [255,64,0], [255,69,0], [255,73,0], [255,77,0], [255,82,0], [255,86,0], [255,90,0], [255,95,0], [255,99,0], [255,103,0], [255,108,0], [255,112,0], [255,116,0], [255,121,0], [255,125,0], [255,129,0], [255,133,0], [255,138,0], [255,142,0], [255,146,0], [255,151,0], [255,155,0], [255,159,0], [255,164,0], [255,168,0], [255,172,0], [255,177,0], [255,181,0], [255,185,0], [255,190,0], [255,194,0], [255,198,0], [255,203,0], [255,207,0], [255,211,0], [255,216,0], [255,220,0], [255,224,0], [255,229,0], [255,233,0], [255,237,0], [255,242,0], [255,246,0], [255,250,0], [255,255,0]],
bCm: [ [0,0,0], [0,0,4], [0,0,8], [0,0,12], [0,0,16], [0,0,20], [0,0,24], [0,0,28], [0,0,32], [0,0,36], [0,0,40], [0,0,44], [0,0,48], [0,0,52], [0,0,56], [0,0,60], [0,0,64], [0,0,68], [0,0,72], [0,0,76], [0,0,80], [0,0,85], [0,0,89], [0,0,93], [0,0,97], [0,0,101], [0,0,105], [0,0,109], [0,0,113], [0,0,117], [0,0,121], [0,0,125], [0,0,129], [0,0,133], [0,0,137], [0,0,141], [0,0,145], [0,0,149], [0,0,153], [0,0,157], [0,0,161], [0,0,165], [0,0,170], [0,0,174], [0,0,178], [0,0,182], [0,0,186], [0,0,190], [0,0,194], [0,0,198], [0,0,202], [0,0,206], [0,0,210], [0,0,214], [0,0,218], [0,0,222], [0,0,226], [0,0,230], [0,0,234], [0,0,238], [0,0,242], [0,0,246], [0,0,250], [0,0,255], [3,0,251], [7,0,247], [11,0,243], [15,0,239], [19,0,235], [23,0,231], [27,0,227], [31,0,223], [35,0,219], [39,0,215], [43,0,211], [47,0,207], [51,0,203], [55,0,199], [59,0,195], [63,0,191], [67,0,187], [71,0,183], [75,0,179], [79,0,175], [83,0,171], [87,0,167], [91,0,163], [95,0,159], [99,0,155], [103,0,151], [107,0,147], [111,0,143], [115,0,139], [119,0,135], [123,0,131], [127,0,127], [131,0,123], [135,0,119], [139,0,115], [143,0,111], [147,0,107], [151,0,103], [155,0,99], [159,0,95], [163,0,91], [167,0,87], [171,0,83], [175,0,79], [179,0,75], [183,0,71], [187,0,67], [191,0,63], [195,0,59], [199,0,55], [203,0,51], [207,0,47], [211,0,43], [215,0,39], [219,0,35], [223,0,31], [227,0,27], [231,0,23], [235,0,19], [239,0,15], [243,0,11], [247,0,7], [251,0,3], [255,0,0], [255,3,0], [255,7,0], [255,11,0], [255,15,0], [255,19,0], [255,23,0], [255,27,0], [255,31,0], [255,35,0], [255,39,0], [255,43,0], [255,47,0], [255,51,0], [255,55,0], [255,59,0], [255,63,0], [255,67,0], [255,71,0], [255,75,0], [255,79,0], [255,83,0], [255,87,0], [255,91,0], [255,95,0], [255,99,0], [255,103,0], [255,107,0], [255,111,0], [255,115,0], [255,119,0], [255,123,0], [255,127,0], [255,131,0], [255,135,0], [255,139,0], [255,143,0], [255,147,0], [255,151,0], [255,155,0], [255,159,0], [255,163,0], [255,167,0], [255,171,0], [255,175,0], [255,179,0], [255,183,0], [255,187,0], [255,191,0], [255,195,0], [255,199,0], [255,203,0], [255,207,0], [255,211,0], [255,215,0], [255,219,0], [255,223,0], [255,227,0], [255,231,0], [255,235,0], [255,239,0], [255,243,0], [255,247,0], [255,251,0], [255,255,0], [255,255,3], [255,255,7], [255,255,11], [255,255,15], [255,255,19], [255,255,23], [255,255,27], [255,255,31], [255,255,35], [255,255,39], [255,255,43], [255,255,47], [255,255,51], [255,255,55], [255,255,59], [255,255,63], [255,255,67], [255,255,71], [255,255,75], [255,255,79], [255,255,83], [255,255,87], [255,255,91], [255,255,95], [255,255,99], [255,255,103], [255,255,107], [255,255,111], [255,255,115], [255,255,119], [255,255,123], [255,255,127], [255,255,131], [255,255,135], [255,255,139], [255,255,143], [255,255,147], [255,255,151], [255,255,155], [255,255,159], [255,255,163], [255,255,167], [255,255,171], [255,255,175], [255,255,179], [255,255,183], [255,255,187], [255,255,191], [255,255,195], [255,255,199], [255,255,203], [255,255,207], [255,255,211], [255,255,215], [255,255,219], [255,255,223], [255,255,227], [255,255,231], [255,255,235], [255,255,239], [255,255,243], [255,255,247], [255,255,251], [255,255,255]],
bbCm: [ [0,0,0], [2,0,0], [4,0,0], [6,0,0], [8,0,0], [10,0,0], [12,0,0], [14,0,0], [16,0,0], [18,0,0], [20,0,0], [22,0,0], [24,0,0], [26,0,0], [28,0,0], [30,0,0], [32,0,0], [34,0,0], [36,0,0], [38,0,0], [40,0,0], [42,0,0], [44,0,0], [46,0,0], [48,0,0], [50,0,0], [52,0,0], [54,0,0], [56,0,0], [58,0,0], [60,0,0], [62,0,0], [64,0,0], [66,0,0], [68,0,0], [70,0,0], [72,0,0], [74,0,0], [76,0,0], [78,0,0], [80,0,0], [82,0,0], [84,0,0], [86,0,0], [88,0,0], [90,0,0], [92,0,0], [94,0,0], [96,0,0], [98,0,0], [100,0,0], [102,0,0], [104,0,0], [106,0,0], [108,0,0], [110,0,0], [112,0,0], [114,0,0], [116,0,0], [118,0,0], [120,0,0], [122,0,0], [124,0,0], [126,0,0], [128,1,0], [130,3,0], [132,5,0], [134,7,0], [136,9,0], [138,11,0], [140,13,0], [142,15,0], [144,17,0], [146,19,0], [148,21,0], [150,23,0], [152,25,0], [154,27,0], [156,29,0], [158,31,0], [160,33,0], [162,35,0], [164,37,0], [166,39,0], [168,41,0], [170,43,0], [172,45,0], [174,47,0], [176,49,0], [178,51,0], [180,53,0], [182,55,0], [184,57,0], [186,59,0], [188,61,0], [190,63,0], [192,65,0], [194,67,0], [196,69,0], [198,71,0], [200,73,0], [202,75,0], [204,77,0], [206,79,0], [208,81,0], [210,83,0], [212,85,0], [214,87,0], [216,89,0], [218,91,0], [220,93,0], [222,95,0], [224,97,0], [226,99,0], [228,101,0], [230,103,0], [232,105,0], [234,107,0], [236,109,0], [238,111,0], [240,113,0], [242,115,0], [244,117,0], [246,119,0], [248,121,0], [250,123,0], [252,125,0], [255,127,0], [255,129,1], [255,131,3], [255,133,5], [255,135,7], [255,137,9], [255,139,11], [255,141,13], [255,143,15], [255,145,17], [255,147,19], [255,149,21], [255,151,23], [255,153,25], [255,155,27], [255,157,29], [255,159,31], [255,161,33], [255,163,35], [255,165,37], [255,167,39], [255,169,41], [255,171,43], [255,173,45], [255,175,47], [255,177,49], [255,179,51], [255,181,53], [255,183,55], [255,185,57], [255,187,59], [255,189,61], [255,191,63], [255,193,65], [255,195,67], [255,197,69], [255,199,71], [255,201,73], [255,203,75], [255,205,77], [255,207,79], [255,209,81], [255,211,83], [255,213,85], [255,215,87], [255,217,89], [255,219,91], [255,221,93], [255,223,95], [255,225,97], [255,227,99], [255,229,101], [255,231,103], [255,233,105], [255,235,107], [255,237,109], [255,239,111], [255,241,113], [255,243,115], [255,245,117], [255,247,119], [255,249,121], [255,251,123], [255,253,125], [255,255,127], [255,255,129], [255,255,131], [255,255,133], [255,255,135], [255,255,137], [255,255,139], [255,255,141], [255,255,143], [255,255,145], [255,255,147], [255,255,149], [255,255,151], [255,255,153], [255,255,155], [255,255,157], [255,255,159], [255,255,161], [255,255,163], [255,255,165], [255,255,167], [255,255,169], [255,255,171], [255,255,173], [255,255,175], [255,255,177], [255,255,179], [255,255,181], [255,255,183], [255,255,185], [255,255,187], [255,255,189], [255,255,191], [255,255,193], [255,255,195], [255,255,197], [255,255,199], [255,255,201], [255,255,203], [255,255,205], [255,255,207], [255,255,209], [255,255,211], [255,255,213], [255,255,215], [255,255,217], [255,255,219], [255,255,221], [255,255,223], [255,255,225], [255,255,227], [255,255,229], [255,255,231], [255,255,233], [255,255,235], [255,255,237], [255,255,239], [255,255,241], [255,255,243], [255,255,245], [255,255,247], [255,255,249], [255,255,251], [255,255,253], [255,255,255]],
blueCm: [ [0,0,0], [0,0,1], [0,0,2], [0,0,3], [0,0,4], [0,0,5], [0,0,6], [0,0,7], [0,0,8], [0,0,9], [0,0,10], [0,0,11], [0,0,12], [0,0,13], [0,0,14], [0,0,15], [0,0,16], [0,0,17], [0,0,18], [0,0,19], [0,0,20], [0,0,21], [0,0,22], [0,0,23], [0,0,24], [0,0,25], [0,0,26], [0,0,27], [0,0,28], [0,0,29], [0,0,30], [0,0,31], [0,0,32], [0,0,33], [0,0,34], [0,0,35], [0,0,36], [0,0,37], [0,0,38], [0,0,39], [0,0,40], [0,0,41], [0,0,42], [0,0,43], [0,0,44], [0,0,45], [0,0,46], [0,0,47], [0,0,48], [0,0,49], [0,0,50], [0,0,51], [0,0,52], [0,0,53], [0,0,54], [0,0,55], [0,0,56], [0,0,57], [0,0,58], [0,0,59], [0,0,60], [0,0,61], [0,0,62], [0,0,63], [0,0,64], [0,0,65], [0,0,66], [0,0,67], [0,0,68], [0,0,69], [0,0,70], [0,0,71], [0,0,72], [0,0,73], [0,0,74], [0,0,75], [0,0,76], [0,0,77], [0,0,78], [0,0,79], [0,0,80], [0,0,81], [0,0,82], [0,0,83], [0,0,84], [0,0,85], [0,0,86], [0,0,87], [0,0,88], [0,0,89], [0,0,90], [0,0,91], [0,0,92], [0,0,93], [0,0,94], [0,0,95], [0,0,96], [0,0,97], [0,0,98], [0,0,99], [0,0,100], [0,0,101], [0,0,102], [0,0,103], [0,0,104], [0,0,105], [0,0,106], [0,0,107], [0,0,108], [0,0,109], [0,0,110], [0,0,111], [0,0,112], [0,0,113], [0,0,114], [0,0,115], [0,0,116], [0,0,117], [0,0,118], [0,0,119], [0,0,120], [0,0,121], [0,0,122], [0,0,123], [0,0,124], [0,0,125], [0,0,126], [0,0,127], [0,0,128], [0,0,129], [0,0,130], [0,0,131], [0,0,132], [0,0,133], [0,0,134], [0,0,135], [0,0,136], [0,0,137], [0,0,138], [0,0,139], [0,0,140], [0,0,141], [0,0,142], [0,0,143], [0,0,144], [0,0,145], [0,0,146], [0,0,147], [0,0,148], [0,0,149], [0,0,150], [0,0,151], [0,0,152], [0,0,153], [0,0,154], [0,0,155], [0,0,156], [0,0,157], [0,0,158], [0,0,159], [0,0,160], [0,0,161], [0,0,162], [0,0,163], [0,0,164], [0,0,165], [0,0,166], [0,0,167], [0,0,168], [0,0,169], [0,0,170], [0,0,171], [0,0,172], [0,0,173], [0,0,174], [0,0,175], [0,0,176], [0,0,177], [0,0,178], [0,0,179], [0,0,180], [0,0,181], [0,0,182], [0,0,183], [0,0,184], [0,0,185], [0,0,186], [0,0,187], [0,0,188], [0,0,189], [0,0,190], [0,0,191], [0,0,192], [0,0,193], [0,0,194], [0,0,195], [0,0,196], [0,0,197], [0,0,198], [0,0,199], [0,0,200], [0,0,201], [0,0,202], [0,0,203], [0,0,204], [0,0,205], [0,0,206], [0,0,207], [0,0,208], [0,0,209], [0,0,210], [0,0,211], [0,0,212], [0,0,213], [0,0,214], [0,0,215], [0,0,216], [0,0,217], [0,0,218], [0,0,219], [0,0,220], [0,0,221], [0,0,222], [0,0,223], [0,0,224], [0,0,225], [0,0,226], [0,0,227], [0,0,228], [0,0,229], [0,0,230], [0,0,231], [0,0,232], [0,0,233], [0,0,234], [0,0,235], [0,0,236], [0,0,237], [0,0,238], [0,0,239], [0,0,240], [0,0,241], [0,0,242], [0,0,243], [0,0,244], [0,0,245], [0,0,246], [0,0,247], [0,0,248], [0,0,249], [0,0,250], [0,0,251], [0,0,252], [0,0,253], [0,0,254], [0,0,255]],
coolCm: [ [0,0,0], [0,0,1], [0,0,3], [0,0,5], [0,0,7], [0,0,9], [0,0,11], [0,0,13], [0,0,15], [0,0,17], [0,0,18], [0,0,20], [0,0,22], [0,0,24], [0,0,26], [0,0,28], [0,0,30], [0,0,32], [0,0,34], [0,0,35], [0,0,37], [0,0,39], [0,0,41], [0,0,43], [0,0,45], [0,0,47], [0,0,49], [0,0,51], [0,0,52], [0,0,54], [0,0,56], [0,0,58], [0,0,60], [0,0,62], [0,0,64], [0,0,66], [0,0,68], [0,0,69], [0,0,71], [0,0,73], [0,0,75], [0,0,77], [0,0,79], [0,0,81], [0,0,83], [0,0,85], [0,0,86], [0,0,88], [0,0,90], [0,0,92], [0,0,94], [0,0,96], [0,0,98], [0,0,100], [0,0,102], [0,0,103], [0,0,105], [0,1,107], [0,2,109], [0,4,111], [0,5,113], [0,6,115], [0,8,117], [0,9,119], [0,10,120], [0,12,122], [0,13,124], [0,14,126], [0,16,128], [0,17,130], [0,18,132], [0,20,134], [0,21,136], [0,23,137], [0,24,139], [0,25,141], [0,27,143], [0,28,145], [1,29,147], [1,31,149], [1,32,151], [1,33,153], [1,35,154], [2,36,156], [2,37,158], [2,39,160], [2,40,162], [2,42,164], [3,43,166], [3,44,168], [3,46,170], [3,47,171], [4,48,173], [4,50,175], [4,51,177], [4,52,179], [4,54,181], [5,55,183], [5,56,185], [5,58,187], [5,59,188], [5,61,190], [6,62,192], [6,63,194], [6,65,196], [6,66,198], [7,67,200], [7,69,202], [7,70,204], [7,71,205], [7,73,207], [8,74,209], [8,75,211], [8,77,213], [8,78,215], [8,80,217], [9,81,219], [9,82,221], [9,84,222], [9,85,224], [9,86,226], [10,88,228], [10,89,230], [10,90,232], [10,92,234], [11,93,236], [11,94,238], [11,96,239], [11,97,241], [11,99,243], [12,100,245], [12,101,247], [12,103,249], [12,104,251], [12,105,253], [13,107,255], [13,108,255], [13,109,255], [13,111,255], [14,112,255], [14,113,255], [14,115,255], [14,116,255], [14,118,255], [15,119,255], [15,120,255], [15,122,255], [15,123,255], [15,124,255], [16,126,255], [16,127,255], [16,128,255], [16,130,255], [17,131,255], [17,132,255], [17,134,255], [17,135,255], [17,136,255], [18,138,255], [18,139,255], [18,141,255], [18,142,255], [18,143,255], [19,145,255], [19,146,255], [19,147,255], [19,149,255], [19,150,255], [20,151,255], [20,153,255], [20,154,255], [20,155,255], [21,157,255], [21,158,255], [21,160,255], [21,161,255], [21,162,255], [22,164,255], [22,165,255], [22,166,255], [22,168,255], [22,169,255], [23,170,255], [23,172,255], [23,173,255], [23,174,255], [24,176,255], [24,177,255], [24,179,255], [24,180,255], [24,181,255], [25,183,255], [25,184,255], [25,185,255], [29,187,255], [32,188,255], [36,189,255], [40,191,255], [44,192,255], [47,193,255], [51,195,255], [55,196,255], [58,198,255], [62,199,255], [66,200,255], [69,202,255], [73,203,255], [77,204,255], [81,206,255], [84,207,255], [88,208,255], [92,210,255], [95,211,255], [99,212,255], [103,214,255], [106,215,255], [110,217,255], [114,218,255], [118,219,255], [121,221,255], [125,222,255], [129,223,255], [132,225,255], [136,226,255], [140,227,255], [143,229,255], [147,230,255], [151,231,255], [155,233,255], [158,234,255], [162,236,255], [166,237,255], [169,238,255], [173,240,255], [177,241,255], [180,242,255], [184,244,255], [188,245,255], [192,246,255], [195,248,255], [199,249,255], [203,250,255], [206,252,255], [210,253,255], [214,255,255], [217,255,255], [221,255,255], [225,255,255], [229,255,255], [232,255,255], [236,255,255], [240,255,255], [243,255,255], [247,255,255], [251,255,255], [255,255,255]],
cubehelix0Cm: [ [0,0,0], [2,1,2], [5,2,5], [5,2,5], [6,2,6], [7,2,7], [10,3,10], [12,5,12], [13,5,14], [14,5,16], [15,5,17], [16,6,20], [17,7,22], [18,8,24], [19,9,26], [20,10,28], [21,11,30], [22,12,33], [22,13,34], [22,14,36], [22,15,38], [24,16,40], [25,17,43], [25,18,45], [25,19,46], [25,20,48], [25,22,50], [25,23,51], [25,25,53], [25,26,54], [25,28,56], [25,28,57], [25,29,59], [25,30,61], [25,33,62], [25,35,63], [25,36,65], [25,37,67], [25,38,68], [25,40,70], [25,43,71], [24,45,72], [23,46,73], [22,48,73], [22,49,75], [22,51,76], [22,52,76], [22,54,76], [22,56,76], [22,57,77], [22,59,78], [22,61,79], [21,63,79], [20,66,79], [20,67,79], [20,68,79], [20,68,79], [20,71,79], [20,73,79], [20,75,78], [20,77,77], [20,79,76], [20,80,76], [20,81,76], [21,83,75], [22,85,74], [22,86,73], [22,89,72], [22,91,71], [23,92,71], [24,93,71], [25,94,71], [26,96,70], [28,99,68], [28,100,68], [29,101,67], [30,102,66], [31,102,65], [32,103,64], [33,104,63], [35,105,62], [38,107,61], [39,107,60], [39,108,59], [40,109,58], [43,110,57], [45,112,56], [47,113,55], [49,113,54], [51,114,53], [54,116,52], [58,117,51], [60,117,50], [62,117,49], [63,117,48], [66,118,48], [68,119,48], [71,119,48], [73,119,48], [76,119,48], [79,120,47], [81,121,46], [84,122,45], [87,122,45], [91,122,45], [94,122,46], [96,122,47], [99,122,48], [103,122,48], [107,122,48], [109,122,49], [112,122,50], [114,122,51], [118,122,52], [122,122,53], [124,122,54], [127,122,55], [130,122,56], [133,122,57], [137,122,58], [140,122,60], [142,122,62], [145,122,63], [149,122,66], [153,122,68], [155,121,70], [158,120,72], [160,119,73], [162,119,75], [164,119,77], [165,119,79], [169,119,81], [173,119,84], [175,119,86], [176,119,89], [178,119,91], [181,119,95], [183,119,99], [186,120,102], [188,121,104], [191,122,107], [192,122,110], [193,122,114], [195,122,117], [197,122,119], [198,122,122], [200,122,126], [201,122,130], [202,123,132], [203,124,135], [204,124,137], [204,125,141], [205,126,144], [206,127,147], [207,127,151], [209,127,155], [209,128,158], [210,129,160], [211,130,163], [211,131,167], [211,132,170], [211,133,173], [211,134,175], [211,135,178], [211,136,182], [211,137,186], [211,138,188], [211,139,191], [211,140,193], [211,142,196], [211,145,198], [210,146,201], [209,147,204], [209,147,206], [209,150,209], [209,153,211], [208,153,213], [207,154,215], [206,155,216], [206,157,218], [206,158,220], [206,160,221], [205,163,224], [204,165,226], [203,167,228], [202,169,230], [201,170,232], [201,172,233], [201,173,234], [200,175,235], [199,176,236], [198,178,237], [197,181,238], [196,183,239], [196,185,239], [196,187,239], [196,188,239], [195,191,240], [193,193,242], [193,194,242], [193,195,242], [193,196,242], [193,198,242], [193,199,242], [193,201,242], [193,204,242], [193,206,242], [193,208,242], [193,209,242], [193,211,242], [193,212,242], [193,214,242], [194,215,242], [195,217,242], [196,219,242], [196,220,242], [196,221,242], [197,223,241], [198,225,240], [198,226,239], [200,228,239], [201,229,239], [202,230,239], [203,231,239], [204,232,239], [205,233,239], [206,234,239], [207,235,239], [208,236,239], [209,237,239], [210,238,239], [212,238,239], [214,239,239], [215,240,239], [216,242,239], [218,243,239], [220,243,239], [221,244,239], [224,246,239], [226,247,239], [228,247,240], [230,247,241], [232,247,242], [234,248,242], [237,249,242], [238,249,243], [240,249,243], [242,249,244], [243,251,246], [244,252,247], [246,252,249], [248,252,250], [249,252,252], [251,253,253], [253,254,254], [255,255,255]],
cubehelix1Cm: [ [0,0,0], [2,0,2], [5,0,5], [6,0,7], [8,0,10], [10,0,12], [12,1,15], [15,2,17], [17,2,20], [18,2,22], [20,2,25], [21,2,29], [22,2,33], [23,3,35], [24,4,38], [25,5,40], [25,6,44], [25,7,48], [26,8,51], [27,9,53], [28,10,56], [28,11,59], [28,12,63], [27,14,66], [26,16,68], [25,17,71], [25,18,73], [25,19,74], [25,20,76], [24,22,80], [22,25,84], [22,27,85], [21,28,87], [20,30,89], [19,33,91], [17,35,94], [16,37,95], [14,39,96], [12,40,96], [11,43,99], [10,45,102], [8,47,102], [6,49,103], [5,51,104], [2,54,104], [0,58,104], [0,60,104], [0,62,104], [0,63,104], [0,66,104], [0,68,104], [0,71,104], [0,73,104], [0,76,104], [0,79,103], [0,81,102], [0,84,102], [0,86,99], [0,89,96], [0,91,96], [0,94,95], [0,96,94], [0,99,91], [0,102,89], [0,103,86], [0,105,84], [0,107,81], [0,109,79], [0,112,76], [0,113,73], [0,115,71], [0,117,68], [0,119,65], [0,122,61], [0,124,58], [0,125,56], [0,127,53], [0,128,51], [0,129,48], [0,130,45], [0,132,42], [0,135,38], [0,136,35], [0,136,33], [0,137,30], [3,138,26], [7,140,22], [10,140,21], [12,140,19], [15,140,17], [19,141,14], [22,142,10], [26,142,8], [29,142,6], [33,142,5], [38,142,2], [43,142,0], [46,142,0], [50,142,0], [53,142,0], [57,141,0], [62,141,0], [66,140,0], [72,140,0], [79,140,0], [83,139,0], [87,138,0], [91,137,0], [98,136,0], [104,135,0], [108,134,0], [113,133,0], [117,132,0], [123,131,0], [130,130,0], [134,129,0], [138,128,0], [142,127,0], [149,126,0], [155,124,0], [159,123,0], [164,121,1], [168,119,2], [174,118,6], [181,117,10], [185,116,12], [189,115,15], [193,114,17], [197,113,21], [200,113,24], [204,112,28], [209,110,33], [214,109,38], [217,108,41], [221,107,45], [224,107,48], [228,105,54], [232,104,61], [234,103,64], [237,102,68], [239,102,71], [243,102,77], [247,102,84], [249,101,89], [250,100,94], [252,99,99], [253,99,105], [255,99,112], [255,99,117], [255,99,122], [255,99,127], [255,99,131], [255,99,136], [255,99,140], [255,100,147], [255,102,155], [255,102,159], [255,102,164], [255,102,168], [255,103,174], [255,104,181], [255,105,185], [255,106,189], [255,107,193], [255,108,200], [255,109,206], [255,111,210], [255,113,215], [255,114,219], [253,117,224], [252,119,229], [250,120,232], [249,121,236], [247,122,239], [244,124,244], [242,127,249], [240,130,251], [238,132,253], [237,135,255], [234,136,255], [232,138,255], [229,140,255], [226,142,255], [224,145,255], [222,147,255], [221,150,255], [219,153,255], [215,156,255], [211,160,255], [209,162,255], [208,164,255], [206,165,255], [204,169,255], [201,173,255], [199,175,255], [198,178,255], [196,181,255], [193,183,255], [191,186,255], [189,188,255], [187,191,255], [186,193,255], [185,195,255], [184,197,255], [183,198,255], [182,202,255], [181,206,255], [180,208,255], [179,209,255], [178,211,255], [177,214,255], [175,216,255], [175,218,255], [175,220,255], [175,221,255], [175,224,255], [175,226,255], [176,228,255], [177,230,255], [178,232,255], [179,234,255], [181,237,255], [181,238,255], [182,238,255], [183,239,255], [184,240,252], [186,242,249], [187,243,249], [189,243,248], [191,244,247], [192,245,246], [194,246,245], [196,247,244], [198,248,243], [201,249,242], [203,250,242], [204,251,242], [206,252,242], [210,252,240], [214,252,239], [216,252,240], [219,252,241], [221,252,242], [224,253,242], [226,255,242], [229,255,243], [232,255,243], [234,255,244], [238,255,246], [242,255,247], [243,255,248], [245,255,249], [247,255,249], [249,255,251], [252,255,253], [255,255,255]],
greenCm: [ [0,0,0], [0,1,0], [0,2,0], [0,3,0], [0,4,0], [0,5,0], [0,6,0], [0,7,0], [0,8,0], [0,9,0], [0,10,0], [0,11,0], [0,12,0], [0,13,0], [0,14,0], [0,15,0], [0,16,0], [0,17,0], [0,18,0], [0,19,0], [0,20,0], [0,21,0], [0,22,0], [0,23,0], [0,24,0], [0,25,0], [0,26,0], [0,27,0], [0,28,0], [0,29,0], [0,30,0], [0,31,0], [0,32,0], [0,33,0], [0,34,0], [0,35,0], [0,36,0], [0,37,0], [0,38,0], [0,39,0], [0,40,0], [0,41,0], [0,42,0], [0,43,0], [0,44,0], [0,45,0], [0,46,0], [0,47,0], [0,48,0], [0,49,0], [0,50,0], [0,51,0], [0,52,0], [0,53,0], [0,54,0], [0,55,0], [0,56,0], [0,57,0], [0,58,0], [0,59,0], [0,60,0], [0,61,0], [0,62,0], [0,63,0], [0,64,0], [0,65,0], [0,66,0], [0,67,0], [0,68,0], [0,69,0], [0,70,0], [0,71,0], [0,72,0], [0,73,0], [0,74,0], [0,75,0], [0,76,0], [0,77,0], [0,78,0], [0,79,0], [0,80,0], [0,81,0], [0,82,0], [0,83,0], [0,84,0], [0,85,0], [0,86,0], [0,87,0], [0,88,0], [0,89,0], [0,90,0], [0,91,0], [0,92,0], [0,93,0], [0,94,0], [0,95,0], [0,96,0], [0,97,0], [0,98,0], [0,99,0], [0,100,0], [0,101,0], [0,102,0], [0,103,0], [0,104,0], [0,105,0], [0,106,0], [0,107,0], [0,108,0], [0,109,0], [0,110,0], [0,111,0], [0,112,0], [0,113,0], [0,114,0], [0,115,0], [0,116,0], [0,117,0], [0,118,0], [0,119,0], [0,120,0], [0,121,0], [0,122,0], [0,123,0], [0,124,0], [0,125,0], [0,126,0], [0,127,0], [0,128,0], [0,129,0], [0,130,0], [0,131,0], [0,132,0], [0,133,0], [0,134,0], [0,135,0], [0,136,0], [0,137,0], [0,138,0], [0,139,0], [0,140,0], [0,141,0], [0,142,0], [0,143,0], [0,144,0], [0,145,0], [0,146,0], [0,147,0], [0,148,0], [0,149,0], [0,150,0], [0,151,0], [0,152,0], [0,153,0], [0,154,0], [0,155,0], [0,156,0], [0,157,0], [0,158,0], [0,159,0], [0,160,0], [0,161,0], [0,162,0], [0,163,0], [0,164,0], [0,165,0], [0,166,0], [0,167,0], [0,168,0], [0,169,0], [0,170,0], [0,171,0], [0,172,0], [0,173,0], [0,174,0], [0,175,0], [0,176,0], [0,177,0], [0,178,0], [0,179,0], [0,180,0], [0,181,0], [0,182,0], [0,183,0], [0,184,0], [0,185,0], [0,186,0], [0,187,0], [0,188,0], [0,189,0], [0,190,0], [0,191,0], [0,192,0], [0,193,0], [0,194,0], [0,195,0], [0,196,0], [0,197,0], [0,198,0], [0,199,0], [0,200,0], [0,201,0], [0,202,0], [0,203,0], [0,204,0], [0,205,0], [0,206,0], [0,207,0], [0,208,0], [0,209,0], [0,210,0], [0,211,0], [0,212,0], [0,213,0], [0,214,0], [0,215,0], [0,216,0], [0,217,0], [0,218,0], [0,219,0], [0,220,0], [0,221,0], [0,222,0], [0,223,0], [0,224,0], [0,225,0], [0,226,0], [0,227,0], [0,228,0], [0,229,0], [0,230,0], [0,231,0], [0,232,0], [0,233,0], [0,234,0], [0,235,0], [0,236,0], [0,237,0], [0,238,0], [0,239,0], [0,240,0], [0,241,0], [0,242,0], [0,243,0], [0,244,0], [0,245,0], [0,246,0], [0,247,0], [0,248,0], [0,249,0], [0,250,0], [0,251,0], [0,252,0], [0,253,0], [0,254,0], [0,255,0]],
greyCm: [ [0,0,0], [1,1,1], [2,2,2], [3,3,3], [4,4,4], [5,5,5], [6,6,6], [7,7,7], [8,8,8], [9,9,9], [10,10,10], [11,11,11], [12,12,12], [13,13,13], [14,14,14], [15,15,15], [16,16,16], [17,17,17], [18,18,18], [19,19,19], [20,20,20], [21,21,21], [22,22,22], [23,23,23], [24,24,24], [25,25,25], [26,26,26], [27,27,27], [28,28,28], [29,29,29], [30,30,30], [31,31,31], [32,32,32], [33,33,33], [34,34,34], [35,35,35], [36,36,36], [37,37,37], [38,38,38], [39,39,39], [40,40,40], [41,41,41], [42,42,42], [43,43,43], [44,44,44], [45,45,45], [46,46,46], [47,47,47], [48,48,48], [49,49,49], [50,50,50], [51,51,51], [52,52,52], [53,53,53], [54,54,54], [55,55,55], [56,56,56], [57,57,57], [58,58,58], [59,59,59], [60,60,60], [61,61,61], [62,62,62], [63,63,63], [64,64,64], [65,65,65], [66,66,66], [67,67,67], [68,68,68], [69,69,69], [70,70,70], [71,71,71], [72,72,72], [73,73,73], [74,74,74], [75,75,75], [76,76,76], [77,77,77], [78,78,78], [79,79,79], [80,80,80], [81,81,81], [82,82,82], [83,83,83], [84,84,84], [85,85,85], [86,86,86], [87,87,87], [88,88,88], [89,89,89], [90,90,90], [91,91,91], [92,92,92], [93,93,93], [94,94,94], [95,95,95], [96,96,96], [97,97,97], [98,98,98], [99,99,99], [100,100,100], [101,101,101], [102,102,102], [103,103,103], [104,104,104], [105,105,105], [106,106,106], [107,107,107], [108,108,108], [109,109,109], [110,110,110], [111,111,111], [112,112,112], [113,113,113], [114,114,114], [115,115,115], [116,116,116], [117,117,117], [118,118,118], [119,119,119], [120,120,120], [121,121,121], [122,122,122], [123,123,123], [124,124,124], [125,125,125], [126,126,126], [127,127,127], [128,128,128], [129,129,129], [130,130,130], [131,131,131], [132,132,132], [133,133,133], [134,134,134], [135,135,135], [136,136,136], [137,137,137], [138,138,138], [139,139,139], [140,140,140], [141,141,141], [142,142,142], [143,143,143], [144,144,144], [145,145,145], [146,146,146], [147,147,147], [148,148,148], [149,149,149], [150,150,150], [151,151,151], [152,152,152], [153,153,153], [154,154,154], [155,155,155], [156,156,156], [157,157,157], [158,158,158], [159,159,159], [160,160,160], [161,161,161], [162,162,162], [163,163,163], [164,164,164], [165,165,165], [166,166,166], [167,167,167], [168,168,168], [169,169,169], [170,170,170], [171,171,171], [172,172,172], [173,173,173], [174,174,174], [175,175,175], [176,176,176], [177,177,177], [178,178,178], [179,179,179], [180,180,180], [181,181,181], [182,182,182], [183,183,183], [184,184,184], [185,185,185], [186,186,186], [187,187,187], [188,188,188], [189,189,189], [190,190,190], [191,191,191], [192,192,192], [193,193,193], [194,194,194], [195,195,195], [196,196,196], [197,197,197], [198,198,198], [199,199,199], [200,200,200], [201,201,201], [202,202,202], [203,203,203], [204,204,204], [205,205,205], [206,206,206], [207,207,207], [208,208,208], [209,209,209], [210,210,210], [211,211,211], [212,212,212], [213,213,213], [214,214,214], [215,215,215], [216,216,216], [217,217,217], [218,218,218], [219,219,219], [220,220,220], [221,221,221], [222,222,222], [223,223,223], [224,224,224], [225,225,225], [226,226,226], [227,227,227], [228,228,228], [229,229,229], [230,230,230], [231,231,231], [232,232,232], [233,233,233], [234,234,234], [235,235,235], [236,236,236], [237,237,237], [238,238,238], [239,239,239], [240,240,240], [241,241,241], [242,242,242], [243,243,243], [244,244,244], [245,245,245], [246,246,246], [247,247,247], [248,248,248], [249,249,249], [250,250,250], [251,251,251], [252,252,252], [253,253,253], [254,254,254], [255,255,255]],
heCm: [ [0,0,0], [42,0,10], [85,0,21], [127,0,31], [127,0,47], [127,0,63], [127,0,79], [127,0,95], [127,0,102], [127,0,109], [127,0,116], [127,0,123], [127,0,131], [127,0,138], [127,0,145], [127,0,152], [127,0,159], [127,8,157], [127,17,155], [127,25,153], [127,34,151], [127,42,149], [127,51,147], [127,59,145], [127,68,143], [127,76,141], [127,85,139], [127,93,136], [127,102,134], [127,110,132], [127,119,130], [127,127,128], [127,129,126], [127,131,124], [127,133,122], [127,135,120], [127,137,118], [127,139,116], [127,141,114], [127,143,112], [127,145,110], [127,147,108], [127,149,106], [127,151,104], [127,153,102], [127,155,100], [127,157,98], [127,159,96], [127,161,94], [127,163,92], [127,165,90], [127,167,88], [127,169,86], [127,171,84], [127,173,82], [127,175,80], [127,177,77], [127,179,75], [127,181,73], [127,183,71], [127,185,69], [127,187,67], [127,189,65], [127,191,63], [128,191,64], [129,191,65], [130,191,66], [131,192,67], [132,192,68], [133,192,69], [134,192,70], [135,193,71], [136,193,72], [137,193,73], [138,193,74], [139,194,75], [140,194,76], [141,194,77], [142,194,78], [143,195,79], [144,195,80], [145,195,81], [146,195,82], [147,196,83], [148,196,84], [149,196,85], [150,196,86], [151,196,87], [152,197,88], [153,197,89], [154,197,90], [155,197,91], [156,198,92], [157,198,93], [158,198,94], [159,198,95], [160,199,96], [161,199,97], [162,199,98], [163,199,99], [164,200,100], [165,200,101], [166,200,102], [167,200,103], [168,201,104], [169,201,105], [170,201,106], [171,201,107], [172,202,108], [173,202,109], [174,202,110], [175,202,111], [176,202,112], [177,203,113], [178,203,114], [179,203,115], [180,203,116], [181,204,117], [182,204,118], [183,204,119], [184,204,120], [185,205,121], [186,205,122], [187,205,123], [188,205,124], [189,206,125], [190,206,126], [191,206,127], [191,206,128], [192,207,129], [192,207,130], [193,208,131], [193,208,132], [194,208,133], [194,209,134], [195,209,135], [195,209,136], [196,210,137], [196,210,138], [197,211,139], [197,211,140], [198,211,141], [198,212,142], [199,212,143], [199,212,144], [200,213,145], [200,213,146], [201,214,147], [201,214,148], [202,214,149], [202,215,150], [203,215,151], [203,216,152], [204,216,153], [204,216,154], [205,217,155], [205,217,156], [206,217,157], [206,218,158], [207,218,159], [207,219,160], [208,219,161], [208,219,162], [209,220,163], [209,220,164], [210,220,165], [210,221,166], [211,221,167], [211,222,168], [212,222,169], [212,222,170], [213,223,171], [213,223,172], [214,223,173], [214,224,174], [215,224,175], [215,225,176], [216,225,177], [216,225,178], [217,226,179], [217,226,180], [218,226,181], [218,227,182], [219,227,183], [219,228,184], [220,228,185], [220,228,186], [221,229,187], [221,229,188], [222,230,189], [222,230,190], [223,230,191], [223,231,192], [224,231,193], [224,231,194], [225,232,195], [225,232,196], [226,233,197], [226,233,198], [227,233,199], [227,234,200], [228,234,201], [228,234,202], [229,235,203], [229,235,204], [230,236,205], [230,236,206], [231,236,207], [231,237,208], [232,237,209], [232,237,210], [233,238,211], [233,238,212], [234,239,213], [234,239,214], [235,239,215], [235,240,216], [236,240,217], [236,240,218], [237,241,219], [237,241,220], [238,242,221], [238,242,222], [239,242,223], [239,243,224], [240,243,225], [240,244,226], [241,244,227], [241,244,228], [242,245,229], [242,245,230], [243,245,231], [243,246,232], [244,246,233], [244,247,234], [245,247,235], [245,247,236], [246,248,237], [246,248,238], [247,248,239], [247,249,240], [248,249,241], [248,250,242], [249,250,243], [249,250,244], [250,251,245], [250,251,246], [251,251,247], [251,252,248], [252,252,249], [252,253,250], [253,253,251], [253,253,252], [254,254,253], [254,254,254], [255,255,255]],
heatCm: [ [0,0,0], [2,1,0], [5,2,0], [8,3,0], [11,4,0], [14,5,0], [17,6,0], [20,7,0], [23,8,0], [26,9,0], [29,10,0], [32,11,0], [35,12,0], [38,13,0], [41,14,0], [44,15,0], [47,16,0], [50,17,0], [53,18,0], [56,19,0], [59,20,0], [62,21,0], [65,22,0], [68,23,0], [71,24,0], [74,25,0], [77,26,0], [80,27,0], [83,28,0], [85,29,0], [88,30,0], [91,31,0], [94,32,0], [97,33,0], [100,34,0], [103,35,0], [106,36,0], [109,37,0], [112,38,0], [115,39,0], [118,40,0], [121,41,0], [124,42,0], [127,43,0], [130,44,0], [133,45,0], [136,46,0], [139,47,0], [142,48,0], [145,49,0], [148,50,0], [151,51,0], [154,52,0], [157,53,0], [160,54,0], [163,55,0], [166,56,0], [169,57,0], [171,58,0], [174,59,0], [177,60,0], [180,61,0], [183,62,0], [186,63,0], [189,64,0], [192,65,0], [195,66,0], [198,67,0], [201,68,0], [204,69,0], [207,70,0], [210,71,0], [213,72,0], [216,73,0], [219,74,0], [222,75,0], [225,76,0], [228,77,0], [231,78,0], [234,79,0], [237,80,0], [240,81,0], [243,82,0], [246,83,0], [249,84,0], [252,85,0], [255,86,0], [255,87,0], [255,88,0], [255,89,0], [255,90,0], [255,91,0], [255,92,0], [255,93,0], [255,94,0], [255,95,0], [255,96,0], [255,97,0], [255,98,0], [255,99,0], [255,100,0], [255,101,0], [255,102,0], [255,103,0], [255,104,0], [255,105,0], [255,106,0], [255,107,0], [255,108,0], [255,109,0], [255,110,0], [255,111,0], [255,112,0], [255,113,0], [255,114,0], [255,115,0], [255,116,0], [255,117,0], [255,118,0], [255,119,0], [255,120,0], [255,121,0], [255,122,0], [255,123,0], [255,124,0], [255,125,0], [255,126,0], [255,127,0], [255,128,0], [255,129,0], [255,130,0], [255,131,0], [255,132,0], [255,133,0], [255,134,0], [255,135,0], [255,136,0], [255,137,0], [255,138,0], [255,139,0], [255,140,0], [255,141,0], [255,142,0], [255,143,0], [255,144,0], [255,145,0], [255,146,0], [255,147,0], [255,148,0], [255,149,0], [255,150,0], [255,151,0], [255,152,0], [255,153,0], [255,154,0], [255,155,0], [255,156,0], [255,157,0], [255,158,0], [255,159,0], [255,160,0], [255,161,0], [255,162,0], [255,163,0], [255,164,0], [255,165,0], [255,166,3], [255,167,6], [255,168,9], [255,169,12], [255,170,15], [255,171,18], [255,172,21], [255,173,24], [255,174,27], [255,175,30], [255,176,33], [255,177,36], [255,178,39], [255,179,42], [255,180,45], [255,181,48], [255,182,51], [255,183,54], [255,184,57], [255,185,60], [255,186,63], [255,187,66], [255,188,69], [255,189,72], [255,190,75], [255,191,78], [255,192,81], [255,193,85], [255,194,88], [255,195,91], [255,196,94], [255,197,97], [255,198,100], [255,199,103], [255,200,106], [255,201,109], [255,202,112], [255,203,115], [255,204,118], [255,205,121], [255,206,124], [255,207,127], [255,208,130], [255,209,133], [255,210,136], [255,211,139], [255,212,142], [255,213,145], [255,214,148], [255,215,151], [255,216,154], [255,217,157], [255,218,160], [255,219,163], [255,220,166], [255,221,170], [255,222,173], [255,223,176], [255,224,179], [255,225,182], [255,226,185], [255,227,188], [255,228,191], [255,229,194], [255,230,197], [255,231,200], [255,232,203], [255,233,206], [255,234,209], [255,235,212], [255,236,215], [255,237,218], [255,238,221], [255,239,224], [255,240,227], [255,241,230], [255,242,233], [255,243,236], [255,244,239], [255,245,242], [255,246,245], [255,247,248], [255,248,251], [255,249,255], [255,250,255], [255,251,255], [255,252,255], [255,253,255], [255,254,255], [255,255,255]],
rainbowCm: [ [255,0,255], [250,0,255], [245,0,255], [240,0,255], [235,0,255], [230,0,255], [225,0,255], [220,0,255], [215,0,255], [210,0,255], [205,0,255], [200,0,255], [195,0,255], [190,0,255], [185,0,255], [180,0,255], [175,0,255], [170,0,255], [165,0,255], [160,0,255], [155,0,255], [150,0,255], [145,0,255], [140,0,255], [135,0,255], [130,0,255], [125,0,255], [120,0,255], [115,0,255], [110,0,255], [105,0,255], [100,0,255], [95,0,255], [90,0,255], [85,0,255], [80,0,255], [75,0,255], [70,0,255], [65,0,255], [60,0,255], [55,0,255], [50,0,255], [45,0,255], [40,0,255], [35,0,255], [30,0,255], [25,0,255], [20,0,255], [15,0,255], [10,0,255], [5,0,255], [0,0,255], [0,5,255], [0,10,255], [0,15,255], [0,20,255], [0,25,255], [0,30,255], [0,35,255], [0,40,255], [0,45,255], [0,50,255], [0,55,255], [0,60,255], [0,65,255], [0,70,255], [0,75,255], [0,80,255], [0,85,255], [0,90,255], [0,95,255], [0,100,255], [0,105,255], [0,110,255], [0,115,255], [0,120,255], [0,125,255], [0,130,255], [0,135,255], [0,140,255], [0,145,255], [0,150,255], [0,155,255], [0,160,255], [0,165,255], [0,170,255], [0,175,255], [0,180,255], [0,185,255], [0,190,255], [0,195,255], [0,200,255], [0,205,255], [0,210,255], [0,215,255], [0,220,255], [0,225,255], [0,230,255], [0,235,255], [0,240,255], [0,245,255], [0,250,255], [0,255,255], [0,255,250], [0,255,245], [0,255,240], [0,255,235], [0,255,230], [0,255,225], [0,255,220], [0,255,215], [0,255,210], [0,255,205], [0,255,200], [0,255,195], [0,255,190], [0,255,185], [0,255,180], [0,255,175], [0,255,170], [0,255,165], [0,255,160], [0,255,155], [0,255,150], [0,255,145], [0,255,140], [0,255,135], [0,255,130], [0,255,125], [0,255,120], [0,255,115], [0,255,110], [0,255,105], [0,255,100], [0,255,95], [0,255,90], [0,255,85], [0,255,80], [0,255,75], [0,255,70], [0,255,65], [0,255,60], [0,255,55], [0,255,50], [0,255,45], [0,255,40], [0,255,35], [0,255,30], [0,255,25], [0,255,20], [0,255,15], [0,255,10], [0,255,5], [0,255,0], [5,255,0], [10,255,0], [15,255,0], [20,255,0], [25,255,0], [30,255,0], [35,255,0], [40,255,0], [45,255,0], [50,255,0], [55,255,0], [60,255,0], [65,255,0], [70,255,0], [75,255,0], [80,255,0], [85,255,0], [90,255,0], [95,255,0], [100,255,0], [105,255,0], [110,255,0], [115,255,0], [120,255,0], [125,255,0], [130,255,0], [135,255,0], [140,255,0], [145,255,0], [150,255,0], [155,255,0], [160,255,0], [165,255,0], [170,255,0], [175,255,0], [180,255,0], [185,255,0], [190,255,0], [195,255,0], [200,255,0], [205,255,0], [210,255,0], [215,255,0], [220,255,0], [225,255,0], [230,255,0], [235,255,0], [240,255,0], [245,255,0], [250,255,0], [255,255,0], [255,250,0], [255,245,0], [255,240,0], [255,235,0], [255,230,0], [255,225,0], [255,220,0], [255,215,0], [255,210,0], [255,205,0], [255,200,0], [255,195,0], [255,190,0], [255,185,0], [255,180,0], [255,175,0], [255,170,0], [255,165,0], [255,160,0], [255,155,0], [255,150,0], [255,145,0], [255,140,0], [255,135,0], [255,130,0], [255,125,0], [255,120,0], [255,115,0], [255,110,0], [255,105,0], [255,100,0], [255,95,0], [255,90,0], [255,85,0], [255,80,0], [255,75,0], [255,70,0], [255,65,0], [255,60,0], [255,55,0], [255,50,0], [255,45,0], [255,40,0], [255,35,0], [255,30,0], [255,25,0], [255,20,0], [255,15,0], [255,10,0], [255,5,0], [255,0,0]],
redCm: [ [0,0,0], [1,0,0], [2,0,0], [3,0,0], [4,0,0], [5,0,0], [6,0,0], [7,0,0], [8,0,0], [9,0,0], [10,0,0], [11,0,0], [12,0,0], [13,0,0], [14,0,0], [15,0,0], [16,0,0], [17,0,0], [18,0,0], [19,0,0], [20,0,0], [21,0,0], [22,0,0], [23,0,0], [24,0,0], [25,0,0], [26,0,0], [27,0,0], [28,0,0], [29,0,0], [30,0,0], [31,0,0], [32,0,0], [33,0,0], [34,0,0], [35,0,0], [36,0,0], [37,0,0], [38,0,0], [39,0,0], [40,0,0], [41,0,0], [42,0,0], [43,0,0], [44,0,0], [45,0,0], [46,0,0], [47,0,0], [48,0,0], [49,0,0], [50,0,0], [51,0,0], [52,0,0], [53,0,0], [54,0,0], [55,0,0], [56,0,0], [57,0,0], [58,0,0], [59,0,0], [60,0,0], [61,0,0], [62,0,0], [63,0,0], [64,0,0], [65,0,0], [66,0,0], [67,0,0], [68,0,0], [69,0,0], [70,0,0], [71,0,0], [72,0,0], [73,0,0], [74,0,0], [75,0,0], [76,0,0], [77,0,0], [78,0,0], [79,0,0], [80,0,0], [81,0,0], [82,0,0], [83,0,0], [84,0,0], [85,0,0], [86,0,0], [87,0,0], [88,0,0], [89,0,0], [90,0,0], [91,0,0], [92,0,0], [93,0,0], [94,0,0], [95,0,0], [96,0,0], [97,0,0], [98,0,0], [99,0,0], [100,0,0], [101,0,0], [102,0,0], [103,0,0], [104,0,0], [105,0,0], [106,0,0], [107,0,0], [108,0,0], [109,0,0], [110,0,0], [111,0,0], [112,0,0], [113,0,0], [114,0,0], [115,0,0], [116,0,0], [117,0,0], [118,0,0], [119,0,0], [120,0,0], [121,0,0], [122,0,0], [123,0,0], [124,0,0], [125,0,0], [126,0,0], [127,0,0], [128,0,0], [129,0,0], [130,0,0], [131,0,0], [132,0,0], [133,0,0], [134,0,0], [135,0,0], [136,0,0], [137,0,0], [138,0,0], [139,0,0], [140,0,0], [141,0,0], [142,0,0], [143,0,0], [144,0,0], [145,0,0], [146,0,0], [147,0,0], [148,0,0], [149,0,0], [150,0,0], [151,0,0], [152,0,0], [153,0,0], [154,0,0], [155,0,0], [156,0,0], [157,0,0], [158,0,0], [159,0,0], [160,0,0], [161,0,0], [162,0,0], [163,0,0], [164,0,0], [165,0,0], [166,0,0], [167,0,0], [168,0,0], [169,0,0], [170,0,0], [171,0,0], [172,0,0], [173,0,0], [174,0,0], [175,0,0], [176,0,0], [177,0,0], [178,0,0], [179,0,0], [180,0,0], [181,0,0], [182,0,0], [183,0,0], [184,0,0], [185,0,0], [186,0,0], [187,0,0], [188,0,0], [189,0,0], [190,0,0], [191,0,0], [192,0,0], [193,0,0], [194,0,0], [195,0,0], [196,0,0], [197,0,0], [198,0,0], [199,0,0], [200,0,0], [201,0,0], [202,0,0], [203,0,0], [204,0,0], [205,0,0], [206,0,0], [207,0,0], [208,0,0], [209,0,0], [210,0,0], [211,0,0], [212,0,0], [213,0,0], [214,0,0], [215,0,0], [216,0,0], [217,0,0], [218,0,0], [219,0,0], [220,0,0], [221,0,0], [222,0,0], [223,0,0], [224,0,0], [225,0,0], [226,0,0], [227,0,0], [228,0,0], [229,0,0], [230,0,0], [231,0,0], [232,0,0], [233,0,0], [234,0,0], [235,0,0], [236,0,0], [237,0,0], [238,0,0], [239,0,0], [240,0,0], [241,0,0], [242,0,0], [243,0,0], [244,0,0], [245,0,0], [246,0,0], [247,0,0], [248,0,0], [249,0,0], [250,0,0], [251,0,0], [252,0,0], [253,0,0], [254,0,0], [255,0,0]],
standardCm: [ [0,0,0], [0,0,3], [1,1,6], [2,2,9], [3,3,12], [4,4,15], [5,5,18], [6,6,21], [7,7,24], [8,8,27], [9,9,30], [10,10,33], [10,10,36], [11,11,39], [12,12,42], [13,13,45], [14,14,48], [15,15,51], [16,16,54], [17,17,57], [18,18,60], [19,19,63], [20,20,66], [20,20,69], [21,21,72], [22,22,75], [23,23,78], [24,24,81], [25,25,85], [26,26,88], [27,27,91], [28,28,94], [29,29,97], [30,30,100], [30,30,103], [31,31,106], [32,32,109], [33,33,112], [34,34,115], [35,35,118], [36,36,121], [37,37,124], [38,38,127], [39,39,130], [40,40,133], [40,40,136], [41,41,139], [42,42,142], [43,43,145], [44,44,148], [45,45,151], [46,46,154], [47,47,157], [48,48,160], [49,49,163], [50,50,166], [51,51,170], [51,51,173], [52,52,176], [53,53,179], [54,54,182], [55,55,185], [56,56,188], [57,57,191], [58,58,194], [59,59,197], [60,60,200], [61,61,203], [61,61,206], [62,62,209], [63,63,212], [64,64,215], [65,65,218], [66,66,221], [67,67,224], [68,68,227], [69,69,230], [70,70,233], [71,71,236], [71,71,239], [72,72,242], [73,73,245], [74,74,248], [75,75,251], [76,76,255], [0,78,0], [1,80,1], [2,82,2], [3,84,3], [4,87,4], [5,89,5], [6,91,6], [7,93,7], [8,95,8], [9,97,9], [9,99,9], [10,101,10], [11,103,11], [12,105,12], [13,108,13], [14,110,14], [15,112,15], [16,114,16], [17,116,17], [18,118,18], [18,120,18], [19,122,19], [20,124,20], [21,126,21], [22,129,22], [23,131,23], [24,133,24], [25,135,25], [26,137,26], [27,139,27], [27,141,27], [28,143,28], [29,145,29], [30,147,30], [31,150,31], [32,152,32], [33,154,33], [34,156,34], [35,158,35], [36,160,36], [36,162,36], [37,164,37], [38,166,38], [39,168,39], [40,171,40], [41,173,41], [42,175,42], [43,177,43], [44,179,44], [45,181,45], [45,183,45], [46,185,46], [47,187,47], [48,189,48], [49,192,49], [50,194,50], [51,196,51], [52,198,52], [53,200,53], [54,202,54], [54,204,54], [55,206,55], [56,208,56], [57,210,57], [58,213,58], [59,215,59], [60,217,60], [61,219,61], [62,221,62], [63,223,63], [63,225,63], [64,227,64], [65,229,65], [66,231,66], [67,234,67], [68,236,68], [69,238,69], [70,240,70], [71,242,71], [72,244,72], [72,246,72], [73,248,73], [74,250,74], [75,252,75], [76,255,76], [78,0,0], [80,1,1], [82,2,2], [84,3,3], [86,4,4], [88,5,5], [91,6,6], [93,7,7], [95,8,8], [97,8,8], [99,9,9], [101,10,10], [103,11,11], [105,12,12], [107,13,13], [109,14,14], [111,15,15], [113,16,16], [115,16,16], [118,17,17], [120,18,18], [122,19,19], [124,20,20], [126,21,21], [128,22,22], [130,23,23], [132,24,24], [134,24,24], [136,25,25], [138,26,26], [140,27,27], [142,28,28], [144,29,29], [147,30,30], [149,31,31], [151,32,32], [153,32,32], [155,33,33], [157,34,34], [159,35,35], [161,36,36], [163,37,37], [165,38,38], [167,39,39], [169,40,40], [171,40,40], [174,41,41], [176,42,42], [178,43,43], [180,44,44], [182,45,45], [184,46,46], [186,47,47], [188,48,48], [190,48,48], [192,49,49], [194,50,50], [196,51,51], [198,52,52], [201,53,53], [203,54,54], [205,55,55], [207,56,56], [209,56,56], [211,57,57], [213,58,58], [215,59,59], [217,60,60], [219,61,61], [221,62,62], [223,63,63], [225,64,64], [228,64,64], [230,65,65], [232,66,66], [234,67,67], [236,68,68], [238,69,69], [240,70,70], [242,71,71], [244,72,72], [246,72,72], [248,73,73], [250,74,74], [252,75,75], [255,76,76]]
};
let cmapOptions = '';
Object.keys(cmaps).forEach(function(c) {
cmapOptions += '<option value="' + c + '">' + c + '</option>';
});
const $html = $('<div>' +
' Colormap: <select id="cmapSelect">' + cmapOptions +
' </select><br>' +
' Center: <span id="cmapCenter"></span>' +
'</div>');
const cmapUpdate = function() {
const val = $('#cmapSelect').val();
$('#cmapSelect').change(function() {
updateCallback(val);
});
return cmaps[val];
};
const spinnerSlider = new Spinner({
$element: $html.find('#cmapCenter'),
init: 128,
min: 1,
sliderMax: 254,
step: 1,
updateCallback: updateCallback
});
return {
html: $html,
getParams: function() {
return spinnerSlider.getValue();
},
getFilter: function() {
/*eslint new-cap: 0*/
return OpenSeadragon.Filters.COLORMAP(cmapUpdate(), spinnerSlider.getValue());
}
};
}
}, {
name: 'Colorize',
help: 'The adjustment range (strength) is from 0 to 100.' +
'The higher the value, the closer the colors in the ' +
'image shift towards the given adjustment color.' +
'Color values are between 0 to 255',
generate: function(updateCallback) {
const redSpinnerId = 'redSpinner-' + idIncrement;
const greenSpinnerId = 'greenSpinner-' + idIncrement;
const blueSpinnerId = 'blueSpinner-' + idIncrement;
const strengthSpinnerId = 'strengthSpinner-' + idIncrement;
/*eslint max-len: 0*/
const $html = $('<div class="wdzt-table-layout">' +
'<div class="wdzt-row-layout">' +
' <div class="wdzt-cell-layout">' +
' Red: <span id="' + redSpinnerId + '"></span>' +
' </div>' +
' <div class="wdzt-cell-layout">' +
' Green: <span id="' + greenSpinnerId + '"></span>' +
' </div>' +
' <div class="wdzt-cell-layout">' +
' Blue: <span id="' + blueSpinnerId + '"></span>' +
' </div>' +
' <div class="wdzt-cell-layout">' +
' Strength: <span id="' + strengthSpinnerId + '"></span>' +
' </div>' +
'</div>' +
'</div>');
const redSpinner = new Spinner({
$element: $html.find('#' + redSpinnerId),
init: 100,
min: 0,
max: 255,
step: 1,
updateCallback: updateCallback
});
const greenSpinner = new Spinner({
$element: $html.find('#' + greenSpinnerId),
init: 20,
min: 0,
max: 255,
step: 1,
updateCallback: updateCallback
});
const blueSpinner = new Spinner({
$element: $html.find('#' + blueSpinnerId),
init: 20,
min: 0,
max: 255,
step: 1,
updateCallback: updateCallback
});
const strengthSpinner = new Spinner({
$element: $html.find('#' + strengthSpinnerId),
init: 50,
min: 0,
max: 100,
step: 1,
updateCallback: updateCallback
});
return {
html: $html,
getParams: function() {
const red = redSpinner.getValue();
const green = greenSpinner.getValue();
const blue = blueSpinner.getValue();
const strength = strengthSpinner.getValue();
return 'R: ' + red + ' G: ' + green + ' B: ' + blue +
' S: ' + strength;
},
getFilter: function() {
const red = redSpinner.getValue();
const green = greenSpinner.getValue();
const blue = blueSpinner.getValue();
const strength = strengthSpinner.getValue();
return function(context) {
const promise = getPromiseResolver();
Caman(context.canvas, function() {
this.colorize(red, green, blue, strength);
this.render(promise.call.back);
});
return promise.promise;
};
}
};
}
}, {
name: 'Contrast',
help: 'Range is from 0 to infinity, although sane values are from 0 ' +
'to 4 or 5. Values between 0 and 1 will lessen the contrast ' +
'while values greater than 1 will increase it.',
generate: function(updateCallback) {
const $html = $('<div></div>');
const spinnerSlider = new SpinnerSlider({
$element: $html,
init: 1.3,
min: 0,
sliderMax: 4,
step: 0.1,
updateCallback: updateCallback
});
return {
html: $html,
getParams: function() {
return spinnerSlider.getValue();
},
getFilter: function() {
return OpenSeadragon.Filters.CONTRAST(
spinnerSlider.getValue());
}
};
}
}, {
name: 'Exposure',
help: 'Range is -100 to 100. Values < 0 will decrease ' +
'exposure while values > 0 will increase exposure',
generate: function(updateCallback) {
const $html = $('<div></div>');
const spinnerSlider = new SpinnerSlider({
$element: $html,
init: 10,
min: -100,
max: 100,
step: 1,
updateCallback: updateCallback
});
return {
html: $html,
getParams: function() {
return spinnerSlider.getValue();
},
getFilter: function() {
const value = spinnerSlider.getValue();
return function(context) {
const promise = getPromiseResolver();
Caman(context.canvas, function() {
this.exposure(value);
this.render(promise.call.back);
});
return promise.promise;
};
}
};
}
}, {
name: 'Gamma',
help: 'Range is from 0 to infinity, although sane values ' +
'are from 0 to 4 or 5. Values between 0 and 1 will ' +
'lessen the contrast while values greater than 1 will increase it.',
generate: function(updateCallback) {
const $html = $('<div></div>');
const spinnerSlider = new SpinnerSlider({
$element: $html,
init: 0.5,
min: 0,
sliderMax: 5,
step: 0.1,
updateCallback: updateCallback
});
return {
html: $html,
getParams: function() {
return spinnerSlider.getValue();
},
getFilter: function() {
const value = spinnerSlider.getValue();
return OpenSeadragon.Filters.GAMMA(value);
}
};
}
}, {
name: 'Hue',
help: 'hue value is between 0 to 100 representing the ' +
'percentage of Hue shift in the 0 to 360 range',
generate: function(updateCallback) {
const $html = $('<div></div>');
const spinnerSlider = new SpinnerSlider({
$element: $html,
init: 20,
min: 0,
max: 100,
step: 1,
updateCallback: updateCallback
});
return {
html: $html,
getParams: function() {
return spinnerSlider.getValue();
},
getFilter: function() {
const value = spinnerSlider.getValue();
return function(context) {
const promise = getPromiseResolver();
Caman(context.canvas, function() {
this.hue(value);
this.render(promise.call.back);
});
return promise.promise;
};
}
};
}
}, {
name: 'Saturation',
help: 'saturation value has to be between -100 and 100',
generate: function(updateCallback) {
const $html = $('<div></div>');
const spinnerSlider = new SpinnerSlider({
$element: $html,
init: 50,
min: -100,
max: 100,
step: 1,
updateCallback: updateCallback
});
return {
html: $html,
getParams: function() {
return spinnerSlider.getValue();
},
getFilter: function() {
const value = spinnerSlider.getValue();
return function(context) {
const promise = getPromiseResolver();
Caman(context.canvas, function() {
this.saturation(value);
this.render(promise.call.back);
});
return promise.promise;
};
}
};
}
}, {
name: 'Vibrance',
help: 'vibrance value has to be between -100 and 100',
generate: function(updateCallback) {
const $html = $('<div></div>');
const spinnerSlider = new SpinnerSlider({
$element: $html,
init: 50,
min: -100,
max: 100,
step: 1,
updateCallback: updateCallback
});
return {
html: $html,
getParams: function() {
return spinnerSlider.getValue();
},
getFilter: function() {
const value = spinnerSlider.getValue();
return function(context) {
const promise = getPromiseResolver();
Caman(context.canvas, function() {
this.vibrance(value);
this.render(promise.call.back);
});
return promise.promise;
};
}
};
}
}, {
name: 'Sepia',
help: 'sepia value has to be between 0 and 100',
generate: function(updateCallback) {
const $html = $('<div></div>');
const spinnerSlider = new SpinnerSlider({
$element: $html,
init: 50,
min: 0,
max: 100,
step: 1,
updateCallback: updateCallback
});
return {
html: $html,
getParams: function() {
return spinnerSlider.getValue();
},
getFilter: function() {
const value = spinnerSlider.getValue();
return function(context) {
const promise = getPromiseResolver();
Caman(context.canvas, function() {
this.sepia(value);
this.render(promise.call.back);
});
return promise.promise;
};
}
};
}
}, {
name: 'Noise',
help: 'Noise cannot be smaller than 0',
generate: function(updateCallback) {
const $html = $('<div></div>');
const spinnerSlider = new SpinnerSlider({
$element: $html,
init: 50,
min: 0,
step: 1,
updateCallback: updateCallback
});
return {
html: $html,
getParams: function() {
return spinnerSlider.getValue();
},
getFilter: function() {
const value = spinnerSlider.getValue();
return function(context) {
const promise = getPromiseResolver();
Caman(context.canvas, function() {
this.noise(value);
this.render(promise.call.back);
});
return promise.promise;
};
}
};
}
}, {
name: 'Greyscale',
generate: function() {
return {
html: '',
getParams: function() {
return '';
},
getFilter: function() {
return OpenSeadragon.Filters.GREYSCALE();
}
};
}
}, {
name: 'Sobel Edge',
generate: function() {
return {
html: '',
getParams: function() {
return '';
},
getFilter: function() {
return function(context) {
const imgData = context.getImageData(
0, 0, context.canvas.width, context.canvas.height);
const pixels = imgData.data;
const originalPixels = context.getImageData(0, 0, context.canvas.width, context.canvas.height).data;
const oneRowOffset = context.canvas.width * 4;
const onePixelOffset = 4;
let Gy, Gx, idx = 0;
for (let i = 1; i < context.canvas.height - 1; i += 1) {
idx = oneRowOffset * i + 4;
for (let j = 1; j < context.canvas.width - 1; j += 1) {
Gy = originalPixels[idx - onePixelOffset + oneRowOffset] + 2 * originalPixels[idx + oneRowOffset] + originalPixels[idx + onePixelOffset + oneRowOffset];
Gy = Gy - (originalPixels[idx - onePixelOffset - oneRowOffset] + 2 * originalPixels[idx - oneRowOffset] + originalPixels[idx + onePixelOffset - oneRowOffset]);
Gx = originalPixels[idx + onePixelOffset - oneRowOffset] + 2 * originalPixels[idx + onePixelOffset] + originalPixels[idx + onePixelOffset + oneRowOffset];
Gx = Gx - (originalPixels[idx - onePixelOffset - oneRowOffset] + 2 * originalPixels[idx - onePixelOffset] + originalPixels[idx - onePixelOffset + oneRowOffset]);
pixels[idx] = Math.sqrt(Gx * Gx + Gy * Gy); // 0.5*Math.abs(Gx) + 0.5*Math.abs(Gy);//100*Math.atan(Gy,Gx);
pixels[idx + 1] = 0;
pixels[idx + 2] = 0;
idx += 4;
}
}
context.putImageData(imgData, 0, 0);
};
}
};
}
}, {
name: 'Brightness',
help: 'Brightness must be between -255 (darker) and 255 (brighter).',
generate: function(updateCallback) {
const $html = $('<div></div>');
const spinnerSlider = new SpinnerSlider({
$element: $html,
init: 50,
min: -255,
max: 255,
step: 1,
updateCallback: updateCallback
});
return {
html: $html,
getParams: function() {
return spinnerSlider.getValue();
},
getFilter: function() {
return OpenSeadragon.Filters.BRIGHTNESS(
spinnerSlider.getValue());
}
};
}
}, {
name: 'Erosion',
help: 'The erosion kernel size must be an odd number.',
generate: function(updateCallback) {
const $html = $('<div></div>');
const spinner = new Spinner({
$element: $html,
init: 3,
min: 3,
step: 2,
updateCallback: updateCallback
});
return {
html: $html,
getParams: function() {
return spinner.getValue();
},
getFilter: function() {
return OpenSeadragon.Filters.MORPHOLOGICAL_OPERATION(
spinner.getValue(), Math.min);
}
};
}
}, {
name: 'Dilation',
help: 'The dilation kernel size must be an odd number.',
generate: function(updateCallback) {
const $html = $('<div></div>');
const spinner = new Spinner({
$element: $html,
init: 3,
min: 3,
step: 2,
updateCallback: updateCallback
});
return {
html: $html,
getParams: function() {
return spinner.getValue();
},
getFilter: function() {
return OpenSeadragon.Filters.MORPHOLOGICAL_OPERATION(
spinner.getValue(), Math.max);
}
};
}
}, {
name: 'Thresholding',
help: 'The threshold must be between 0 and 255.',
generate: function(updateCallback) {
const $html = $('<div></div>');
const spinnerSlider = new SpinnerSlider({
$element: $html,
init: 127,
min: 0,
max: 255,
step: 1,
updateCallback: updateCallback
});
return {
html: $html,
getParams: function() {
return spinnerSlider.getValue();
},
getFilter: function() {
return OpenSeadragon.Filters.THRESHOLDING(
spinnerSlider.getValue());
}
};
}
}];
availableFilters.sort(function(f1, f2) {
return f1.name.localeCompare(f2.name);
});
let idIncrement = 0;
const hashTable = {};
availableFilters.forEach(function(filter) {
const $li = $('<li></li>');
const $plus = $('<img src="static/plus.png" alt="+" class="button">');
$li.append($plus);
$li.append(filter.name);
$li.appendTo($('#available'));
$plus.click(function() {
const id = 'selected_' + idIncrement++;
const generatedFilter = filter.generate(updateFilters);
hashTable[id] = {
name: filter.name,
generatedFilter: generatedFilter
};
const $li = $('<li id="' + id + '"><div class="wdzt-table-layout"><div class="wdzt-row-layout"></div></div></li>');
const $minus = $('<div class="wdzt-cell-layout"><img src="static/minus.png" alt="-" class="button"></div>');
$li.find('.wdzt-row-layout').append($minus);
$li.find('.wdzt-row-layout').append('<div class="wdzt-cell-layout filterLabel">' + filter.name + '</div>');
if (filter.help) {
const $help = $('<div class="wdzt-cell-layout"><span title="' + filter.help + '">&nbsp;?&emsp;</span></div>');
$help.tooltip();
$li.find('.wdzt-row-layout').append($help);
}
$li.find('.wdzt-row-layout').append(
$('<div class="wdzt-cell-layout wdzt-full-width"></div>')
.append(generatedFilter.html));
$minus.click(function() {
delete hashTable[id];
$li.remove();
updateFilters();
});
$li.appendTo($('#selected'));
updateFilters();
});
});
$('#selected').sortable({
containment: 'parent',
axis: 'y',
tolerance: 'pointer',
update: updateFilters
});
function getPromiseResolver() {
let call = {};
let promise = new OpenSeadragon.Promise(resolve => {
call.back = resolve;
});
return {call, promise};
}
function updateFilters() {
const filters = [];
$('#selected li').each(function() {
const id = this.id;
const filter = hashTable[id];
filters.push(filter.generatedFilter.getFilter());
});
viewer.setFilterOptions({
filters: {
processors: filters
}
});
}

View File

@ -0,0 +1,74 @@
<!DOCTYPE html>
<!--
/*
* Modified and maintained by the OpenSeadragon Community.
*
* This software was orignally developed at the National Institute of Standards and
* Technology by employees of the Federal Government. NIST assumes
* no responsibility whatsoever for its use by other parties, and makes no
* guarantees, expressed or implied, about its quality, reliability, or
* any other characteristic.
*/
-->
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>OpenSeadragon Filtering Plugin Demo</title>
<script type="text/javascript" src='/build/openseadragon/openseadragon.js'></script>
<!-- JQuery -->
<script src="/test/lib/jquery-1.9.1.min.js"></script>
<link rel="stylesheet" href="/test/lib/jquery-ui-1.10.2/css/smoothness/jquery-ui-1.10.2.min.css">
<script src="/test/lib/jquery-ui-1.10.2/js/jquery-ui-1.10.2.min.js"></script>
<!-- Local -->
<link rel="stylesheet" href="style.css">
<script src="plugin.js"></script>
<!-- Thirdparty -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/camanjs/4.1.2/caman.full.min.js"></script>
</head>
<body>
<section class="home home-title">
<h1>OpenSeadragon filtering plugin demo.</h1>
<p>You might want to check the plugin repository to see if the plugin code is up to date.</p>
</section>
<section class="demo">
<div class="wdzt-table-layout wdzt-full-width">
<div class="wdzt-row-layout">
<div class="wdzt-cell-layout column-2">
<div id="openseadragon"></div>
</div>
<div class="wdzt-cell-layout column-2">
<h3>Available filters</h3>
<ul id="available">
</ul>
<h3>Selected filters</h3>
<ul id="selected"></ul>
<p>Drag and drop the selected filters to set their order.</p>
<br>
<label>
<input type="checkbox" onchange="viewer.setDebugMode(this.checked);">
Debug mode
</label>
</div>
</div>
</div>
</section>
<script src="demo.js"></script>
<!-- Google analytics -->
<script async type="text/javascript" id="_fed_an_ua_tag" src="https://dap.digitalgov.gov/Universal-Federated-Analytics-Min.js?agency=NIST&subagency=github&pua=UA-66610693-1&yt=true&exts=ppsx,pps,f90,sch,rtf,wrl,txz,m1v,xlsm,msi,xsd,f,tif,eps,mpg,xml,pl,xlt,c">
</script>
</body>
</html>

View File

@ -0,0 +1,371 @@
/*
* Modified and maintained by the OpenSeadragon Community.
*
* This software was orignally developed at the National Institute of Standards and
* Technology by employees of the Federal Government. NIST assumes
* no responsibility whatsoever for its use by other parties, and makes no
* guarantees, expressed or implied, about its quality, reliability, or
* any other characteristic.
* @author Antoine Vandecreme <antoine.vandecreme@nist.gov>
*/
(function() {
'use strict';
const $ = window.OpenSeadragon;
if (!$) {
throw new Error('OpenSeadragon is missing.');
}
// Requires OpenSeadragon >=2.1
if (!$.version || $.version.major < 2 ||
$.version.major === 2 && $.version.minor < 1) {
throw new Error(
'Filtering plugin requires OpenSeadragon version >= 2.1');
}
$.Viewer.prototype.setFilterOptions = function(options) {
if (!this.filterPluginInstance) {
options = options || {};
options.viewer = this;
this.filterPluginInstance = new $.FilterPlugin(options);
} else {
setOptions(this.filterPluginInstance, options);
}
};
/**
* @class FilterPlugin
* @param {Object} options The options
* @param {OpenSeadragon.Viewer} options.viewer The viewer to attach this
* plugin to.
* @param {Object[]} options.filters The filters to apply to the images.
* @param {OpenSeadragon.TiledImage[]} options.filters[x].items The tiled images
* on which to apply the filter.
* @param {function|function[]} options.filters[x].processors The processing
* function(s) to apply to the images. The parameter of this function is
* the context to modify.
*/
$.FilterPlugin = function(options) {
options = options || {};
if (!options.viewer) {
throw new Error('A viewer must be specified.');
}
const self = this;
this.viewer = options.viewer;
this.viewer.addHandler('tile-loaded', tileLoadedHandler);
this.viewer.addHandler('tile-needs-update', tileUpdateHandler);
// filterIncrement allows to determine whether a tile contains the
// latest filters results.
this.filterIncrement = 0;
setOptions(this, options);
async function tileLoadedHandler(event) {
await applyFilters(event.tile, event.tiledImage);
}
function tileUpdateHandler(event) {
const tile = event.tile;
const incrementCount = tile._filterIncrement;
if (incrementCount === self.filterIncrement) {
//we _know_ we have up-to-date data to render
return;
}
//go async otherwise
return applyFilters(tile, event.tiledImage);
}
async function applyFilters(tile, tiledImage) {
const processors = getFiltersProcessors(self, tiledImage);
if (processors.length === 0) {
//restore the original data
const context = await tile.getOriginalData('context2d',
false);
tile.setData(context, 'context2d');
tile._filterIncrement = self.filterIncrement;
return;
}
const contextCopy = await tile.getOriginalData('context2d');
const currentIncrement = self.filterIncrement;
for (let i = 0; i < processors.length; i++) {
if (self.filterIncrement !== currentIncrement) {
break;
}
await processors[i](contextCopy);
}
tile._filterIncrement = self.filterIncrement;
await tile.setData(contextCopy, 'context2d');
}
};
function setOptions(instance, options) {
options = options || {};
const filters = options.filters;
instance.filters = !filters ? [] :
$.isArray(filters) ? filters : [filters];
for (let i = 0; i < instance.filters.length; i++) {
const filter = instance.filters[i];
if (!filter.processors) {
throw new Error('Filter processors must be specified.');
}
filter.processors = $.isArray(filter.processors) ?
filter.processors : [filter.processors];
}
instance.filterIncrement++;
instance.viewer.world.invalidateItems();
instance.viewer.forceRedraw();
}
function getFiltersProcessors(instance, item) {
if (instance.filters.length === 0) {
return [];
}
let globalProcessors = null;
for (let i = 0; i < instance.filters.length; i++) {
const filter = instance.filters[i];
if (!filter.items) {
globalProcessors = filter.processors;
} else if (filter.items === item ||
$.isArray(filter.items) && filter.items.indexOf(item) >= 0) {
return filter.processors;
}
}
return globalProcessors ? globalProcessors : [];
}
$.Filters = {
THRESHOLDING: function(threshold) {
if (threshold < 0 || threshold > 255) {
throw new Error('Threshold must be between 0 and 255.');
}
return function(context) {
const imgData = context.getImageData(
0, 0, context.canvas.width, context.canvas.height);
const pixels = imgData.data;
for (let i = 0; i < pixels.length; i += 4) {
const r = pixels[i];
const g = pixels[i + 1];
const b = pixels[i + 2];
const v = (r + g + b) / 3;
pixels[i] = pixels[i + 1] = pixels[i + 2] =
v < threshold ? 0 : 255;
}
context.putImageData(imgData, 0, 0);
};
},
BRIGHTNESS: function(adjustment) {
if (adjustment < -255 || adjustment > 255) {
throw new Error(
'Brightness adjustment must be between -255 and 255.');
}
const precomputedBrightness = [];
for (let i = 0; i < 256; i++) {
precomputedBrightness[i] = i + adjustment;
}
return function(context) {
const imgData = context.getImageData(
0, 0, context.canvas.width, context.canvas.height);
const pixels = imgData.data;
for (let i = 0; i < pixels.length; i += 4) {
pixels[i] = precomputedBrightness[pixels[i]];
pixels[i + 1] = precomputedBrightness[pixels[i + 1]];
pixels[i + 2] = precomputedBrightness[pixels[i + 2]];
}
context.putImageData(imgData, 0, 0);
};
},
CONTRAST: function(adjustment) {
if (adjustment < 0) {
throw new Error('Contrast adjustment must be positive.');
}
const precomputedContrast = [];
for (let i = 0; i < 256; i++) {
precomputedContrast[i] = i * adjustment;
}
return function(context) {
const imgData = context.getImageData(
0, 0, context.canvas.width, context.canvas.height);
const pixels = imgData.data;
for (let i = 0; i < pixels.length; i += 4) {
pixels[i] = precomputedContrast[pixels[i]];
pixels[i + 1] = precomputedContrast[pixels[i + 1]];
pixels[i + 2] = precomputedContrast[pixels[i + 2]];
}
context.putImageData(imgData, 0, 0);
};
},
GAMMA: function(adjustment) {
if (adjustment < 0) {
throw new Error('Gamma adjustment must be positive.');
}
const precomputedGamma = [];
for (let i = 0; i < 256; i++) {
precomputedGamma[i] = Math.pow(i / 255, adjustment) * 255;
}
return function(context) {
const imgData = context.getImageData(
0, 0, context.canvas.width, context.canvas.height);
const pixels = imgData.data;
for (let i = 0; i < pixels.length; i += 4) {
pixels[i] = precomputedGamma[pixels[i]];
pixels[i + 1] = precomputedGamma[pixels[i + 1]];
pixels[i + 2] = precomputedGamma[pixels[i + 2]];
}
context.putImageData(imgData, 0, 0);
};
},
GREYSCALE: function() {
return function(context) {
const imgData = context.getImageData(
0, 0, context.canvas.width, context.canvas.height);
const pixels = imgData.data;
for (let i = 0; i < pixels.length; i += 4) {
const val = (pixels[i] + pixels[i + 1] + pixels[i + 2]) / 3;
pixels[i] = val;
pixels[i + 1] = val;
pixels[i + 2] = val;
}
context.putImageData(imgData, 0, 0);
};
},
INVERT: function() {
const precomputedInvert = [];
for (let i = 0; i < 256; i++) {
precomputedInvert[i] = 255 - i;
}
return function(context) {
const imgData = context.getImageData(
0, 0, context.canvas.width, context.canvas.height);
const pixels = imgData.data;
for (let i = 0; i < pixels.length; i += 4) {
pixels[i] = precomputedInvert[pixels[i]];
pixels[i + 1] = precomputedInvert[pixels[i + 1]];
pixels[i + 2] = precomputedInvert[pixels[i + 2]];
}
context.putImageData(imgData, 0, 0);
};
},
MORPHOLOGICAL_OPERATION: function(kernelSize, comparator) {
if (kernelSize % 2 === 0) {
throw new Error('The kernel size must be an odd number.');
}
const kernelHalfSize = Math.floor(kernelSize / 2);
if (!comparator) {
throw new Error('A comparator must be defined.');
}
return function(context) {
const width = context.canvas.width;
const height = context.canvas.height;
const imgData = context.getImageData(0, 0, width, height);
const originalPixels = context.getImageData(0, 0, width, height)
.data;
let offset;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
offset = (y * width + x) * 4;
let r = originalPixels[offset],
g = originalPixels[offset + 1],
b = originalPixels[offset + 2];
for (let j = 0; j < kernelSize; j++) {
for (let i = 0; i < kernelSize; i++) {
const pixelX = x + i - kernelHalfSize;
const pixelY = y + j - kernelHalfSize;
if (pixelX >= 0 && pixelX < width &&
pixelY >= 0 && pixelY < height) {
offset = (pixelY * width + pixelX) * 4;
r = comparator(originalPixels[offset], r);
g = comparator(
originalPixels[offset + 1], g);
b = comparator(
originalPixels[offset + 2], b);
}
}
}
imgData.data[offset] = r;
imgData.data[offset + 1] = g;
imgData.data[offset + 2] = b;
}
}
context.putImageData(imgData, 0, 0);
};
},
CONVOLUTION: function(kernel) {
if (!$.isArray(kernel)) {
throw new Error('The kernel must be an array.');
}
const kernelSize = Math.sqrt(kernel.length);
if ((kernelSize + 1) % 2 !== 0) {
throw new Error('The kernel must be a square matrix with odd' +
'width and height.');
}
const kernelHalfSize = (kernelSize - 1) / 2;
return function(context) {
const width = context.canvas.width;
const height = context.canvas.height;
const imgData = context.getImageData(0, 0, width, height);
const originalPixels = context.getImageData(0, 0, width, height)
.data;
let offset;
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
let r = 0, g = 0, b = 0;
for (let j = 0; j < kernelSize; j++) {
for (let i = 0; i < kernelSize; i++) {
const pixelX = x + i - kernelHalfSize;
const pixelY = y + j - kernelHalfSize;
if (pixelX >= 0 && pixelX < width &&
pixelY >= 0 && pixelY < height) {
offset = (pixelY * width + pixelX) * 4;
const weight = kernel[j * kernelSize + i];
r += originalPixels[offset] * weight;
g += originalPixels[offset + 1] * weight;
b += originalPixels[offset + 2] * weight;
}
}
}
offset = (y * width + x) * 4;
imgData.data[offset] = r;
imgData.data[offset + 1] = g;
imgData.data[offset + 2] = b;
}
}
context.putImageData(imgData, 0, 0);
};
},
COLORMAP: function(cmap, ctr) {
const resampledCmap = cmap.slice(0);
const diff = 255 - ctr;
for (let i = 0; i < 256; i++) {
let position = i > ctr ?
Math.min((i - ctr) / diff * 128 + 128,255) | 0 :
Math.max(0, i / (ctr / 128)) | 0;
resampledCmap[i] = cmap[position];
}
return function(context) {
const imgData = context.getImageData(
0, 0, context.canvas.width, context.canvas.height);
const pxl = imgData.data;
for (let i = 0; i < pxl.length; i += 4) {
const v = (pxl[i] + pxl[i + 1] + pxl[i + 2]) / 3 | 0;
const c = resampledCmap[v];
pxl[i] = c[0];
pxl[i + 1] = c[1];
pxl[i + 2] = c[2];
}
context.putImageData(imgData, 0, 0);
};
}
};
}());

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

View File

@ -0,0 +1,81 @@
/*
* Modified and maintained by the OpenSeadragon Community.
*
* This software was orignally developed at the National Institute of Standards and
* Technology by employees of the Federal Government. NIST assumes
* no responsibility whatsoever for its use by other parties, and makes no
* guarantees, expressed or implied, about its quality, reliability, or
* any other characteristic.
*/
.demo {
line-height: normal;
}
.demo h3 {
margin-top: 5px;
margin-bottom: 5px;
}
#openseadragon {
width: 100%;
height: 700px;
background-color: black;
}
.wdzt-table-layout {
display: table;
}
.wdzt-row-layout {
display: table-row;
}
.wdzt-cell-layout {
display: table-cell;
}
.wdzt-full-width {
width: 100%;
}
.wdzt-menu-slider {
margin-left: 10px;
margin-right: 10px;
}
.column-2 {
width: 50%;
vertical-align: top;
padding: 3px;
}
#available {
list-style-type: none;
}
ul {
padding: 0;
border: 1px solid black;
min-height: 25px;
}
li {
padding: 3px;
}
#selected {
list-style-type: none;
}
.button {
cursor: pointer;
vertical-align: text-top;
}
.filterLabel {
min-width: 120px;
}
#selected .filterLabel {
cursor: move;
}