changeset 1720:b8d19f53aaca

display the instance number, and the wc/ww info (work-in-progress)
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 01 Dec 2020 12:13:43 +0100
parents 9a1f79d21a3f
children d4a8e2b19a65
files Applications/StoneWebViewer/NOTES.txt Applications/StoneWebViewer/WebApplication/app.js Applications/StoneWebViewer/WebApplication/index.html Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp
diffstat 4 files changed, 95 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/StoneWebViewer/NOTES.txt	Tue Dec 01 10:42:45 2020 +0100
+++ b/Applications/StoneWebViewer/NOTES.txt	Tue Dec 01 12:13:43 2020 +0100
@@ -22,6 +22,14 @@
   current frame by skipping 1/20th of the frames in the series.
 
 
+- The Stone Web viewer displays a color block at the bottom-right of
+  each viewport. A "red" color means that the current frame is still
+  being loaded, so don't trust what is currently displayed. A "yellow"
+  color means that the viewport displays a low-quality preview (JPEG).
+  A "green" color means that the viewport contains an image with the
+  same quality as the source DICOM image.
+
+
 - The Stone Web viewer uses the DICOM identifiers, while the Osimis Web
   viewer uses the Orthanc identifiers.
   https://book.orthanc-server.com/faq/orthanc-ids.html
--- a/Applications/StoneWebViewer/WebApplication/app.js	Tue Dec 01 10:42:45 2020 +0100
+++ b/Applications/StoneWebViewer/WebApplication/app.js	Tue Dec 01 12:13:43 2020 +0100
@@ -137,7 +137,10 @@
       cineFramesPerSecond: 30,
       cineTimeoutId: null,
       cineLoadingFrame: false,
-      videoUri: ''
+      videoUri: '',
+      windowingCenter: 0, 
+      windowingWidth: 0,
+      instanceNumber: 0
     }
   },
   watch: {
@@ -155,6 +158,9 @@
       this.cineMode = '';
       this.cineLoadingFrame = false;
       this.cineRate = 30;   // Default value
+      this.windowingCenter = 0;
+      this.windowingWidth = 0;
+      this.instanceNumber = 0;
       
       if (this.cineTimeoutId !== null) {
         clearTimeout(this.cineTimeoutId);
@@ -239,6 +245,7 @@
         that.currentFrame = (args.detail.currentFrame + 1);
         that.numberOfFrames = args.detail.numberOfFrames;
         that.quality = args.detail.quality;
+        that.instanceNumber = args.detail.instanceNumber;
       }
     });
 
@@ -274,6 +281,14 @@
         });
       }
     });
+
+    window.addEventListener('WindowingUpdated', function(args) {
+      if (args.detail.canvasId == that.canvasId) {
+        that.windowingCenter = args.detail.windowingCenter;
+        that.windowingWidth = args.detail.windowingWidth;
+        console.log(that.windowingCenter + ' ' + that.windowingWidth);
+      }
+    });
   },
   methods: {
     DragDrop: function(event) {
--- a/Applications/StoneWebViewer/WebApplication/index.html	Tue Dec 01 10:42:45 2020 +0100
+++ b/Applications/StoneWebViewer/WebApplication/index.html	Tue Dec 01 12:13:43 2020 +0100
@@ -618,9 +618,12 @@
                     {{ app.FormatDate(content.series.tags[STUDY_DATE]) }}<br/>
                     {{ content.series.tags[SERIES_NUMBER] }} | {{ content.series.tags[SERIES_DESCRIPTION] }}
                   </div>
-                  <div class="wv-overlay-timeline-wrapper wvPrintExclude">
-                    <div style="text-align:left; padding:5px" v-show="numberOfFrames != 0">
-                      <div style="width: 12em; padding: 1em;" v-show="cineControls">
+                  <div class="wv-overlay-bottomleft wvPrintExclude" style="bottom: 0px">
+                    <div v-show="instanceNumber != 0" style="padding-bottom: 1em">
+                      Instance number: {{ instanceNumber }}
+                    </div>
+                    <span v-show="numberOfFrames != 0">
+                      <div style="width: 12em;" v-show="cineControls">
                         <label>
                           Frame rate
                           <span class="wv-play-button-config-framerate-wrapper">
@@ -638,7 +641,9 @@
                           <i class="fas fa-step-backward"></i>
                         </button>
                       </div>
-                      &nbsp;&nbsp;{{ currentFrame }} / {{ numberOfFrames }}&nbsp;&nbsp;
+                      <span data-toggle="tooltip" data-title="Current frame number">
+                        &nbsp;&nbsp;{{ currentFrame }} / {{ numberOfFrames }}&nbsp;&nbsp;
+                      </span>
                       <div class="btn-group btn-group-sm" role="group">                        
                         <button class="btn btn-primary" @click="IncrementFrame()">
                           <i class="fas fa-step-forward"></i>
@@ -658,15 +663,20 @@
                           <i class="fas fa-play"></i>
                         </button>
                       </div>
-                    </div>
+                    </span>
                   </div>
                   <div class="wv-overlay-bottomright wvPrintExclude" style="bottom: 0px">
-                    <div v-show="quality == stone.DisplayedFrameQuality.NONE"
-                         style="display:block;background-color:red;width:1em;height:1em" />
-                    <div v-show="quality == stone.DisplayedFrameQuality.LOW"
-                         style="display:block;background-color:orange;width:1em;height:1em" />
-                    <div v-show="quality == stone.DisplayedFrameQuality.HIGH"
-                         style="display:block;background-color:green;width:1em;height:1em" />
+                    <div v-if="windowingWidth != 0">
+                      ww/cc: {{ windowingCenter }} / {{ windowingWidth }}
+                    </div>
+                    <div style="padding-top: 0.5em">
+                      <div v-show="quality == stone.DisplayedFrameQuality.NONE"
+                           style="display:inline-block;background-color:red;width:1em;height:1em" />
+                      <div v-show="quality == stone.DisplayedFrameQuality.LOW"
+                           style="display:inline-block;background-color:orange;width:1em;height:1em" />
+                      <div v-show="quality == stone.DisplayedFrameQuality.HIGH"
+                           style="display:inline-block;background-color:green;width:1em;height:1em" />
+                    </div>
                   </div>
                 </div>
               </div>
--- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Tue Dec 01 10:42:45 2020 +0100
+++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Tue Dec 01 12:13:43 2020 +0100
@@ -1177,7 +1177,8 @@
     virtual void SignalFrameUpdated(const ViewerViewport& viewport,
                                     size_t currentFrame,
                                     size_t countFrames,
-                                    DisplayedFrameQuality quality) = 0;
+                                    DisplayedFrameQuality quality,
+                                    unsigned int instanceNumber) = 0;
 
     virtual void SignalCrosshair(const ViewerViewport& viewport,
                                  const OrthancStone::Vector& click) = 0;
@@ -1185,6 +1186,10 @@
     virtual void SignalSynchronizedBrowsing(const ViewerViewport& viewport,
                                             const OrthancStone::Vector& click,
                                             const OrthancStone::Vector& normal) = 0;
+
+    virtual void SignalWindowingUpdated(const ViewerViewport& viewport,
+                                        double windowingCenter,
+                                        double windowingWidth) = 0;
   };
 
 private:
@@ -1655,9 +1660,19 @@
 
     ScheduleNextPrefetch();
     
-    if (observer_.get() != NULL)
+    if (frames_.get() != NULL &&
+        cursor_.get() != NULL &&
+        observer_.get() != NULL)
     {
-      observer_->SignalFrameUpdated(*this, cursorIndex, frames_->GetFramesCount(), quality);
+      const Orthanc::DicomMap& instance = frames_->GetInstanceOfFrame(cursor_->GetCurrentIndex()).GetTags();
+
+      uint32_t instanceNumber;
+      if (!instance.ParseUnsignedInteger32(instanceNumber, Orthanc::DICOM_TAG_INSTANCE_NUMBER))
+      {
+        instanceNumber = 0;
+      }
+      
+      observer_->SignalFrameUpdated(*this, cursorIndex, frames_->GetFramesCount(), quality, instanceNumber);
     }
   }
   
@@ -2141,7 +2156,7 @@
     if (observer_.get() != NULL)
     {
       observer_->SignalFrameUpdated(*this, cursor_->GetCurrentIndex(),
-                                    frames_->GetFramesCount(), DisplayedFrameQuality_None);
+                                    frames_->GetFramesCount(), DisplayedFrameQuality_None, 0);
     }
 
     centralPhysicalWidth_ = 1;
@@ -2406,13 +2421,11 @@
     
     if (windowingPresetCenters_.empty())
     {
-      windowingCenter_ = 128;
-      windowingWidth_ = 256;
+      SetWindowing(128, 256);
     }
     else
     {
-      windowingCenter_ = windowingPresetCenters_[0];
-      windowingWidth_ = windowingPresetWidths_[0];
+      SetWindowing(windowingPresetCenters_[0], windowingPresetWidths_[0]);
     }
   }
 
@@ -2422,6 +2435,11 @@
     windowingCenter_ = windowingCenter;
     windowingWidth_ = windowingWidth;
     UpdateCurrentTextureParameters();
+
+    if (observer_.get() != NULL)
+    {
+      observer_->SignalWindowingUpdated(*this, windowingCenter, windowingWidth);
+    }
   }
 
   void FlipX()
@@ -2747,7 +2765,8 @@
   virtual void SignalFrameUpdated(const ViewerViewport& viewport,
                                   size_t currentFrame,
                                   size_t countFrames,
-                                  DisplayedFrameQuality quality) ORTHANC_OVERRIDE
+                                  DisplayedFrameQuality quality,
+                                  unsigned int instanceNumber) ORTHANC_OVERRIDE
   {
     EM_ASM({
         const customEvent = document.createEvent("CustomEvent");
@@ -2755,13 +2774,14 @@
                                     { "canvasId" : UTF8ToString($0),
                                         "currentFrame" : $1,
                                         "numberOfFrames" : $2,
-                                        "quality" : $3 });
+                                        "quality" : $3,
+                                        "instanceNumber" : $4 });
         window.dispatchEvent(customEvent);
       },
       viewport.GetCanvasId().c_str(),
       static_cast<int>(currentFrame),
       static_cast<int>(countFrames),
-      quality);
+      quality, instanceNumber);
 
     UpdateReferenceLines();
   }
@@ -2836,6 +2856,25 @@
       sopInstanceUid.c_str(),
       dataUriScheme.c_str());
   }
+
+  virtual void SignalWindowingUpdated(const ViewerViewport& viewport,
+                                      double windowingCenter,
+                                      double windowingWidth) ORTHANC_OVERRIDE
+  {
+    EM_ASM({
+        const customEvent = document.createEvent("CustomEvent");
+        customEvent.initCustomEvent("WindowingUpdated", false, false,
+                                    { "canvasId" : UTF8ToString($0),
+                                        "windowingCenter" : $1,
+                                        "windowingWidth" : $2 });
+        window.dispatchEvent(customEvent);
+      },
+      viewport.GetCanvasId().c_str(),
+      static_cast<int>(boost::math::iround<double>(windowingCenter)),
+      static_cast<int>(boost::math::iround<double>(windowingWidth)));
+
+    UpdateReferenceLines();
+  }
 };