changeset 2012:50b9bc19dc62

More than one custom image decoder can be installed (e.g. to handle different transfer syntaxes)
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 10 Jun 2016 17:54:26 +0200
parents 5b3b2de4e018
children f6e68c0c2737
files NEWS OrthancServer/OrthancRestApi/OrthancRestResources.cpp Plugins/Engine/OrthancPlugins.cpp Plugins/Engine/OrthancPlugins.h
diffstat 4 files changed, 54 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Fri Jun 10 09:26:26 2016 +0200
+++ b/NEWS	Fri Jun 10 17:54:26 2016 +0200
@@ -25,6 +25,7 @@
 * New callback to handle C-Move requests: OrthancPluginRegisterMoveCallback()
 * New function: "OrthancPluginHttpClient()" to do HTTP requests with full control
 * New function: "OrthancPluginGenerateUuid()" to generate a UUID
+* More than one custom image decoder can be installed (e.g. to handle different transfer syntaxes)
 
 Lua
 ---
--- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp	Fri Jun 10 09:26:26 2016 +0200
+++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp	Fri Jun 10 17:54:26 2016 +0200
@@ -380,7 +380,14 @@
         // TODO create a cache of file
         std::string dicomContent;
         context.ReadFile(dicomContent, publicId, FileContentType_Dicom);
-        decoded.reset(context.GetPlugins().Decode(dicomContent.c_str(), dicomContent.size(), frame));
+        decoded.reset(context.GetPlugins().DecodeUnsafe(dicomContent.c_str(), dicomContent.size(), frame));
+
+        /**
+         * Note that we call "DecodeUnsafe()": We do not fallback to
+         * the builtin decoder if no installed decoder plugin is able
+         * to decode the image. This allows us to take advantage of
+         * the cache below.
+         **/
       }
 #endif
 
--- a/Plugins/Engine/OrthancPlugins.cpp	Fri Jun 10 09:26:26 2016 +0200
+++ b/Plugins/Engine/OrthancPlugins.cpp	Fri Jun 10 17:54:26 2016 +0200
@@ -344,6 +344,7 @@
     typedef std::list<OrthancPluginOnStoredInstanceCallback>  OnStoredCallbacks;
     typedef std::list<OrthancPluginOnChangeCallback>  OnChangeCallbacks;
     typedef std::list<OrthancPluginIncomingHttpRequestFilter>  IncomingHttpRequestFilters;
+    typedef std::list<OrthancPluginDecodeImageCallback>  DecodeImageCallbacks;
     typedef std::map<Property, std::string>  Properties;
 
     PluginsManager manager_;
@@ -353,7 +354,7 @@
     OnChangeCallbacks  onChangeCallbacks_;
     OrthancPluginFindCallback  findCallback_;
     OrthancPluginWorklistCallback  worklistCallback_;
-    OrthancPluginDecodeImageCallback  decodeImageCallback_;
+    DecodeImageCallbacks  decodeImageCallbacks_;
     _OrthancPluginMoveCallback moveCallbacks_;
     IncomingHttpRequestFilters  incomingHttpRequestFilters_;
     std::auto_ptr<StorageAreaFactory>  storageArea_;
@@ -376,7 +377,6 @@
       context_(NULL), 
       findCallback_(NULL),
       worklistCallback_(NULL),
-      decodeImageCallback_(NULL),
       argc_(1),
       argv_(NULL)
     {
@@ -1104,16 +1104,9 @@
 
     boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_);
 
-    if (pimpl_->decodeImageCallback_ != NULL)
-    {
-      LOG(ERROR) << "Can only register one plugin to handle the decompression of DICOM images";
-      throw OrthancException(ErrorCode_Plugin);
-    }
-    else
-    {
-      LOG(INFO) << "Plugin has registered a callback to decode DICOM images";
-      pimpl_->decodeImageCallback_ = p.callback;
-    }
+    pimpl_->decodeImageCallbacks_.push_back(p.callback);
+    LOG(INFO) << "Plugin has registered a callback to decode DICOM images (" 
+              << pimpl_->decodeImageCallbacks_.size() << " decoder(s) now active)";
   }
 
 
@@ -2968,31 +2961,48 @@
   bool OrthancPlugins::HasCustomImageDecoder()
   {
     boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_);
-    return (pimpl_->decodeImageCallback_ != NULL);
+    return !pimpl_->decodeImageCallbacks_.empty();
   }
 
 
-  ImageAccessor*  OrthancPlugins::Decode(const void* dicom,
-                                         size_t size,
-                                         unsigned int frame)
+  ImageAccessor*  OrthancPlugins::DecodeUnsafe(const void* dicom,
+                                               size_t size,
+                                               unsigned int frame)
   {
+    boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_);
+
+    for (PImpl::DecodeImageCallbacks::const_iterator
+           decoder = pimpl_->decodeImageCallbacks_.begin();
+         decoder != pimpl_->decodeImageCallbacks_.end(); ++decoder)
     {
-      boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_);
-      if (pimpl_->decodeImageCallback_ != NULL)
+      OrthancPluginImage* pluginImage = NULL;
+      if ((*decoder) (&pluginImage, dicom, size, frame) == OrthancPluginErrorCode_Success &&
+          pluginImage != NULL)
       {
-        OrthancPluginImage* pluginImage = NULL;
-        if (pimpl_->decodeImageCallback_(&pluginImage, dicom, size, frame) == OrthancPluginErrorCode_Success &&
-            pluginImage != NULL)
-        {
-          return reinterpret_cast<ImageAccessor*>(pluginImage);
-        }
-
-        LOG(INFO) << "The installed image decoding plugins cannot handle an image, fallback to the built-in decoder";
+        return reinterpret_cast<ImageAccessor*>(pluginImage);
       }
     }
 
-    DefaultDicomImageDecoder defaultDecoder;
-    return defaultDecoder.Decode(dicom, size, frame);  // TODO RETURN NULL ???
+    return NULL;
+  }
+
+
+  ImageAccessor* OrthancPlugins::Decode(const void* dicom,
+                                        size_t size,
+                                        unsigned int frame)
+  {
+    ImageAccessor* result = DecodeUnsafe(dicom, size, frame);
+
+    if (result != NULL)
+    {
+      return result;
+    }
+    else
+    {
+      LOG(INFO) << "The installed image decoding plugins cannot handle an image, fallback to the built-in decoder";
+      DefaultDicomImageDecoder defaultDecoder;
+      return defaultDecoder.Decode(dicom, size, frame); 
+    }
   }
 
 
--- a/Plugins/Engine/OrthancPlugins.h	Fri Jun 10 09:26:26 2016 +0200
+++ b/Plugins/Engine/OrthancPlugins.h	Fri Jun 10 17:54:26 2016 +0200
@@ -260,6 +260,13 @@
 
     bool HasCustomImageDecoder();
 
+    // Contrarily to "Decode()", this method does not fallback to the
+    // builtin image decoder, if no installed custom decoder can
+    // handle the image (it returns NULL in this case).
+    ImageAccessor* DecodeUnsafe(const void* dicom,
+                                size_t size,
+                                unsigned int frame);
+
     virtual ImageAccessor* Decode(const void* dicom,
                                   size_t size,
                                   unsigned int frame);