Mercurial > hg > orthanc
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, ¶ms); } + 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, ¶ms); + } #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,