diff --git a/script/openseadragon/openseadragon-filtering.js b/script/openseadragon/openseadragon-filtering.js deleted file mode 100644 index aabbb9d..0000000 --- a/script/openseadragon/openseadragon-filtering.js +++ /dev/null @@ -1,493 +0,0 @@ -/* - * This software was developed at the National Institute of Standards and - * Technology by employees of the Federal Government in the course of - * their official duties. Pursuant to title 17 Section 105 of the United - * States Code this software is not subject to copyright protection and is - * in the public domain. This software is an experimental system. 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. We would appreciate acknowledgement if the - * software is used. - */ - -/** - * - * @author Antoine Vandecreme - */ -(function() { - - 'use strict'; - - var $ = window.OpenSeadragon; - if (!$) { - $ = require('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 {String} [options.loadMode='async'] Set to sync to have the filters - * applied synchronously. It will only work if the filters are all synchronous. - * Note that depending on how complex the filters are, it may also hang the browser. - * @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 parameters of this function are - * the context to modify and a callback to call upon completion. - */ - $.FilterPlugin = function(options) { - options = options || {}; - if (!options.viewer) { - throw new Error('A viewer must be specified.'); - } - var self = this; - this.viewer = options.viewer; - - this.viewer.addHandler('tile-loaded', tileLoadedHandler); - this.viewer.addHandler('tile-drawing', tileDrawingHandler); - - // filterIncrement allows to determine whether a tile contains the - // latest filters results. - this.filterIncrement = 0; - - setOptions(this, options); - - - function tileLoadedHandler(event) { - var processors = getFiltersProcessors(self, event.tiledImage); - if (processors.length === 0) { - return; - } - var tile = event.tile; - var image = event.data; - if (image !== null && image !== undefined) { - var canvas = window.document.createElement('canvas'); - canvas.width = image.width; - canvas.height = image.height; - var context = canvas.getContext('2d'); - context.drawImage(image, 0, 0); - tile._renderedContext = context; - var callback = event.getCompletionCallback(); - applyFilters(context, processors, callback); - tile._filterIncrement = self.filterIncrement; - } - } - - - function applyFilters(context, filtersProcessors, callback) { - if (callback) { - var currentIncrement = self.filterIncrement; - var callbacks = []; - for (var i = 0; i < filtersProcessors.length - 1; i++) { - (function(i) { - callbacks[i] = function() { - // If the increment has changed, stop the computation - // chain immediately. - if (self.filterIncrement !== currentIncrement) { - return; - } - filtersProcessors[i + 1](context, callbacks[i + 1]); - }; - })(i); - } - callbacks[filtersProcessors.length - 1] = function() { - // If the increment has changed, do not call the callback. - // (We don't want OSD to draw an outdated tile in the canvas). - if (self.filterIncrement !== currentIncrement) { - return; - } - callback(); - }; - filtersProcessors[0](context, callbacks[0]); - } else { - for (var i = 0; i < filtersProcessors.length; i++) { - filtersProcessors[i](context, function() { - }); - } - } - } - - function tileDrawingHandler(event) { - var tile = event.tile; - var rendered = event.rendered; - if (rendered._filterIncrement === self.filterIncrement) { - return; - } - var processors = getFiltersProcessors(self, event.tiledImage); - if (processors.length === 0) { - if (rendered._originalImageData) { - // Restore initial data. - rendered.putImageData(rendered._originalImageData, 0, 0); - delete rendered._originalImageData; - } - rendered._filterIncrement = self.filterIncrement; - return; - } - - if (rendered._originalImageData) { - // The tile has been previously filtered (by another filter), - // restore it first. - rendered.putImageData(rendered._originalImageData, 0, 0); - } else { - rendered._originalImageData = rendered.getImageData( - 0, 0, rendered.canvas.width, rendered.canvas.height); - } - - if (tile._renderedContext) { - if (tile._filterIncrement === self.filterIncrement) { - var imgData = tile._renderedContext.getImageData(0, 0, - tile._renderedContext.canvas.width, - tile._renderedContext.canvas.height); - rendered.putImageData(imgData, 0, 0); - delete tile._renderedContext; - delete tile._filterIncrement; - rendered._filterIncrement = self.filterIncrement; - return; - } - delete tile._renderedContext; - delete tile._filterIncrement; - } - applyFilters(rendered, processors); - rendered._filterIncrement = self.filterIncrement; - } - }; - - function setOptions(instance, options) { - options = options || {}; - var filters = options.filters; - instance.filters = !filters ? [] : - $.isArray(filters) ? filters : [filters]; - for (var i = 0; i < instance.filters.length; i++) { - var 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++; - - if (options.loadMode === 'sync') { - instance.viewer.forceRedraw(); - } else { - var itemsToReset = []; - for (var i = 0; i < instance.filters.length; i++) { - var filter = instance.filters[i]; - if (!filter.items) { - itemsToReset = getAllItems(instance.viewer.world); - break; - } - if ($.isArray(filter.items)) { - for (var j = 0; j < filter.items.length; j++) { - addItemToReset(filter.items[j], itemsToReset); - } - } else { - addItemToReset(filter.items, itemsToReset); - } - } - for (var i = 0; i < itemsToReset.length; i++) { - itemsToReset[i].reset(); - } - } - } - - function addItemToReset(item, itemsToReset) { - if (itemsToReset.indexOf(item) >= 0) { - throw new Error('An item can not have filters ' + - 'assigned multiple times.'); - } - itemsToReset.push(item); - } - - function getAllItems(world) { - var result = []; - for (var i = 0; i < world.getItemCount(); i++) { - result.push(world.getItemAt(i)); - } - return result; - } - - function getFiltersProcessors(instance, item) { - if (instance.filters.length === 0) { - return []; - } - - var globalProcessors = null; - for (var i = 0; i < instance.filters.length; i++) { - var 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, callback) { - var imgData = context.getImageData( - 0, 0, context.canvas.width, context.canvas.height); - var pixels = imgData.data; - for (var i = 0; i < pixels.length; i += 4) { - var r = pixels[i]; - var g = pixels[i + 1]; - var b = pixels[i + 2]; - var v = (r + g + b) / 3; - pixels[i] = pixels[i + 1] = pixels[i + 2] = - v < threshold ? 0 : 255; - } - context.putImageData(imgData, 0, 0); - callback(); - }; - }, - BRIGHTNESS: function(adjustment) { - if (adjustment < -255 || adjustment > 255) { - throw new Error( - 'Brightness adjustment must be between -255 and 255.'); - } - var precomputedBrightness = []; - for (var i = 0; i < 256; i++) { - precomputedBrightness[i] = i + adjustment; - } - return function(context, callback) { - var imgData = context.getImageData( - 0, 0, context.canvas.width, context.canvas.height); - var pixels = imgData.data; - for (var 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); - callback(); - }; - }, - CONTRAST: function(adjustment) { - if (adjustment < 0) { - throw new Error('Contrast adjustment must be positive.'); - } - var precomputedContrast = []; - for (var i = 0; i < 256; i++) { - precomputedContrast[i] = i * adjustment; - } - return function(context, callback) { - var imgData = context.getImageData( - 0, 0, context.canvas.width, context.canvas.height); - var pixels = imgData.data; - for (var 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); - callback(); - }; - }, - GAMMA: function(adjustment) { - if (adjustment < 0) { - throw new Error('Gamma adjustment must be positive.'); - } - var precomputedGamma = []; - for (var i = 0; i < 256; i++) { - precomputedGamma[i] = Math.pow(i / 255, adjustment) * 255; - } - return function(context, callback) { - var imgData = context.getImageData( - 0, 0, context.canvas.width, context.canvas.height); - var pixels = imgData.data; - for (var 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); - callback(); - }; - }, - GREYSCALE: function() { - return function(context, callback) { - var imgData = context.getImageData( - 0, 0, context.canvas.width, context.canvas.height); - var pixels = imgData.data; - for (var i = 0; i < pixels.length; i += 4) { - var 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); - callback(); - }; - }, - INVERT: function() { - var precomputedInvert = []; - for (var i = 0; i < 256; i++) { - precomputedInvert[i] = 255 - i; - } - return function(context, callback) { - var imgData = context.getImageData( - 0, 0, context.canvas.width, context.canvas.height); - var pixels = imgData.data; - for (var 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); - callback(); - }; - }, - MORPHOLOGICAL_OPERATION: function(kernelSize, comparator) { - if (kernelSize % 2 === 0) { - throw new Error('The kernel size must be an odd number.'); - } - var kernelHalfSize = Math.floor(kernelSize / 2); - - if (!comparator) { - throw new Error('A comparator must be defined.'); - } - - return function(context, callback) { - var width = context.canvas.width; - var height = context.canvas.height; - var imgData = context.getImageData(0, 0, width, height); - var originalPixels = context.getImageData(0, 0, width, height) - .data; - var offset; - - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - offset = (y * width + x) * 4; - var r = originalPixels[offset]; - var g = originalPixels[offset + 1]; - var b = originalPixels[offset + 2]; - for (var j = 0; j < kernelSize; j++) { - for (var i = 0; i < kernelSize; i++) { - var pixelX = x + i - kernelHalfSize; - var 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); - callback(); - }; - }, - CONVOLUTION: function(kernel) { - if (!$.isArray(kernel)) { - throw new Error('The kernel must be an array.'); - } - var 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.'); - } - var kernelHalfSize = (kernelSize - 1) / 2; - - return function(context, callback) { - var width = context.canvas.width; - var height = context.canvas.height; - var imgData = context.getImageData(0, 0, width, height); - var originalPixels = context.getImageData(0, 0, width, height) - .data; - var offset; - - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - var r = 0; - var g = 0; - var b = 0; - for (var j = 0; j < kernelSize; j++) { - for (var i = 0; i < kernelSize; i++) { - var pixelX = x + i - kernelHalfSize; - var pixelY = y + j - kernelHalfSize; - if (pixelX >= 0 && pixelX < width && - pixelY >= 0 && pixelY < height) { - offset = (pixelY * width + pixelX) * 4; - var 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); - callback(); - }; - }, - COLORMAP: function(cmap, ctr) { - var resampledCmap = cmap.slice(0); - var diff = 255 - ctr; - for(var i = 0; i < 256; i++) { - var position = 0; - if(i > ctr) { - position = Math.min((i - ctr) / diff * 128 + 128,255) | 0; - }else{ - position = Math.max(0, i / (ctr / 128)) | 0; - } - resampledCmap[i] = cmap[position]; - } - return function(context, callback) { - var imgData = context.getImageData( - 0, 0, context.canvas.width, context.canvas.height); - var pxl = imgData.data; - for (var i = 0; i < pxl.length; i += 4) { - var v = (pxl[i] + pxl[i + 1] + pxl[i + 2]) / 3 | 0; - var c = resampledCmap[v]; - pxl[i] = c[0]; - pxl[i + 1] = c[1]; - pxl[i + 2] = c[2]; - } - context.putImageData(imgData, 0, 0); - callback(); - }; - } - }; - -}());