Author: jodogne-guest Date: 2015-12-07 15:27:48 +0000 (Mon, 07 Dec 2015) New Revision: 20664
Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.8.4/ trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.8.4/LICENSE trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.8.4/README.md trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.8.4/cornerstone.css trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.8.4/cornerstone.js Removed: trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.7.1/ Modified: trunk/packages/orthanc-webviewer/trunk/debian/changelog trunk/packages/orthanc-webviewer/trunk/debian/rules Log: Upgrade Cornerstone version: 0.7.1 to 0.8.4 Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.8.4/LICENSE =================================================================== --- trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.8.4/LICENSE (rev 0) +++ trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.8.4/LICENSE 2015-12-07 15:27:48 UTC (rev 20664) @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Chris Hafey (cha...@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.8.4/README.md =================================================================== --- trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.8.4/README.md (rev 0) +++ trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.8.4/README.md 2015-12-07 15:27:48 UTC (rev 20664) @@ -0,0 +1,252 @@ +Cornerstone Core +================ + +Cornerstone is an open source project with a goal to deliver a complete web based medical imaging platform. This +repository contains the Cornerstone Core component which is a lightweight JavaScript library for displaying +medical images in modern web browsers that support the HTML5 canvas element. +Cornerstone Core is not meant to be a complete application itself, but instead a component +that can be used as part of larger more complex applications. See the +[CornerstoneDemo](http://chafey.github.io/cornerstoneDemo/) for an example of using the various Cornerstone +libraries to build a simple study viewer. + +Cornerstone Core is agnostic to the actual container used to store image pixels as well as the transport mechanism +used to get the image data. In fact, Cornerstone Core itself has no ability to read/parse or load images and instead +depends on one or more [ImageLoaders](https://github.com/chafey/cornerstone/wiki/ImageLoader) to function. +The goal here is to avoid constraining developers to work within a single container and transport (e.g. DICOM) since +images are stored in a variety of formats (including proprietary). By providing flexibility with respect to the +container and transport, the highest performance image display may be obtained as no conversion to an alternate +container or transport is required. It is hoped that developers feel empowered to load images from any type of image +container using any kind of transport. See the +[CornerstoneWADOImageLoader](https://github.com/chafey/cornerstoneWADOImageLoader) project for an example +of a DICOM WADO based Image Loader. + +Cornerstone Core is agnostic to the exact interaction paradigm being used. It does not include any mouse, touch or +keyboard bindings to manipulate the various image properties such as scale, translation or ww/wc. The goal here +is to avoid constraining developers using this library to fit into a given ui paradigm. It is hoped that developers +are empowered to create new paradigms possibly using new input mechanisms to interact with medical images (e.g. +[Kinect](http://en.wikipedia.org/wiki/Kinect) or [Accelerometer](http://en.wikipedia.org/wiki/Accelerometer). +Cornerstone does provide a set of API's allowing manipulation of the image properties via javascript. +See the [CornerstoneTools](https://github.com/chafey/cornerstoneTools) library for an example of common tools built on top of +Cornerstone. + +Community +--------- + +Have questions? Try posting on our [google groups forum](https://groups.google.com/forum/#!forum/cornerstone-platform). + +Live Examples +--------------- +The best way to see the power of this library is to actually see it in use. + +[Click here for a list of examples of using the Cornerstone library.](https://rawgit.com/chafey/cornerstone/master/example/index.html) + +Install +------- + +Get a packaged source file: + +* [cornerstone.js](https://raw.githubusercontent.com/chafey/cornerstone/master/dist/cornerstone.js) +* [cornerstone.min.js](https://raw.githubusercontent.com/chafey/cornerstone/master/dist/cornerstone.min.js) + +Or install via [Bower](http://bower.io/): + +> bower install cornerstone + + +Key Features +------------ + + * HTML5/Javascript based library to easily add interactive medical images to web applications + * Serves as a foundation to build more complex medical imaging applications from - enterprise viewer, report viewer, etc. + * Supports all HTML5 based browsers including mobile, tablet and desktop + * Displays all common medical image formats (e.g. 8 bit grayscale, 16 bit grayscale, RGB color) + * High performance image display + * Retrieval of images from different systems with different protocols via Image Loader plugin design + * API support for changing viewport properties (e.g. ww/wc, zoom, pan, invert) + +Build System +============ + +This project uses grunt to build the software. + +Pre-requisites: +--------------- + +NodeJs - [click to visit web site for installation instructions](http://nodejs.org). + +grunt-cli + +> npm install -g grunt-cli + +bower + +> npm install -g bower + +Common Tasks +------------ + +Update dependencies (after each pull): +> npm install + +> bower install + +Running the build: +> grunt + +Automatically running the build and unit tests after each source change: +> grunt watch + +Links +===== + +[View the wiki for documentation on the concepts and APIs](https://github.com/chafey/cornerstone/wiki) + +[View Roadmap](docs/roadmap.md) + +[View Backlog](docs/backlog.md) + +[comp.protocols.dicom thread](https://groups.google.com/forum/#!topic/comp.protocols.dicom/_2fMh69GdAM) + +[Trello](https://trello.com/b/tGTDIyt4/cornerstone) + +[CornerstoneTools](https://github.com/chafey/cornerstoneTools) - A library of common tools that can be used with Cornerstone + +[CornerstoneWADOImageLoader ](https://github.com/chafey/cornerstoneWADOImageLoader) - A Cornerstone Image Loader that works with WADO + +[dicomParser ](https://github.com/chafey/dicomParser) - A JavaScript library designed to parse DICOM for web browsers + +Code Contributors +================= + +I welcome pull requests, please see FAQ below for guidance on this. + +* @simonmd - CSS improvements in the cornerstoneDemo application +* @doncharkowsky - The angle tool in cornerstoneTools +* @prasath-rasterimages - Touch event bindings in cornerstoneTools +* @jpamburn - Performance optimizations for signed data, fixes for image caching +* @jmhmd - for getPixels() implementation +* @devishree-raster - for flip and rotate implementation + +FAQ +=== + +_Why did you decide to license this library using the open source MIT license?_ + +The main reason this library is released as [open source](http://en.wikipedia.org/wiki/Open_source) is +that I believe that medical imaging in particular can do a lot more to improve patient outcomes +but the cost of doing so is prohibitive. Making this library open source removes the cost barrier and will +hopefully usher in a new set of medical imaging based applications. + +The old adage [a picture is worth a thousand words](http://en.wikipedia.org/wiki/A_picture_is_worth_a_thousand_words) +is very true in medical imaging. When a patient is going through a disease process, they often face fear +and confusion. Medical terminology amplifies these issues as it is hard to understand and therefore +disempowering. Medical imaging allows a mysterious health issue to be visualized and therefore brings a +level of understanding that just can't be accomplished via textual information found in lab or radiology +reports. By helping a patient (and its supporting friends/family) connect with the disease visually through +images, it is believed that fear, anxiety and confusion will all be reduced which +will increase optimism and therefore patient outcomes. + +It is my hope that this library be used to build a variety of applications and experiences +to deliver on this vision. The MIT license allows this library to be used in any type of application - personal, +open source and commercial and is therefore appropriate to support this vision. If you are reading this, +I hope you can join me in this mission as there is still a lot to be done. + +_Why doesn't Cornerstone natively support the display of DICOM images?_ + +While DICOM has support for just about every type of medical image, there are many cases where medical images +are not stored in DICOM format. In many cases, a PACS may receive DICOM images but store them in a proprietary +format on disk. In this case, it can be faster to access images by having an image loader that works with +a proprietary PACS interface that would not require conversion from the proprietary format into a standard format +like DICOM. Another example of this is is dermatology where images are often taken using standard +digital cameras and are stored as JPEG not DICOM. + +The main reason this library is not based around DICOM is that it wants to reach the widest possible adoption +and that will be accomplished by supporting as many types of image containers and transports possible. +Another side effect of this approach is that the code base is smaller and easier to understand since +it is focused on doing exactly one thing. That being said, it is is expected that the majority of images +displayed using this library will have originated as DICOM images. It is therefore important to make sure +that there are no limitations with respect to displaying the different types of DICOM images and have robust +supporting libraries for DICOM. Separate libraries to add DICOM specific support already exist, check out the +[CornerstoneWADOImageLoader](https://github.com/chafey/cornerstoneWADOImageLoader) library and +the (dicomParser)[https://github.com/chafey/dicomParser] library. + +_Why doesn't Cornerstone include basic tools like ww/wc using the mouse?_ + +There is no standard for user interaction in medical imaging and a wide variety of interaction paradigms exist. +For example, one medical imaging application may use the left mouse button to adjust ww/wc and another may use the +right mouse button. The main reason this library does not include tools is that it wants to reach the widest possible +adoption and that will only be accomplished by making any interaction paradigm possible. No tools +are therefore provided with this library allowing users of the library to choose +whatever interaction paradigm they like. It is also hoped that this approach will make it easier for developers +to experiment with new user input mechanisms like [Kinect](http://en.wikipedia.org/wiki/Kinect) or +[Accelerometer](http://en.wikipedia.org/wiki/Accelerometer). Another side effect of this +approach is that the code base is smaller and easier to understand since it is focused on doing exactly one +thing. Tools are provided using the separate [CornerstoneTools](https://github.com/chafey/cornerstoneTools) +if desired. + +_Why does this library require HTML5 canvas when IE8 is the main browser used in healthcare?_ + +The fact that IE8 is the most popular commonly used web browser in healthcare right now is a temporary +situation. It is expected that 50% of the industry will have HTML5 based web browsers deployed by the end +of 2015 and 90% by 2017. The library made a tradeoff to focus on the future platform to keep the code base +simple and avoid compromises related to older browser technology. Note that it may be possible to get +this library to work on IE8 using [excanvas](https://code.google.com/p/explorercanvas/) but I haven't tried +it yet. + +_Why doesn't this library support stacks of images?_ + +Images stack functionality such as a CT series or MRI series can actually be quite complex. Regardless of +what stack functionality is desired, all stacks ultimately need to be able to display a single image and that +is what this library is focused on doing. Stack functionality is therefore pushed up to a higher layer. The +[CornerstoneTools](https://github.com/chafey/cornerstoneTools) contains stack functionality and is a good place +to look to see how various stack related functionality is implemented. + +_How do you envision this library supporting 3D functionality such as MPR, MIP and VR?_ + +This library would be responsible for displaying the rendered image to the user. The rendering of the +3D image would be done by some other library - perhaps on the server side. This library is purely 2D and has +no knowledge of 3D image space. It will probably make sense to have several layers on top of this library +to provide 3D functionality. For example, one layer that has a 3D viewport with properties such as transformation +matrix, slice thickness, transfer function/LUT, segmentation masks, etc. And another 3D tools layer that provides +various tools on top of the 3d viewport (rotate, zoom, segment, scroll, etc). I do have a working 3D server that +is integrated with cornerstone but am keeping the code closed for now (this may change in the future - TBD). + +_Why did you add jQuery as a dependency?_ + +Primarily for its custom event handling. + +_I would like to contribute code - how do I do this?_ + +Fork the repository, make your change and submit a pull request. + +_Any guidance on submitting changes?_ + +While I do appreciate code contributions, I will not merge it unless it meets the following criteria: + +* Functionality is appropriate for the repository. Consider posting on the forum if you are not sure +* Code quality is acceptable. I don't have coding standards defined, but make sure it passes jshint and looks like + the rest of the code in the repository. +* Quality of design is acceptable. This is a bit subjective so you should consider posting on the forum for specific guidance + +I will provide feedback on your pull request if it fails to meet any of the above. + +Please consider separate pull requests for each feature as big pull requests are very time consuming to understand. +It is highly probably that I will reject a large pull request due to the time it would take to comprehend. + +_Will you add feature XYZ for me?_ + +If it is in the roadmap, I intend to implement it some day - probably when I actually need it. If you really need +something now and are willing to pay for it, try posting on the cornerstone platform google group + +_How mature is Cornerstone?_ + +Each repository is at a different level of maturity. There are at least 50 image viewer projects using Cornerstone +and the feedback has been consistently strong about the architecture, design and quality. The cornerstoneTools library +is the least mature from a framework and breadth of functionality perspective - but the implemented features work well. + +Copyright +========= + +Copyright 2015 Chris Hafey [cha...@gmail.com](mailto:cha...@gmail.com) + + Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.8.4/cornerstone.css =================================================================== --- trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.8.4/cornerstone.css (rev 0) +++ trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.8.4/cornerstone.css 2015-12-07 15:27:48 UTC (rev 20664) @@ -0,0 +1,17 @@ +/*! cornerstone - v0.8.4 - 2015-09-12 | (c) 2014 Chris Hafey | https://github.com/chafey/cornerstone */ +.cornerstone-enabled-image { + + /* prevent text selection from occurring when dragging the mouse on the div */ + /* http://stackoverflow.com/questions/826782/css-rule-to-disable-text-selection-highlighting */ + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + + /* force the cursor to always be the default arrow. This prevents it from changing to an ibar when it is + over HTML based text overlays (four corners */ + cursor:default; +} + Added: trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.8.4/cornerstone.js =================================================================== --- trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.8.4/cornerstone.js (rev 0) +++ trunk/packages/orthanc-webviewer/trunk/debian/JS/cornerstone-0.8.4/cornerstone.js 2015-12-07 15:27:48 UTC (rev 20664) @@ -0,0 +1,2022 @@ +/*! cornerstone - v0.8.4 - 2015-09-12 | (c) 2014 Chris Hafey | https://github.com/chafey/cornerstone */ +if(typeof cornerstone === 'undefined'){ + cornerstone = { + internal : {}, + rendering: {} + }; +} + +(function (cornerstone) { + + "use strict"; + + function disable(element) { + if(element === undefined) { + throw "disable: element element must not be undefined"; + } + + // Search for this element in this list of enabled elements + var enabledElements = cornerstone.getEnabledElements(); + for(var i=0; i < enabledElements.length; i++) { + if(enabledElements[i].element === element) { + // We found it! + + // Fire an event so dependencies can cleanup + var eventData = { + element : element + }; + $(element).trigger("CornerstoneElementDisabled", eventData); + + // remove the child dom elements that we created (e.g.canvas) + enabledElements[i].element.removeChild(enabledElements[i].canvas); + + // remove this element from the list of enabled elements + enabledElements.splice(i, 1); + return; + } + } + } + + // module/private exports + cornerstone.disable = disable; + +}(cornerstone)); +/** + * This module is responsible for enabling an element to display images with cornerstone + */ +(function ($, cornerstone) { + + "use strict"; + + /** + * sets a new image object for a given element + * @param element + * @param image + */ + function displayImage(element, image, viewport) { + if(element === undefined) { + throw "displayImage: parameter element cannot be undefined"; + } + if(image === undefined) { + throw "displayImage: parameter image cannot be undefined"; + } + + var enabledElement = cornerstone.getEnabledElement(element); + + enabledElement.image = image; + + if(enabledElement.viewport === undefined) { + enabledElement.viewport = cornerstone.internal.getDefaultViewport(enabledElement.canvas, image); + } + + // merge viewport + if(viewport) { + for(var attrname in viewport) + { + if(viewport[attrname] !== null) { + enabledElement.viewport[attrname] = viewport[attrname]; + } + } + } + + var now = new Date(); + var frameRate; + if(enabledElement.lastImageTimeStamp !== undefined) { + var timeSinceLastImage = now.getTime() - enabledElement.lastImageTimeStamp; + frameRate = (1000 / timeSinceLastImage).toFixed(); + } else { + } + enabledElement.lastImageTimeStamp = now.getTime(); + + var newImageEventData = { + viewport : enabledElement.viewport, + element : enabledElement.element, + image : enabledElement.image, + enabledElement : enabledElement, + frameRate : frameRate + }; + + $(enabledElement.element).trigger("CornerstoneNewImage", newImageEventData); + + cornerstone.updateImage(element); + } + + // module/private exports + cornerstone.displayImage = displayImage; +}($, cornerstone)); +/** + * This module is responsible for immediately drawing an enabled element + */ + +(function ($, cornerstone) { + + "use strict"; + + /** + * Immediately draws the enabled element + * + * @param element + */ + function draw(element) { + var enabledElement = cornerstone.getEnabledElement(element); + + if(enabledElement.image === undefined) { + throw "draw: image has not been loaded yet"; + } + + cornerstone.drawImage(enabledElement); + } + + // Module exports + cornerstone.draw = draw; + +}($, cornerstone)); +/** + * This module is responsible for drawing invalidated enabled elements + */ + +(function ($, cornerstone) { + + "use strict"; + + /** + * Draws all invalidated enabled elements and clears the invalid flag after drawing it + */ + function drawInvalidated() + { + var enabledElements = cornerstone.getEnabledElements(); + for(var i=0;i < enabledElements.length; i++) { + var ee = enabledElements[i]; + if(ee.invalid === true) { + cornerstone.drawImage(ee); + } + } + } + + // Module exports + cornerstone.drawInvalidated = drawInvalidated; +}($, cornerstone)); +/** + * This module is responsible for enabling an element to display images with cornerstone + */ +(function (cornerstone) { + + "use strict"; + + function enable(element) { + if(element === undefined) { + throw "enable: parameter element cannot be undefined"; + } + + var canvas = document.createElement('canvas'); + element.appendChild(canvas); + + var el = { + element: element, + canvas: canvas, + image : undefined, // will be set once image is loaded + invalid: false, // true if image needs to be drawn, false if not + data : {} + }; + cornerstone.addEnabledElement(el); + + cornerstone.resize(element, true); + + return element; + } + + // module/private exports + cornerstone.enable = enable; +}(cornerstone)); +(function (cornerstone) { + + "use strict"; + + function getElementData(el, dataType) { + var ee = cornerstone.getEnabledElement(el); + if(ee.data.hasOwnProperty(dataType) === false) + { + ee.data[dataType] = {}; + } + return ee.data[dataType]; + } + + function removeElementData(el, dataType) { + var ee = cornerstone.getEnabledElement(el); + delete ee.data[dataType]; + } + + // module/private exports + cornerstone.getElementData = getElementData; + cornerstone.removeElementData = removeElementData; + +}(cornerstone)); +(function (cornerstone) { + + "use strict"; + + var enabledElements = []; + + function getEnabledElement(element) { + if(element === undefined) { + throw "getEnabledElement: parameter element must not be undefined"; + } + for(var i=0; i < enabledElements.length; i++) { + if(enabledElements[i].element == element) { + return enabledElements[i]; + } + } + + throw "element not enabled"; + } + + function addEnabledElement(enabledElement) { + if(enabledElement === undefined) { + throw "getEnabledElement: enabledElement element must not be undefined"; + } + + enabledElements.push(enabledElement); + } + + function getEnabledElementsByImageId(imageId) { + var ees = []; + enabledElements.forEach(function(enabledElement) { + if(enabledElement.image && enabledElement.image.imageId === imageId) { + ees.push(enabledElement); + } + }); + return ees; + } + + function getEnabledElements() { + return enabledElements; + } + + // module/private exports + cornerstone.getEnabledElement = getEnabledElement; + cornerstone.addEnabledElement = addEnabledElement; + cornerstone.getEnabledElementsByImageId = getEnabledElementsByImageId; + cornerstone.getEnabledElements = getEnabledElements; +}(cornerstone)); +/** + * This module will fit an image to fit inside the canvas displaying it such that all pixels + * in the image are viewable + */ +(function (cornerstone) { + + "use strict"; + + function getImageSize(enabledElement) { + if(enabledElement.viewport.rotation === 0 ||enabledElement.viewport.rotation === 180) { + return { + width: enabledElement.image.width, + height: enabledElement.image.height + }; + } else { + return { + width: enabledElement.image.height, + height: enabledElement.image.width + }; + } + } + + /** + * Adjusts an images scale and center so the image is centered and completely visible + * @param element + */ + function fitToWindow(element) + { + var enabledElement = cornerstone.getEnabledElement(element); + var imageSize = getImageSize(enabledElement); + + var verticalScale = enabledElement.canvas.height / imageSize.height; + var horizontalScale= enabledElement.canvas.width / imageSize.width; + if(horizontalScale < verticalScale) { + enabledElement.viewport.scale = horizontalScale; + } + else + { + enabledElement.viewport.scale = verticalScale; + } + enabledElement.viewport.translation.x = 0; + enabledElement.viewport.translation.y = 0; + cornerstone.updateImage(element); + } + + cornerstone.fitToWindow = fitToWindow; +}(cornerstone)); + +/** + * This file is responsible for returning the default viewport for an image + */ + +(function ($, cornerstone) { + + "use strict"; + + /** + * returns a default viewport for display the specified image on the specified + * enabled element. The default viewport is fit to window + * + * @param element + * @param image + */ + function getDefaultViewportForImage(element, image) { + var enabledElement = cornerstone.getEnabledElement(element); + var viewport = cornerstone.internal.getDefaultViewport(enabledElement.canvas, image); + return viewport; + } + + // Module exports + cornerstone.getDefaultViewportForImage = getDefaultViewportForImage; +}($, cornerstone)); +/** + * This module is responsible for returning the currently displayed image for an element + */ + +(function ($, cornerstone) { + + "use strict"; + + /** + * returns the currently displayed image for an element or undefined if no image has + * been displayed yet + * + * @param element + */ + function getImage(element) { + var enabledElement = cornerstone.getEnabledElement(element); + return enabledElement.image; + } + + // Module exports + cornerstone.getImage = getImage; +}($, cornerstone)); +/** + * This module returns a subset of the stored pixels of an image + */ +(function (cornerstone) { + + "use strict"; + + /** + * Returns array of pixels with modality LUT transformation applied + */ + function getPixels(element, x, y, width, height) { + + var storedPixels = cornerstone.getStoredPixels(element, x, y, width, height); + var ee = cornerstone.getEnabledElement(element); + + var mlutfn = cornerstone.internal.getModalityLUT(ee.image.slope, ee.image.intercept, ee.viewport.modalityLUT); + + var modalityPixels = storedPixels.map(mlutfn); + + return modalityPixels; + } + + // module exports + cornerstone.getPixels = getPixels; +}(cornerstone)); +/** + * This module returns a subset of the stored pixels of an image + */ +(function (cornerstone) { + + "use strict"; + + /** + * Returns an array of stored pixels given a rectangle in the image + * @param element + * @param x + * @param y + * @param width + * @param height + * @returns {Array} + */ + function getStoredPixels(element, x, y, width, height) { + if(element === undefined) { + throw "getStoredPixels: parameter element must not be undefined"; + } + + x = Math.round(x); + y = Math.round(y); + var ee = cornerstone.getEnabledElement(element); + var storedPixels = []; + var index = 0; + var pixelData = ee.image.getPixelData(); + for(var row=0; row < height; row++) { + for(var column=0; column < width; column++) { + var spIndex = ((row + y) * ee.image.columns) + (column + x); + storedPixels[index++] = pixelData[spIndex]; + } + } + return storedPixels; + } + + // module exports + cornerstone.getStoredPixels = getStoredPixels; +}(cornerstone)); +/** + * This module contains functions to deal with getting and setting the viewport for an enabled element + */ +(function (cornerstone) { + + "use strict"; + + /** + * Returns the viewport for the specified enabled element + * @param element + * @returns {*} + */ + function getViewport(element) { + var enabledElement = cornerstone.getEnabledElement(element); + + var viewport = enabledElement.viewport; + if(viewport === undefined) { + return undefined; + } + return { + scale : viewport.scale, + translation : { + x : viewport.translation.x, + y : viewport.translation.y + }, + voi : { + windowWidth: viewport.voi.windowWidth, + windowCenter : viewport.voi.windowCenter + }, + invert : viewport.invert, + pixelReplication: viewport.pixelReplication, + rotation: viewport.rotation, + hflip: viewport.hflip, + vflip: viewport.vflip, + modalityLUT: viewport.modalityLUT, + voiLUT: viewport.voiLUT + }; + } + + // module/private exports + cornerstone.getViewport = getViewport; + +}(cornerstone)); + +/** + * This module deals with caching images + */ + +(function (cornerstone) { + + "use strict"; + + var imageCache = {}; + + var cachedImages = []; + + var maximumSizeInBytes = 1024 * 1024 * 1024; // 1 GB + var cacheSizeInBytes = 0; + + function setMaximumSizeBytes(numBytes) { + if (numBytes === undefined) { + throw "setMaximumSizeBytes: parameter numBytes must not be undefined"; + } + if (numBytes.toFixed === undefined) { + throw "setMaximumSizeBytes: parameter numBytes must be a number"; + } + + maximumSizeInBytes = numBytes; + purgeCacheIfNecessary(); + } + + function purgeCacheIfNecessary() { + // if max cache size has not been exceeded, do nothing + if (cacheSizeInBytes <= maximumSizeInBytes) { + return; + } + + // cache size has been exceeded, create list of images sorted by timeStamp + // so we can purge the least recently used image + function compare(a,b) { + if (a.timeStamp > b.timeStamp) { + return -1; + } + if (a.timeStamp < b.timeStamp) { + return 1; + } + return 0; + } + cachedImages.sort(compare); + + // remove images as necessary + while(cacheSizeInBytes > maximumSizeInBytes) { + var lastCachedImage = cachedImages[cachedImages.length - 1]; + cacheSizeInBytes -= lastCachedImage.sizeInBytes; + delete imageCache[lastCachedImage.imageId]; + lastCachedImage.imagePromise.reject(); + cachedImages.pop(); + $(cornerstone).trigger('CornerstoneImageCachePromiseRemoved', {imageId: lastCachedImage.imageId}); + } + + var cacheInfo = cornerstone.imageCache.getCacheInfo(); + $(cornerstone).trigger('CornerstoneImageCacheFull', cacheInfo); + } + + function putImagePromise(imageId, imagePromise) { + if (imageId === undefined) { + throw "getImagePromise: imageId must not be undefined"; + } + if (imagePromise === undefined) { + throw "getImagePromise: imagePromise must not be undefined"; + } + + if (imageCache.hasOwnProperty(imageId) === true) { + throw "putImagePromise: imageId already in cache"; + } + + var cachedImage = { + loaded : false, + imageId : imageId, + imagePromise : imagePromise, + timeStamp : new Date(), + sizeInBytes: 0 + }; + + imageCache[imageId] = cachedImage; + cachedImages.push(cachedImage); + + imagePromise.then(function(image) { + cachedImage.loaded = true; + + if (image.sizeInBytes === undefined) { + throw "putImagePromise: image does not have sizeInBytes property or"; + } + if (image.sizeInBytes.toFixed === undefined) { + throw "putImagePromise: image.sizeInBytes is not a number"; + } + cachedImage.sizeInBytes = image.sizeInBytes; + cacheSizeInBytes += cachedImage.sizeInBytes; + purgeCacheIfNecessary(); + }); + } + + function getImagePromise(imageId) { + if (imageId === undefined) { + throw "getImagePromise: imageId must not be undefined"; + } + var cachedImage = imageCache[imageId]; + if (cachedImage === undefined) { + return undefined; + } + + // bump time stamp for cached image + cachedImage.timeStamp = new Date(); + return cachedImage.imagePromise; + } + + function removeImagePromise(imageId) { + if (imageId === undefined) { + throw "removeImagePromise: imageId must not be undefined"; + } + var cachedImage = imageCache[imageId]; + if (cachedImage === undefined) { + throw "removeImagePromise: imageId must not be undefined"; + } + cachedImages.splice( cachedImages.indexOf(cachedImage), 1); + cacheSizeInBytes -= cachedImage.sizeInBytes; + delete imageCache[imageId]; + + return cachedImage.imagePromise; + } + + function getCacheInfo() { + return { + maximumSizeInBytes : maximumSizeInBytes, + cacheSizeInBytes : cacheSizeInBytes, + numberOfImagesCached: cachedImages.length + }; + } + + function purgeCache() { + while (cachedImages.length > 0) { + var removedCachedImage = cachedImages.pop(); + delete imageCache[removedCachedImage.imageId]; + removedCachedImage.imagePromise.reject(); + } + cacheSizeInBytes = 0; + } + + // module exports + cornerstone.imageCache = { + putImagePromise : putImagePromise, + getImagePromise: getImagePromise, + removeImagePromise: removeImagePromise, + setMaximumSizeBytes: setMaximumSizeBytes, + getCacheInfo : getCacheInfo, + purgeCache: purgeCache, + cachedImages: cachedImages + }; + +}(cornerstone)); + +/** + * This module deals with ImageLoaders, loading images and caching images + */ + +(function ($, cornerstone) { + + "use strict"; + + var imageLoaders = {}; + + var unknownImageLoader; + + function loadImageFromImageLoader(imageId) { + var colonIndex = imageId.indexOf(":"); + var scheme = imageId.substring(0, colonIndex); + var loader = imageLoaders[scheme]; + var imagePromise; + if(loader === undefined || loader === null) { + if(unknownImageLoader !== undefined) { + imagePromise = unknownImageLoader(imageId); + return imagePromise; + } + else { + return undefined; + } + } + imagePromise = loader(imageId); + + // broadcast an image loaded event once the image is loaded + // This is based on the idea here: http://stackoverflow.com/questions/3279809/global-custom-events-in-jquery + imagePromise.then(function(image) { + $(cornerstone).trigger('CornerstoneImageLoaded', {image: image}); + }); + + return imagePromise; + } + + // Loads an image given an imageId and returns a promise which will resolve + // to the loaded image object or fail if an error occurred. The loaded image + // is not stored in the cache + function loadImage(imageId) { + if(imageId === undefined) { + throw "loadImage: parameter imageId must not be undefined"; + } + + var imagePromise = cornerstone.imageCache.getImagePromise(imageId); + if(imagePromise !== undefined) { + return imagePromise; + } + + imagePromise = loadImageFromImageLoader(imageId); + if(imagePromise === undefined) { + throw "loadImage: no image loader for imageId"; + } + + return imagePromise; + } + + // Loads an image given an imageId and returns a promise which will resolve + // to the loaded image object or fail if an error occurred. The image is + // stored in the cache + function loadAndCacheImage(imageId) { + if(imageId === undefined) { + throw "loadAndCacheImage: parameter imageId must not be undefined"; + } + + var imagePromise = cornerstone.imageCache.getImagePromise(imageId); + if(imagePromise !== undefined) { + return imagePromise; + } + + imagePromise = loadImageFromImageLoader(imageId); + if(imagePromise === undefined) { + throw "loadAndCacheImage: no image loader for imageId"; + } + + cornerstone.imageCache.putImagePromise(imageId, imagePromise); + + return imagePromise; + } + + + // registers an imageLoader plugin with cornerstone for the specified scheme + function registerImageLoader(scheme, imageLoader) { + imageLoaders[scheme] = imageLoader; + } + + // Registers a new unknownImageLoader and returns the previous one (if it exists) + function registerUnknownImageLoader(imageLoader) { + var oldImageLoader = unknownImageLoader; + unknownImageLoader = imageLoader; + return oldImageLoader; + } + + // module exports + + cornerstone.loadImage = loadImage; + cornerstone.loadAndCacheImage = loadAndCacheImage; + cornerstone.registerImageLoader = registerImageLoader; + cornerstone.registerUnknownImageLoader = registerUnknownImageLoader; + +}($, cornerstone)); + +(function (cornerstone) { + + "use strict"; + + function calculateTransform(enabledElement, scale) { + + var transform = new cornerstone.internal.Transform(); + transform.translate(enabledElement.canvas.width/2, enabledElement.canvas.height / 2); + + //Apply the rotation before scaling for non square pixels + var angle = enabledElement.viewport.rotation; + if(angle!==0) { + transform.rotate(angle*Math.PI/180); + } + + // apply the scale + var widthScale = enabledElement.viewport.scale; + var heightScale = enabledElement.viewport.scale; + if(enabledElement.image.rowPixelSpacing < enabledElement.image.columnPixelSpacing) { + widthScale = widthScale * (enabledElement.image.columnPixelSpacing / enabledElement.image.rowPixelSpacing); + } + else if(enabledElement.image.columnPixelSpacing < enabledElement.image.rowPixelSpacing) { + heightScale = heightScale * (enabledElement.image.rowPixelSpacing / enabledElement.image.columnPixelSpacing); + } + transform.scale(widthScale, heightScale); + + // unrotate to so we can translate unrotated + if(angle!==0) { + transform.rotate(-angle*Math.PI/180); + } + + // apply the pan offset + transform.translate(enabledElement.viewport.translation.x, enabledElement.viewport.translation.y); + + // rotate again so we can apply general scale + if(angle!==0) { + transform.rotate(angle*Math.PI/180); + } + + if(scale !== undefined) { + // apply the font scale + transform.scale(scale, scale); + } + + //Apply Flip if required + if(enabledElement.viewport.hflip) { + transform.scale(-1,1); + } + + if(enabledElement.viewport.vflip) { + transform.scale(1,-1); + } + + // translate the origin back to the corner of the image so the event handlers can draw in image coordinate system + transform.translate(-enabledElement.image.width / 2 , -enabledElement.image.height/ 2); + return transform; + } + + // Module exports + cornerstone.internal.calculateTransform = calculateTransform; +}(cornerstone)); +/** + * This module is responsible for drawing an image to an enabled elements canvas element + */ + +(function ($, cornerstone) { + + "use strict"; + + /** + * Internal API function to draw an image to a given enabled element + * @param enabledElement + * @param invalidated - true if pixel data has been invalidated and cached rendering should not be used + */ + function drawImage(enabledElement, invalidated) { + + var start = new Date(); + + enabledElement.image.render(enabledElement, invalidated); + + var context = enabledElement.canvas.getContext('2d'); + + var end = new Date(); + var diff = end - start; + //console.log(diff + ' ms'); + + var eventData = { + viewport : enabledElement.viewport, + element : enabledElement.element, + image : enabledElement.image, + enabledElement : enabledElement, + canvasContext: context, + renderTimeInMs : diff + }; + + $(enabledElement.element).trigger("CornerstoneImageRendered", eventData); + enabledElement.invalid = false; + } + + // Module exports + cornerstone.internal.drawImage = drawImage; + cornerstone.drawImage = drawImage; + +}($, cornerstone)); +/** + * This module generates a lut for an image + */ + +(function (cornerstone) { + + "use strict"; + + function generateLutNew(image, windowWidth, windowCenter, invert, modalityLUT, voiLUT) + { + if(image.lut === undefined) { + image.lut = new Int16Array(image.maxPixelValue - Math.min(image.minPixelValue,0)+1); + } + var lut = image.lut; + var maxPixelValue = image.maxPixelValue; + var minPixelValue = image.minPixelValue; + + var mlutfn = cornerstone.internal.getModalityLUT(image.slope, image.intercept, modalityLUT); + var vlutfn = cornerstone.internal.getVOILUT(windowWidth, windowCenter, voiLUT); + + var offset = 0; + if(minPixelValue < 0) { + offset = minPixelValue; + } + var storedValue; + var modalityLutValue; + var voiLutValue; + var clampedValue; + + for(storedValue = image.minPixelValue; storedValue <= maxPixelValue; storedValue++) + { + modalityLutValue = mlutfn(storedValue); + voiLutValue = vlutfn(modalityLutValue); + clampedValue = Math.min(Math.max(voiLutValue, 0), 255); + if(!invert) { + lut[storedValue+ (-offset)] = Math.round(clampedValue); + } else { + lut[storedValue + (-offset)] = Math.round(255 - clampedValue); + } + } + return lut; + } + + + + /** + * Creates a LUT used while rendering to convert stored pixel values to + * display pixels + * + * @param image + * @returns {Array} + */ + function generateLut(image, windowWidth, windowCenter, invert, modalityLUT, voiLUT) + { + if(modalityLUT || voiLUT) { + return generateLutNew(image, windowWidth, windowCenter, invert, modalityLUT, voiLUT); + } + + if(image.lut === undefined) { + image.lut = new Int16Array(image.maxPixelValue - Math.min(image.minPixelValue,0)+1); + } + var lut = image.lut; + + var maxPixelValue = image.maxPixelValue; + var minPixelValue = image.minPixelValue; + var slope = image.slope; + var intercept = image.intercept; + var localWindowWidth = windowWidth; + var localWindowCenter = windowCenter; + var modalityLutValue; + var voiLutValue; + var clampedValue; + var storedValue; + + // NOTE: As of Nov 2014, most javascript engines have lower performance when indexing negative indexes. + // We improve performance by offsetting the pixel values for signed data to avoid negative indexes + // when generating the lut and then undo it in storedPixelDataToCanvasImagedata. Thanks to @jpambrun + // for this contribution! + + var offset = 0; + if(minPixelValue < 0) { + offset = minPixelValue; + } + + if(invert === true) { + for(storedValue = image.minPixelValue; storedValue <= maxPixelValue; storedValue++) + { + modalityLutValue = storedValue * slope + intercept; + voiLutValue = (((modalityLutValue - (localWindowCenter)) / (localWindowWidth) + 0.5) * 255.0); + clampedValue = Math.min(Math.max(voiLutValue, 0), 255); + lut[storedValue + (-offset)] = Math.round(255 - clampedValue); + } + } + else { + for(storedValue = image.minPixelValue; storedValue <= maxPixelValue; storedValue++) + { + modalityLutValue = storedValue * slope + intercept; + voiLutValue = (((modalityLutValue - (localWindowCenter)) / (localWindowWidth) + 0.5) * 255.0); + clampedValue = Math.min(Math.max(voiLutValue, 0), 255); + lut[storedValue+ (-offset)] = Math.round(clampedValue); + } + } + } + + + // Module exports + cornerstone.internal.generateLutNew = generateLutNew; + cornerstone.internal.generateLut = generateLut; + cornerstone.generateLutNew = generateLutNew; + cornerstone.generateLut = generateLut; +}(cornerstone)); + +/** + * This module contains a function to get a default viewport for an image given + * a canvas element to display it in + * + */ +(function (cornerstone) { + + "use strict"; + + /** + * Creates a new viewport object containing default values for the image and canvas + * @param canvas + * @param image + * @returns viewport object + */ + function getDefaultViewport(canvas, image) { + if(canvas === undefined) { + throw "getDefaultViewport: parameter canvas must not be undefined"; + } + if(image === undefined) { + throw "getDefaultViewport: parameter image must not be undefined"; + } + var viewport = { + scale : 1.0, + translation : { + x : 0, + y : 0 + }, + voi : { + windowWidth: image.windowWidth, + windowCenter: image.windowCenter, + }, + invert: image.invert, + pixelReplication: false, + rotation: 0, + hflip: false, + vflip: false, + modalityLUT: image.modalityLUT, + voiLUT: image.voiLUT + }; + + // fit image to window + var verticalScale = canvas.height / image.rows; + var horizontalScale= canvas.width / image.columns; + if(horizontalScale < verticalScale) { + viewport.scale = horizontalScale; + } + else { + viewport.scale = verticalScale; + } + return viewport; + } + + // module/private exports + cornerstone.internal.getDefaultViewport = getDefaultViewport; + cornerstone.getDefaultViewport = getDefaultViewport; +}(cornerstone)); + +(function (cornerstone) { + + "use strict"; + + function getTransform(enabledElement) + { + // For now we will calculate it every time it is requested. In the future, we may want to cache + // it in the enabled element to speed things up + var transform = cornerstone.internal.calculateTransform(enabledElement); + return transform; + } + + // Module exports + cornerstone.internal.getTransform = getTransform; + +}(cornerstone)); +/** + * This module is responsible for drawing an image to an enabled elements canvas element + */ + +(function ($, cornerstone) { + + "use strict"; + + cornerstone.drawImage = cornerstone.internal.drawImage; + cornerstone.generateLut = cornerstone.internal.generateLut; + cornerstone.storedPixelDataToCanvasImageData = cornerstone.internal.storedPixelDataToCanvasImageData; + cornerstone.storedColorPixelDataToCanvasImageData = cornerstone.internal.storedColorPixelDataToCanvasImageData; + +}($, cornerstone)); +/** + * This module generates a Modality LUT + */ + +(function (cornerstone) { + + "use strict"; + + + function generateLinearModalityLUT(slope, intercept) { + var localSlope = slope; + var localIntercept = intercept; + return function(sp) { + return sp * localSlope + localIntercept; + } + } + + function generateNonLinearModalityLUT(modalityLUT) { + var minValue = modalityLUT.lut[0]; + var maxValue = modalityLUT.lut[modalityLUT.lut.length -1]; + var maxValueMapped = modalityLUT.firstValueMapped + modalityLUT.lut.length; + return function(sp) { + if(sp < modalityLUT.firstValueMapped) { + return minValue; + } + else if(sp >= maxValueMapped) + { + return maxValue; + } + else + { + return modalityLUT.lut[sp]; + } + } + } + + function getModalityLUT(slope, intercept, modalityLUT) { + if (modalityLUT) { + return generateNonLinearModalityLUT(modalityLUT); + } else { + return generateLinearModalityLUT(slope, intercept); + } + } + + // Module exports + cornerstone.internal.getModalityLUT = getModalityLUT; + +}(cornerstone)); + +/** + * This module contains a function to convert stored pixel values to display pixel values using a LUT + */ +(function (cornerstone) { + + "use strict"; + + function storedColorPixelDataToCanvasImageData(image, lut, canvasImageDataData) + { + var minPixelValue = image.minPixelValue; + var canvasImageDataIndex = 0; + var storedPixelDataIndex = 0; + var numPixels = image.width * image.height * 4; + var storedPixelData = image.getPixelData(); + var localLut = lut; + var localCanvasImageDataData = canvasImageDataData; + // NOTE: As of Nov 2014, most javascript engines have lower performance when indexing negative indexes. + // We have a special code path for this case that improves performance. Thanks to @jpambrun for this enhancement + if(minPixelValue < 0){ + while(storedPixelDataIndex < numPixels) { + localCanvasImageDataData[canvasImageDataIndex++] = localLut[storedPixelData[storedPixelDataIndex++] + (-minPixelValue)]; // red + localCanvasImageDataData[canvasImageDataIndex++] = localLut[storedPixelData[storedPixelDataIndex++] + (-minPixelValue)]; // green + localCanvasImageDataData[canvasImageDataIndex] = localLut[storedPixelData[storedPixelDataIndex] + (-minPixelValue)]; // blue + storedPixelDataIndex+=2; + canvasImageDataIndex+=2; + } + }else{ + while(storedPixelDataIndex < numPixels) { + localCanvasImageDataData[canvasImageDataIndex++] = localLut[storedPixelData[storedPixelDataIndex++]]; // red + localCanvasImageDataData[canvasImageDataIndex++] = localLut[storedPixelData[storedPixelDataIndex++]]; // green + localCanvasImageDataData[canvasImageDataIndex] = localLut[storedPixelData[storedPixelDataIndex]]; // blue + storedPixelDataIndex+=2; + canvasImageDataIndex+=2; + } + } + } + + // Module exports + cornerstone.internal.storedColorPixelDataToCanvasImageData = storedColorPixelDataToCanvasImageData; + cornerstone.storedColorPixelDataToCanvasImageData = storedColorPixelDataToCanvasImageData; + +}(cornerstone)); + +/** + * This module contains a function to convert stored pixel values to display pixel values using a LUT + */ +(function (cornerstone) { + + "use strict"; + + /** + * This function transforms stored pixel values into a canvas image data buffer + * by using a LUT. This is the most performance sensitive code in cornerstone and + * we use a special trick to make this go as fast as possible. Specifically we + * use the alpha channel only to control the luminance rather than the red, green and + * blue channels which makes it over 3x faster. The canvasImageDataData buffer needs + * to be previously filled with white pixels. + * + * NOTE: Attribution would be appreciated if you use this technique! + * + * @param pixelData the pixel data + * @param lut the lut + * @param canvasImageDataData a canvasImgageData.data buffer filled with white pixels + */ + function storedPixelDataToCanvasImageData(image, lut, canvasImageDataData) + { + var pixelData = image.getPixelData(); + var minPixelValue = image.minPixelValue; + var canvasImageDataIndex = 3; + var storedPixelDataIndex = 0; + var localNumPixels = pixelData.length; + var localPixelData = pixelData; + var localLut = lut; + var localCanvasImageDataData = canvasImageDataData; + // NOTE: As of Nov 2014, most javascript engines have lower performance when indexing negative indexes. + // We have a special code path for this case that improves performance. Thanks to @jpambrun for this enhancement + if(minPixelValue < 0){ + while(storedPixelDataIndex < localNumPixels) { + localCanvasImageDataData[canvasImageDataIndex] = localLut[localPixelData[storedPixelDataIndex++] + (-minPixelValue)]; // alpha + canvasImageDataIndex += 4; + } + }else{ + while(storedPixelDataIndex < localNumPixels) { + localCanvasImageDataData[canvasImageDataIndex] = localLut[localPixelData[storedPixelDataIndex++]]; // alpha + canvasImageDataIndex += 4; + } + } + } + + // Module exports + cornerstone.internal.storedPixelDataToCanvasImageData = storedPixelDataToCanvasImageData; + cornerstone.storedPixelDataToCanvasImageData = storedPixelDataToCanvasImageData; + +}(cornerstone)); + +// Last updated November 2011 +// By Simon Sarris +// www.simonsarris.com +// sar...@acm.org +// +// Free to use and distribute at will +// So long as you are nice to people, etc + +// Simple class for keeping track of the current transformation matrix + +// For instance: +// var t = new Transform(); +// t.rotate(5); +// var m = t.m; +// ctx.setTransform(m[0], m[1], m[2], m[3], m[4], m[5]); + +// Is equivalent to: +// ctx.rotate(5); + +// But now you can retrieve it :) + +(function (cornerstone) { + + "use strict"; + + + // Remember that this does not account for any CSS transforms applied to the canvas + function Transform() { + this.reset(); + } + + Transform.prototype.reset = function() { + this.m = [1,0,0,1,0,0]; + }; + + Transform.prototype.clone = function() { + var transform = new Transform(); + transform.m[0] = this.m[0]; + transform.m[1] = this.m[1]; + transform.m[2] = this.m[2]; + transform.m[3] = this.m[3]; + transform.m[4] = this.m[4]; + transform.m[5] = this.m[5]; + return transform; + }; + + + Transform.prototype.multiply = function(matrix) { + var m11 = this.m[0] * matrix.m[0] + this.m[2] * matrix.m[1]; + var m12 = this.m[1] * matrix.m[0] + this.m[3] * matrix.m[1]; + + var m21 = this.m[0] * matrix.m[2] + this.m[2] * matrix.m[3]; + var m22 = this.m[1] * matrix.m[2] + this.m[3] * matrix.m[3]; + + var dx = this.m[0] * matrix.m[4] + this.m[2] * matrix.m[5] + this.m[4]; + var dy = this.m[1] * matrix.m[4] + this.m[3] * matrix.m[5] + this.m[5]; + + this.m[0] = m11; + this.m[1] = m12; + this.m[2] = m21; + this.m[3] = m22; + this.m[4] = dx; + this.m[5] = dy; + }; + + Transform.prototype.invert = function() { + var d = 1 / (this.m[0] * this.m[3] - this.m[1] * this.m[2]); + var m0 = this.m[3] * d; + var m1 = -this.m[1] * d; + var m2 = -this.m[2] * d; + var m3 = this.m[0] * d; + var m4 = d * (this.m[2] * this.m[5] - this.m[3] * this.m[4]); + var m5 = d * (this.m[1] * this.m[4] - this.m[0] * this.m[5]); + this.m[0] = m0; + this.m[1] = m1; + this.m[2] = m2; + this.m[3] = m3; + this.m[4] = m4; + this.m[5] = m5; + }; + + Transform.prototype.rotate = function(rad) { + var c = Math.cos(rad); + var s = Math.sin(rad); + var m11 = this.m[0] * c + this.m[2] * s; + var m12 = this.m[1] * c + this.m[3] * s; + var m21 = this.m[0] * -s + this.m[2] * c; + var m22 = this.m[1] * -s + this.m[3] * c; + this.m[0] = m11; + this.m[1] = m12; + this.m[2] = m21; + this.m[3] = m22; + }; + + Transform.prototype.translate = function(x, y) { + this.m[4] += this.m[0] * x + this.m[2] * y; + this.m[5] += this.m[1] * x + this.m[3] * y; + }; + + Transform.prototype.scale = function(sx, sy) { + this.m[0] *= sx; + this.m[1] *= sx; + this.m[2] *= sy; + this.m[3] *= sy; + }; + + Transform.prototype.transformPoint = function(px, py) { + var x = px; + var y = py; + px = x * this.m[0] + y * this.m[2] + this.m[4]; + py = x * this.m[1] + y * this.m[3] + this.m[5]; + return {x: px, y: py}; + }; + + cornerstone.internal.Transform = Transform; +}(cornerstone)); +/** + * This module generates a VOI LUT + */ + +(function (cornerstone) { + + "use strict"; + + function generateLinearVOILUT(windowWidth, windowCenter) { + return function(modalityLutValue) { + return (((modalityLutValue - (windowCenter)) / (windowWidth) + 0.5) * 255.0); + } + } + + function generateNonLinearVOILUT(voiLUT) { + var shift = voiLUT.numBitsPerEntry - 8; + var minValue = voiLUT.lut[0] >> shift; + var maxValue = voiLUT.lut[voiLUT.lut.length -1] >> shift; + var maxValueMapped = voiLUT.firstValueMapped + voiLUT.lut.length - 1; + return function(modalityLutValue) { + if(modalityLutValue < voiLUT.firstValueMapped) { + return minValue; + } + else if(modalityLutValue >= maxValueMapped) + { + return maxValue; + } + else + { + return voiLUT.lut[modalityLutValue - voiLUT.firstValueMapped] >> shift; + } + } + } + + function getVOILUT(windowWidth, windowCenter, voiLUT) { + if(voiLUT) { + return generateNonLinearVOILUT(voiLUT); + } else { + return generateLinearVOILUT(windowWidth, windowCenter); + } + } + + // Module exports + cornerstone.internal.getVOILUT = getVOILUT; +}(cornerstone)); + +/** + * This module contains a function to make an image is invalid + */ +(function (cornerstone) { + + "use strict"; + + /** + * Sets the invalid flag on the enabled element and fire an event + * @param element + */ + function invalidate(element) { + var enabledElement = cornerstone.getEnabledElement(element); + enabledElement.invalid = true; + var eventData = { + element: element + }; + $(enabledElement.element).trigger("CornerstoneInvalidated", eventData); + } + + // module exports + cornerstone.invalidate = invalidate; +}(cornerstone)); +/** + * This module contains a function to immediately invalidate an image + */ +(function (cornerstone) { + + "use strict"; + + /** + * Forces the image to be updated/redrawn for the specified enabled element + * @param element + */ + function invalidateImageId(imageId) { + + var enabledElements = cornerstone.getEnabledElementsByImageId(imageId); + enabledElements.forEach(function(enabledElement) { + cornerstone.drawImage(enabledElement, true); + }); + } + + // module exports + cornerstone.invalidateImageId = invalidateImageId; +}(cornerstone)); +/** + * This module contains a helper function to covert page coordinates to pixel coordinates + */ +(function (cornerstone) { + + "use strict"; + + /** + * Converts a point in the page coordinate system to the pixel coordinate + * system + * @param element + * @param pageX + * @param pageY + * @returns {{x: number, y: number}} + */ + function pageToPixel(element, pageX, pageY) { + var enabledElement = cornerstone.getEnabledElement(element); + + if(enabledElement.image === undefined) { + throw "image has not been loaded yet"; + } + + var image = enabledElement.image; + + // convert the pageX and pageY to the canvas client coordinates + var rect = element.getBoundingClientRect(); + var clientX = pageX - rect.left - window.pageXOffset; + var clientY = pageY - rect.top - window.pageYOffset; + + var pt = {x: clientX, y: clientY}; + var transform = cornerstone.internal.getTransform(enabledElement); + transform.invert(); + return transform.transformPoint(pt.x, pt.y); + } + + // module/private exports + cornerstone.pageToPixel = pageToPixel; + +}(cornerstone)); + +(function (cornerstone) { + + "use strict"; + + /** + * Converts a point in the pixel coordinate system to the canvas coordinate system + * system. This can be used to render using canvas context without having the weird + * side effects that come from scaling and non square pixels + * @param element + * @param pt + * @returns {x: number, y: number} + */ + function pixelToCanvas(element, pt) { + var enabledElement = cornerstone.getEnabledElement(element); + var transform = cornerstone.internal.getTransform(enabledElement); + return transform.transformPoint(pt.x, pt.y); + } + + // module/private exports + cornerstone.pixelToCanvas = pixelToCanvas; + +}(cornerstone)); + +/** + * This module is responsible for drawing an image to an enabled elements canvas element + */ + +(function (cornerstone) { + + "use strict"; + + var colorRenderCanvas = document.createElement('canvas'); + var colorRenderCanvasContext; + var colorRenderCanvasData; + + var lastRenderedImageId; + var lastRenderedViewport = {}; + + function initializeColorRenderCanvas(image) + { + // Resize the canvas + colorRenderCanvas.width = image.width; + colorRenderCanvas.height = image.height; + + // get the canvas data so we can write to it directly + colorRenderCanvasContext = colorRenderCanvas.getContext('2d'); + colorRenderCanvasContext.fillStyle = 'white'; + colorRenderCanvasContext.fillRect(0,0, colorRenderCanvas.width, colorRenderCanvas.height); + colorRenderCanvasData = colorRenderCanvasContext.getImageData(0,0,image.width, image.height); + } + + + function getLut(image, viewport) + { + // if we have a cached lut and it has the right values, return it immediately + if(image.lut !== undefined && + image.lut.windowCenter === viewport.voi.windowCenter && + image.lut.windowWidth === viewport.voi.windowWidth && + image.lut.invert === viewport.invert) { + return image.lut; + } + + // lut is invalid or not present, regenerate it and cache it + cornerstone.generateLut(image, viewport.voi.windowWidth, viewport.voi.windowCenter, viewport.invert); + image.lut.windowWidth = viewport.voi.windowWidth; + image.lut.windowCenter = viewport.voi.windowCenter; + image.lut.invert = viewport.invert; + return image.lut; + } + + function doesImageNeedToBeRendered(enabledElement, image) + { + if(image.imageId !== lastRenderedImageId || + lastRenderedViewport.windowCenter !== enabledElement.viewport.voi.windowCenter || + lastRenderedViewport.windowWidth !== enabledElement.viewport.voi.windowWidth || + lastRenderedViewport.invert !== enabledElement.viewport.invert || + lastRenderedViewport.rotation !== enabledElement.viewport.rotation || + lastRenderedViewport.hflip !== enabledElement.viewport.hflip || + lastRenderedViewport.vflip !== enabledElement.viewport.vflip + ) + { + return true; + } + + return false; + } + + function getRenderCanvas(enabledElement, image, invalidated) + { + // apply the lut to the stored pixel data onto the render canvas + + if(enabledElement.viewport.voi.windowWidth === enabledElement.image.windowWidth && + enabledElement.viewport.voi.windowCenter === enabledElement.image.windowCenter && + enabledElement.viewport.invert === false) + { + // the color image voi/invert has not been modified, request the canvas that contains + // it so we can draw it directly to the display canvas + return image.getCanvas(); + } + else + { + if(doesImageNeedToBeRendered(enabledElement, image) === false && invalidated !== true) { + return colorRenderCanvas; + } + + // If our render canvas does not match the size of this image reset it + // NOTE: This might be inefficient if we are updating multiple images of different + // sizes frequently. + if(colorRenderCanvas.width !== image.width || colorRenderCanvas.height != image.height) { + initializeColorRenderCanvas(image); + } + + // get the lut to use + var colorLut = getLut(image, enabledElement.viewport); + + // the color image voi/invert has been modified - apply the lut to the underlying + // pixel data and put it into the renderCanvas + cornerstone.storedColorPixelDataToCanvasImageData(image, colorLut, colorRenderCanvasData.data); + colorRenderCanvasContext.putImageData(colorRenderCanvasData, 0, 0); + return colorRenderCanvas; + } + } + + /** + * API function to render a color image to an enabled element + * @param enabledElement + * @param invalidated - true if pixel data has been invaldiated and cached rendering should not be used + */ + function renderColorImage(enabledElement, invalidated) { + + if(enabledElement === undefined) { + throw "drawImage: enabledElement parameter must not be undefined"; + } + var image = enabledElement.image; + if(image === undefined) { + throw "drawImage: image must be loaded before it can be drawn"; + } + + // get the canvas context and reset the transform + var context = enabledElement.canvas.getContext('2d'); + context.setTransform(1, 0, 0, 1, 0, 0); + + // clear the canvas + context.fillStyle = 'black'; + context.fillRect(0,0, enabledElement.canvas.width, enabledElement.canvas.height); + + // turn off image smooth/interpolation if pixelReplication is set in the viewport + if(enabledElement.viewport.pixelReplication === true) { + context.imageSmoothingEnabled = false; + context.mozImageSmoothingEnabled = false; // firefox doesn't support imageSmoothingEnabled yet + } + else { + context.imageSmoothingEnabled = true; + context.mozImageSmoothingEnabled = true; + } + + // save the canvas context state and apply the viewport properties + context.save(); + cornerstone.setToPixelCoordinateSystem(enabledElement, context); + + var renderCanvas = getRenderCanvas(enabledElement, image, invalidated); + + context.drawImage(renderCanvas, 0,0, image.width, image.height, 0, 0, image.width, image.height); + + context.restore(); + + lastRenderedImageId = image.imageId; + lastRenderedViewport.windowCenter = enabledElement.viewport.voi.windowCenter; + lastRenderedViewport.windowWidth = enabledElement.viewport.voi.windowWidth; + lastRenderedViewport.invert = enabledElement.viewport.invert; + lastRenderedViewport.rotation = enabledElement.viewport.rotation; + lastRenderedViewport.hflip = enabledElement.viewport.hflip; + lastRenderedViewport.vflip = enabledElement.viewport.vflip; + } + + // Module exports + cornerstone.rendering.colorImage = renderColorImage; + cornerstone.renderColorImage = renderColorImage; +}(cornerstone)); + +/** + * This module is responsible for drawing a grayscale imageß + */ + +(function (cornerstone) { + + "use strict"; + + var grayscaleRenderCanvas = document.createElement('canvas'); + var grayscaleRenderCanvasContext; + var grayscaleRenderCanvasData; + + var lastRenderedImageId; + var lastRenderedViewport = {}; + + function initializeGrayscaleRenderCanvas(image) + { + // Resize the canvas + grayscaleRenderCanvas.width = image.width; + grayscaleRenderCanvas.height = image.height; + + // NOTE - we need to fill the render canvas with white pixels since we control the luminance + // using the alpha channel to improve rendering performance. + grayscaleRenderCanvasContext = grayscaleRenderCanvas.getContext('2d'); + grayscaleRenderCanvasContext.fillStyle = 'white'; + grayscaleRenderCanvasContext.fillRect(0,0, grayscaleRenderCanvas.width, grayscaleRenderCanvas.height); + grayscaleRenderCanvasData = grayscaleRenderCanvasContext.getImageData(0,0,image.width, image.height); + } + + function lutMatches(a, b) { + // if undefined, they are equal + if(!a && !b) { + return true; + } + // if one is undefined, not equal + if(!a || !b) { + return false; + } + // check the unique ids + return (a.id !== b.id) + } + + function getLut(image, viewport, invalidated) + { + // if we have a cached lut and it has the right values, return it immediately + if(image.lut !== undefined && + image.lut.windowCenter === viewport.voi.windowCenter && + image.lut.windowWidth === viewport.voi.windowWidth && + lutMatches(image.lut.modalityLUT, viewport.modalityLUT) && + lutMatches(image.lut.voiLUT, viewport.voiLUT) && + image.lut.invert === viewport.invert && + invalidated !== true) { + return image.lut; + } + + // lut is invalid or not present, regenerate it and cache it + cornerstone.generateLut(image, viewport.voi.windowWidth, viewport.voi.windowCenter, viewport.invert, viewport.modalityLUT, viewport.voiLUT); + image.lut.windowWidth = viewport.voi.windowWidth; + image.lut.windowCenter = viewport.voi.windowCenter; + image.lut.invert = viewport.invert; + image.lut.voiLUT = viewport.voiLUT; + image.lut.modalityLUT = viewport.modalityLUT; + return image.lut; + } + + function doesImageNeedToBeRendered(enabledElement, image) + { + if(image.imageId !== lastRenderedImageId || + lastRenderedViewport.windowCenter !== enabledElement.viewport.voi.windowCenter || + lastRenderedViewport.windowWidth !== enabledElement.viewport.voi.windowWidth || + lastRenderedViewport.invert !== enabledElement.viewport.invert || + lastRenderedViewport.rotation !== enabledElement.viewport.rotation || + lastRenderedViewport.hflip !== enabledElement.viewport.hflip || + lastRenderedViewport.vflip !== enabledElement.viewport.vflip || + lastRenderedViewport.modalityLUT !== enabledElement.viewport.modalityLUT || + lastRenderedViewport.voiLUT !== enabledElement.viewport.voiLUT + ) + { + return true; + } + + return false; + } + + function getRenderCanvas(enabledElement, image, invalidated) + { + // apply the lut to the stored pixel data onto the render canvas + + if(doesImageNeedToBeRendered(enabledElement, image) === false && invalidated !== true) { + return grayscaleRenderCanvas; + } + + // If our render canvas does not match the size of this image reset it + // NOTE: This might be inefficient if we are updating multiple images of different + // sizes frequently. + if(grayscaleRenderCanvas.width !== image.width || grayscaleRenderCanvas.height != image.height) { + initializeGrayscaleRenderCanvas(image); + } + + // get the lut to use + var lut = getLut(image, enabledElement.viewport, invalidated); + // gray scale image - apply the lut and put the resulting image onto the render canvas + cornerstone.storedPixelDataToCanvasImageData(image, lut, grayscaleRenderCanvasData.data); + grayscaleRenderCanvasContext.putImageData(grayscaleRenderCanvasData, 0, 0); + return grayscaleRenderCanvas; + } + + /** + * API function to draw a grayscale image to a given enabledElement + * @param enabledElement + * @param invalidated - true if pixel data has been invaldiated and cached rendering should not be used + */ + function renderGrayscaleImage(enabledElement, invalidated) { + + if(enabledElement === undefined) { + throw "drawImage: enabledElement parameter must not be undefined"; + } + var image = enabledElement.image; + if(image === undefined) { + throw "drawImage: image must be loaded before it can be drawn"; + } + + // get the canvas context and reset the transform + var context = enabledElement.canvas.getContext('2d'); + context.setTransform(1, 0, 0, 1, 0, 0); + + // clear the canvas + context.fillStyle = 'black'; + context.fillRect(0,0, enabledElement.canvas.width, enabledElement.canvas.height); + + // turn off image smooth/interpolation if pixelReplication is set in the viewport + if(enabledElement.viewport.pixelReplication === true) { + context.imageSmoothingEnabled = false; + context.mozImageSmoothingEnabled = false; // firefox doesn't support imageSmoothingEnabled yet + } + else { + context.imageSmoothingEnabled = true; + context.mozImageSmoothingEnabled = true; + } + + // save the canvas context state and apply the viewport properties + cornerstone.setToPixelCoordinateSystem(enabledElement, context); + + var renderCanvas = getRenderCanvas(enabledElement, image, invalidated); + + // Draw the render canvas half the image size (because we set origin to the middle of the canvas above) + context.drawImage(renderCanvas, 0,0, image.width, image.height, 0, 0, image.width, image.height); + + lastRenderedImageId = image.imageId; + lastRenderedViewport.windowCenter = enabledElement.viewport.voi.windowCenter; + lastRenderedViewport.windowWidth = enabledElement.viewport.voi.windowWidth; + lastRenderedViewport.invert = enabledElement.viewport.invert; + lastRenderedViewport.rotation = enabledElement.viewport.rotation; + lastRenderedViewport.hflip = enabledElement.viewport.hflip; + lastRenderedViewport.vflip = enabledElement.viewport.vflip; + lastRenderedViewport.modalityLUT = enabledElement.viewport.modalityLUT; + lastRenderedViewport.voiLUT = enabledElement.viewport.voiLUT; + } + + // Module exports + cornerstone.rendering.grayscaleImage = renderGrayscaleImage; + cornerstone.renderGrayscaleImage = renderGrayscaleImage; + +}(cornerstone)); + +/** + * This module is responsible for drawing an image to an enabled elements canvas element + */ + +(function (cornerstone) { + + "use strict"; + + /** + * API function to draw a standard web image (PNG, JPG) to an enabledImage + * + * @param enabledElement + * @param invalidated - true if pixel data has been invaldiated and cached rendering should not be used + */ + function renderWebImage(enabledElement, invalidated) { + + if(enabledElement === undefined) { + throw "drawImage: enabledElement parameter must not be undefined"; + } + var image = enabledElement.image; + if(image === undefined) { + throw "drawImage: image must be loaded before it can be drawn"; + } + + // get the canvas context and reset the transform + var context = enabledElement.canvas.getContext('2d'); + context.setTransform(1, 0, 0, 1, 0, 0); + + // clear the canvas + context.fillStyle = 'black'; + context.fillRect(0,0, enabledElement.canvas.width, enabledElement.canvas.height); + + // turn off image smooth/interpolation if pixelReplication is set in the viewport + if(enabledElement.viewport.pixelReplication === true) { + context.imageSmoothingEnabled = false; + context.mozImageSmoothingEnabled = false; // firefox doesn't support imageSmoothingEnabled yet + } + else { + context.imageSmoothingEnabled = true; + context.mozImageSmoothingEnabled = true; + } + + // save the canvas context state and apply the viewport properties + cornerstone.setToPixelCoordinateSystem(enabledElement, context); + + // if the viewport ww/wc and invert all match the initial state of the image, we can draw the image + // directly. If any of those are changed, we call renderColorImage() to apply the lut + if(enabledElement.viewport.voi.windowWidth === enabledElement.image.windowWidth && + enabledElement.viewport.voi.windowCenter === enabledElement.image.windowCenter && + enabledElement.viewport.invert === false) + { + context.drawImage(image.getImage(), 0, 0, image.width, image.height, 0, 0, image.width, image.height); + } else { + cornerstone.renderColorImage(enabledElement, invalidated); + } + + } + + // Module exports + cornerstone.rendering.webImage = renderWebImage; + cornerstone.renderWebImage = renderWebImage; + +}(cornerstone)); +/** + */ +(function (cornerstone) { + + "use strict"; + + /** + * Resets the viewport to the default settings + * + * @param element + */ + function reset(element) + { + var enabledElement = cornerstone.getEnabledElement(element); + var defaultViewport = cornerstone.internal.getDefaultViewport(enabledElement.canvas, enabledElement.image); + enabledElement.viewport = defaultViewport; + cornerstone.updateImage(element); + } + + cornerstone.reset = reset; +}(cornerstone)); + +/** + * This module is responsible for enabling an element to display images with cornerstone + */ +(function (cornerstone) { + + "use strict"; + + function setCanvasSize(element, canvas) + { + // the device pixel ratio is 1.0 for normal displays and > 1.0 + // for high DPI displays like Retina + /* + + This functionality is disabled due to buggy behavior on systems with mixed DPI's. If the canvas + is created on a display with high DPI (e.g. 2.0) and then the browser window is dragged to + a different display with a different DPI (e.g. 1.0), the canvas is not recreated so the pageToPixel + produces incorrect results. I couldn't find any way to determine when the DPI changed other than + by polling which is not very clean. If anyone has any ideas here, please let me know, but for now + we will disable this functionality. We may want + to add a mechanism to optionally enable this functionality if we can determine it is safe to do + so (e.g. iPad or iPhone or perhaps enumerate the displays on the system. I am choosing + to be cautious here since I would rather not have bug reports or safety issues related to this + scenario. + + var devicePixelRatio = window.devicePixelRatio; + if(devicePixelRatio === undefined) { + devicePixelRatio = 1.0; + } + */ + + canvas.width = element.clientWidth; + canvas.height = element.clientHeight; + canvas.style.width = element.clientWidth + "px"; + canvas.style.height = element.clientHeight + "px"; + } + + /** + * resizes an enabled element and optionally fits the image to window + * @param element + * @param fitToWindow true to refit, false to leave viewport parameters as they are + */ + function resize(element, fitToWindow) { + + var enabledElement = cornerstone.getEnabledElement(element); + + setCanvasSize(element, enabledElement.canvas); + + if(enabledElement.image === undefined ) { + return; + } + + if(fitToWindow === true) { + cornerstone.fitToWindow(element); + } + else { + cornerstone.updateImage(element); + } + } + + // module/private exports + cornerstone.resize = resize; + +}(cornerstone)); +/** + * This module contains a function that will set the canvas context to the pixel coordinates system + * making it easy to draw geometry on the image + */ + +(function (cornerstone) { + + "use strict"; + + /** + * Sets the canvas context transformation matrix to the pixel coordinate system. This allows + * geometry to be driven using the canvas context using coordinates in the pixel coordinate system + * @param ee + * @param context + * @param scale optional scaler to apply + */ + function setToPixelCoordinateSystem(enabledElement, context, scale) + { + if(enabledElement === undefined) { + throw "setToPixelCoordinateSystem: parameter enabledElement must not be undefined"; + } + if(context === undefined) { + throw "setToPixelCoordinateSystem: parameter context must not be undefined"; + } + + var transform = cornerstone.internal.calculateTransform(enabledElement, scale); + context.setTransform(transform.m[0],transform.m[1],transform.m[2],transform.m[3],transform.m[4],transform.m[5],transform.m[6]); + } + + // Module exports + cornerstone.setToPixelCoordinateSystem = setToPixelCoordinateSystem; +}(cornerstone)); +/** + * This module contains functions to deal with getting and setting the viewport for an enabled element + */ +(function (cornerstone) { + + "use strict"; + + /** + * Sets the viewport for an element and corrects invalid values + * + * @param element - DOM element of the enabled element + * @param viewport - Object containing the viewport properties + * @returns {*} + */ + function setViewport(element, viewport) { + + var enabledElement = cornerstone.getEnabledElement(element); + + enabledElement.viewport.scale = viewport.scale; + enabledElement.viewport.translation.x = viewport.translation.x; + enabledElement.viewport.translation.y = viewport.translation.y; + enabledElement.viewport.voi.windowWidth = viewport.voi.windowWidth; + enabledElement.viewport.voi.windowCenter = viewport.voi.windowCenter; + enabledElement.viewport.invert = viewport.invert; + enabledElement.viewport.pixelReplication = viewport.pixelReplication; + enabledElement.viewport.rotation = viewport.rotation; + enabledElement.viewport.hflip = viewport.hflip; + enabledElement.viewport.vflip = viewport.vflip; + enabledElement.viewport.modalityLUT = viewport.modalityLUT; + enabledElement.viewport.voiLUT = viewport.voiLUT; + + // prevent window width from being too small (note that values close to zero are valid and can occur with + // PET images in particular) + if(enabledElement.viewport.voi.windowWidth < 0.000001) { + enabledElement.viewport.voi.windowWidth = 0.000001; + } + // prevent scale from getting too small + if(enabledElement.viewport.scale < 0.0001) { + enabledElement.viewport.scale = 0.25; + } + + if(enabledElement.viewport.rotation===360 || enabledElement.viewport.rotation===-360) { + enabledElement.viewport.rotation = 0; + } + + // Force the image to be updated since the viewport has been modified + cornerstone.updateImage(element); + } + + + // module/private exports + cornerstone.setViewport = setViewport; + +}(cornerstone)); + +/** + * This module contains a function to immediately redraw an image + */ +(function (cornerstone) { + + "use strict"; + + /** + * Forces the image to be updated/redrawn for the specified enabled element + * @param element + */ + function updateImage(element, invalidated) { + var enabledElement = cornerstone.getEnabledElement(element); + + if(enabledElement.image === undefined) { + throw "updateImage: image has not been loaded yet"; + } + + cornerstone.drawImage(enabledElement, invalidated); + } + + // module exports + cornerstone.updateImage = updateImage; + +}(cornerstone)); \ No newline at end of file Modified: trunk/packages/orthanc-webviewer/trunk/debian/changelog =================================================================== --- trunk/packages/orthanc-webviewer/trunk/debian/changelog 2015-12-06 21:13:17 UTC (rev 20663) +++ trunk/packages/orthanc-webviewer/trunk/debian/changelog 2015-12-07 15:27:48 UTC (rev 20664) @@ -1,3 +1,9 @@ +orthanc-webviewer (2.0-2) UNRELEASED; urgency=medium + + * Upgrade Cornerstone version: 0.7.1 to 0.8.4 + + -- Sebastien Jodogne <s.jodo...@gmail.com> Mon, 07 Dec 2015 16:23:47 +0100 + orthanc-webviewer (2.0-1) unstable; urgency=medium * New upstream version. Modified: trunk/packages/orthanc-webviewer/trunk/debian/rules =================================================================== --- trunk/packages/orthanc-webviewer/trunk/debian/rules 2015-12-06 21:13:17 UTC (rev 20663) +++ trunk/packages/orthanc-webviewer/trunk/debian/rules 2015-12-07 15:27:48 UTC (rev 20664) @@ -28,9 +28,9 @@ # Place the third-party JavaScript libraries at the location # expected by CMake - yui-compressor debian/JS/cornerstone-0.7.1/cornerstone.js > \ + yui-compressor debian/JS/cornerstone-0.8.4/cornerstone.js > \ ${JAVASCRIPT_LIBS}/cornerstone.min.js - yui-compressor debian/JS/cornerstone-0.7.1/cornerstone.css > \ + yui-compressor debian/JS/cornerstone-0.8.4/cornerstone.css > \ ${JAVASCRIPT_LIBS}/cornerstone.min.css yui-compressor debian/JS/jsPanel-2.3.3/jquery.jspanel.js > \ _______________________________________________ debian-med-commit mailing list debian-med-commit@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/debian-med-commit