[med-svn] r20664 - in trunk/packages/orthanc-webviewer/trunk/debian: . JS JS/cornerstone-0.8.4
Sebastien Jodogne
jodogne-guest at moszumanska.debian.org
Mon Dec 7 15:27:49 UTC 2015
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 (chafey at 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 [chafey at gmail.com](mailto:chafey at 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
+// sarris at 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.jodogne at 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 > \
More information about the debian-med-commit
mailing list