[med-svn] [Git][med-team/orthanc-dicomweb][master] 6 commits: New upstream version 1.21+dfsg
Sebastien Jodogne (@jodogne-guest)
gitlab at salsa.debian.org
Tue Aug 19 14:11:30 BST 2025
Sebastien Jodogne pushed to branch master at Debian Med / orthanc-dicomweb
Commits:
609a59e3 by jodogne-guest at 2025-08-19T14:53:15+02:00
New upstream version 1.21+dfsg
- - - - -
0cadb3ed by jodogne-guest at 2025-08-19T14:53:15+02:00
Update upstream source from tag 'upstream/1.21+dfsg'
Update to upstream version '1.21+dfsg'
with Debian dir 146477b0e613b47ffff2edcaa68cc3ad13d1f7b0
- - - - -
569db06e by jodogne-guest at 2025-08-19T14:55:18+02:00
preparing 1.21+dfsg-1
- - - - -
5afb407d by jodogne-guest at 2025-08-19T14:58:57+02:00
fix the path to EmbedResources.py
- - - - -
fd78fd35 by jodogne-guest at 2025-08-19T15:01:12+02:00
fix the minimum version of orthanc
- - - - -
d6042b26 by jodogne-guest at 2025-08-19T15:10:38+02:00
Upload to unstable
- - - - -
18 changed files:
- .hg_archival.txt
- CMakeLists.txt
- NEWS
- Plugin/Configuration.cpp
- Plugin/Configuration.h
- Plugin/DicomWebClient.cpp
- Plugin/Plugin.cpp
- Plugin/WadoRs.cpp
- Plugin/WadoRsRetrieveRendered.cpp
- Resources/Orthanc/CMake/DownloadOrthancFramework.cmake
- Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp
- Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h
- TODO
- debian/changelog
- debian/control
- debian/patches/cmake
- + debian/patches/embed-resources
- debian/patches/series
Changes:
=====================================
.hg_archival.txt
=====================================
@@ -1,6 +1,6 @@
repo: d5f45924411123cfd02d035fd50b8e37536eadef
-node: 10c61ebe30b04c5716c8d333d925c2f1bc5157ac
-branch: OrthancDicomWeb-1.20
+node: 00cae2648bcb72d3ff12e6244ca63a2bc467b935
+branch: OrthancDicomWeb-1.21
latesttag: null
-latesttagdistance: 625
-changessincelatesttag: 674
+latesttagdistance: 635
+changessincelatesttag: 685
=====================================
CMakeLists.txt
=====================================
@@ -23,7 +23,7 @@ cmake_minimum_required(VERSION 2.8)
project(OrthancDicomWeb)
-set(ORTHANC_DICOM_WEB_VERSION "1.20")
+set(ORTHANC_DICOM_WEB_VERSION "1.21")
if (ORTHANC_DICOM_WEB_VERSION STREQUAL "mainline")
set(ORTHANC_FRAMEWORK_DEFAULT_VERSION "mainline")
=====================================
NEWS
=====================================
@@ -1,3 +1,17 @@
+Version 1.21 (2025-08-14)
+=========================
+
+* New configuration "WadoRsLoaderThreadsCount" to configure how many threads are loading
+ files from the storage when answering to a WADO-RS query. A value > 1 is meaningful
+ only if the storage is a distributed network storage (e.g object storage plugin).
+ A value of 0 means reading and writing are performed in sequence (default behaviour).
+* New configuration "EnablePerformanceLogs" to display performance logs. Currently
+ only showing the time required to execute a WADO-RS query. For example:
+ WADO-RS: elapsed: 26106623 us, rate: 14.86 instances/s, 155.23Mbps
+* Fix false errors logs generated e.g when OHIF requests the /dicom-web/studies/../metadata route:
+ "dicom-web:/Configuration.cpp:643] Unsupported return MIME type: application/dicom+json, multipart/related; type=application/octet-stream; transfer-syntax=*, will return DICOM+JSON"
+
+
Version 1.20 (2025-05-12)
=========================
=====================================
Plugin/Configuration.cpp
=====================================
@@ -626,21 +626,21 @@ namespace OrthancPlugins
std::string accept;
Orthanc::Toolbox::ToLowerCase(accept, acceptHeader);
- if (accept == "application/dicom+json" ||
- accept == "application/json" ||
- accept == "*/*")
+ if (accept.find("application/dicom+json") != std::string::npos ||
+ accept.find("application/json") != std::string::npos ||
+ accept.find("*/*") != std::string::npos)
{
return false;
}
- else if (accept == "application/dicom+xml" ||
- accept == "application/xml" ||
- accept == "text/xml")
+ else if (accept.find("application/dicom+xml") != std::string::npos ||
+ accept.find("application/xml") != std::string::npos ||
+ accept.find("text/xml") != std::string::npos)
{
return true;
}
else
{
- LOG(ERROR) << "Unsupported return MIME type: " << accept <<
+ LOG(WARNING) << "Unsupported return MIME type: " << accept <<
", will return DICOM+JSON";
return false;
}
@@ -691,6 +691,16 @@ namespace OrthancPlugins
return globalConfiguration_->GetBooleanValue("ReadOnly", false);
}
+ unsigned int GetWadoRsLoaderThreadsCount()
+ {
+ return GetUnsignedIntegerValue("WadoRsLoaderThreadsCount", 0);
+ }
+
+ bool IsPerformanceLogsEnabled()
+ {
+ return GetBooleanValue("EnablePerformanceLogs", false);
+ }
+
MetadataMode GetMetadataMode(Orthanc::ResourceType level)
{
static const std::string FULL = "Full";
=====================================
Plugin/Configuration.h
=====================================
@@ -141,8 +141,12 @@ namespace OrthancPlugins
unsigned int GetMetadataWorkerThreadsCount();
+ unsigned int GetWadoRsLoaderThreadsCount();
+
bool IsMetadataCacheEnabled();
bool IsReadOnly();
+
+ bool IsPerformanceLogsEnabled();
}
}
=====================================
Plugin/DicomWebClient.cpp
=====================================
@@ -386,21 +386,6 @@ static void SubmitJob(OrthancPluginRestOutput* output,
}
-static void AddInstance(std::list<std::string>& target,
- const Json::Value& instance)
-{
- std::string id;
- if (OrthancPlugins::LookupStringValue(id, instance, "ID"))
- {
- target.push_back(id);
- }
- else
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
- }
-}
-
-
static bool GetSequenceSize(size_t& result,
const Json::Value& answer,
const std::string& tag,
@@ -556,7 +541,6 @@ static void ParseStowRequest(std::list<std::string>& instances /* out */,
Json::Value tmpInstances;
if (OrthancPlugins::RestApiGet(tmpResource, "/instances/" + resource, false))
{
- // AddInstance(instances, tmpResource);
instances.push_back(resource);
AddResourceForJobContent(resourcesForJobContent, Orthanc::ResourceType_Instance, resource);
}
@@ -577,7 +561,6 @@ static void ParseStowRequest(std::list<std::string>& instances /* out */,
for (Json::Value::ArrayIndex j = 0; j < tmpInstances.size(); j++)
{
- // AddInstance(instances, tmpInstances[j]);
instances.push_back(tmpInstances[j].asString());
AddResourceForJobContent(resourcesForJobContent, Orthanc::ResourceType_Instance, tmpInstances[j].asString());
}
=====================================
Plugin/Plugin.cpp
=====================================
@@ -746,6 +746,8 @@ extern "C"
std::string publicUrlRoot = OrthancPlugins::Configuration::GetPublicRoot();
LOG(WARNING) << "DICOMweb public root: " << publicUrlRoot;
+
+ LOG(WARNING) << "The DICOMWeb plugin will use " << (OrthancPlugins::Configuration::GetWadoRsLoaderThreadsCount() == 0 ? 1 : OrthancPlugins::Configuration::GetWadoRsLoaderThreadsCount()) << " threads to load DICOM files for WADO-RS queries";
}
else
{
=====================================
Plugin/WadoRs.cpp
=====================================
@@ -32,6 +32,7 @@
#include <Toolbox.h>
#include <SerializationToolbox.h>
#include <MultiThreading/SharedMessageQueue.h>
+#include <MultiThreading/Semaphore.h>
#include <Compression/GzipCompressor.h>
#include <memory>
@@ -359,6 +360,234 @@ static void AcceptBulkData(const OrthancPluginHttpRequest* request)
}
}
+class InstanceToPreload : public Orthanc::IDynamicObject
+{
+private:
+ std::string instanceId_;
+ bool transcode_;
+
+public:
+ explicit InstanceToPreload(const std::string& instanceId, bool transcode) :
+ instanceId_(instanceId),
+ transcode_(transcode)
+ {
+ }
+
+ virtual ~InstanceToPreload() ORTHANC_OVERRIDE
+ {
+ }
+
+ const std::string& GetInstanceId() const {return instanceId_;}
+
+ bool NeedsTranscoding() const {return transcode_;}
+};
+
+
+class LoadedInstance : public Orthanc::IDynamicObject
+{
+private:
+ std::unique_ptr<OrthancPlugins::DicomInstance> dicom_;
+
+public:
+ explicit LoadedInstance(OrthancPlugins::DicomInstance* dicom) :
+ dicom_(dicom)
+ {
+ }
+
+ virtual ~LoadedInstance() ORTHANC_OVERRIDE
+ {
+ }
+
+ OrthancPlugins::DicomInstance* ReleaseInstance()
+ {
+ return dicom_.release();
+ }
+};
+
+
+class InstanceLoader : public boost::noncopyable
+{
+protected:
+ bool transcode_;
+ Orthanc::DicomTransferSyntax targetTransferSyntax_;
+
+ OrthancPlugins::DicomInstance* GetAndTranscodeDicom(InstanceToPreload* instanceToLoad)
+ {
+ std::unique_ptr<OrthancPlugins::DicomInstance> dicom(OrthancPlugins::DicomInstance::Load(instanceToLoad->GetInstanceId(),
+ OrthancPluginLoadDicomInstanceMode_WholeDicom));
+ if (transcode_ && instanceToLoad->NeedsTranscoding())
+ {
+ dicom.reset(dicom->Transcode(dicom->GetBuffer(),
+ dicom->GetSize(),
+ Orthanc::GetTransferSyntaxUid(targetTransferSyntax_)));
+ }
+
+ return dicom.release();
+ }
+
+public:
+ explicit InstanceLoader(bool transcode, Orthanc::DicomTransferSyntax targetTransferSyntax)
+ : transcode_(transcode),
+ targetTransferSyntax_(targetTransferSyntax)
+ {
+ }
+
+ virtual ~InstanceLoader()
+ {
+ }
+
+ virtual void PrepareDicom(const std::string& instanceId, bool transcode) = 0;
+
+ virtual OrthancPlugins::DicomInstance* GetNextDicom() = 0;
+
+};
+
+
+class ThreadedInstanceLoader : public InstanceLoader
+{
+ std::vector<boost::thread*> threads_;
+
+ Orthanc::SharedMessageQueue instancesToPreload_;
+
+ Orthanc::SharedMessageQueue loadedInstances_;
+
+ Orthanc::Semaphore bufferSemaphore_;
+
+public:
+ ThreadedInstanceLoader(size_t threadCount, bool transcode, Orthanc::DicomTransferSyntax transferSyntax)
+ : InstanceLoader(transcode, transferSyntax),
+ instancesToPreload_(0),
+ loadedInstances_(0),
+ bufferSemaphore_(3*threadCount) // to limit the number of loaded instances in memory
+ {
+ for (size_t i = 0; i < threadCount; i++)
+ {
+ threads_.push_back(new boost::thread(PreloaderWorkerThread, this));
+ }
+ }
+
+ virtual ~ThreadedInstanceLoader()
+ {
+ Clear();
+ }
+
+ void Clear()
+ {
+ for (size_t i = 0; i < threads_.size(); i++)
+ {
+ instancesToPreload_.Enqueue(NULL);
+ }
+
+ for (size_t i = 0; i < threads_.size(); i++)
+ {
+ if (threads_[i]->joinable())
+ {
+ threads_[i]->join();
+ }
+ delete threads_[i];
+ }
+
+ threads_.clear();
+ }
+
+ static void PreloaderWorkerThread(ThreadedInstanceLoader* that)
+ {
+ static uint16_t threadCounter = 0;
+ Orthanc::Logging::SetCurrentThreadName(std::string("WADO-LOAD-") + boost::lexical_cast<std::string>(threadCounter++));
+
+ while (true)
+ {
+ std::unique_ptr<InstanceToPreload> instanceToPreload(dynamic_cast<InstanceToPreload*>(that->instancesToPreload_.Dequeue(0)));
+ if (instanceToPreload.get() == NULL) // that's the signal to exit the thread
+ {
+ return;
+ }
+
+ // wait for the consumers, no need to accumulate instances in memory if loaders are faster than writers
+ that->bufferSemaphore_.Acquire();
+
+ try
+ {
+ std::unique_ptr<OrthancPlugins::DicomInstance> dicom(that->GetAndTranscodeDicom(instanceToPreload.get()));
+ that->loadedInstances_.Enqueue(new LoadedInstance(dicom.release()));
+ }
+ catch (Orthanc::OrthancException& e)
+ {
+ LOG(ERROR) << "Error while loading instances " << e.GetDetails();
+ that->loadedInstances_.Enqueue(NULL);
+ }
+ catch (...)
+ {
+ LOG(ERROR) << "Unknown error while loading instances ";
+ that->loadedInstances_.Enqueue(NULL);
+ }
+
+ }
+ }
+
+ virtual void PrepareDicom(const std::string& instanceId, bool transcode) ORTHANC_OVERRIDE
+ {
+ instancesToPreload_.Enqueue(new InstanceToPreload(instanceId, transcode));
+ }
+
+ virtual OrthancPlugins::DicomInstance* GetNextDicom() ORTHANC_OVERRIDE
+ {
+ std::unique_ptr<LoadedInstance> loadedInstance(dynamic_cast<LoadedInstance*>(loadedInstances_.Dequeue(0)));
+
+ // unlock preloader threads to buffer the following instances
+ bufferSemaphore_.Release();
+
+ if (loadedInstance.get() != NULL)
+ {
+ return loadedInstance->ReleaseInstance();
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+};
+
+
+class SynchronousInstanceLoader : public InstanceLoader
+{
+ std::list<boost::shared_ptr<InstanceToPreload> > instancesToLoad_;
+
+public:
+ SynchronousInstanceLoader(bool transcode, Orthanc::DicomTransferSyntax transferSyntax)
+ : InstanceLoader(transcode, transferSyntax)
+ {
+ }
+
+ virtual ~SynchronousInstanceLoader()
+ {
+ Clear();
+ }
+
+ void Clear()
+ {
+ instancesToLoad_.clear();
+ }
+
+ virtual void PrepareDicom(const std::string& instanceId, bool transcode) ORTHANC_OVERRIDE
+ {
+ instancesToLoad_.push_back(boost::shared_ptr<InstanceToPreload>(new InstanceToPreload(instanceId, transcode)));
+ }
+
+ virtual OrthancPlugins::DicomInstance* GetNextDicom() ORTHANC_OVERRIDE
+ {
+ boost::shared_ptr<InstanceToPreload> instanceToLoad(instancesToLoad_.front());
+ instancesToLoad_.pop_front();
+
+ if (instanceToLoad.get() == NULL)
+ {
+ return NULL;
+ }
+
+ return GetAndTranscodeDicom(instanceToLoad.get());
+ }
+};
+
static void AnswerListOfDicomInstances(OrthancPluginRestOutput* output,
Orthanc::ResourceType level,
@@ -366,6 +595,10 @@ static void AnswerListOfDicomInstances(OrthancPluginRestOutput* output,
bool transcode,
Orthanc::DicomTransferSyntax targetSyntax /* only if transcoding */)
{
+ Orthanc::Toolbox::ElapsedTimer perfTimer;
+ size_t perfTotalSizeInBytes = 0;
+ size_t perfTotalInstancesCount = 0;
+
if (level != Orthanc::ResourceType_Study &&
level != Orthanc::ResourceType_Series &&
level != Orthanc::ResourceType_Instance)
@@ -381,17 +614,76 @@ static void AnswerListOfDicomInstances(OrthancPluginRestOutput* output,
{
Json::Value tmp = Json::objectValue;
tmp["ID"] = publicId;
-
+
+ if (transcode)
+ {
+ std::string sourceTransferSyntax;
+ if (OrthancPlugins::RestApiGetString(sourceTransferSyntax, "/instances/" + publicId + "/metadata/TransferSyntax", false))
+ {
+ tmp["Metadata"] = Json::objectValue;
+ tmp["Metadata"]["TransferSyntax"] = sourceTransferSyntax;
+ }
+ }
+
instances = Json::arrayValue;
instances.append(tmp);
}
else
{
- if (!OrthancPlugins::RestApiGet(instances, GetResourceUri(level, publicId) + "/instances", false))
+ if (CanUseExtendedFind())
{
- // Internal error
- OrthancPluginSendHttpStatusCode(context, output, 400);
- return;
+ Json::Value toolsFindPayload;
+
+ toolsFindPayload["Query"] = Json::objectValue;
+ toolsFindPayload["ResponseContent"] = Json::arrayValue;
+ toolsFindPayload["Level"] = "Instance";
+
+ if (transcode)
+ {
+ toolsFindPayload["ResponseContent"].append("Metadata");
+ }
+
+ if (level == Orthanc::ResourceType_Patient)
+ {
+ toolsFindPayload["ParentPatient"] = publicId;
+ }
+ else if (level == Orthanc::ResourceType_Study)
+ {
+ toolsFindPayload["ParentStudy"] = publicId;
+ }
+ else if (level == Orthanc::ResourceType_Series)
+ {
+ toolsFindPayload["ParentSeries"] = publicId;
+ }
+
+ if (!OrthancPlugins::RestApiPost(instances, "/tools/find", toolsFindPayload, false))
+ {
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource, "Unable to list instances");
+ }
+ }
+ else
+ {
+ if (!OrthancPlugins::RestApiGet(instances, GetResourceUri(level, publicId) + "/instances", false))
+ {
+ // Internal error
+ OrthancPluginSendHttpStatusCode(context, output, 400);
+ return;
+ }
+
+ if (transcode)
+ {
+ for (Json::Value::ArrayIndex i = 0; i < instances.size(); i++)
+ {
+ const std::string uri = "/instances/" + instances[i]["ID"].asString();
+
+ std::string sourceTransferSyntax;
+ if (OrthancPlugins::RestApiGetString(sourceTransferSyntax, uri + "/metadata/TransferSyntax", false))
+ {
+ instances[i]["Metadata"] = Json::objectValue;
+ instances[i]["Metadata"]["TransferSyntax"] = sourceTransferSyntax;
+ }
+ }
+ }
}
}
@@ -400,60 +692,68 @@ static void AnswerListOfDicomInstances(OrthancPluginRestOutput* output,
throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
}
+ // single threaded or multi threaded loading ?
+ std::unique_ptr<InstanceLoader> loader;
+
+ const unsigned int workersCount = OrthancPlugins::Configuration::GetWadoRsLoaderThreadsCount();
+
+ if (workersCount > 0 && level != Orthanc::ResourceType_Instance)
+ {
+ loader.reset(new ThreadedInstanceLoader(workersCount, transcode, targetSyntax));
+ }
+ else
+ {
+ loader.reset(new SynchronousInstanceLoader(transcode, targetSyntax));
+ }
+
for (Json::Value::ArrayIndex i = 0; i < instances.size(); i++)
{
- const std::string uri = "/instances/" + instances[i]["ID"].asString();
-
bool transcodeThisInstance;
-
- std::string sourceTransferSyntax;
- if (!transcode)
+ Orthanc::DicomTransferSyntax currentSyntax;
+
+ if (!transcode || !instances[i].isMember("Metadata") || !instances[i]["Metadata"].isMember("TransferSyntax"))
{
transcodeThisInstance = false;
}
- else if (OrthancPlugins::RestApiGetString(sourceTransferSyntax, uri + "/metadata/TransferSyntax", false))
+ else if (Orthanc::LookupTransferSyntax(currentSyntax, instances[i]["Metadata"]["TransferSyntax"].asString()))
{
- // Avoid transcoding if the source file already uses the expected transfer syntax
- Orthanc::DicomTransferSyntax syntax;
- if (Orthanc::LookupTransferSyntax(syntax, sourceTransferSyntax))
- {
- transcodeThisInstance = (syntax != targetSyntax);
- }
- else
- {
- transcodeThisInstance = true;
- }
+ transcodeThisInstance = (currentSyntax != targetSyntax);
}
else
{
- // The transfer syntax of the source file is unknown, transcode it to be sure
transcodeThisInstance = true;
}
-
- OrthancPlugins::MemoryBuffer dicom;
- if (dicom.RestApiGet(uri + "/file", false))
- {
- if (transcodeThisInstance)
- {
- std::unique_ptr<OrthancPlugins::DicomInstance> transcoded(
- OrthancPlugins::DicomInstance::Transcode(
- dicom.GetData(), dicom.GetSize(), Orthanc::GetTransferSyntaxUid(targetSyntax)));
- if (OrthancPluginSendMultipartItem(
- context, output, reinterpret_cast<const char*>(transcoded->GetBuffer()),
- transcoded->GetSize()) != 0)
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
- }
- }
- else
+ loader->PrepareDicom(instances[i]["ID"].asString(), transcodeThisInstance);
+ }
+
+ perfTotalInstancesCount = instances.size();
+
+ for (Json::Value::ArrayIndex i = 0; i < instances.size(); i++)
+ {
+ std::unique_ptr<OrthancPlugins::DicomInstance> dicom(loader->GetNextDicom());
+
+ if (dicom.get() != NULL)
+ {
+ if (OrthancPluginSendMultipartItem(
+ context, output, reinterpret_cast<const char*>(dicom->GetBuffer()),
+ dicom->GetSize()) != 0)
{
- if (OrthancPluginSendMultipartItem(context, output, dicom.GetData(), dicom.GetSize()) != 0)
- {
- throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
- }
+ throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
}
+ perfTotalSizeInBytes += dicom->GetSize();
}
+ else
+ {
+ LOG(WARNING) << "Failed to load an instance";
+ }
+ }
+
+ if (OrthancPlugins::Configuration::IsPerformanceLogsEnabled())
+ {
+ uint64_t elapsedMicrosends = perfTimer.GetElapsedMicroseconds();
+ float instancesPerSeconds = float(perfTotalInstancesCount) / (float(elapsedMicrosends) / 1000000.0f);
+ LOG(INFO) << "WADO-RS: elapsed: " << perfTimer.GetElapsedMicroseconds() << " us, rate: " << std::fixed << std::setprecision(2) << instancesPerSeconds << " instances/s, " << Orthanc::Toolbox::GetHumanTransferSpeed(false, perfTotalSizeInBytes, elapsedMicrosends * 1000);
}
}
=====================================
Plugin/WadoRsRetrieveRendered.cpp
=====================================
@@ -849,7 +849,7 @@ static void AnswerFrameRendered(OrthancPluginRestOutput* output,
apiClient.SetPath(std::string("/instances/") + instanceId + "/frames/0/raw");
if (apiClient.Execute())
{
- apiClient.Forward(OrthancPlugins::GetGlobalContext(), output);
+ apiClient.ExecuteAndForwardAnswer(OrthancPlugins::GetGlobalContext(), output);
return;
}
}
=====================================
Resources/Orthanc/CMake/DownloadOrthancFramework.cmake
=====================================
@@ -171,6 +171,10 @@ if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "hg" OR
set(ORTHANC_FRAMEWORK_MD5 "0e971f32f4f3e4951e0f3b5de49a3da6")
elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.7")
set(ORTHANC_FRAMEWORK_MD5 "f27c27d7a7a694dab1fd7f0a99d9715a")
+ elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.8")
+ set(ORTHANC_FRAMEWORK_MD5 "eb1c719234338e8277b80d3453563e9f")
+ elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.9")
+ set(ORTHANC_FRAMEWORK_MD5 "66b5a2ee60706c4a502896083b9e1a01")
# Below this point are development snapshots that were used to
# release some plugin, before an official release of the Orthanc
@@ -515,7 +519,6 @@ if (ORTHANC_FRAMEWORK_SOURCE STREQUAL "system")
include(${CMAKE_CURRENT_LIST_DIR}/Compiler.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/DownloadPackage.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/AutoGeneratedCode.cmake)
- set(EMBED_RESOURCES_PYTHON ${CMAKE_CURRENT_LIST_DIR}/EmbedResources.py)
if (ORTHANC_FRAMEWORK_USE_SHARED)
list(GET CMAKE_FIND_LIBRARY_PREFIXES 0 Prefix)
=====================================
Resources/Orthanc/Plugins/OrthancPluginCppWrapper.cpp
=====================================
@@ -220,37 +220,60 @@ namespace OrthancPlugins
}
+ void MemoryBuffer::Clear()
+ {
+ if (buffer_.data != NULL)
+ {
+ OrthancPluginFreeMemoryBuffer(GetGlobalContext(), &buffer_);
+ buffer_.data = NULL;
+ buffer_.size = 0;
+ }
+ }
+
+
#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
- MemoryBuffer::MemoryBuffer(const void* buffer,
- size_t size)
+ void MemoryBuffer::Assign(const void* buffer,
+ size_t size)
{
uint32_t s = static_cast<uint32_t>(size);
if (static_cast<size_t>(s) != size)
{
ORTHANC_PLUGINS_THROW_EXCEPTION(NotEnoughMemory);
}
- else if (OrthancPluginCreateMemoryBuffer(GetGlobalContext(), &buffer_, s) !=
- OrthancPluginErrorCode_Success)
+
+ Clear();
+
+ if (OrthancPluginCreateMemoryBuffer(GetGlobalContext(), &buffer_, s) !=
+ OrthancPluginErrorCode_Success)
{
ORTHANC_PLUGINS_THROW_EXCEPTION(NotEnoughMemory);
}
else
{
- memcpy(buffer_.data, buffer, size);
+ if (size > 0)
+ {
+ memcpy(buffer_.data, buffer, size);
+ }
}
}
#endif
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
+ void MemoryBuffer::Assign(const std::string& s)
+ {
+ Assign(s.empty() ? NULL : s.c_str(), s.size());
+ }
+#endif
+
- void MemoryBuffer::Clear()
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
+ void MemoryBuffer::AssignJson(const Json::Value& value)
{
- if (buffer_.data != NULL)
- {
- OrthancPluginFreeMemoryBuffer(GetGlobalContext(), &buffer_);
- buffer_.data = NULL;
- buffer_.size = 0;
- }
+ std::string s;
+ WriteFastJson(s, value);
+ Assign(s);
}
+#endif
void MemoryBuffer::Assign(OrthancPluginMemoryBuffer& other)
@@ -673,7 +696,7 @@ namespace OrthancPlugins
{
OrthancString str;
str.Assign(OrthancPluginDicomBufferToJson
- (GetGlobalContext(), GetData(), GetSize(), format, flags, maxStringLength));
+ (GetGlobalContext(), reinterpret_cast<const char*>(GetData()), GetSize(), format, flags, maxStringLength));
str.ToJson(target);
}
@@ -1566,7 +1589,7 @@ namespace OrthancPlugins
{
if (!answer.IsEmpty())
{
- result.assign(answer.GetData(), answer.GetSize());
+ result.assign(reinterpret_cast<const char*>(answer.GetData()), answer.GetSize());
}
return true;
}
@@ -2052,6 +2075,26 @@ namespace OrthancPlugins
DoPost(target, index, uri, body, headers));
}
+ bool OrthancPeers::DoPost(Json::Value& target,
+ size_t index,
+ const std::string& uri,
+ const std::string& body,
+ const HttpHeaders& headers,
+ unsigned int timeout) const
+ {
+ MemoryBuffer buffer;
+
+ if (DoPost(buffer, index, uri, body, headers, timeout))
+ {
+ buffer.ToJson(target);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
bool OrthancPeers::DoPost(Json::Value& target,
size_t index,
@@ -2098,6 +2141,17 @@ namespace OrthancPlugins
const std::string& uri,
const std::string& body,
const HttpHeaders& headers) const
+ {
+ return DoPost(target, index, uri, body, headers, timeout_);
+ }
+
+
+ bool OrthancPeers::DoPost(MemoryBuffer& target,
+ size_t index,
+ const std::string& uri,
+ const std::string& body,
+ const HttpHeaders& headers,
+ unsigned int timeout) const
{
if (index >= index_.size())
{
@@ -2117,7 +2171,7 @@ namespace OrthancPlugins
OrthancPluginErrorCode code = OrthancPluginCallPeerApi
(GetGlobalContext(), *answer, NULL, &status, peers_,
static_cast<uint32_t>(index), OrthancPluginHttpMethod_Post, uri.c_str(),
- pluginHeaders.GetSize(), pluginHeaders.GetKeys(), pluginHeaders.GetValues(), body.empty() ? NULL : body.c_str(), body.size(), timeout_);
+ pluginHeaders.GetSize(), pluginHeaders.GetKeys(), pluginHeaders.GetValues(), body.empty() ? NULL : body.c_str(), body.size(), timeout);
if (code == OrthancPluginErrorCode_Success)
{
@@ -4068,6 +4122,16 @@ namespace OrthancPlugins
}
#endif
+ void GetGetArguments(GetArguments& result, const OrthancPluginHttpRequest* request)
+ {
+ result.clear();
+
+ for (uint32_t i = 0; i < request->getCount; ++i)
+ {
+ result[request->getKeys[i]] = request->getValues[i];
+ }
+ }
+
void GetHttpHeaders(HttpHeaders& result, const OrthancPluginHttpRequest* request)
{
result.clear();
@@ -4168,6 +4232,11 @@ namespace OrthancPlugins
{
path_ += "?" + getArguments;
}
+
+ if (request->bodySize > 0 && request->body != NULL)
+ {
+ requestBody_.assign(reinterpret_cast<const char*>(request->body), request->bodySize);
+ }
}
#endif
@@ -4188,6 +4257,15 @@ namespace OrthancPlugins
#endif
+#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
+ void RestApiClient::SetRequestHeader(const std::string& key,
+ const std::string& value)
+ {
+ requestHeaders_[key] = value;
+ }
+#endif
+
+
#if HAS_ORTHANC_PLUGIN_GENERIC_CALL_REST_API == 1
bool RestApiClient::Execute()
{
@@ -4235,9 +4313,17 @@ namespace OrthancPlugins
}
}
- void RestApiClient::Forward(OrthancPluginContext* context, OrthancPluginRestOutput* output)
+ void RestApiClient::ExecuteAndForwardAnswer(OrthancPluginContext* context, OrthancPluginRestOutput* output)
+ {
+ if (Execute())
+ {
+ ForwardAnswer(context, output);
+ }
+ }
+
+ void RestApiClient::ForwardAnswer(OrthancPluginContext* context, OrthancPluginRestOutput* output)
{
- if (Execute() && httpStatus_ == 200)
+ if (httpStatus_ == 200)
{
const char* mimeType = NULL;
for (HttpHeaders::const_iterator h = answerHeaders_.begin(); h != answerHeaders_.end(); ++h)
@@ -4316,4 +4402,209 @@ namespace OrthancPlugins
}
}
#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+ KeyValueStore::Iterator::Iterator(OrthancPluginKeysValuesIterator *iterator) :
+ iterator_(iterator)
+ {
+ if (iterator_ == NULL)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
+ }
+ }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+ KeyValueStore::Iterator::~Iterator()
+ {
+ OrthancPluginFreeKeysValuesIterator(OrthancPlugins::GetGlobalContext(), iterator_);
+ }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+ bool KeyValueStore::Iterator::Next()
+ {
+ uint8_t done;
+ OrthancPluginErrorCode code = OrthancPluginKeysValuesIteratorNext(OrthancPlugins::GetGlobalContext(), &done, iterator_);
+
+ if (code != OrthancPluginErrorCode_Success)
+ {
+ ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+ }
+ else
+ {
+ return (done != 0);
+ }
+ }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+ std::string KeyValueStore::Iterator::GetKey() const
+ {
+ const char* s = OrthancPluginKeysValuesIteratorGetKey(OrthancPlugins::GetGlobalContext(), iterator_);
+ if (s == NULL)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(InternalError);
+ }
+ else
+ {
+ return s;
+ }
+ }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+ void KeyValueStore::Iterator::GetValue(std::string& value) const
+ {
+ OrthancPlugins::MemoryBuffer valueBuffer;
+ OrthancPluginErrorCode code = OrthancPluginKeysValuesIteratorGetValue(OrthancPlugins::GetGlobalContext(), *valueBuffer, iterator_);
+
+ if (code != OrthancPluginErrorCode_Success)
+ {
+ ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+ }
+ else
+ {
+ valueBuffer.ToString(value);
+ }
+ }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+ void KeyValueStore::Store(const std::string& key,
+ const void* value,
+ size_t valueSize)
+ {
+ if (static_cast<size_t>(static_cast<uint32_t>(valueSize)) != valueSize)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(NotEnoughMemory);
+ }
+
+ OrthancPluginErrorCode code = OrthancPluginStoreKeyValue(OrthancPlugins::GetGlobalContext(), storeId_.c_str(),
+ key.c_str(), value, static_cast<uint32_t>(valueSize));
+ if (code != OrthancPluginErrorCode_Success)
+ {
+ ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+ }
+ }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+ bool KeyValueStore::GetValue(std::string& value,
+ const std::string& key)
+ {
+ uint8_t found = false;
+ OrthancPlugins::MemoryBuffer valueBuffer;
+ OrthancPluginErrorCode code = OrthancPluginGetKeyValue(OrthancPlugins::GetGlobalContext(), &found,
+ *valueBuffer, storeId_.c_str(), key.c_str());
+
+ if (code != OrthancPluginErrorCode_Success)
+ {
+ ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+ }
+ else if (found)
+ {
+ valueBuffer.ToString(value);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+ void KeyValueStore::DeleteKey(const std::string& key)
+ {
+ OrthancPluginErrorCode code = OrthancPluginDeleteKeyValue(OrthancPlugins::GetGlobalContext(),
+ storeId_.c_str(), key.c_str());
+
+ if (code != OrthancPluginErrorCode_Success)
+ {
+ ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+ }
+ }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+ KeyValueStore::Iterator* KeyValueStore::CreateIterator()
+ {
+ return new Iterator(OrthancPluginCreateKeysValuesIterator(OrthancPlugins::GetGlobalContext(), storeId_.c_str()));
+ }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_QUEUES == 1
+ void Queue::Enqueue(const void* value,
+ size_t valueSize)
+ {
+ if (static_cast<size_t>(static_cast<uint32_t>(valueSize)) != valueSize)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(NotEnoughMemory);
+ }
+
+ OrthancPluginErrorCode code = OrthancPluginEnqueueValue(OrthancPlugins::GetGlobalContext(),
+ queueId_.c_str(), value, static_cast<uint32_t>(valueSize));
+
+ if (code != OrthancPluginErrorCode_Success)
+ {
+ ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+ }
+ }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_QUEUES == 1
+ bool Queue::DequeueInternal(std::string& value,
+ OrthancPluginQueueOrigin origin)
+ {
+ uint8_t found = false;
+ OrthancPlugins::MemoryBuffer valueBuffer;
+
+ OrthancPluginErrorCode code = OrthancPluginDequeueValue(OrthancPlugins::GetGlobalContext(), &found,
+ *valueBuffer, queueId_.c_str(), origin);
+
+ if (code != OrthancPluginErrorCode_Success)
+ {
+ ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+ }
+ else if (found)
+ {
+ valueBuffer.ToString(value);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_QUEUES == 1
+ uint64_t Queue::GetSize()
+ {
+ uint64_t size = 0;
+ OrthancPluginErrorCode code = OrthancPluginGetQueueSize(OrthancPlugins::GetGlobalContext(), queueId_.c_str(), &size);
+
+ if (code != OrthancPluginErrorCode_Success)
+ {
+ ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code);
+ }
+ else
+ {
+ return size;
+ }
+ }
+#endif
}
=====================================
Resources/Orthanc/Plugins/OrthancPluginCppWrapper.h
=====================================
@@ -134,6 +134,14 @@
# define HAS_ORTHANC_PLUGIN_LOG_MESSAGE 0
#endif
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 12, 8)
+# define HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES 1
+# define HAS_ORTHANC_PLUGIN_QUEUES 1
+#else
+# define HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES 0
+# define HAS_ORTHANC_PLUGIN_QUEUES 0
+#endif
+
// Macro to tag a function as having been deprecated
#if (__cplusplus >= 201402L) // C++14
@@ -172,6 +180,8 @@ namespace OrthancPlugins
{
typedef std::map<std::string, std::string> HttpHeaders;
+ typedef std::map<std::string, std::string> GetArguments;
+
typedef void (*RestCallback) (OrthancPluginRestOutput* output,
const char* url,
const OrthancPluginHttpRequest* request);
@@ -203,13 +213,6 @@ namespace OrthancPlugins
public:
MemoryBuffer();
-#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
- // This constructor makes a copy of the given buffer in the memory
- // handled by the Orthanc core
- MemoryBuffer(const void* buffer,
- size_t size);
-#endif
-
~MemoryBuffer()
{
Clear();
@@ -220,6 +223,20 @@ namespace OrthancPlugins
return &buffer_;
}
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
+ // Copy of the given buffer into the memory managed by the Orthanc core
+ void Assign(const void* buffer,
+ size_t size);
+#endif
+
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
+ void Assign(const std::string& s);
+#endif
+
+#if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 7, 0)
+ void AssignJson(const Json::Value& value);
+#endif
+
// This transfers ownership from "other" to "this"
void Assign(OrthancPluginMemoryBuffer& other);
@@ -227,11 +244,11 @@ namespace OrthancPlugins
OrthancPluginMemoryBuffer Release();
- const char* GetData() const
+ const void* GetData() const
{
if (buffer_.size > 0)
{
- return reinterpret_cast<const char*>(buffer_.data);
+ return buffer_.data;
}
else
{
@@ -854,6 +871,13 @@ namespace OrthancPlugins
const std::string& body,
const HttpHeaders& headers) const;
+ bool DoPost(MemoryBuffer& target,
+ size_t index,
+ const std::string& uri,
+ const std::string& body,
+ const HttpHeaders& headers,
+ unsigned int timeout) const;
+
bool DoPost(MemoryBuffer& target,
const std::string& name,
const std::string& uri,
@@ -866,6 +890,13 @@ namespace OrthancPlugins
const std::string& body,
const HttpHeaders& headers) const;
+ bool DoPost(Json::Value& target,
+ size_t index,
+ const std::string& uri,
+ const std::string& body,
+ const HttpHeaders& headers,
+ unsigned int timeout) const;
+
bool DoPost(Json::Value& target,
const std::string& name,
const std::string& uri,
@@ -1402,6 +1433,9 @@ void GetHttpHeaders(HttpHeaders& result, const OrthancPluginHttpRequest* request
// helper method to re-serialize the get arguments from the SDK into a string
void SerializeGetArguments(std::string& output, const OrthancPluginHttpRequest* request);
+// helper method to convert Get arguments from the plugin SDK to a std::map
+void GetGetArguments(GetArguments& result, const OrthancPluginHttpRequest* request);
+
#if HAS_ORTHANC_PLUGIN_WEBDAV == 1
class IWebDavCollection : public boost::noncopyable
{
@@ -1559,6 +1593,9 @@ void SerializeGetArguments(std::string& output, const OrthancPluginHttpRequest*
void AddRequestHeader(const std::string& key,
const std::string& value);
+ void SetRequestHeader(const std::string& key,
+ const std::string& value);
+
const HttpHeaders& GetRequestHeaders() const
{
return requestHeaders_;
@@ -1589,10 +1626,14 @@ void SerializeGetArguments(std::string& output, const OrthancPluginHttpRequest*
return requestBody_;
}
+ // Execute only
bool Execute();
+ // Forward response as is
+ void ForwardAnswer(OrthancPluginContext* context, OrthancPluginRestOutput* output);
+
// Execute and forward the response as is
- void Forward(OrthancPluginContext* context, OrthancPluginRestOutput* output);
+ void ExecuteAndForwardAnswer(OrthancPluginContext* context, OrthancPluginRestOutput* output);
uint16_t GetHttpStatus() const;
@@ -1604,4 +1645,101 @@ void SerializeGetArguments(std::string& output, const OrthancPluginHttpRequest*
bool GetAnswerJson(Json::Value& output) const;
};
#endif
+
+
+#if HAS_ORTHANC_PLUGIN_KEY_VALUE_STORES == 1
+ class KeyValueStore : public boost::noncopyable
+ {
+ public:
+ class Iterator : public boost::noncopyable
+ {
+ private:
+ OrthancPluginKeysValuesIterator *iterator_;
+
+ public:
+ explicit Iterator(OrthancPluginKeysValuesIterator *iterator);
+
+ ~Iterator();
+
+ bool Next();
+
+ std::string GetKey() const;
+
+ void GetValue(std::string& target) const;
+ };
+
+ private:
+ std::string storeId_;
+
+ public:
+ explicit KeyValueStore(const std::string& storeId) :
+ storeId_(storeId)
+ {
+ }
+
+ const std::string& GetStoreId() const
+ {
+ return storeId_;
+ }
+
+ void Store(const std::string& key,
+ const void* value,
+ size_t valueSize);
+
+ void Store(const std::string& key,
+ const std::string& value)
+ {
+ Store(key, value.empty() ? NULL : value.c_str(), value.size());
+ }
+
+ bool GetValue(std::string& value,
+ const std::string& key);
+
+ void DeleteKey(const std::string& key);
+
+ Iterator* CreateIterator();
+ };
+#endif
+
+
+#if HAS_ORTHANC_PLUGIN_QUEUES == 1
+ class Queue : public boost::noncopyable
+ {
+ private:
+ std::string queueId_;
+
+ bool DequeueInternal(std::string& value, OrthancPluginQueueOrigin origin);
+
+ public:
+ explicit Queue(const std::string& queueId) :
+ queueId_(queueId)
+ {
+ }
+
+ const std::string& GetQueueId() const
+ {
+ return queueId_;
+ }
+
+ void Enqueue(const void* value,
+ size_t valueSize);
+
+ void Enqueue(const std::string& value)
+ {
+ Enqueue(value.empty() ? NULL : value.c_str(), value.size());
+ }
+
+ bool DequeueBack(std::string& value)
+ {
+ return DequeueInternal(value, OrthancPluginQueueOrigin_Back);
+ }
+
+ bool DequeueFront(std::string& value)
+ {
+ return DequeueInternal(value, OrthancPluginQueueOrigin_Front);
+ }
+
+ uint64_t GetSize();
+ };
+#endif
}
=====================================
TODO
=====================================
@@ -1,3 +1,6 @@
+* Force usage of StudyInstanceUID & SeriesInstanceUID in WADO-URI for single instances:
+ https://discourse.orthanc-server.org/t/dicomweb-wado-uri-does-not-work-if-duplicated-instances/5863
+
* https://orthanc.uclouvain.be/book/plugins/dicomweb.html#retrieving-dicom-resources-from-a-wado-rs-server
=====================================
debian/changelog
=====================================
@@ -1,3 +1,9 @@
+orthanc-dicomweb (1.21+dfsg-1) unstable; urgency=medium
+
+ * New upstream version
+
+ -- Sebastien Jodogne <s.jodogne at gmail.com> Tue, 19 Aug 2025 14:53:25 +0200
+
orthanc-dicomweb (1.20+dfsg-1) unstable; urgency=medium
* New upstream version
=====================================
debian/control
=====================================
@@ -28,7 +28,7 @@ Package: orthanc-dicomweb
Architecture: any
Depends: ${misc:Depends},
${shlibs:Depends},
- orthanc (>= 1.11.1)
+ orthanc (>= 1.12.5)
Built-Using: ${orthancframework:Built-Using}
Description: Plugin to extend Orthanc with support of WADO and DICOMweb
Orthanc DICOMweb is a plugin to Orthanc, the lightweight, RESTful Vendor
=====================================
debian/patches/cmake
=====================================
@@ -2,10 +2,10 @@ Description: Fix the inclusion of the JavaScript libraries
Author: Sebastien Jodogne <s.jodogne at orthanc-labs.com>
---
This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
-Index: OrthancDicomWeb-1.20/CMakeLists.txt
+Index: OrthancDicomWeb-1.21/CMakeLists.txt
===================================================================
---- OrthancDicomWeb-1.20.orig/CMakeLists.txt
-+++ OrthancDicomWeb-1.20/CMakeLists.txt
+--- OrthancDicomWeb-1.21.orig/CMakeLists.txt
++++ OrthancDicomWeb-1.21/CMakeLists.txt
@@ -92,7 +92,7 @@ else()
endif()
=====================================
debian/patches/embed-resources
=====================================
@@ -0,0 +1,18 @@
+Description: Fix the path to EmbedResources.py
+Author: Sebastien Jodogne <s.jodogne at orthanc-labs.com>
+Forwarded: https://orthanc.uclouvain.be/hg/orthanc-dicomweb/rev/d3bc898d8124
+---
+This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
+Index: OrthancDicomWeb-1.21/Resources/Orthanc/CMake/AutoGeneratedCode.cmake
+===================================================================
+--- OrthancDicomWeb-1.21.orig/Resources/Orthanc/CMake/AutoGeneratedCode.cmake
++++ OrthancDicomWeb-1.21/Resources/Orthanc/CMake/AutoGeneratedCode.cmake
+@@ -20,7 +20,7 @@
+ # <http://www.gnu.org/licenses/>.
+
+
+-set(EMBED_RESOURCES_PYTHON "${CMAKE_CURRENT_LIST_DIR}/../EmbedResources.py"
++set(EMBED_RESOURCES_PYTHON "${CMAKE_CURRENT_LIST_DIR}/EmbedResources.py"
+ CACHE INTERNAL "Path to the EmbedResources.py script from Orthanc")
+ set(AUTOGENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/AUTOGENERATED")
+ set(AUTOGENERATED_SOURCES)
=====================================
debian/patches/series
=====================================
@@ -1 +1,2 @@
cmake
+embed-resources
View it on GitLab: https://salsa.debian.org/med-team/orthanc-dicomweb/-/compare/59cc8ab837500d1f45aceb80ff41d4bf1002a9aa...d6042b26e68b9d5d403936e67e212a9326967d49
--
View it on GitLab: https://salsa.debian.org/med-team/orthanc-dicomweb/-/compare/59cc8ab837500d1f45aceb80ff41d4bf1002a9aa...d6042b26e68b9d5d403936e67e212a9326967d49
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20250819/df1ba658/attachment-0001.htm>
More information about the debian-med-commit
mailing list