changeset 6052:78f4c1da54d3 attach-custom-data

merge
author Alain Mazy <am@orthanc.team>
date Thu, 20 Mar 2025 18:24:24 +0100 (2 months ago)
parents 55f171e6ea4a (diff) e83414b2b98d (current diff)
children 3f560fa6db5b
files
diffstat 7 files changed, 205 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Tue Mar 18 13:39:20 2025 +0100
+++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Thu Mar 20 18:24:24 2025 +0100
@@ -4726,6 +4726,59 @@
     reinterpret_cast<PImpl::PluginHttpOutput*>(p.output)->SendMultipartItem(p.answer, p.answerSize, headers);
   }
 
+  // static FileInfo CreateFileInfoFromPluginAttachment(OrthancPluginAttachment* attachment)
+  // {
+  //   return FileInfo(attachment->uuid,
+  //                   Orthanc::Plugins::Convert(attachment->contentType),
+  //                   attachment->uncompressedSize,
+  //                   attachment->uncompressedHash
+  //                                        )    fileInfo()
+  // }
+
+  static FileInfo Convert(const OrthancPluginAttachment2& attachment)
+  {
+    std::string uuid, customData;
+    if (attachment.uuid != NULL)
+    {
+      uuid = attachment.uuid;
+    }
+    else
+    {
+      uuid = Toolbox::GenerateUuid();
+    }
+
+    if (attachment.customData != NULL)
+    {
+      customData = std::string(reinterpret_cast<const char*>(attachment.customData), attachment.customDataSize);
+    }
+
+    return FileInfo(uuid,
+                    Orthanc::Plugins::Convert(static_cast<OrthancPluginContentType>(attachment.contentType)),
+                    attachment.uncompressedSize,
+                    attachment.uncompressedHash,
+                    Orthanc::Plugins::Convert(static_cast<OrthancPluginCompressionType>(attachment.compressionType)),
+                    attachment.compressedSize,
+                    attachment.compressedHash,
+                    customData);
+  }
+
+  void OrthancPlugins::ApplyAdoptAttachment(const _OrthancPluginAdoptAttachment& parameters)
+  {
+    PImpl::ServerContextReference lock(*pimpl_);
+    FileInfo adoptedFile = Convert(*(parameters.attachmentInfo));
+
+    if (adoptedFile.GetContentType() == FileContentType_Dicom)
+    {
+      std::unique_ptr<DicomInstanceToStore> dicom(DicomInstanceToStore::CreateFromBuffer(parameters.buffer, parameters.bufferSize));
+      dicom->SetOrigin(DicomInstanceOrigin::FromPlugins());
+
+      std::string resultPublicId;
+
+      ServerContext::StoreResult result = lock.GetContext().AdoptAttachment(resultPublicId, *dicom, StoreInstanceMode_Default, adoptedFile);
+
+      // TODO_ATTACH_CUSTOM_DATA: handle result
+    }
+  }
 
   void OrthancPlugins::ApplyLoadDicomInstance(const _OrthancPluginLoadDicomInstance& params)
   {
@@ -5816,6 +5869,14 @@
         return true;
       }
 
+      case _OrthancPluginService_AdoptAttachment:
+      {
+        const _OrthancPluginAdoptAttachment& p =
+          *reinterpret_cast<const _OrthancPluginAdoptAttachment*>(parameters);
+        ApplyAdoptAttachment(p);
+        return true;
+      }
+
       default:
         return false;
     }
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.h	Tue Mar 18 13:39:20 2025 +0100
+++ b/OrthancServer/Plugins/Engine/OrthancPlugins.h	Thu Mar 20 18:24:24 2025 +0100
@@ -223,6 +223,8 @@
 
     void ApplyLoadDicomInstance(const _OrthancPluginLoadDicomInstance& parameters);
 
+    void ApplyAdoptAttachment(const _OrthancPluginAdoptAttachment& parameters);
+
     void ComputeHash(_OrthancPluginService service,
                      const void* parameters);
 
--- a/OrthancServer/Plugins/Engine/PluginsEnumerations.cpp	Tue Mar 18 13:39:20 2025 +0100
+++ b/OrthancServer/Plugins/Engine/PluginsEnumerations.cpp	Thu Mar 20 18:24:24 2025 +0100
@@ -680,5 +680,21 @@
           throw OrthancException(ErrorCode_ParameterOutOfRange);
       }
     }
+
+    CompressionType Convert(OrthancPluginCompressionType type)
+    {
+      switch (type)
+      {
+        case OrthancPluginCompressionType_None:
+          return CompressionType_None;
+
+        case OrthancPluginCompressionType_ZlibWithSize:
+          return CompressionType_ZlibWithSize;
+
+        default:
+          throw OrthancException(ErrorCode_ParameterOutOfRange);
+      }
+    }
+
   }
 }
--- a/OrthancServer/Plugins/Engine/PluginsEnumerations.h	Tue Mar 18 13:39:20 2025 +0100
+++ b/OrthancServer/Plugins/Engine/PluginsEnumerations.h	Thu Mar 20 18:24:24 2025 +0100
@@ -75,6 +75,8 @@
     OrthancPluginConstraintType Convert(ConstraintType constraint);
 
     OrthancPluginCompressionType Convert(CompressionType type);
+
+    CompressionType Convert(OrthancPluginCompressionType type);
   }
 }
 
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Tue Mar 18 13:39:20 2025 +0100
+++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Thu Mar 20 18:24:24 2025 +0100
@@ -469,6 +469,7 @@
     _OrthancPluginService_SetMetricsIntegerValue = 43,              /* New in Orthanc 1.12.1 */
     _OrthancPluginService_SetCurrentThreadName = 44,                /* New in Orthanc 1.12.2 */
     _OrthancPluginService_LogMessage = 45,                          /* New in Orthanc 1.12.4 */
+    _OrthancPluginService_AdoptAttachment = 46,                     /* New in Orthanc 1.12.7 */
 
 
     /* Registration of callbacks */
@@ -1480,7 +1481,7 @@
    * @param target Memory buffer where to store the content of the file. It must be allocated by the
    * plugin using OrthancPluginCreateMemoryBuffer64(). The core of Orthanc will free it.
    * @param uuid The UUID of the file of interest.
-   * @param customData The custom data of the file to be removed.
+   * @param customData The custom data of the file of interest.
    * @param type The content type corresponding to this file.
    * @ingroup Callbacks
    **/
@@ -1504,7 +1505,7 @@
    * The memory buffer is allocated and freed by Orthanc. The length of the range
    * of interest corresponds to the size of this buffer.
    * @param uuid The UUID of the file of interest.
-   * @param customData The custom data of the file to be removed.
+   * @param customData The custom data of the file of interest.
    * @param type The content type corresponding to this file.
    * @param rangeStart Start position of the requested range in the file.
    * @return 0 if success, other value if error.
@@ -9766,6 +9767,61 @@
     return context->InvokeService(context, _OrthancPluginService_SendStreamChunk, &params);
   }
 
+  typedef struct
+  {
+    const char* uuid;
+    int32_t     contentType;
+    uint64_t    uncompressedSize;
+    const char* uncompressedHash;
+    int32_t     compressionType;
+    uint64_t    compressedSize;
+    const char* compressedHash;
+    const void* customData;
+    uint64_t    customDataSize;
+  } OrthancPluginAttachment2;
+
+
+  typedef struct
+  {
+    const void*                   buffer; /* in */
+    uint64_t                      bufferSize; /* in, can be only the beginning of a DICOM file (until the pixel data) */
+    // TODO_ATTACH_CUSTOM_DATA uint64_t                      pixelDataOffset; /* in, zero = undefined */
+    OrthancPluginAttachment2*     attachmentInfo;  /* in, uuid may not be defined */
+    OrthancPluginResourceType     attachToResourceType; /* in */
+    const char*                   attachToResourceId; /* in */
+    OrthancPluginMemoryBuffer*    createdResourceId; /* out */
+    OrthancPluginMemoryBuffer*    attachmentUuid;    /* out */
+  } _OrthancPluginAdoptAttachment;
+  
+  /**
+   * @brief Tell Orthanc to adopt an existing attachment.
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+TODO_ATTACH_CUSTOM_DATA TODO TODO
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginAdoptAttachment(
+    OrthancPluginContext*         context,
+    const void*                   buffer,
+    uint64_t                      bufferSize,
+    // TODO_ATTACH_CUSTOM_DATA uint64_t                      pixelDataOffset,
+    OrthancPluginAttachment2*     attachmentInfo,
+    OrthancPluginResourceType     attachToResourceType,
+    const char*                   attachToResourceId,
+    OrthancPluginMemoryBuffer*    createdResourceId, /* out */
+    OrthancPluginMemoryBuffer*    attachmentUuid) /* out */
+  {
+    _OrthancPluginAdoptAttachment params;
+    params.buffer = buffer;
+    params.bufferSize = bufferSize;
+    // TODO_ATTACH_CUSTOM_DATA ? params.pixelDataOffset = pixelDataOffset; 
+    params.attachmentInfo = attachmentInfo;
+    params.attachToResourceType = attachToResourceType;
+    params.attachToResourceId = attachToResourceId;
+    params.createdResourceId = createdResourceId;
+    params.attachmentUuid = attachmentUuid;
+
+    return context->InvokeService(context, _OrthancPluginService_AdoptAttachment, &params);
+  }
 
 #ifdef  __cplusplus
 }
--- a/OrthancServer/Sources/ServerContext.cpp	Tue Mar 18 13:39:20 2025 +0100
+++ b/OrthancServer/Sources/ServerContext.cpp	Thu Mar 20 18:24:24 2025 +0100
@@ -606,6 +606,37 @@
                                                                   StoreInstanceMode mode,
                                                                   bool isReconstruct)
   {
+    FileInfo adoptedFileNotUsed;
+
+    return StoreAfterTranscoding(resultPublicId,
+                                 dicom,
+                                 mode,
+                                 isReconstruct,
+                                 false,
+                                 adoptedFileNotUsed);
+  }
+
+  ServerContext::StoreResult ServerContext::AdoptAttachment(std::string& resultPublicId,
+                                                            DicomInstanceToStore& dicom,
+                                                            StoreInstanceMode mode,
+                                                            const FileInfo& adoptedFile)
+  {
+    return StoreAfterTranscoding(resultPublicId,
+                                 dicom,
+                                 mode,
+                                 false,
+                                 true,
+                                 adoptedFile);
+  }
+
+
+  ServerContext::StoreResult ServerContext::StoreAfterTranscoding(std::string& resultPublicId,
+                                                                  DicomInstanceToStore& dicom,
+                                                                  StoreInstanceMode mode,
+                                                                  bool isReconstruct,
+                                                                  bool isAdoption,
+                                                                  const FileInfo& adoptedFile)
+  {
     bool overwrite;
     switch (mode)
     {
@@ -708,10 +739,18 @@
       // TODO Should we use "gzip" instead?
       CompressionType compression = (compressionEnabled_ ? CompressionType_ZlibWithSize : CompressionType_None);
 
-      FileInfo dicomInfo = accessor.Write(dicom.GetBufferData(), dicom.GetBufferSize(), FileContentType_Dicom, compression, storeMD5_, &dicom);
+      ServerIndex::Attachments attachments;
+      FileInfo dicomInfo;
 
-      ServerIndex::Attachments attachments;
-      attachments.push_back(dicomInfo);
+      if (!isAdoption)
+      {
+        dicomInfo = accessor.Write(dicom.GetBufferData(), dicom.GetBufferSize(), FileContentType_Dicom, compression, storeMD5_, &dicom);
+        attachments.push_back(dicomInfo);
+      }
+      else
+      {
+        attachments.push_back(adoptedFile);
+      }
 
       FileInfo dicomUntilPixelData;
       if (hasPixelDataOffset &&
@@ -763,7 +802,10 @@
             
       if (result.GetStatus() != StoreStatus_Success)
       {
-        accessor.Remove(dicomInfo);
+        if (!isAdoption)
+        {
+          accessor.Remove(dicomInfo);
+        }
 
         if (dicomUntilPixelData.IsValid())
         {
@@ -777,7 +819,14 @@
         switch (result.GetStatus())
         {
           case StoreStatus_Success:
-            LOG(INFO) << "New instance stored (" << resultPublicId << ")";
+            if (isAdoption)
+            {
+              LOG(INFO) << "New instance adopted (" << resultPublicId << ")";
+            }
+            else
+            {
+              LOG(INFO) << "New instance stored (" << resultPublicId << ")";
+            }
             break;
 
           case StoreStatus_AlreadyStored:
--- a/OrthancServer/Sources/ServerContext.h	Tue Mar 18 13:39:20 2025 +0100
+++ b/OrthancServer/Sources/ServerContext.h	Thu Mar 20 18:24:24 2025 +0100
@@ -269,6 +269,13 @@
                                       StoreInstanceMode mode,
                                       bool isReconstruct);
 
+    StoreResult StoreAfterTranscoding(std::string& resultPublicId,
+                                      DicomInstanceToStore& dicom,
+                                      StoreInstanceMode mode,
+                                      bool isReconstruct,
+                                      bool isAdoption,
+                                      const FileInfo& adoptedFile);
+
     // This method must only be called from "ServerIndex"!
     void RemoveFile(const std::string& fileUuid,
                     FileContentType type,
@@ -357,6 +364,11 @@
                       DicomInstanceToStore& dicom,
                       StoreInstanceMode mode);
 
+    StoreResult AdoptAttachment(std::string& resultPublicId,
+                                DicomInstanceToStore& dicom,
+                                StoreInstanceMode mode,
+                                const FileInfo& adoptedFile);
+
     StoreResult TranscodeAndStore(std::string& resultPublicId,
                                   DicomInstanceToStore* dicom,
                                   StoreInstanceMode mode,