# HG changeset patch # User Alain Mazy # Date 1705940051 -3600 # Node ID 4b3f5986eca15824461c8843496ef4d4dab3c418 # Parent 42e6593aa78eba1ec7266cc123c8d3651f1ec989 Added a 'KeepLabels' option in /modify routes (default = false) diff -r 42e6593aa78e -r 4b3f5986eca1 NEWS --- a/NEWS Wed Jan 10 07:21:50 2024 +0100 +++ b/NEWS Mon Jan 22 17:14:11 2024 +0100 @@ -1,6 +1,12 @@ Pending changes in the mainline =============================== +REST API +-------- + +* API version upgraded to 23 +* Added a 'KeepLabels' option in /modify routes (default = false) + Maintenance ----------- diff -r 42e6593aa78e -r 4b3f5986eca1 OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake --- a/OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake Wed Jan 10 07:21:50 2024 +0100 +++ b/OrthancFramework/Resources/CMake/OrthancFrameworkParameters.cmake Mon Jan 22 17:14:11 2024 +0100 @@ -38,7 +38,7 @@ # Version of the Orthanc API, can be retrieved from "/system" URI in # order to check whether new URI endpoints are available even if using # the mainline version of Orthanc -set(ORTHANC_API_VERSION "22") +set(ORTHANC_API_VERSION "23") ##################################################################### diff -r 42e6593aa78e -r 4b3f5986eca1 OrthancFramework/Sources/DicomParsing/DicomModification.cpp --- a/OrthancFramework/Sources/DicomParsing/DicomModification.cpp Wed Jan 10 07:21:50 2024 +0100 +++ b/OrthancFramework/Sources/DicomParsing/DicomModification.cpp Mon Jan 22 17:14:11 2024 +0100 @@ -525,6 +525,7 @@ DicomModification::DicomModification() : removePrivateTags_(false), + keepLabels_(false), level_(ResourceType_Instance), allowManualIdentifiers_(true), keepStudyInstanceUid_(false), @@ -692,6 +693,16 @@ return removePrivateTags_; } + void DicomModification::SetKeepLabels(bool keep) + { + keepLabels_ = keep; + } + + bool DicomModification::AreLabelsKept() const + { + return keepLabels_; + } + void DicomModification::SetLevel(ResourceType level) { uidMap_.clear(); @@ -1273,6 +1284,11 @@ SetRemovePrivateTags(true); } + if (GetBooleanValue("KeepLabels", request, false)) + { + SetKeepLabels(true); + } + if (request.isMember("Remove")) { ParseListOfTags(*this, request["Remove"], TagOperation_Remove, force); @@ -1391,6 +1407,11 @@ SetRemovePrivateTags(false); } + if (GetBooleanValue("KeepLabels", request, false)) + { + SetKeepLabels(true); + } + if (request.isMember("Remove")) { ParseListOfTags(*this, request["Remove"], TagOperation_Remove, force); diff -r 42e6593aa78e -r 4b3f5986eca1 OrthancFramework/Sources/DicomParsing/DicomModification.h --- a/OrthancFramework/Sources/DicomParsing/DicomModification.h Wed Jan 10 07:21:50 2024 +0100 +++ b/OrthancFramework/Sources/DicomParsing/DicomModification.h Mon Jan 22 17:14:11 2024 +0100 @@ -131,6 +131,7 @@ SetOfTags keep_; Replacements replacements_; bool removePrivateTags_; + bool keepLabels_; ResourceType level_; UidMap uidMap_; SetOfTags privateTagsToKeep_; @@ -223,6 +224,10 @@ bool ArePrivateTagsRemoved() const; + void SetKeepLabels(bool keep); + + bool AreLabelsKept() const; + void SetLevel(ResourceType level); ResourceType GetLevel() const; diff -r 42e6593aa78e -r 4b3f5986eca1 OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp --- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Wed Jan 10 07:21:50 2024 +0100 +++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp Mon Jan 22 17:14:11 2024 +0100 @@ -3620,6 +3620,17 @@ } + void StatelessDatabaseOperations::AddLabels(const std::string& publicId, + ResourceType level, + const std::set& labels) + { + for (std::set::const_iterator it = labels.begin(); it != labels.end(); ++it) + { + ModifyLabel(publicId, level, *it, LabelOperation_Add); + } + } + + void StatelessDatabaseOperations::ModifyLabel(const std::string& publicId, ResourceType level, const std::string& label, diff -r 42e6593aa78e -r 4b3f5986eca1 OrthancServer/Sources/Database/StatelessDatabaseOperations.h --- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.h Wed Jan 10 07:21:50 2024 +0100 +++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.h Mon Jan 22 17:14:11 2024 +0100 @@ -785,6 +785,10 @@ const std::string& label, LabelOperation operation); + void AddLabels(const std::string& publicId, + ResourceType level, + const std::set& labels); + bool HasLabelsSupport(); }; } diff -r 42e6593aa78e -r 4b3f5986eca1 OrthancServer/Sources/OrthancRestApi/OrthancRestAnonymizeModify.cpp --- a/OrthancServer/Sources/OrthancRestApi/OrthancRestAnonymizeModify.cpp Wed Jan 10 07:21:50 2024 +0100 +++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestAnonymizeModify.cpp Mon Jan 22 17:14:11 2024 +0100 @@ -46,6 +46,7 @@ static const char* const INTERPRET_BINARY_TAGS = "InterpretBinaryTags"; static const char* const KEEP = "Keep"; static const char* const KEEP_PRIVATE_TAGS = "KeepPrivateTags"; +static const char* const KEEP_LABELS = "KeepLabels"; static const char* const KEEP_SOURCE = "KeepSource"; static const char* const LEVEL = "Level"; static const char* const PARENT = "Parent"; @@ -122,6 +123,8 @@ "configuration option `DeidentifyLogsDicomVersion` for possible values.", false) .SetRequestField(KEEP_PRIVATE_TAGS, RestApiCallDocumentation::Type_Boolean, "Keep the private tags from the DICOM instances (defaults to `false`)", false) + .SetRequestField(KEEP_LABELS, RestApiCallDocumentation::Type_Boolean, + "Keep the labels of all resources level (defaults to `false`)", false) .SetRequestField(REPLACE, RestApiCallDocumentation::Type_JsonObject, "Associative array to change the value of some DICOM tags in the DICOM instances. " INFO_SUBSEQUENCES, false) .SetRequestField(REMOVE, RestApiCallDocumentation::Type_JsonListOfStrings, @@ -1068,6 +1071,8 @@ "Associative array to change the value of some DICOM tags in the new study. " "These tags must be part of the \"Patient Module Attributes\" or the \"General Study " "Module Attributes\", as specified by the DICOM 2011 standard in Tables C.7-1 and C.7-3.", false) + .SetRequestField(KEEP_LABELS, RestApiCallDocumentation::Type_Boolean, + "Keep the labels of all resources level (defaults to `false`)", false) .SetRequestField(REMOVE, RestApiCallDocumentation::Type_JsonListOfStrings, "List of tags that must be removed in the new study (from the same modules as in the `Replace` option)", false) .SetRequestField(KEEP_SOURCE, RestApiCallDocumentation::Type_Boolean, diff -r 42e6593aa78e -r 4b3f5986eca1 OrthancServer/Sources/ServerJobs/ResourceModificationJob.cpp --- a/OrthancServer/Sources/ServerJobs/ResourceModificationJob.cpp Wed Jan 10 07:21:50 2024 +0100 +++ b/OrthancServer/Sources/ServerJobs/ResourceModificationJob.cpp Mon Jan 22 17:14:11 2024 +0100 @@ -210,7 +210,11 @@ std::unique_ptr originalHasher; std::unique_ptr modified; - + std::set instanceLabels; + std::set seriesLabels; + std::set studyLabels; + std::set patientLabels; + try { ServerContext::DicomCacheLocker locker(GetContext(), instance); @@ -234,6 +238,15 @@ boost::recursive_mutex::scoped_lock lock(mutex_); // DicomModification object is not thread safe, we must protect it from here modification_->Apply(*modified); + + if (modification_->AreLabelsKept()) + { + GetContext().GetIndex().ListLabels(instanceLabels, instance, ResourceType_Instance); + // we must also save the parent labels. This instance might currently be the only one in the hierarchy and therefore it might be in charge of restoring all labels of the hierarchy + GetContext().GetIndex().ListLabels(seriesLabels, originalHasher->HashSeries(), ResourceType_Series); + GetContext().GetIndex().ListLabels(studyLabels, originalHasher->HashStudy(), ResourceType_Study); + GetContext().GetIndex().ListLabels(patientLabels, originalHasher->HashPatient(), ResourceType_Patient); + } } const std::string modifiedUid = IDicomTranscoder::GetSopInstanceUid(modified->GetDcmtkObject()); @@ -318,6 +331,19 @@ "Error while storing a modified instance " + instance); } + { + boost::recursive_mutex::scoped_lock lock(mutex_); // DicomModification object is not thread safe, we must protect it from here + + if (modification_->AreLabelsKept()) + { + GetContext().GetIndex().AddLabels(instance, ResourceType_Instance, instanceLabels); + GetContext().GetIndex().AddLabels(modifiedHasher.HashSeries(), ResourceType_Series, seriesLabels); + GetContext().GetIndex().AddLabels(modifiedHasher.HashStudy(), ResourceType_Study, studyLabels); + GetContext().GetIndex().AddLabels(modifiedHasher.HashPatient(), ResourceType_Patient, patientLabels); + } + } + + /** * The assertion below will fail if automated transcoding to a * lossy transfer syntax is enabled in the Orthanc core, and if