changeset 1701:b5a8bf32d969

new configuration options: "CombinedToolEnabled", "CombinedToolBehaviour" and "DownloadAsJpegEnabled"
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 27 Nov 2020 12:21:26 +0100
parents f1bd464dc3e1
children bc40b6450261
files Applications/StoneWebViewer/WebApplication/app.js Applications/StoneWebViewer/WebApplication/configuration.json Applications/StoneWebViewer/WebApplication/index.html Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp
diffstat 4 files changed, 128 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/StoneWebViewer/WebApplication/app.js	Fri Nov 27 10:55:21 2020 +0100
+++ b/Applications/StoneWebViewer/WebApplication/app.js	Fri Nov 27 12:21:26 2020 +0100
@@ -44,6 +44,63 @@
 }
 
 
+// https://stackoverflow.com/a/21797381/881731
+function Base64ToArrayBuffer(base64) {
+  var binary_string = window.atob(base64);
+  var len = binary_string.length;
+  var bytes = new Uint8Array(len);
+  for (var i = 0; i < len; i++) {
+    bytes[i] = binary_string.charCodeAt(i);
+  }
+  return bytes.buffer;
+}
+
+
+function SaveDataUriScheme(filename, dataUriScheme) {
+  var mimeType = dataUriScheme.split(',')[0].split(':')[1].split(';')[0];
+  var base64 = dataUriScheme.split(',')[1];
+
+  var blob = new Blob([ Base64ToArrayBuffer(base64) ], {
+    type: mimeType
+  });
+
+  var link = document.createElement('a');
+  link.href = window.URL.createObjectURL(blob);
+  link.download = filename;
+  link.click();
+};
+
+
+// Check out "enum WebViewerAction" in "StoneWebViewer.cpp" for the
+// possible values
+function ConvertMouseAction(config, defaultAction)
+{
+  if (config === undefined) {
+    return defaultAction;
+  }
+  if (config == "Windowing") {
+    return stone.WebViewerAction.WINDOWING;
+  }
+  else if (config == "Zoom") {
+    return stone.WebViewerAction.ZOOM;
+  }
+  else if (config == "Pan") {
+    return stone.WebViewerAction.PAN;
+  }
+  else if (config == "Rotate") {
+    return stone.WebViewerAction.ROTATE;
+  }
+  else if (config == "Crosshair") {
+    return stone.WebViewerAction.CROSSHAIR;
+  }
+  else {
+    alert('Unsupported mouse action in the configuration file: ' + config);
+    return stone.WebViewerAction.PAN;
+  }
+}
+
+
+
 Vue.component('viewport', {
   props: [ 'left', 'top', 'width', 'height', 'canvasId', 'active', 'series', 'viewportIndex',
            'showInfo' ],
@@ -715,7 +772,8 @@
       }
     },
     
-    FormatDate(date) {
+    FormatDate: function(date)
+    {
       if (date === undefined ||
           date.length == 0) {
         return '';
@@ -733,6 +791,28 @@
           return format.replace(/YYYY/g, year).replace(/MM/g, month).replace(/DD/g, day);
         }
       }
+    },
+
+    DownloadJpeg: function()
+    {
+      var canvas = document.getElementById(this.GetActiveCanvas());
+      SaveDataUriScheme('StoneWebViewerScreenshot.jpg', canvas.toDataURL('image/jpeg'));
+    },
+
+    SetCombinedToolActions: function()
+    {
+      var left = stone.WebViewerAction.WINDOWING;
+      var middle = stone.WebViewerAction.PAN;
+      var right = stone.WebViewerAction.ZOOM;
+
+      var behaviour = this.globalConfiguration['CombinedToolBehaviour'];
+      if (behaviour !== undefined) {
+        left = ConvertMouseAction(behaviour['LeftMouseButton'], left);
+        middle = ConvertMouseAction(behaviour['MiddleMouseButton'], middle);
+        right = ConvertMouseAction(behaviour['RightMouseButton'], right);
+      }
+      
+      this.SetMouseButtonActions(left, middle, right);
     }
   },
   
@@ -759,6 +839,8 @@
   stone.SetSoftwareRendering(localStorage.settingSoftwareRendering == '1');
   console.warn('Stone properly initialized');
 
+  app.SetCombinedToolActions();
+  
   var selectedStudies = getParameterFromUrl('selectedStudies');
   var study = getParameterFromUrl('study');
   var series = getParameterFromUrl('series');
--- a/Applications/StoneWebViewer/WebApplication/configuration.json	Fri Nov 27 10:55:21 2020 +0100
+++ b/Applications/StoneWebViewer/WebApplication/configuration.json	Fri Nov 27 12:21:26 2020 +0100
@@ -2,11 +2,6 @@
   "StoneWebViewer" :
   {
     /**
-     * Enables/disables the print button.
-     **/
-    "PrintEnabled" : true,
-
-    /**
      * Defines how dates are displayed in the UI. If this option is not
      * set, the DICOM tags will be displayed as such. "DD" will be
      * replaced by the day, "MM" by the month, and "YYYY" by the year.
@@ -19,15 +14,41 @@
      * and window center.
      **/
     "WindowingPresets" : [
-      {"Name": "CT Lung", "WindowCenter": -400, "WindowWidth": 1600},
-      {"Name": "CT Abdomen", "WindowCenter": 60, "WindowWidth": 400},
-      {"Name": "CT Bone", "WindowCenter": 300, "WindowWidth": 1500},
-      {"Name": "CT Brain", "WindowCenter": 40, "WindowWidth": 80},
-      {"Name": "CT Chest", "WindowCenter": 40, "WindowWidth": 400},
-      {"Name": "CT Angio", "WindowCenter": 300, "WindowWidth": 600}
+      {"Name" : "CT Lung",    "WindowCenter" : -400, "WindowWidth" : 1600},
+      {"Name" : "CT Abdomen", "WindowCenter" : 60,   "WindowWidth" : 400},
+      {"Name" : "CT Bone",    "WindowCenter" : 300,  "WindowWidth" : 1500},
+      {"Name" : "CT Brain",   "WindowCenter" : 40,   "WindowWidth" : 80},
+      {"Name" : "CT Chest",   "WindowCenter" : 40,   "WindowWidth" : 400},
+      {"Name" : "CT Angio",   "WindowCenter" : 300,  "WindowWidth" : 600}
     ],
     
     /**
+     * Enables/disables the combined tool. This is the default mode
+     * for mouse interactions. The combined tool allows to access the
+     * windowing, zoom and pan from a single mouse configuration. The
+     * behaviour of the combined tool is defined in
+     * CombinedToolBehaviour. The available mouse actions are
+     * "Crosshair", "Windowing", "Pan", "Rotate" and "Zoom".
+     **/
+    "CombinedToolEnabled" : true,
+    "CombinedToolBehaviour" : {
+      "LeftMouseButton" : "Windowing",
+      "MiddleMouseButton" : "Pan",
+      "RightMouseButton" : "Zoom"
+    },
+
+    /**
+     * Enables/disables the print button.
+     **/
+    "PrintEnabled" : true,
+
+    /**
+     * Enables/disables the button to download a screenshot of the
+     * active viewport as a JPEG file.
+     **/
+    "DownloadAsJpegEnabled" : true,
+    
+    /**
      * The allowed origin for messages corresponding to dynamic actions
      * triggered by another Web page using "window.postMessage()". The
      * special value "*" will allow any origin, which is an insecure
--- a/Applications/StoneWebViewer/WebApplication/index.html	Fri Nov 27 10:55:21 2020 +0100
+++ b/Applications/StoneWebViewer/WebApplication/index.html	Fri Nov 27 12:21:26 2020 +0100
@@ -309,10 +309,10 @@
                 </div>
                 
                 <div class="tbGroup__buttons--bottom" v-show="mouseActionsVisible">
-                  <div class="inline-object">
+                  <div class="inline-object" v-if="globalConfiguration.CombinedToolEnabled">
                     <button class="wvButton"
                             data-toggle="tooltip" data-title="Combined tool"
-                            @click="SetMouseButtonActions(stone.WebViewerAction.GRAYSCALE_WINDOWING, stone.WebViewerAction.PAN, stone.WebViewerAction.ZOOM)">
+                            @click="SetCombinedToolActions()">
                       <i class="far fa-hand-point-up"></i>
                     </button>
                   </div>
@@ -463,6 +463,14 @@
               </button>
             </div>
 
+            <div class="ng-scope inline-object" v-if="globalConfiguration.DownloadAsJpegEnabled">
+              <button class="wvButton--underline text-center"
+                      data-toggle="tooltip" data-title="Download as JPEG"
+                      v-on:click="DownloadJpeg()">
+                <i class="fas fa-file-download"></i>
+              </button>
+            </div>
+
             <div class="ng-scope inline-object">
               <button class="wvButton--underline text-center"
                       data-toggle="tooltip" data-title="User preferences"
--- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Fri Nov 27 10:55:21 2020 +0100
+++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Fri Nov 27 12:21:26 2020 +0100
@@ -129,7 +129,7 @@
 
 enum STONE_WEB_VIEWER_EXPORT WebViewerAction
 {
-  WebViewerAction_GrayscaleWindowing,
+  WebViewerAction_Windowing,
     WebViewerAction_Zoom,
     WebViewerAction_Pan,
     WebViewerAction_Rotate,
@@ -142,7 +142,7 @@
 {
   switch (action)
   {
-    case WebViewerAction_GrayscaleWindowing:
+    case WebViewerAction_Windowing:
       return OrthancStone::MouseAction_GrayscaleWindowing;
       
     case WebViewerAction_Zoom:
@@ -2658,7 +2658,7 @@
 static boost::shared_ptr<OrthancStone::WebAssemblyLoadersContext> context_;
 static std::string stringBuffer_;
 static bool softwareRendering_ = false;
-static WebViewerAction leftButtonAction_ = WebViewerAction_GrayscaleWindowing;
+static WebViewerAction leftButtonAction_ = WebViewerAction_Windowing;
 static WebViewerAction middleButtonAction_ = WebViewerAction_Pan;
 static WebViewerAction rightButtonAction_ = WebViewerAction_Zoom;