changeset 6199:b39a8bcc0062 attach-custom-data

documenting OrthancPluginAdoptDicomInstance()
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 13 Jun 2025 15:01:35 +0200
parents 3d0b6bca6f2e
children ebf70f0cde4c af8f7a9c3ae7
files OrthancServer/Plugins/Engine/OrthancPlugins.cpp OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h
diffstat 2 files changed, 59 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Fri Jun 13 13:27:42 2025 +0200
+++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp	Fri Jun 13 15:01:35 2025 +0200
@@ -1761,7 +1761,8 @@
     std::unique_ptr<OrthancPluginDatabaseV4>  databaseV4_;  // New in Orthanc 1.12.0
     PluginsErrorDictionary  dictionary_;
     std::string databaseServerIdentifier_;   // New in Orthanc 1.9.2
-    unsigned int maxDatabaseRetries_;   // New in Orthanc 1.9.2
+    unsigned int maxDatabaseRetries_;        // New in Orthanc 1.9.2
+    bool hasStorageAreaCustomData_;          // New in Orthanc 1.12.8
 
     explicit PImpl(const std::string& databaseServerIdentifier) : 
       contextRefCount_(0),
@@ -1772,7 +1773,8 @@
       argc_(1),
       argv_(NULL),
       databaseServerIdentifier_(databaseServerIdentifier),
-      maxDatabaseRetries_(0)
+      maxDatabaseRetries_(0),
+      hasStorageAreaCustomData_(false)
     {
       memset(&moveCallbacks_, 0, sizeof(moveCallbacks_));
     }
@@ -4542,15 +4544,21 @@
 
   void OrthancPlugins::ApplyAdoptDicomInstance(const _OrthancPluginAdoptDicomInstance& parameters)
   {
+    if (!pimpl_->hasStorageAreaCustomData_)
+    {
+      LOG(WARNING) << "The adoption of a DICOM instance should only be used in combination with a custom "
+                   << "storage area registered using OrthancPluginRegisterStorageArea3()";
+    }
+
     std::string md5;
-    Toolbox::ComputeMD5(md5, parameters.buffer, parameters.bufferSize);
-
-    std::unique_ptr<DicomInstanceToStore> dicom(DicomInstanceToStore::CreateFromBuffer(parameters.buffer, parameters.bufferSize));
+    Toolbox::ComputeMD5(md5, parameters.dicom, parameters.dicomSize);
+
+    std::unique_ptr<DicomInstanceToStore> dicom(DicomInstanceToStore::CreateFromBuffer(parameters.dicom, parameters.dicomSize));
     dicom->SetOrigin(DicomInstanceOrigin::FromPlugins());
 
     const std::string attachmentUuid = Toolbox::GenerateUuid();
 
-    FileInfo adoptedFile(attachmentUuid, FileContentType_Dicom, parameters.bufferSize, md5);
+    FileInfo adoptedFile(attachmentUuid, FileContentType_Dicom, parameters.dicomSize, md5);
     adoptedFile.SetCustomData(parameters.customData, parameters.customDataSize);
 
     std::string instanceId;
@@ -5928,6 +5936,7 @@
             const _OrthancPluginRegisterStorageArea3& p = 
               *reinterpret_cast<const _OrthancPluginRegisterStorageArea3*>(parameters);
             pimpl_->storageArea_.reset(new StorageAreaFactory(plugin, p, GetErrorDictionary()));
+            pimpl_->hasStorageAreaCustomData_ = true;
           }
           else
           {
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Fri Jun 13 13:27:42 2025 +0200
+++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h	Fri Jun 13 15:01:35 2025 +0200
@@ -1145,14 +1145,14 @@
 
 
   /**
-   * The store status response to AdoptDicomInstance.
+   * The store status related to the adoption of a DICOM instance.
    **/
   typedef enum
   {
     OrthancPluginStoreStatus_Success = 0,         /*!< The file has been stored/adopted */
     OrthancPluginStoreStatus_AlreadyStored = 1,   /*!< The file has already been stored/adopted (only if OverwriteInstances is set to false)*/
     OrthancPluginStoreStatus_Failure = 2,         /*!< The file could not be stored/adopted */
-    OrthancPluginStoreStatus_FilteredOut = 3,     /*!< The file has been filtered out by a lua script or a plugin */
+    OrthancPluginStoreStatus_FilteredOut = 3,     /*!< The file has been filtered out by a Lua script or a plugin */
     OrthancPluginStoreStatus_StorageFull = 4,     /*!< The storage is full (only if MaximumStorageSize/MaximumPatientCount is set and MaximumStorageMode is Reject)*/
 
     _OrthancPluginStoreStatus_INTERNAL = 0x7fffffff
@@ -9803,25 +9803,57 @@
     OrthancPluginMemoryBuffer*    instanceId;
     OrthancPluginMemoryBuffer*    attachmentUuid;
     OrthancPluginStoreStatus*     storeStatus;
-    const void*                   buffer;
-    uint64_t                      bufferSize;
+    const void*                   dicom;
+    uint64_t                      dicomSize;
     const void*                   customData;
     uint32_t                      customDataSize;
   } _OrthancPluginAdoptDicomInstance;
 
   /**
-   * @brief Request Orthanc to adopt an existing attachment.
-   *
-   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
-TODO_ATTACH_CUSTOM_DATA TODO TODO
+   * @brief Adopt a DICOM instance read from the filesystem.
+   *
+   * This function requests Orthanc to create a DICOM resource at the
+   * "Instance" level in its database, using the content of a DICOM
+   * instance read from the filesystem. The newly created DICOM
+   * resource is associated with an attachment whose content type is
+   * "OrthancPluginContentType_Dicom". The attachment is associated
+   * with the provided custom data.
+   *
+   * This function should only be used in combination with a custom
+   * storage area featuring support for custom data (i.e., installed
+   * using OrthancPluginRegisterStorageArea3()). The custom storage
+   * area is responsible for *not* duplicating the DICOM file into the
+   * storage area of Orthanc, hence the name "Adopt". The support for
+   * custom data is necessary for the custom storage area to
+   * distinguish between adopted and non-adopted DICOM instances.
+   *
+   * Check out the "AdoptDicomInstance" plugin in the source
+   * distribution of Orthanc for a working sample:
+   * https://orthanc.uclouvain.be/hg/orthanc/file/default/OrthancServer/Plugins/Samples/AdoptDicomInstance/
+   *
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param instanceId The target memory buffer that will be filled by
+   * the Orthanc core with the public identifier of the newly created
+   * instance. It must be freed with OrthancPluginFreeMemoryBuffer().
+   * @param attachmentUuid The target memory buffer that will be
+   * filled by the Orthanc core with the UUID of the newly created
+   * attachment corresponding to the adopted DICOM instance. It must
+   * be freed with OrthancPluginFreeMemoryBuffer().
+   * @param storeStatus Variable that will be filled by the Orthanc core
+   * with the status of store operation.
+   * @param dicom Pointer to the DICOM instance read from the filesystem.
+   * @param dicomSize Size of the DICOM instance.
+   * @param customData The custom data to associated with the attachment.
+   * @param customDataSize The size of the custom data.
+   * @return 0 if success, other value if error.
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginAdoptDicomInstance(
     OrthancPluginContext*         context,
     OrthancPluginMemoryBuffer*    instanceId,        /* out */
     OrthancPluginMemoryBuffer*    attachmentUuid,    /* out */
     OrthancPluginStoreStatus*     storeStatus,       /* out */
-    const void*                   buffer,
-    uint64_t                      bufferSize,
+    const void*                   dicom,
+    uint64_t                      dicomSize,
     const void*                   customData,
     uint32_t                      customDataSize)
   {
@@ -9829,8 +9861,8 @@
     params.instanceId = instanceId;
     params.attachmentUuid = attachmentUuid;
     params.storeStatus = storeStatus;
-    params.buffer = buffer;
-    params.bufferSize = bufferSize;
+    params.dicom = dicom;
+    params.dicomSize = dicomSize;
     params.customData = customData;
     params.customDataSize = customDataSize;