diff Plugins/Engine/OrthancPlugins.cpp @ 3916:0e3849268a55 transcoding

new plugin SDK primitives related to OrthancPluginDicomInstance
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 11 May 2020 21:07:36 +0200
parents f0dd5ded8927
children 6f11b3233a06
line wrap: on
line diff
--- a/Plugins/Engine/OrthancPlugins.cpp	Mon May 11 15:13:16 2020 +0200
+++ b/Plugins/Engine/OrthancPlugins.cpp	Mon May 11 21:07:36 2020 +0200
@@ -1761,19 +1761,84 @@
   }
 
 
+  class OrthancPlugins::IDicomInstance : public boost::noncopyable
+  {
+  public:
+    virtual ~IDicomInstance()
+    {
+    }
+
+    virtual bool CanBeFreed() const = 0;
+
+    virtual const DicomInstanceToStore& GetInstance() const = 0;
+  };
+
+
+  class OrthancPlugins::DicomInstanceFromCallback : public IDicomInstance
+  {
+  private:
+    const DicomInstanceToStore&  instance_;
+
+  public:
+    DicomInstanceFromCallback(const DicomInstanceToStore& instance) :
+      instance_(instance)
+    {
+    }
+
+    virtual bool CanBeFreed() const ORTHANC_OVERRIDE
+    {
+      return false;
+    }
+
+    virtual const DicomInstanceToStore& GetInstance() const ORTHANC_OVERRIDE
+    {
+      return instance_;
+    };
+  };
+
+
+  class OrthancPlugins::DicomInstanceFromBuffer : public IDicomInstance
+  {
+  private:
+    std::string           buffer_;
+    DicomInstanceToStore  instance_;
+
+  public:
+    DicomInstanceFromBuffer(const void* buffer,
+                            size_t size)
+    {
+      buffer_.assign(reinterpret_cast<const char*>(buffer), size);
+      instance_.SetBuffer(buffer_.empty() ? NULL : buffer_.c_str(), buffer_.size());
+      instance_.SetOrigin(DicomInstanceOrigin::FromPlugins());
+    }
+
+    virtual bool CanBeFreed() const ORTHANC_OVERRIDE
+    {
+      return true;
+    }
+
+    virtual const DicomInstanceToStore& GetInstance() const ORTHANC_OVERRIDE
+    {
+      return instance_;
+    };
+  };
+
+
   void OrthancPlugins::SignalStoredInstance(const std::string& instanceId,
-                                            DicomInstanceToStore& instance,
+                                            const DicomInstanceToStore& instance,
                                             const Json::Value& simplifiedTags)
   {
+    DicomInstanceFromCallback wrapped(instance);
+    
     boost::recursive_mutex::scoped_lock lock(pimpl_->storedCallbackMutex_);
 
     for (PImpl::OnStoredCallbacks::const_iterator
            callback = pimpl_->onStoredCallbacks_.begin(); 
          callback != pimpl_->onStoredCallbacks_.end(); ++callback)
     {
-      OrthancPluginErrorCode error = (*callback) 
-        (reinterpret_cast<OrthancPluginDicomInstance*>(&instance),
-         instanceId.c_str());
+      OrthancPluginErrorCode error = (*callback) (
+        reinterpret_cast<OrthancPluginDicomInstance*>(&wrapped),
+        instanceId.c_str());
 
       if (error != OrthancPluginErrorCode_Success)
       {
@@ -1787,14 +1852,15 @@
   bool OrthancPlugins::FilterIncomingInstance(const DicomInstanceToStore& instance,
                                               const Json::Value& simplified)
   {
+    DicomInstanceFromCallback wrapped(instance);
+    
     boost::recursive_mutex::scoped_lock lock(pimpl_->invokeServiceMutex_);
     
     for (PImpl::IncomingDicomInstanceFilters::const_iterator
            filter = pimpl_->incomingDicomInstanceFilters_.begin();
          filter != pimpl_->incomingDicomInstanceFilters_.end(); ++filter)
     {
-      int32_t allowed = (*filter) (
-        reinterpret_cast<const OrthancPluginDicomInstance*>(&instance));
+      int32_t allowed = (*filter) (reinterpret_cast<const OrthancPluginDicomInstance*>(&wrapped));
 
       if (allowed == 0)
       {
@@ -2451,14 +2517,19 @@
   }
 
 
-  static void AccessDicomInstance(_OrthancPluginService service,
-                                  const void* parameters)
+  void OrthancPlugins::AccessDicomInstance(_OrthancPluginService service,
+                                           const void* parameters)
   {
     const _OrthancPluginAccessDicomInstance& p = 
       *reinterpret_cast<const _OrthancPluginAccessDicomInstance*>(parameters);
 
+    if (p.instance == NULL)
+    {
+      throw OrthancException(ErrorCode_NullPointer);
+    }
+
     const DicomInstanceToStore& instance =
-      *reinterpret_cast<const DicomInstanceToStore*>(p.instance);
+      reinterpret_cast<const IDicomInstance*>(p.instance)->GetInstance();
 
     switch (service)
     {
@@ -2523,6 +2594,10 @@
         *p.resultInt64 = instance.HasPixelData();
         return;
 
+      case _OrthancPluginService_GetInstanceFramesCount:  // New in Orthanc 1.7.0
+        *p.resultInt64 = instance.GetParsedDicomFile().GetFramesCount();
+        return;
+        
       default:
         throw OrthancException(ErrorCode_InternalError);
     }
@@ -2606,6 +2681,79 @@
   }
 
 
+  void OrthancPlugins::AccessDicomInstance2(_OrthancPluginService service,
+                                            const void* parameters)
+  {
+    const _OrthancPluginAccessDicomInstance2& p = 
+      *reinterpret_cast<const _OrthancPluginAccessDicomInstance2*>(parameters);
+
+    if (p.instance == NULL)
+    {
+      throw OrthancException(ErrorCode_NullPointer);
+    }
+
+    const DicomInstanceToStore& instance =
+      reinterpret_cast<const IDicomInstance*>(p.instance)->GetInstance();
+
+    switch (service)
+    {
+      case _OrthancPluginService_GetInstanceFramesCount:
+        *p.targetUint32 = instance.GetParsedDicomFile().GetFramesCount();
+        return;
+        
+      case _OrthancPluginService_GetInstanceRawFrame:
+      {
+        if (p.targetBuffer == NULL)
+        {
+          throw OrthancException(ErrorCode_NullPointer);
+        }
+
+        p.targetBuffer->data = NULL;
+        p.targetBuffer->size = 0;
+        
+        MimeType mime;
+        std::string frame;
+        instance.GetParsedDicomFile().GetRawFrame(frame, mime, p.frameIndex);
+        CopyToMemoryBuffer(*p.targetBuffer, frame);
+        return;
+      }
+        
+      case _OrthancPluginService_GetInstanceDecodedFrame:
+      {
+        bool hasDecoderPlugin;
+
+        {
+          boost::mutex::scoped_lock lock(pimpl_->decodeImageCallbackMutex_);
+          hasDecoderPlugin = !pimpl_->decodeImageCallbacks_.empty();
+        }
+
+        std::unique_ptr<ImageAccessor> decoded;
+        if (p.targetImage == NULL)
+        {
+          throw OrthancException(ErrorCode_NullPointer);
+        }
+        else if (hasDecoderPlugin)
+        {
+          // TODO - This call could be speeded up the future, if a
+          // "decoding context" gets introduced in the decoder plugins
+          
+          decoded.reset(Decode(instance.GetBufferData(), instance.GetBufferSize(), p.frameIndex));
+        }
+        else
+        {
+          decoded.reset(DicomImageDecoder::Decode(instance.GetParsedDicomFile(), p.frameIndex));
+        }
+
+        *(p.targetImage) = ReturnImage(decoded);
+        return;
+      }
+        
+      default:
+        throw OrthancException(ErrorCode_InternalError);
+    }
+  }
+
+
   void OrthancPlugins::UncompressImage(const void* parameters)
   {
     const _OrthancPluginUncompressImage& p = *reinterpret_cast<const _OrthancPluginUncompressImage*>(parameters);
@@ -3481,6 +3629,12 @@
         AccessDicomInstance(service, parameters);
         return true;
 
+      case _OrthancPluginService_GetInstanceFramesCount:
+      case _OrthancPluginService_GetInstanceRawFrame:
+      case _OrthancPluginService_GetInstanceDecodedFrame:
+        AccessDicomInstance2(service, parameters);
+        return true;
+
       case _OrthancPluginService_SetGlobalProperty:
       {
         const _OrthancPluginGlobalProperty& p = 
@@ -4027,6 +4181,37 @@
         GetTagName(parameters);
         return true;
 
+      case _OrthancPluginService_CreateDicomInstance:
+      {
+        const _OrthancPluginCreateDicomInstance& p =
+          *reinterpret_cast<const _OrthancPluginCreateDicomInstance*>(parameters);
+        *(p.target) = reinterpret_cast<OrthancPluginDicomInstance*>(
+          new DicomInstanceFromBuffer(p.buffer, p.size));
+        return true;
+      }
+        
+      case _OrthancPluginService_FreeDicomInstance:
+      {
+        const _OrthancPluginFreeDicomInstance& p =
+          *reinterpret_cast<const _OrthancPluginFreeDicomInstance*>(parameters);
+
+        if (p.dicom != NULL)
+        {
+          IDicomInstance* obj = reinterpret_cast<IDicomInstance*>(p.dicom);
+          
+          if (obj->CanBeFreed())
+          {
+            delete obj;
+          }
+          else
+          {
+            throw OrthancException(ErrorCode_Plugin, "Cannot free a DICOM instance provided to a callback");
+          }
+        }
+
+        return true;
+      }
+
       default:
         return false;
     }