Mercurial > hg > orthanc
changeset 4845:02d77189d8ba received-instance-callback
added ReceivedInstanceCallback + sample C++ plugin
author | Alain Mazy <am@osimis.io> |
---|---|
date | Thu, 09 Dec 2021 17:22:40 +0100 |
parents | 55e8fb8e8028 |
children | 4addabcab158 |
files | OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp OrthancFramework/Sources/DicomParsing/ParsedDicomFile.cpp OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h OrthancFramework/UnitTestsSources/DicomMapTests.cpp OrthancServer/Plugins/Engine/OrthancPlugins.cpp OrthancServer/Plugins/Engine/OrthancPlugins.h OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h OrthancServer/Plugins/Samples/Sanitizer/CMakeLists.txt OrthancServer/Plugins/Samples/Sanitizer/Plugin.cpp OrthancServer/Sources/ServerContext.cpp OrthancServer/Sources/ServerEnumerations.h |
diffstat | 11 files changed, 443 insertions(+), 12 deletions(-) [+] |
line wrap: on
line diff
--- a/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp Tue Dec 07 14:01:17 2021 +0100 +++ b/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp Thu Dec 09 17:22:40 2021 +0100 @@ -734,10 +734,15 @@ if (!(flags & DicomToJsonFlags_ConvertBinaryToNull)) { Uint8* data = NULL; + Uint16* data16 = NULL; if (element.getUint8Array(data) == EC_Normal) { return new DicomValue(reinterpret_cast<const char*>(data), element.getLength(), true); } + else if (element.getUint16Array(data16) == EC_Normal) + { + return new DicomValue(reinterpret_cast<const char*>(data16), element.getLength(), true); + } } return new DicomValue; @@ -1851,6 +1856,23 @@ break; } + case EVR_xs: // unsigned short, signed short or multiple values + { + if (decoded->find('\\') != std::string::npos) + { + ok = element.putString(decoded->c_str()).good(); + } + else if (decoded->find('-') != std::string::npos) + { + ok = element.putSint16(boost::lexical_cast<Sint16>(*decoded)).good(); + } + else + { + ok = element.putUint16(boost::lexical_cast<Uint16>(*decoded)).good(); + } + break; + } + case EVR_US: // unsigned short { ok = element.putUint16(boost::lexical_cast<Uint16>(*decoded)).good(); @@ -1902,7 +1924,6 @@ **/ case EVR_ox: // OB or OW depending on context - case EVR_xs: // SS or US depending on context case EVR_lt: // US, SS or OW depending on context, used for LUT Data (thus the name) case EVR_na: // na="not applicable", for data which has no VR case EVR_up: // up="unsigned pointer", used internally for DICOMDIR suppor
--- a/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.cpp Tue Dec 07 14:01:17 2021 +0100 +++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.cpp Thu Dec 09 17:22:40 2021 +0100 @@ -1195,6 +1195,10 @@ EmbedImage(mime, content); break; + case MimeType_Binary: + EmbedImage(mime, content); + break; + case MimeType_Pdf: EmbedPdf(content); break; @@ -1254,6 +1258,12 @@ break; } + case MimeType_Binary: + { + EmbedRawPixelData(content); + break; + } + default: throw OrthancException(ErrorCode_NotImplemented); } @@ -1407,7 +1417,24 @@ } } - + void ParsedDicomFile::EmbedRawPixelData(const std::string& content) + { + DcmTag key(DICOM_TAG_PIXEL_DATA.GetGroup(), + DICOM_TAG_PIXEL_DATA.GetElement()); + + std::unique_ptr<DcmPixelData> pixels(new DcmPixelData(key)); + + Uint8* target = NULL; + pixels->createUint8Array(content.size(), target); + memcpy(target, content.c_str(), content.size()); + + if (!GetDcmtkObject().getDataset()->insert(pixels.release(), false, false).good()) + { + throw OrthancException(ErrorCode_InternalError); + } + } + + Encoding ParsedDicomFile::DetectEncoding(bool& hasCodeExtensions) const { return FromDcmtkBridge::DetectEncoding(hasCodeExtensions,
--- a/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h Tue Dec 07 14:01:17 2021 +0100 +++ b/OrthancFramework/Sources/DicomParsing/ParsedDicomFile.h Thu Dec 09 17:22:40 2021 +0100 @@ -212,6 +212,8 @@ void EmbedImage(MimeType mime, const std::string& content); + void EmbedRawPixelData(const std::string& content); + Encoding DetectEncoding(bool& hasCodeExtensions) const; // WARNING: This function only sets the encoding, it will not
--- a/OrthancFramework/UnitTestsSources/DicomMapTests.cpp Tue Dec 07 14:01:17 2021 +0100 +++ b/OrthancFramework/UnitTestsSources/DicomMapTests.cpp Thu Dec 09 17:22:40 2021 +0100 @@ -756,6 +756,15 @@ ASSERT_FALSE(d > d); } +TEST(ParsedDicomFile, canIncludeXsVrTags) +{ + Json::Value tags; + tags["0028,0034"] = "1\\1"; // PixelAspectRatio + tags["0028,1101"] = "256\\0\\16"; // RedPaletteColorLookupTableDescriptor which is declared as xs VR in dicom.dic + + std::unique_ptr<ParsedDicomFile> dicom(ParsedDicomFile::CreateFromJson(tags, DicomFromJsonFlags_DecodeDataUriScheme, "")); + // simply make sure it does not throw ! +} #if ORTHANC_SANDBOXED != 1
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Tue Dec 07 14:01:17 2021 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.cpp Thu Dec 09 17:22:40 2021 +0100 @@ -1168,6 +1168,7 @@ typedef std::list<OrthancPluginIncomingHttpRequestFilter2> IncomingHttpRequestFilters2; typedef std::list<OrthancPluginIncomingDicomInstanceFilter> IncomingDicomInstanceFilters; typedef std::list<OrthancPluginIncomingCStoreInstanceFilter> IncomingCStoreInstanceFilters; + typedef std::list<OrthancPluginReceivedInstanceCallback> ReceivedInstanceCallbacks; typedef std::list<OrthancPluginDecodeImageCallback> DecodeImageCallbacks; typedef std::list<OrthancPluginTranscoderCallback> TranscoderCallbacks; typedef std::list<OrthancPluginJobsUnserializer> JobsUnserializers; @@ -1191,6 +1192,7 @@ IncomingHttpRequestFilters2 incomingHttpRequestFilters2_; IncomingDicomInstanceFilters incomingDicomInstanceFilters_; IncomingCStoreInstanceFilters incomingCStoreInstanceFilters_; // New in Orthanc 1.9.8 + ReceivedInstanceCallbacks receivedInstanceCallbacks_; // New in Orthanc 1.9.8 RefreshMetricsCallbacks refreshMetricsCallbacks_; StorageCommitmentScpCallbacks storageCommitmentScpCallbacks_; std::unique_ptr<StorageAreaFactory> storageArea_; @@ -2295,6 +2297,70 @@ } + bool OrthancPlugins::ApplyReceivedInstanceCallbacks(const void* receivedDicom, + size_t receivedDicomSize, + void** modifiedDicomBufferData, + size_t& modifiedDicomBufferSize) + { + uint64_t modifiedDicomSize64 = 0; + *modifiedDicomBufferData = NULL; + + boost::recursive_mutex::scoped_lock lock(pimpl_->invokeServiceMutex_); + + for (PImpl::ReceivedInstanceCallbacks::const_iterator + callback = pimpl_->receivedInstanceCallbacks_.begin(); + callback != pimpl_->receivedInstanceCallbacks_.end(); ++callback) + { + OrthancPluginReceivedInstanceCallbackResult callbackResult = (*callback) (receivedDicom, + receivedDicomSize, + modifiedDicomBufferData, + &modifiedDicomSize64); + + if (callbackResult == OrthancPluginReceivedInstanceCallbackResult_Discard) + { + if (modifiedDicomSize64 > 0 || *modifiedDicomBufferData != NULL) + { + free(modifiedDicomBufferData); + throw OrthancException(ErrorCode_Plugin, "The ReceivedInstanceCallback plugin is returning a modified buffer while it has discarded the instance"); + } + return false; + } + else if (callbackResult == OrthancPluginReceivedInstanceCallbackResult_KeepAsIs) + { + if (modifiedDicomSize64 > 0 || *modifiedDicomBufferData != NULL) + { + free(modifiedDicomBufferData); + throw OrthancException(ErrorCode_Plugin, "The ReceivedInstanceCallback plugin is returning a modified buffer while it has not modified the instance"); + } + return true; + } + else if (callbackResult == OrthancPluginReceivedInstanceCallbackResult_Modified) + { + if (modifiedDicomSize64 > 0 && modifiedDicomBufferData != NULL) + { + if (static_cast<size_t>(modifiedDicomSize64) != modifiedDicomSize64) // Orthanc is running in 32bits and has received a > 4GB buffer + { + free(modifiedDicomBufferData); + throw OrthancException(ErrorCode_Plugin, "The Plugin has returned a > 4GB which is too large for Orthanc running in 32bits"); + } + + modifiedDicomBufferSize = static_cast<size_t>(modifiedDicomSize64); + return true; + } + else + { + throw OrthancException(ErrorCode_Plugin, "The ReceivedInstanceCallback plugin is not returning a modified buffer while it has modified the instance"); + } + } + else + { + throw OrthancException(ErrorCode_Plugin, "The ReceivedInstanceCallback has returned an invalid value"); + } + } + + return STATUS_Success; + } + void OrthancPlugins::SignalChangeInternal(OrthancPluginChangeType changeType, OrthancPluginResourceType resourceType, const char* resource) @@ -2521,6 +2587,14 @@ pimpl_->incomingCStoreInstanceFilters_.push_back(p.callback); } + void OrthancPlugins::RegisterReceivedInstanceCallback(const void* parameters) + { + const _OrthancPluginReceivedInstanceCallback& p = + *reinterpret_cast<const _OrthancPluginReceivedInstanceCallback*>(parameters); + + CLOG(INFO, PLUGINS) << "Plugin has registered a received instance callback"; + pimpl_->receivedInstanceCallbacks_.push_back(p.callback); + } void OrthancPlugins::RegisterRefreshMetricsCallback(const void* parameters) { @@ -5004,6 +5078,10 @@ RegisterIncomingCStoreInstanceFilter(parameters); return true; + case _OrthancPluginService_RegisterReceivedInstanceCallback: + RegisterReceivedInstanceCallback(parameters); + return true; + case _OrthancPluginService_RegisterRefreshMetricsCallback: RegisterRefreshMetricsCallback(parameters); return true;
--- a/OrthancServer/Plugins/Engine/OrthancPlugins.h Tue Dec 07 14:01:17 2021 +0100 +++ b/OrthancServer/Plugins/Engine/OrthancPlugins.h Thu Dec 09 17:22:40 2021 +0100 @@ -136,6 +136,8 @@ void RegisterIncomingCStoreInstanceFilter(const void* parameters); + void RegisterReceivedInstanceCallback(const void* parameters); + void RegisterRefreshMetricsCallback(const void* parameters); void RegisterStorageCommitmentScpCallback(const void* parameters); @@ -285,6 +287,11 @@ virtual uint16_t FilterIncomingCStoreInstance(const DicomInstanceToStore& instance, const Json::Value& simplified) ORTHANC_OVERRIDE; + virtual bool ApplyReceivedInstanceCallbacks(const void* receivedDicomBuffer, + size_t receivedDicomBufferSize, + void** modifiedDicomBufferData, + size_t& modifiedDicomBufferSize); + bool HasStorageArea() const; IStorageArea* CreateStorageArea(); // To be freed after use
--- a/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h Tue Dec 07 14:01:17 2021 +0100 +++ b/OrthancServer/Plugins/Include/orthanc/OrthancCPlugin.h Thu Dec 09 17:22:40 2021 +0100 @@ -463,6 +463,7 @@ _OrthancPluginService_RegisterTranscoderCallback = 1015, /* New in Orthanc 1.7.0 */ _OrthancPluginService_RegisterStorageArea2 = 1016, /* New in Orthanc 1.9.0 */ _OrthancPluginService_RegisterIncomingCStoreInstanceFilter = 1017, /* New in Orthanc 1.9.8 */ + _OrthancPluginService_RegisterReceivedInstanceCallback = 1018, /* New in Orthanc 1.9.8 */ /* Sending answers to REST calls */ _OrthancPluginService_AnswerBuffer = 2000, @@ -1001,7 +1002,19 @@ is already in use */ } OrthancPluginStorageCommitmentFailureReason; - + + /** + * The return value of ReceivedInstanceCallback + **/ + typedef enum + { + OrthancPluginReceivedInstanceCallbackResult_KeepAsIs = 1, /*!< Keep the instance as is */ + OrthancPluginReceivedInstanceCallbackResult_Modified = 2, /*!< Modified the instance */ + OrthancPluginReceivedInstanceCallbackResult_Discard = 3, /*!< Tell Orthanc to discard the instance */ + + _OrthancPluginReceivedInstanceCallbackResult_INTERNAL = 0x7fffffff + } OrthancPluginReceivedInstanceCallbackResult; + /** * @brief A 32-bit memory buffer allocated by the core system of Orthanc. @@ -7823,6 +7836,73 @@ } /** + * @brief Callback to possibly modify a DICOM instance received + * by Orthanc through any source (C-Store or Rest API) + * + * Signature of a callback function that is triggered whenever + * Orthanc receives a new DICOM instance (through DICOM protocol or + * Rest API), and that answers a possibly modified version of the + * DICOM that should be stored in Orthanc. + * + * This callback is called immediately after receiption: before + * transcoding and before filtering (FilterIncomingInstance). + * + * @param receivedDicomBuffer A buffer containing the received DICOM (input). + * @param receivedDicomBufferSize The size of the received DICOM (input) + * @param modifiedDicomBuffer A buffer containing the modified DICOM (output). + * This buffer will be freed by the Orthanc Core and must have + * been allocated by malloc in your plugin or by Orthanc core through + * a plugin method. + * @param modifiedDicomBufferSize The size of the modified DICOM (output) + * @return OrthancPluginReceivedInstanceCallbackResult_KeepAsIs to accept the instance as is + * OrthancPluginReceivedInstanceCallbackResult_Modified to store the modified DICOM + * OrthancPluginReceivedInstanceCallbackResult_Discard to tell Orthanc to discard the instance + * @ingroup Callback + **/ + typedef OrthancPluginReceivedInstanceCallbackResult (*OrthancPluginReceivedInstanceCallback) ( + const void* receivedDicomBuffer, + uint64_t receivedDicomBufferSize, + void** modifiedDicomBuffer, + uint64_t* modifiedDicomBufferSize + ); + + + typedef struct + { + OrthancPluginReceivedInstanceCallback callback; + } _OrthancPluginReceivedInstanceCallback; + + /** + * @brief Register a callback to possibly modify a DICOM instance received + * by Orthanc through any source (C-Store or Rest API) + * + * + * @warning Your callback function will be called synchronously with + * the core of Orthanc. This implies that deadlocks might emerge if + * you call other core primitives of Orthanc in your callback (such + * deadlocks are particular visible in the presence of other plugins + * or Lua scripts). It is thus strongly advised to avoid any call to + * the REST API of Orthanc in the callback. If you have to call + * other primitives of Orthanc, you should make these calls in a + * separate thread, passing the pending events to be processed + * through a message queue. + * + * @param context The Orthanc plugin context, as received by OrthancPluginInitialize(). + * @param callback The callback. + * @return 0 if success, other value if error. + * @ingroup Callbacks + **/ + ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterReceivedInstanceCallback( + OrthancPluginContext* context, + OrthancPluginReceivedInstanceCallback callback) + { + _OrthancPluginReceivedInstanceCallback params; + params.callback = callback; + + return context->InvokeService(context, _OrthancPluginService_RegisterReceivedInstanceCallback, ¶ms); + } + + /** * @brief Get the transfer syntax of a DICOM file. * * This function returns a pointer to a newly created string that
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Plugins/Samples/Sanitizer/CMakeLists.txt Thu Dec 09 17:22:40 2021 +0100 @@ -0,0 +1,47 @@ +# Orthanc - A Lightweight, RESTful DICOM Store +# Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics +# Department, University Hospital of Liege, Belgium +# Copyright (C) 2017-2021 Osimis S.A., Belgium +# Copyright (C) 2021-2021 Sebastien Jodogne, ICTEAM UCLouvain, Belgium +# +# This program is free software: you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +cmake_minimum_required(VERSION 2.8) + +project(Sanitizer) + +SET(STATIC_BUILD OFF CACHE BOOL "Static build of the third-party libraries (necessary for Windows)") +SET(ALLOW_DOWNLOADS OFF CACHE BOOL "Allow CMake to download packages") + +SET(USE_SYSTEM_JSONCPP ON CACHE BOOL "Use the system version of JsonCpp") +SET(USE_SYSTEM_BOOST ON CACHE BOOL "Use the system version of boost") + +include(${CMAKE_SOURCE_DIR}/../Common/OrthancPlugins.cmake) +include(${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Resources/CMake/JsonCppConfiguration.cmake) +include(${CMAKE_SOURCE_DIR}/../../../../OrthancFramework/Resources/CMake/BoostConfiguration.cmake) + +add_library(Sanitizer SHARED + ${CMAKE_SOURCE_DIR}/../Common/OrthancPluginCppWrapper.cpp + ${JSONCPP_SOURCES} + ${BOOST_SOURCES} + Plugin.cpp + ) + + +install( + TARGETS Sanitizer + RUNTIME DESTINATION lib # Destination for Windows + LIBRARY DESTINATION share/orthanc/plugins # Destination for Linux + )
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/Plugins/Samples/Sanitizer/Plugin.cpp Thu Dec 09 17:22:40 2021 +0100 @@ -0,0 +1,125 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2021 Osimis S.A., Belgium + * Copyright (C) 2021-2021 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + **/ + + +#include "../../../../OrthancFramework/Sources/Compatibility.h" +#include "../Common/OrthancPluginCppWrapper.h" + +#include <boost/filesystem.hpp> +#include <json/value.h> +#include <string.h> +#include <iostream> + + + + +OrthancPluginReceivedInstanceCallbackResult ReceivedInstanceCallback(const void* receivedDicomBuffer, + uint64_t receivedDicomBufferSize, + void** modifiedDicomBuffer, + uint64_t* modifiedDicomBufferSize) + // OrthancPluginMemoryBuffer* modifiedDicomBuffer) +{ + // note: this sample plugin won't work with multi-frame images or badly formed images + // OrthancPluginCreateDicom and OrthancPluginDicomBufferToJson do not support multi-frame and are quite touchy with invalid tag values + + Json::Value receivedDicomAsJson; + OrthancPlugins::OrthancString str; + str.Assign(OrthancPluginDicomBufferToJson + (OrthancPlugins::GetGlobalContext(), + receivedDicomBuffer, + receivedDicomBufferSize, + OrthancPluginDicomToJsonFormat_Short, + static_cast<OrthancPluginDicomToJsonFlags>(OrthancPluginDicomToJsonFlags_IncludeBinary | OrthancPluginDicomToJsonFlags_IncludePrivateTags | OrthancPluginDicomToJsonFlags_IncludeUnknownTags | OrthancPluginDicomToJsonFlags_SkipGroupLengths | OrthancPluginDicomToJsonFlags_IncludePixelData), + 0)); + + str.ToJson(receivedDicomAsJson); + + if (receivedDicomAsJson["0008,0080"] != "My Institution") + { + receivedDicomAsJson["0008,0080"] = "My Institution"; + + OrthancPluginMemoryBuffer modifiedDicom; + std::string serializedModifiedDicomAsJson; + OrthancPlugins::WriteFastJson(serializedModifiedDicomAsJson, receivedDicomAsJson); + OrthancPluginErrorCode createResult = OrthancPluginCreateDicom(OrthancPlugins::GetGlobalContext(), + &modifiedDicom, + serializedModifiedDicomAsJson.c_str(), + NULL, + OrthancPluginCreateDicomFlags_DecodeDataUriScheme); + + if (createResult == OrthancPluginErrorCode_Success) + { + *modifiedDicomBuffer = modifiedDicom.data; + *modifiedDicomBufferSize = modifiedDicom.size; + + return OrthancPluginReceivedInstanceCallbackResult_Modified; + } + else + { + return OrthancPluginReceivedInstanceCallbackResult_KeepAsIs; + } + } + + return OrthancPluginReceivedInstanceCallbackResult_KeepAsIs; +} + + +extern "C" +{ + ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* c) + { + OrthancPlugins::SetGlobalContext(c); + + /* Check the version of the Orthanc core */ + // if (OrthancPluginCheckVersion(c) == 0) + // { + // OrthancPlugins::ReportMinimalOrthancVersion(ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER, + // ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER, + // ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER); + // return -1; + // } + + OrthancPlugins::LogWarning("Sanitizer plugin is initializing"); + OrthancPluginSetDescription(c, "Sample plugin to sanitize incoming DICOM instances."); + + OrthancPluginRegisterReceivedInstanceCallback(c, ReceivedInstanceCallback); + + return 0; + } + + + ORTHANC_PLUGINS_API void OrthancPluginFinalize() + { + OrthancPlugins::LogWarning("Sanitizer plugin is finalizing"); + } + + + ORTHANC_PLUGINS_API const char* OrthancPluginGetName() + { + return "sanitizer"; + } + + + ORTHANC_PLUGINS_API const char* OrthancPluginGetVersion() + { + return "0.1"; + } +}
--- a/OrthancServer/Sources/ServerContext.cpp Tue Dec 07 14:01:17 2021 +0100 +++ b/OrthancServer/Sources/ServerContext.cpp Thu Dec 09 17:22:40 2021 +0100 @@ -47,6 +47,7 @@ #include "../../OrthancFramework/Sources/HttpServer/HttpStreamTranscoder.h" #include "../../OrthancFramework/Sources/JobsEngine/SetOfInstancesJob.h" #include "../../OrthancFramework/Sources/Logging.h" +#include "../../OrthancFramework/Sources/MallocMemoryBuffer.h" #include "../../OrthancFramework/Sources/MetricsRegistry.h" #include "../Plugins/Engine/OrthancPlugins.h" @@ -694,13 +695,47 @@ ServerContext::StoreResult ServerContext::Store(std::string& resultPublicId, - DicomInstanceToStore& dicom, + DicomInstanceToStore& receivedDicom, StoreInstanceMode mode) - { + { + DicomInstanceToStore* dicom = &receivedDicom; + std::unique_ptr<DicomInstanceToStore> modifiedDicom; + + void* modifiedDicomBuffer = NULL; + size_t modifiedDicomBufferSize = 0; + + std::unique_ptr<MallocMemoryBuffer> raii(new MallocMemoryBuffer); + +#if ORTHANC_ENABLE_PLUGINS == 1 + if (HasPlugins()) + { + + bool store = GetPlugins().ApplyReceivedInstanceCallbacks(receivedDicom.GetBufferData(), + receivedDicom.GetBufferSize(), + &modifiedDicomBuffer, + modifiedDicomBufferSize); + raii->Assign(modifiedDicomBuffer, modifiedDicomBufferSize, ::free); + + if (!store) + { + StoreResult result; + result.SetStatus(StoreStatus_FilteredOut); + return result; + } + + if (modifiedDicomBufferSize > 0 && modifiedDicomBuffer != NULL) + { + modifiedDicom.reset(DicomInstanceToStore::CreateFromBuffer(modifiedDicomBuffer, modifiedDicomBufferSize)); + modifiedDicom->SetOrigin(dicom->GetOrigin()); + dicom = modifiedDicom.get(); + } + } +#endif + if (!isIngestTranscoding_) { // No automated transcoding. This was the only path in Orthanc <= 1.6.1. - return StoreAfterTranscoding(resultPublicId, dicom, mode); + return StoreAfterTranscoding(resultPublicId, *dicom, mode); } else { @@ -709,7 +744,7 @@ bool transcode = false; DicomTransferSyntax sourceSyntax; - if (!dicom.LookupTransferSyntax(sourceSyntax) || + if (!dicom->LookupTransferSyntax(sourceSyntax) || sourceSyntax == ingestTransferSyntax_) { // Don't transcode if the incoming DICOM is already in the proper transfer syntax @@ -736,7 +771,7 @@ if (!transcode) { // No transcoding - return StoreAfterTranscoding(resultPublicId, dicom, mode); + return StoreAfterTranscoding(resultPublicId, *dicom, mode); } else { @@ -745,7 +780,7 @@ syntaxes.insert(ingestTransferSyntax_); IDicomTranscoder::DicomImage source; - source.SetExternalBuffer(dicom.GetBufferData(), dicom.GetBufferSize()); + source.SetExternalBuffer(dicom->GetBufferData(), dicom->GetBufferSize()); IDicomTranscoder::DicomImage transcoded; if (Transcode(transcoded, source, syntaxes, true /* allow new SOP instance UID */)) @@ -753,7 +788,7 @@ std::unique_ptr<ParsedDicomFile> tmp(transcoded.ReleaseAsParsedDicomFile()); std::unique_ptr<DicomInstanceToStore> toStore(DicomInstanceToStore::CreateFromParsedDicomFile(*tmp)); - toStore->SetOrigin(dicom.GetOrigin()); + toStore->SetOrigin(dicom->GetOrigin()); StoreResult result = StoreAfterTranscoding(resultPublicId, *toStore, mode); assert(resultPublicId == tmp->GetHasher().HashInstance()); @@ -763,7 +798,7 @@ else { // Cannot transcode => store the original file - return StoreAfterTranscoding(resultPublicId, dicom, mode); + return StoreAfterTranscoding(resultPublicId, *dicom, mode); } } }
--- a/OrthancServer/Sources/ServerEnumerations.h Tue Dec 07 14:01:17 2021 +0100 +++ b/OrthancServer/Sources/ServerEnumerations.h Thu Dec 09 17:22:40 2021 +0100 @@ -61,7 +61,7 @@ StoreStatus_Success, StoreStatus_AlreadyStored, StoreStatus_Failure, - StoreStatus_FilteredOut // Removed by NewInstanceFilter + StoreStatus_FilteredOut // Removed by NewInstanceFilter or ReceivedInstanceCallback }; enum DicomTagType