changeset 1704:902d13889ae4

LoadMultipartInstanceInViewport() in C++
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 27 Nov 2020 17:15:09 +0100
parents 76c590a62755
children 3d62634d442f
files Applications/StoneWebViewer/WebApplication/app.js Applications/StoneWebViewer/WebApplication/index.html Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp
diffstat 3 files changed, 125 insertions(+), 60 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/StoneWebViewer/WebApplication/app.js	Fri Nov 27 16:36:43 2020 +0100
+++ b/Applications/StoneWebViewer/WebApplication/app.js	Fri Nov 27 17:15:09 2020 +0100
@@ -102,7 +102,7 @@
 
 
 Vue.component('viewport', {
-  props: [ 'left', 'top', 'width', 'height', 'canvasId', 'active', 'series', 'viewportIndex',
+  props: [ 'left', 'top', 'width', 'height', 'canvasId', 'active', 'content', 'viewportIndex',
            'showInfo' ],
   template: '#viewport-template',
   data: function () {
@@ -128,7 +128,7 @@
        **/
       this.cineLoadingFrame = false;
     },
-    series: function(newVal, oldVal) {
+    content: function(newVal, oldVal) {
       this.status = 'loading';
       this.cineControls = false;
       this.cineMode = '';
@@ -202,9 +202,9 @@
       var pdfPointer = args.detail.pdfPointer;
       var pdfSize = args.detail.pdfSize;
 
-      if ('tags' in that.series &&
-          that.series.tags[STUDY_INSTANCE_UID] == studyInstanceUid &&
-          that.series.tags[SERIES_INSTANCE_UID] == seriesInstanceUid) {
+      if ('tags' in that.content &&
+          that.content.tags[STUDY_INSTANCE_UID] == studyInstanceUid &&
+          that.content.tags[SERIES_INSTANCE_UID] == seriesInstanceUid) {
 
         that.status = 'pdf';
         var pdf = new Uint8Array(HEAPU8.subarray(pdfPointer, pdfPointer + pdfSize));
@@ -228,7 +228,10 @@
       event.preventDefault();
 
       // The "parseInt()" is because of Microsoft Edge Legacy (*)
-      this.$emit('updated-series', parseInt(event.dataTransfer.getData('seriesIndex'), 10));
+      this.$emit('updated-series', {
+        seriesIndex: parseInt(event.dataTransfer.getData('seriesIndex'), 10),
+        sopInstanceUid: event.dataTransfer.getData('sopInstanceUid')
+      });
     },
     MakeActive: function() {
       this.$emit('selected-viewport');
@@ -336,28 +339,28 @@
       viewport1Left: '0%',
       viewport1Top: '0%',
       viewport1Visible: true,
-      viewport1Series: {},
+      viewport1Content: {},
       
       viewport2Width: '100%',
       viewport2Height: '100%',
       viewport2Left: '0%',
       viewport2Top: '0%',
       viewport2Visible: false,
-      viewport2Series: {},
+      viewport2Content: {},
 
       viewport3Width: '100%',
       viewport3Height: '100%',
       viewport3Left: '0%',
       viewport3Top: '0%',
       viewport3Visible: false,
-      viewport3Series: {},
+      viewport3Content: {},
 
       viewport4Width: '100%',
       viewport4Height: '100%',
       viewport4Left: '0%',
       viewport4Top: '0%',
       viewport4Visible: false,
-      viewport4Series: {},
+      viewport4Content: {},
 
       showWindowing: false,
       windowingPresets: [],
@@ -420,17 +423,17 @@
     GetActiveSeries: function() {
       var s = [];
 
-      if ('tags' in this.viewport1Series)
-        s.push(this.viewport1Series.tags[SERIES_INSTANCE_UID]);
+      if ('tags' in this.viewport1Content)
+        s.push(this.viewport1Content.tags[SERIES_INSTANCE_UID]);
 
-      if ('tags' in this.viewport2Series)
-        s.push(this.viewport2Series.tags[SERIES_INSTANCE_UID]);
+      if ('tags' in this.viewport2Content)
+        s.push(this.viewport2Content.tags[SERIES_INSTANCE_UID]);
 
-      if ('tags' in this.viewport3Series)
-        s.push(this.viewport3Series.tags[SERIES_INSTANCE_UID]);
+      if ('tags' in this.viewport3Content)
+        s.push(this.viewport3Content.tags[SERIES_INSTANCE_UID]);
 
-      if ('tags' in this.viewport4Series)
-        s.push(this.viewport4Series.tags[SERIES_INSTANCE_UID]);
+      if ('tags' in this.viewport4Content)
+        s.push(this.viewport4Content.tags[SERIES_INSTANCE_UID]);
 
       return s;
     },
@@ -518,31 +521,40 @@
       event.dataTransfer.setData('seriesIndex', seriesIndex.toString());
     },
 
+    MultiframeInstanceDragStart: function(event, seriesIndex, sopInstanceUid) {
+      event.dataTransfer.setData('seriesIndex', seriesIndex.toString());
+      event.dataTransfer.setData('sopInstanceUid', sopInstanceUid.toString());
+    },
+
     SetViewportSeriesInstanceUid: function(viewportIndex, seriesInstanceUid) {
       if (seriesInstanceUid in this.seriesIndex) {
-        this.SetViewportSeries(viewportIndex, this.seriesIndex[seriesInstanceUid]);
+        this.SetViewportSeries(viewportIndex, {
+          seriesIndex: this.seriesIndex[seriesInstanceUid]
+        });
       }
     },
     
-    SetViewportSeries: function(viewportIndex, seriesIndex) {
-      var series = this.series[seriesIndex];
+    SetViewportSeries: function(viewportIndex, info) {
+      var series = this.series[info.seriesIndex];
       
       if (viewportIndex == 1) {
-        this.viewport1Series = series;
+        this.viewport1Content = series;
       }
       else if (viewportIndex == 2) {
-        this.viewport2Series = series;
+        this.viewport2Content = series;
       }
       else if (viewportIndex == 3) {
-        this.viewport3Series = series;
+        this.viewport3Content = series;
       }
       else if (viewportIndex == 4) {
-        this.viewport4Series = series;
+        this.viewport4Content = series;
       }
     },
     
     ClickSeries: function(seriesIndex) {
-      this.SetViewportSeries(this.activeViewport, seriesIndex);
+      this.SetViewportSeries(this.activeViewport, {
+        seriesIndex: seriesIndex
+      });
     },
     
     HideViewport: function(index) {
@@ -673,24 +685,24 @@
         // https://fr.vuejs.org/2016/02/06/common-gotchas/#Why-isn%E2%80%99t-the-DOM-updating
         this.$set(this.series, index, series);
 
-        if ('tags' in this.viewport1Series &&
-            this.viewport1Series.tags[SERIES_INSTANCE_UID] == seriesInstanceUid) {
-          this.$set(this.viewport1Series, series);
+        if ('tags' in this.viewport1Content &&
+            this.viewport1Content.tags[SERIES_INSTANCE_UID] == seriesInstanceUid) {
+          this.$set(this.viewport1Content, series);
         }
 
-        if ('tags' in this.viewport2Series &&
-            this.viewport2Series.tags[SERIES_INSTANCE_UID] == seriesInstanceUid) {
-          this.$set(this.viewport2Series, series);
+        if ('tags' in this.viewport2Content &&
+            this.viewport2Content.tags[SERIES_INSTANCE_UID] == seriesInstanceUid) {
+          this.$set(this.viewport2Content, series);
         }
 
-        if ('tags' in this.viewport3Series &&
-            this.viewport3Series.tags[SERIES_INSTANCE_UID] == seriesInstanceUid) {
-          this.$set(this.viewport3Series, series);
+        if ('tags' in this.viewport3Content &&
+            this.viewport3Content.tags[SERIES_INSTANCE_UID] == seriesInstanceUid) {
+          this.$set(this.viewport3Content, series);
         }
 
-        if ('tags' in this.viewport4Series &&
-            this.viewport4Series.tags[SERIES_INSTANCE_UID] == seriesInstanceUid) {
-          this.$set(this.viewport4Series, series);
+        if ('tags' in this.viewport4Content &&
+            this.viewport4Content.tags[SERIES_INSTANCE_UID] == seriesInstanceUid) {
+          this.$set(this.viewport4Content, series);
         }
       }
     },
--- a/Applications/StoneWebViewer/WebApplication/index.html	Fri Nov 27 16:36:43 2020 +0100
+++ b/Applications/StoneWebViewer/WebApplication/index.html	Fri Nov 27 17:15:09 2020 +0100
@@ -245,9 +245,9 @@
                           <!-- Series with multiple multiframe instances (CINE) -->
                           <li class="wvSerieslist__seriesItem"
                               v-bind:class="{ highlighted : GetActiveSeries().includes(series[seriesIndex].tags['0020,000e']), 'wvSerieslist__seriesItem--list' : leftMode != 'grid', 'wvSerieslist__seriesItem--grid' : leftMode == 'grid' }"
-                              v-on:dragstart="SeriesDragStart($event, seriesIndex)"
-                              v-on:click="ClickSeries(seriesIndex)"
-                              v-for="(numberOfFrames, sopInstanceUid) in series[seriesIndex].multiframeInstances">
+                              v-for="(numberOfFrames, sopInstanceUid) in series[seriesIndex].multiframeInstances"
+                              v-on:dragstart="MultiframeInstanceDragStart($event, seriesIndex, sopInstanceUid)"
+                              v-on:click="ClickMultiframeInstance(seriesIndex, sopInstanceUid)">
                             <div class="wvSerieslist__picture" style="z-index:0"
                                  draggable="true">
                               <img v-if="series[seriesIndex].type == stone.ThumbnailType.IMAGE"
@@ -264,8 +264,8 @@
 
                             <div v-if="leftMode == 'full'" class="wvSerieslist__information"
                                  draggable="true"
-                                 v-on:dragstart="SeriesDragStart($event, seriesIndex)"
-                                 v-on:click="ClickSeries(seriesIndex)">
+                                 v-on:dragstart="MultiframeInstanceDragStart($event, seriesIndex, sopInstanceUid)"
+                                 v-on:click="MultiframeInstanceDragStart($event, seriesIndex, sopInstanceUid)">
                               <p class="wvSerieslist__label">
                                 [{{ series[seriesIndex].tags['0008,0060'] }}]
                                 {{ series[seriesIndex].tags['0008,103e'] }}
@@ -523,7 +523,7 @@
                         v-on:selected-viewport="activeViewport=1"
                         v-show="viewport1Visible"
                         canvas-id="canvas1"
-                        v-bind:series="viewport1Series"
+                        v-bind:content="viewport1Content"
                         v-bind:left="viewport1Left"
                         v-bind:top="viewport1Top"
                         v-bind:width="viewport1Width"
@@ -534,7 +534,7 @@
                         v-on:selected-viewport="activeViewport=2"
                         v-show="viewport2Visible"
                         canvas-id="canvas2"
-                        v-bind:series="viewport2Series"
+                        v-bind:content="viewport2Content"
                         v-bind:left="viewport2Left"
                         v-bind:top="viewport2Top"
                         v-bind:width="viewport2Width"
@@ -545,7 +545,7 @@
                         v-on:selected-viewport="activeViewport=3"
                         v-show="viewport3Visible"
                         canvas-id="canvas3"
-                        v-bind:series="viewport3Series"
+                        v-bind:content="viewport3Content"
                         v-bind:left="viewport3Left"
                         v-bind:top="viewport3Top"
                         v-bind:width="viewport3Width"
@@ -556,7 +556,7 @@
                         v-on:selected-viewport="activeViewport=4"
                         v-show="viewport4Visible"
                         canvas-id="canvas4"
-                        v-bind:series="viewport4Series"
+                        v-bind:content="viewport4Content"
                         v-bind:left="viewport4Left"
                         v-bind:top="viewport4Top"
                         v-bind:width="viewport4Width"
@@ -579,12 +579,12 @@
                          width: width, 
                          height: height }">
         <div v-bind:class="{ 'wvSplitpane__cellBorder--selected' : active, 
-                           'wvSplitpane__cellBorder' : series.color == '', 
-                           'wvSplitpane__cellBorder--blue' : series.color == 'blue', 
-                           'wvSplitpane__cellBorder--red' : series.color == 'red',
-                           'wvSplitpane__cellBorder--green' : series.color == 'green', 
-                           'wvSplitpane__cellBorder--yellow' : series.color == 'yellow', 
-                           'wvSplitpane__cellBorder--violet' : series.color == 'violet'
+                           'wvSplitpane__cellBorder' : content.color == '', 
+                           'wvSplitpane__cellBorder--blue' : content.color == 'blue', 
+                           'wvSplitpane__cellBorder--red' : content.color == 'red',
+                           'wvSplitpane__cellBorder--green' : content.color == 'green', 
+                           'wvSplitpane__cellBorder--yellow' : content.color == 'yellow', 
+                           'wvSplitpane__cellBorder--violet' : content.color == 'violet'
                            }" 
              ondragover="event.preventDefault()"
              v-on:drop="DragDrop($event)"
@@ -600,14 +600,14 @@
 
               <div v-show="showInfo">
                 <div class="wv-overlay">
-                  <div v-if="'tags' in series" class="wv-overlay-topleft">
-                    {{ series.tags['0010,0010'] }}<br/>
-                    {{ series.tags['0010,0020'] }}
+                  <div v-if="'tags' in content" class="wv-overlay-topleft">
+                    {{ content.tags['0010,0010'] }}<br/>
+                    {{ content.tags['0010,0020'] }}
                   </div>
-                  <div v-if="'tags' in series" class="wv-overlay-topright">
-                    {{ series.tags['0008,1030'] }}<br/>
-                    {{ app.FormatDate(series.tags['0008,0020']) }}<br/>
-                    {{ series.tags['0020,0011'] }} | {{ series.tags['0008,103e'] }}
+                  <div v-if="'tags' in content" class="wv-overlay-topright">
+                    {{ content.tags['0008,1030'] }}<br/>
+                    {{ app.FormatDate(content.tags['0008,0020']) }}<br/>
+                    {{ content.tags['0020,0011'] }} | {{ content.tags['0008,103e'] }}
                   </div>
                   <div class="wv-overlay-timeline-wrapper wvPrintExclude">
                     <div style="text-align:left; padding:5px" v-show="numberOfFrames != 0">
--- a/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Fri Nov 27 16:36:43 2020 +0100
+++ b/Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp	Fri Nov 27 17:15:09 2020 +0100
@@ -575,6 +575,35 @@
     }
   }
 
+  bool SortMultipartInstanceFrames(OrthancStone::SortedFrames& target,
+                                   const std::string& seriesInstanceUid,
+                                   const std::string& sopInstanceUid) const
+  {
+    OrthancStone::SeriesMetadataLoader::Accessor accessor(*metadataLoader_, seriesInstanceUid);
+    
+    if (accessor.IsComplete())
+    {
+      for (size_t i = 0; i < accessor.GetInstancesCount(); i++)
+      {
+        std::string s;
+        if (accessor.GetInstance(i).LookupStringValue(s, Orthanc::DICOM_TAG_SOP_INSTANCE_UID, false) &&
+            s == sopInstanceUid)
+        {
+          target.Clear();
+          target.AddInstance(accessor.GetInstance(i));
+          target.Sort();
+          return true;
+        }
+      }
+      
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
+
   size_t GetSeriesNumberOfFrames(const std::string& seriesInstanceUid) const
   {
     OrthancStone::SeriesMetadataLoader::Accessor accessor(*metadataLoader_, seriesInstanceUid);
@@ -3078,6 +3107,30 @@
 
 
   EMSCRIPTEN_KEEPALIVE
+  int LoadMultipartInstanceInViewport(const char* canvas,
+                                      const char* seriesInstanceUid,
+                                      const char* sopInstanceUid)
+  {
+    try
+    {
+      std::unique_ptr<OrthancStone::SortedFrames> frames(new OrthancStone::SortedFrames);
+      
+      if (GetResourcesLoader().SortMultipartInstanceFrames(*frames, seriesInstanceUid, sopInstanceUid))
+      {
+        GetViewport(canvas)->SetFrames(frames.release());
+        return 1;
+      }
+      else
+      {
+        return 0;
+      }
+    }
+    EXTERN_CATCH_EXCEPTIONS;
+    return 0;
+  }
+
+
+  EMSCRIPTEN_KEEPALIVE
   void AllViewportsUpdateSize(int fitContent)
   {
     try