Mercurial > hg > orthanc
diff OrthancFramework/Sources/DicomParsing/DicomModification.cpp @ 5807:8279eaab0d1d attach-custom-data tip
merged default -> attach-custom-data
author | Alain Mazy <am@orthanc.team> |
---|---|
date | Tue, 24 Sep 2024 11:39:52 +0200 |
parents | f7adfb22e20e |
children |
line wrap: on
line diff
--- a/OrthancFramework/Sources/DicomParsing/DicomModification.cpp Thu Sep 15 18:13:17 2022 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomModification.cpp Tue Sep 24 11:39:52 2024 +0200 @@ -2,8 +2,9 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2022 Osimis S.A., Belgium - * Copyright (C) 2021-2022 Sebastien Jodogne, ICTEAM UCLouvain, Belgium + * Copyright (C) 2017-2023 Osimis S.A., Belgium + * Copyright (C) 2024-2024 Orthanc Team SRL, Belgium + * Copyright (C) 2021-2024 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -43,6 +44,9 @@ static const std::string ORTHANC_DEIDENTIFICATION_METHOD_2021b = "Orthanc " ORTHANC_VERSION " - PS 3.15-2021b Table E.1-1 Basic Profile"; +static const std::string ORTHANC_DEIDENTIFICATION_METHOD_2023b = + "Orthanc " ORTHANC_VERSION " - PS 3.15-2023b Table E.1-1 Basic Profile"; + namespace Orthanc { namespace @@ -314,7 +318,7 @@ * data sets including: * https://wiki.cancerimagingarchive.net/display/Public/Lung+CT+Segmentation+Challenge+2017) * Tested in "test_anonymize_relationships_5". Introduced - * in: https://hg.orthanc-server.com/orthanc/rev/3513 + * in: https://orthanc.uclouvain.be/hg/orthanc/rev/3513 **/ newValue = that_.MapDicomIdentifier(value, ResourceType_Study); } @@ -427,7 +431,8 @@ if (it->second->asString() == ORTHANC_DEIDENTIFICATION_METHOD_2008 || it->second->asString() == ORTHANC_DEIDENTIFICATION_METHOD_2017c || - it->second->asString() == ORTHANC_DEIDENTIFICATION_METHOD_2021b) + it->second->asString() == ORTHANC_DEIDENTIFICATION_METHOD_2021b || + it->second->asString() == ORTHANC_DEIDENTIFICATION_METHOD_2023b) { delete it->second; replacements_.erase(it); @@ -521,6 +526,7 @@ DicomModification::DicomModification() : removePrivateTags_(false), + keepLabels_(false), level_(ResourceType_Instance), allowManualIdentifiers_(true), keepStudyInstanceUid_(false), @@ -540,6 +546,7 @@ void DicomModification::Keep(const DicomTag& tag) { + keep_.insert(tag); removals_.erase(tag); clearings_.erase(tag); uids_.erase(tag); @@ -636,6 +643,11 @@ return replacements_.find(tag) != replacements_.end(); } + bool DicomModification::IsKept(const DicomTag& tag) const + { + return keep_.find(tag) != keep_.end(); + } + const Json::Value& DicomModification::GetReplacement(const DicomTag& tag) const { Replacements::const_iterator it = replacements_.find(tag); @@ -682,6 +694,16 @@ return removePrivateTags_; } + void DicomModification::SetKeepLabels(bool keep) + { + keepLabels_ = keep; + } + + bool DicomModification::AreLabelsKept() const + { + return keepLabels_; + } + void DicomModification::SetLevel(ResourceType level) { uidMap_.clear(); @@ -714,7 +736,7 @@ * Values below come from the hardcoded UID of Orthanc 1.9.3 * in DicomModification::RelationshipsVisitor::VisitString() and * DicomModification::RelationshipsVisitor::RemoveRelationships() - * https://hg.orthanc-server.com/orthanc/file/Orthanc-1.9.3/OrthancFramework/Sources/DicomParsing/DicomModification.cpp#l117 + * https://orthanc.uclouvain.be/hg/orthanc/file/Orthanc-1.9.3/OrthancFramework/Sources/DicomParsing/DicomModification.cpp#l117 **/ uids_.clear(); @@ -825,9 +847,6 @@ * generated automatically by calling: * "../../../OrthancServer/Resources/GenerateAnonymizationProfile.py * https://raw.githubusercontent.com/jodogne/dicom-specification/master/2021b/part15.xml" - * - * http://dicom.nema.org/medical/dicom/2021b/output/chtml/part15/chapter_E.html#table_E.1-1a - * http://dicom.nema.org/medical/dicom/2021b/output/chtml/part15/chapter_E.html#table_E.1-1 **/ #include "DicomModification_Anonymization2021b.impl.h" @@ -837,10 +856,31 @@ } + void DicomModification::SetupAnonymization2023b() + { + /** + * This is Table E.1-1 from PS 3.15-2023b (DICOM Part 15: Security + * and System Management Profiles), "basic profile" column. It was + * generated automatically by calling: + * "../../../OrthancServer/Resources/GenerateAnonymizationProfile.py + * https://raw.githubusercontent.com/jodogne/dicom-specification/master/2023b/part15.xml" + * + * http://dicom.nema.org/medical/dicom/current/output/chtml/part15/chapter_E.html#table_E.1-1a + * http://dicom.nema.org/medical/dicom/current/output/chtml/part15/chapter_E.html#table_E.1-1 + **/ + +#include "DicomModification_Anonymization2023b.impl.h" + + // Set the DeidentificationMethod tag + ReplaceInternal(DICOM_TAG_DEIDENTIFICATION_METHOD, ORTHANC_DEIDENTIFICATION_METHOD_2023b); + } + + void DicomModification::SetupAnonymization(DicomVersion version) { isAnonymization_ = true; + keep_.clear(); removals_.clear(); clearings_.clear(); removedRanges_.clear(); @@ -867,6 +907,10 @@ SetupAnonymization2021b(); break; + case DicomVersion_2023b: + SetupAnonymization2023b(); + break; + default: throw OrthancException(ErrorCode_ParameterOutOfRange); } @@ -918,22 +962,12 @@ IsRemoved(DICOM_TAG_SERIES_INSTANCE_UID) || IsRemoved(DICOM_TAG_SOP_INSTANCE_UID)) { - throw OrthancException(ErrorCode_BadRequest); + throw OrthancException(ErrorCode_BadRequest, "It is forbidden to remove one of the main Dicom identifiers"); } - - // Sanity checks at the patient level - bool isReplacedPatientId = (IsReplaced(DICOM_TAG_PATIENT_ID) || - uids_.find(DICOM_TAG_PATIENT_ID) != uids_.end()); - - if (level_ == ResourceType_Patient && !isReplacedPatientId) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a patient, her PatientID is required to be modified"); - } - if (!allowManualIdentifiers_) { + // Sanity checks at the patient level if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) { throw OrthancException(ErrorCode_BadRequest, @@ -951,18 +985,8 @@ throw OrthancException(ErrorCode_BadRequest, "When modifying a patient, the SopInstanceUID cannot be manually modified"); } - } - - // Sanity checks at the study level - if (level_ == ResourceType_Study && isReplacedPatientId) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a study, the parent PatientID cannot be manually modified"); - } - - if (!allowManualIdentifiers_) - { + // Sanity checks at the study level if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) { throw OrthancException(ErrorCode_BadRequest, @@ -974,24 +998,8 @@ throw OrthancException(ErrorCode_BadRequest, "When modifying a study, the SopInstanceUID cannot be manually modified"); } - } - - // Sanity checks at the series level - if (level_ == ResourceType_Series && isReplacedPatientId) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a series, the parent PatientID cannot be manually modified"); - } - - if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying a series, the parent StudyInstanceUID cannot be manually modified"); - } - - if (!allowManualIdentifiers_) - { + // Sanity checks at the series level if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID)) { throw OrthancException(ErrorCode_BadRequest, @@ -1000,25 +1008,6 @@ } - // Sanity checks at the instance level - if (level_ == ResourceType_Instance && isReplacedPatientId) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying an instance, the parent PatientID cannot be manually modified"); - } - - if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying an instance, the parent StudyInstanceUID cannot be manually modified"); - } - - if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest, - "When modifying an instance, the parent SeriesInstanceUID cannot be manually modified"); - } - // (0) Create a summary of the source file, if a custom generator // is provided if (identifierGenerator_ != NULL) @@ -1296,6 +1285,11 @@ SetRemovePrivateTags(true); } + if (GetBooleanValue("KeepLabels", request, false)) + { + SetKeepLabels(true); + } + if (request.isMember("Remove")) { ParseListOfTags(*this, request["Remove"], TagOperation_Remove, force); @@ -1321,6 +1315,62 @@ { privateCreator_ = SerializationToolbox::ReadString(request, "PrivateCreator"); } + + if (!force) + { + /** + * Sanity checks about the manual replacement of DICOM + * identifiers. Those checks were part of + * "DicomModification::Apply()" in Orthanc <= 1.11.2, and + * couldn't be disabled even if using the "Force" flag. Check + * out: + * https://groups.google.com/g/orthanc-users/c/xMUUZAnBa5g/m/WCEu-U2NBQAJ + **/ + bool isReplacedPatientId = (IsReplaced(DICOM_TAG_PATIENT_ID) || + uids_.find(DICOM_TAG_PATIENT_ID) != uids_.end()); + + if (level_ == ResourceType_Patient && !isReplacedPatientId) + { + throw OrthancException(ErrorCode_BadRequest, + "When modifying a patient, her PatientID is required to be modified."); + } + + if (level_ == ResourceType_Study && isReplacedPatientId) + { + throw OrthancException(ErrorCode_BadRequest, + "When modifying a study, the parent PatientID cannot be manually modified"); + } + + if (level_ == ResourceType_Series && isReplacedPatientId) + { + throw OrthancException(ErrorCode_BadRequest, + "When modifying a series, the parent PatientID cannot be manually modified"); + } + + if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) + { + throw OrthancException(ErrorCode_BadRequest, + "When modifying a series, the parent StudyInstanceUID cannot be manually modified"); + } + + if (level_ == ResourceType_Instance && isReplacedPatientId) + { + throw OrthancException(ErrorCode_BadRequest, + "When modifying an instance, the parent PatientID cannot be manually modified"); + } + + if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) + { + throw OrthancException(ErrorCode_BadRequest, + "When modifying an instance, the parent StudyInstanceUID cannot be manually modified"); + } + + if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) + { + throw OrthancException(ErrorCode_BadRequest, + "When modifying an instance, the parent SeriesInstanceUID cannot be manually modified"); + } + } } @@ -1336,7 +1386,9 @@ // DicomVersion version = DicomVersion_2008; // For Orthanc <= 1.2.0 // DicomVersion version = DicomVersion_2017c; // For Orthanc between 1.3.0 and 1.9.3 - DicomVersion version = DicomVersion_2021b; // For Orthanc >= 1.9.4 + // DicomVersion version = DicomVersion_2021b; // For Orthanc >= 1.9.4 + DicomVersion version = DicomVersion_2023b; // For Orthanc >= 1.12.1 + if (request.isMember("DicomVersion")) { if (request["DicomVersion"].type() != Json::stringValue) @@ -1356,6 +1408,11 @@ SetRemovePrivateTags(false); } + if (GetBooleanValue("KeepLabels", request, false)) + { + SetKeepLabels(true); + } + if (request.isMember("Remove")) { ParseListOfTags(*this, request["Remove"], TagOperation_Remove, force); @@ -1585,7 +1642,7 @@ * 1.5.0 and 1.6.1. This compatibility was broken between 1.7.0 * and 1.9.3: Indeed, an exception was thrown in "ReadBoolean()" * if "KEEP_SOP_INSTANCE_UID" was absent, because of changeset: - * https://hg.orthanc-server.com/orthanc/rev/3860 + * https://orthanc.uclouvain.be/hg/orthanc/rev/3860 **/ keepSopInstanceUid_ = false; } @@ -1830,4 +1887,13 @@ (tag == DICOM_TAG_SOP_INSTANCE_UID && !keepSopInstanceUid_)); } + + void DicomModification::GetReplacedTags(std::set<DicomTag>& target) const + { + target.clear(); + for (Replacements::const_iterator it = replacements_.begin(); it != replacements_.end(); ++it) + { + target.insert(it->first); + } + } }