changeset 1327:4f8db2d202c8 broker

OrthancSeriesProgressiveLoader now has two modes that can be selected at object creation : - progressive (will first load jpeg50, then jpeg90 then PAM) - non-progressive (will directly load PAM (uncompressed)) Please note that the slice loading order remains dynamic and depending upon the slice that the client code wishes to extract from the volume.
author Benjamin Golinvaux <bgo@osimis.io>
date Wed, 25 Mar 2020 14:34:27 +0100
parents 55166e57a77c
children fd616c4a5904
files Framework/Deprecated/Loaders/LoaderCache.cpp Framework/Deprecated/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp Framework/Deprecated/Loaders/OrthancSeriesVolumeProgressiveLoader.h Framework/Scene2D/OpenGLCompositor.cpp
diffstat 4 files changed, 106 insertions(+), 80 deletions(-) [+]
line wrap: on
line diff
--- a/Framework/Deprecated/Loaders/LoaderCache.cpp	Tue Mar 24 21:32:35 2020 +0100
+++ b/Framework/Deprecated/Loaders/LoaderCache.cpp	Wed Mar 25 14:34:27 2020 +0100
@@ -83,7 +83,9 @@
         boost::shared_ptr<OrthancStone::DicomVolumeImage> volumeImage(new OrthancStone::DicomVolumeImage);
         boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> loader;
       
-        loader = OrthancSeriesVolumeProgressiveLoader::Create(loadersContext_, volumeImage);
+        // true means "use progressive quality"
+        // false means "load high quality slices only"
+        loader = OrthancSeriesVolumeProgressiveLoader::Create(loadersContext_, volumeImage, false);
         loader->LoadSeries(seriesUuid);
         seriesVolumeProgressiveLoaders_[seriesUuid] = loader;
       }
--- a/Framework/Deprecated/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp	Tue Mar 24 21:32:35 2020 +0100
+++ b/Framework/Deprecated/Loaders/OrthancSeriesVolumeProgressiveLoader.cpp	Wed Mar 25 14:34:27 2020 +0100
@@ -21,6 +21,7 @@
 
 #include "OrthancSeriesVolumeProgressiveLoader.h"
 
+#include "../../StoneException.h"
 #include "../../Loaders/ILoadersContext.h"
 #include "../../Loaders/BasicFetchingItemsSorter.h"
 #include "../../Loaders/BasicFetchingStrategy.h"
@@ -64,11 +65,9 @@
       }
     }
   };
-
     
-    
-  void OrthancSeriesVolumeProgressiveLoader::SeriesGeometry::CheckSlice(size_t index,
-                                                                        const OrthancStone::DicomInstanceParameters& reference) const
+  void OrthancSeriesVolumeProgressiveLoader::SeriesGeometry::CheckSlice(
+    size_t index, const OrthancStone::DicomInstanceParameters& reference) const
   {
     const OrthancStone::DicomInstanceParameters& slice = *slices_[index];
       
@@ -260,16 +259,15 @@
   {
     assert(strategy_.get() != NULL);
       
-    unsigned int sliceIndex, quality;
+    unsigned int sliceIndex = 0, quality = 0;
       
     if (strategy_->GetNext(sliceIndex, quality))
     {
-
-#if USE_SINGLE_QUALITY
-      assert(quality == SINGLE_QUALITY);
-#else
-      assert(quality <= BEST_QUALITY);
-#endif
+      if (!progressiveQuality_)
+      {
+        ORTHANC_ASSERT(quality == QUALITY_00, "INTERNAL ERROR. quality != QUALITY_00 in "
+                       << "OrthancSeriesVolumeProgressiveLoader::ScheduleNextSliceDownload");
+      }
 
       const OrthancStone::DicomInstanceParameters& slice = seriesGeometry_.GetSliceParameters(sliceIndex);
           
@@ -281,10 +279,7 @@
 
       std::unique_ptr<OrthancStone::OracleCommandBase> command;
         
-#if USE_SINGLE_QUALITY
-#else
-      if (quality == BEST_QUALITY)
-#endif
+      if (!progressiveQuality_ || quality == QUALITY_02)
       {
         std::unique_ptr<OrthancStone::GetOrthancImageCommand> tmp(new OrthancStone::GetOrthancImageCommand);
         // TODO: review the following comment. 
@@ -304,23 +299,22 @@
         //  << " URI = " << tmp->GetUri();
         command.reset(tmp.release());
       }
-#if USE_SINGLE_QUALITY
-#else
-      else
+      else // progressive mode is true AND quality is not final (different from QUALITY_02
       {
-        std::unique_ptr<OrthancStone::GetOrthancWebViewerJpegCommand> tmp(new OrthancStone::GetOrthancWebViewerJpegCommand);
+        std::unique_ptr<OrthancStone::GetOrthancWebViewerJpegCommand> tmp(
+          new OrthancStone::GetOrthancWebViewerJpegCommand);
+
         // TODO: review the following comment. Commented out by bgo on 2019-07-19
         // (gzip for jpeg seems overkill)
         //tmp->SetHttpHeader("Accept-Encoding", "gzip");
         tmp->SetInstance(instance);
-        tmp->SetQuality((quality == 0 ? 50 : 90));
+        tmp->SetQuality((quality == 0 ? 50 : 90)); // QUALITY_00 is Jpeg50 while QUALITY_01 is Jpeg90
         tmp->SetExpectedPixelFormat(slice.GetExpectedPixelFormat());
         LOG(TRACE)
           << "OrthancSeriesVolumeProgressiveLoader.ScheduleNextSliceDownload()"
           << " sliceIndex = " << sliceIndex << " slice quality = " << quality;
         command.reset(tmp.release());
       }
-#endif
 
       command->AcquirePayload(new Orthanc::SingleValueObject<unsigned int>(sliceIndex));
       
@@ -386,15 +380,15 @@
       volume_->SetDicomParameters(parameters);
       volume_->GetPixelData().Clear();
 
-#if USE_SINGLE_QUALITY
+      // If we are in progressive mode, the Fetching strategy will first request QUALITY_00, then QUALITY_01, then
+      // QUALITY_02... Otherwise, it's only QUALITY_00
+      unsigned int maxQuality = QUALITY_00;
+      if (progressiveQuality_)
+        maxQuality = QUALITY_02;
+
       strategy_.reset(new OrthancStone::BasicFetchingStrategy(
         sorter_->CreateSorter(static_cast<unsigned int>(slicesCount)),
-        SINGLE_QUALITY));
-#else
-      strategy_.reset(new OrthancStone::BasicFetchingStrategy(
-        sorter_->CreateSorter(static_cast<unsigned int>(slicesCount)), 
-        BEST_QUALITY));
-#endif
+        maxQuality));
 
       assert(simultaneousDownloads_ != 0);
       for (unsigned int i = 0; i < simultaneousDownloads_; i++)
@@ -413,13 +407,22 @@
                                                              const Orthanc::ImageAccessor& image,
                                                              unsigned int quality)
   {
-    assert(sliceIndex < slicesQuality_.size() &&
+    ORTHANC_ASSERT(sliceIndex < slicesQuality_.size() &&
            slicesQuality_.size() == volume_->GetPixelData().GetDepth());
       
+    if (!progressiveQuality_)
+    {
+      ORTHANC_ASSERT(quality                    == QUALITY_00);
+      ORTHANC_ASSERT(slicesQuality_[sliceIndex] == QUALITY_00);
+    }
+
     if (quality >= slicesQuality_[sliceIndex])
     {
       {
-        OrthancStone::ImageBuffer3D::SliceWriter writer(volume_->GetPixelData(), OrthancStone::VolumeProjection_Axial, sliceIndex);
+        OrthancStone::ImageBuffer3D::SliceWriter writer(volume_->GetPixelData(), 
+                                                        OrthancStone::VolumeProjection_Axial, 
+                                                        sliceIndex);
+        
         Orthanc::ImageProcessing::Copy(writer.GetAccessor(), image);
       }
 
@@ -434,30 +437,35 @@
     ScheduleNextSliceDownload();
   }
 
-  void OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent(const OrthancStone::GetOrthancImageCommand::SuccessMessage& message)
+  void OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent(
+    const OrthancStone::GetOrthancImageCommand::SuccessMessage& message)
   {
-#if USE_SINGLE_QUALITY
-    SetSliceContent(GetSliceIndexPayload(message.GetOrigin()), message.GetImage(), SINGLE_QUALITY);
-#else
-    SetSliceContent(GetSliceIndexPayload(message.GetOrigin()), message.GetImage(), BEST_QUALITY);
-#endif
+    unsigned int quality = QUALITY_00;
+    if (progressiveQuality_)
+      quality = QUALITY_02;
+
+    SetSliceContent(GetSliceIndexPayload(message.GetOrigin()), 
+                                         message.GetImage(),
+                                         quality);
   }
 
-#if USE_SINGLE_QUALITY
-#else
-  void OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent(const OrthancStone::GetOrthancWebViewerJpegCommand::SuccessMessage& message)
+  void OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent(
+    const OrthancStone::GetOrthancWebViewerJpegCommand::SuccessMessage& message)
   {
+    ORTHANC_ASSERT(progressiveQuality_, "INTERNAL ERROR: OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent"
+                   << " called while progressiveQuality_ is false!");
+
     LOG(TRACE) << "OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent";
     unsigned int quality;
       
     switch (dynamic_cast<const OrthancStone::GetOrthancWebViewerJpegCommand&>(message.GetOrigin()).GetQuality())
     {
       case 50:
-        quality = LOW_QUALITY;
+        quality = QUALITY_00;
         break;
 
       case 90:
-        quality = MIDDLE_QUALITY;
+        quality = QUALITY_01;
         break;
 
       default:
@@ -466,13 +474,14 @@
       
     SetSliceContent(GetSliceIndexPayload(message.GetOrigin()), message.GetImage(), quality);
   }
-#endif
 
   OrthancSeriesVolumeProgressiveLoader::OrthancSeriesVolumeProgressiveLoader(
     OrthancStone::ILoadersContext& loadersContext,
-    const boost::shared_ptr<OrthancStone::DicomVolumeImage>& volume)
+    boost::shared_ptr<OrthancStone::DicomVolumeImage> volume,
+    bool progressiveQuality)
     : loadersContext_(loadersContext)
     , active_(false)
+    , progressiveQuality_(progressiveQuality)
     , simultaneousDownloads_(4)
     , volume_(volume)
     , sorter_(new OrthancStone::BasicFetchingItemsSorter::Factory)
@@ -483,12 +492,14 @@
   boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> 
     OrthancSeriesVolumeProgressiveLoader::Create(
       OrthancStone::ILoadersContext& loadersContext,
-      const boost::shared_ptr<OrthancStone::DicomVolumeImage>& volume)
+      boost::shared_ptr<OrthancStone::DicomVolumeImage> volume,
+      bool progressiveQuality)
   {
     std::auto_ptr<OrthancStone::ILoadersContext::ILock> lock(loadersContext.Lock());
 
     boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> obj(
-        new OrthancSeriesVolumeProgressiveLoader(loadersContext,volume));
+        new OrthancSeriesVolumeProgressiveLoader(
+          loadersContext, volume, progressiveQuality));
 
     obj->Register<OrthancStone::OrthancRestApiCommand::SuccessMessage>(
       lock->GetOracleObservable(),
@@ -498,12 +509,10 @@
       lock->GetOracleObservable(),
       &OrthancSeriesVolumeProgressiveLoader::LoadBestQualitySliceContent);
 
-#if USE_SINGLE_QUALITY
-#else
     obj->Register<OrthancStone::GetOrthancWebViewerJpegCommand::SuccessMessage>(
       lock->GetOracleObservable(),
       &OrthancSeriesVolumeProgressiveLoader::LoadJpegSliceContent);
-#endif
+
     return obj;
   }
 
@@ -533,10 +542,8 @@
 
   void OrthancSeriesVolumeProgressiveLoader::LoadSeries(const std::string& seriesId)
   {
-//    LOG(TRACE) << "OrthancSeriesVolumeProgressiveLoader::LoadSeries seriesId=" << seriesId;
     if (active_)
     {
-//      LOG(TRACE) << "OrthancSeriesVolumeProgressiveLoader::LoadSeries NOT ACTIVE! --> ERROR";
       LOG(ERROR) << "OrthancSeriesVolumeProgressiveLoader::LoadSeries(const std::string& seriesId): (active_)";
       throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
     }
--- a/Framework/Deprecated/Loaders/OrthancSeriesVolumeProgressiveLoader.h	Tue Mar 24 21:32:35 2020 +0100
+++ b/Framework/Deprecated/Loaders/OrthancSeriesVolumeProgressiveLoader.h	Wed Mar 25 14:34:27 2020 +0100
@@ -38,9 +38,6 @@
 
 #include <boost/shared_ptr.hpp>
 
-#define USE_SINGLE_QUALITY 1
-
-
 namespace OrthancStone
 {
   class ILoadersContext;
@@ -59,15 +56,10 @@
     public IGeometryProvider
   {
   private:
-#if USE_SINGLE_QUALITY
-    static const unsigned int SINGLE_QUALITY = 0;
-#else
-    static const unsigned int LOW_QUALITY = 0;
-    static const unsigned int MIDDLE_QUALITY = 1;
-    static const unsigned int BEST_QUALITY = 2;
-#endif
-
-    
+    static const unsigned int QUALITY_00 = 0;
+    static const unsigned int QUALITY_01 = 1;
+    static const unsigned int QUALITY_02 = 2;
+        
     class ExtractedSlice;
     
     /** Helper class internal to OrthancSeriesVolumeProgressiveLoader */
@@ -119,32 +111,34 @@
 
     void LoadBestQualitySliceContent(const OrthancStone::GetOrthancImageCommand::SuccessMessage& message);
 
-#if USE_SINGLE_QUALITY
-#else
     void LoadJpegSliceContent(const OrthancStone::GetOrthancWebViewerJpegCommand::SuccessMessage& message);
-#endif
 
-    OrthancStone::ILoadersContext&                loadersContext_;
+    OrthancStone::ILoadersContext&  loadersContext_;
     bool                                          active_;
+    bool                                          progressiveQuality_;
     unsigned int                                  simultaneousDownloads_;
     SeriesGeometry                                seriesGeometry_;
-    boost::shared_ptr<OrthancStone::DicomVolumeImage>           volume_;
+    boost::shared_ptr<OrthancStone::DicomVolumeImage> volume_;
     std::unique_ptr<OrthancStone::IFetchingItemsSorter::IFactory> sorter_;
-    std::unique_ptr<OrthancStone::IFetchingStrategy>              strategy_;
-    std::vector<unsigned int>                     slicesQuality_;
-    bool                                          volumeImageReadyInHighQuality_;
-
-
+    std::unique_ptr<OrthancStone::IFetchingStrategy> strategy_;
+    std::vector<unsigned int>     slicesQuality_;
+    bool                          volumeImageReadyInHighQuality_;
+    
     OrthancSeriesVolumeProgressiveLoader(
       OrthancStone::ILoadersContext& loadersContext,
-      const boost::shared_ptr<OrthancStone::DicomVolumeImage>& volume);
+      boost::shared_ptr<OrthancStone::DicomVolumeImage> volume,
+      bool progressiveQuality);
   
   public:
     ORTHANC_STONE_DEFINE_ORIGIN_MESSAGE(__FILE__, __LINE__, VolumeImageReadyInHighQuality, OrthancSeriesVolumeProgressiveLoader);
 
+    /**
+    See doc for the progressiveQuality_ field
+    */
     static boost::shared_ptr<OrthancSeriesVolumeProgressiveLoader> Create(
       OrthancStone::ILoadersContext& context,
-      const boost::shared_ptr<OrthancStone::DicomVolumeImage>& volume);
+      boost::shared_ptr<OrthancStone::DicomVolumeImage> volume,
+      bool progressiveQuality = false);
 
     virtual ~OrthancSeriesVolumeProgressiveLoader();
 
--- a/Framework/Scene2D/OpenGLCompositor.cpp	Tue Mar 24 21:32:35 2020 +0100
+++ b/Framework/Scene2D/OpenGLCompositor.cpp	Wed Mar 25 14:34:27 2020 +0100
@@ -13,7 +13,7 @@
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Affero General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  **/
@@ -150,11 +150,34 @@
   {
     if (!context_.IsContextLost())
     {
-      context_.MakeCurrent(); // this can throw if context lost!
-      for (Fonts::iterator it = fonts_.begin(); it != fonts_.end(); ++it)
+      try
       {
-        assert(it->second != NULL);
-        delete it->second;
+        try
+        {
+          context_.MakeCurrent(); // this can throw if context lost!
+        }
+        catch (...)
+        {
+          LOG(ERROR) << "context_.MakeCurrent() failed in OpenGLCompositor::~OpenGLCompositor()!";
+        }
+
+        for (Fonts::iterator it = fonts_.begin(); it != fonts_.end(); ++it)
+        {
+          try
+          {
+
+            assert(it->second != NULL);
+            delete it->second;
+          }
+          catch (...)
+          {
+            LOG(ERROR) << "Exception thrown while deleting OpenGL-based font!";
+          }
+        }
+      }
+      catch (...)
+      {
+        // logging threw an exception!
       }
     }
   }