# HG changeset patch # User Sebastien Jodogne # Date 1622821123 -7200 # Node ID 2e850edf03d6032e9b5a071daaeae0f5228c6439 # Parent 521e39b3f2c090c4d071ad95a84da3d3ea500e37 Full support for the anonymization of subsequences containing tags whose VR is UI diff -r 521e39b3f2c0 -r 2e850edf03d6 NEWS --- a/NEWS Thu Jun 03 21:06:34 2021 +0200 +++ b/NEWS Fri Jun 04 17:38:43 2021 +0200 @@ -17,6 +17,7 @@ Maintenance ----------- +* Full support for the anonymization of subsequences containing tags whose VR is UI * Fix issue #146 (Update Anonyization to 2019c) - was actually updated to 2021b diff -r 521e39b3f2c0 -r 2e850edf03d6 OrthancFramework/Sources/DicomParsing/DicomModification.cpp --- a/OrthancFramework/Sources/DicomParsing/DicomModification.cpp Thu Jun 03 21:06:34 2021 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomModification.cpp Fri Jun 04 17:38:43 2021 +0200 @@ -44,6 +44,27 @@ namespace Orthanc { + DicomModification::DicomTagRange::DicomTagRange(uint16_t groupFrom, + uint16_t groupTo, + uint16_t elementFrom, + uint16_t elementTo) : + groupFrom_(groupFrom), + groupTo_(groupTo), + elementFrom_(elementFrom), + elementTo_(elementTo) + { + } + + + bool DicomModification::DicomTagRange::Contains(const DicomTag& tag) const + { + return (tag.GetGroup() >= groupFrom_ && + tag.GetGroup() <= groupTo_ && + tag.GetElement() >= elementFrom_ && + tag.GetElement() <= elementTo_); + } + + class DicomModification::RelationshipsVisitor : public ITagVisitor { private: @@ -124,58 +145,51 @@ ValueRepresentation vr, const std::string& value) { + // Note that all the tags in "uids_" have the VR UI (unique + // identifier), and are considered as strings + if (!IsEnabled(tag)) { return Action_None; } - else if (parentTags.size() == 2 && - parentTags[0] == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_SEQUENCE && - parentTags[1] == DICOM_TAG_RT_REFERENCED_STUDY_SEQUENCE && - tag == DICOM_TAG_REFERENCED_SOP_INSTANCE_UID) - { - // in RT-STRUCT, this ReferencedSOPInstanceUID is actually referencing a StudyInstanceUID !! - // (observed in many data sets including: https://wiki.cancerimagingarchive.net/display/Public/Lung+CT+Segmentation+Challenge+2017) - // tested in test_anonymize_relationships_5 - newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Study); - return Action_Replace; - } - else if (tag == DICOM_TAG_FRAME_OF_REFERENCE_UID || - tag == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_UID || - tag == DICOM_TAG_REFERENCED_SOP_INSTANCE_UID || - tag == DICOM_TAG_RELATED_FRAME_OF_REFERENCE_UID) - { - newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Instance); - return Action_Replace; - } - else if (parentTags.size() == 1 && - parentTags[0] == DICOM_TAG_CURRENT_REQUESTED_PROCEDURE_EVIDENCE_SEQUENCE && + else if (!parentTags.empty() && // Don't anonymize twice the anonymization done by "MapDicomTags()" tag == DICOM_TAG_STUDY_INSTANCE_UID) { - newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Study); + newValue = that_.MapDicomIdentifier(value, ResourceType_Study); return Action_Replace; } - else if (parentTags.size() == 2 && - parentTags[0] == DICOM_TAG_CURRENT_REQUESTED_PROCEDURE_EVIDENCE_SEQUENCE && - parentTags[1] == DICOM_TAG_REFERENCED_SERIES_SEQUENCE && + else if (!parentTags.empty() && // Don't anonymize twice the anonymization done by "MapDicomTags()" tag == DICOM_TAG_SERIES_INSTANCE_UID) { - newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Series); + newValue = that_.MapDicomIdentifier(value, ResourceType_Series); + return Action_Replace; + } + else if (!parentTags.empty() && // Don't anonymize twice the anonymization done by "MapDicomTags()" + tag == DICOM_TAG_SOP_INSTANCE_UID) + { + newValue = that_.MapDicomIdentifier(value, ResourceType_Instance); return Action_Replace; } - else if (parentTags.size() == 3 && - parentTags[0] == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_SEQUENCE && - parentTags[1] == DICOM_TAG_RT_REFERENCED_STUDY_SEQUENCE && - parentTags[2] == DICOM_TAG_RT_REFERENCED_SERIES_SEQUENCE && - tag == DICOM_TAG_SERIES_INSTANCE_UID) + else if (that_.uids_.find(tag) != that_.uids_.end()) { - newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Series); - return Action_Replace; - } - else if (parentTags.size() == 1 && - parentTags[0] == DICOM_TAG_REFERENCED_SERIES_SEQUENCE && - tag == DICOM_TAG_SERIES_INSTANCE_UID) - { - newValue = that_.MapDicomIdentifier(Toolbox::StripSpaces(value), ResourceType_Series); + assert(vr == ValueRepresentation_UniqueIdentifier || + vr == ValueRepresentation_NotSupported /* for older versions of DCMTK */); + + if (parentTags.size() == 2 && + parentTags[0] == DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_SEQUENCE && + parentTags[1] == DICOM_TAG_RT_REFERENCED_STUDY_SEQUENCE && + tag == DICOM_TAG_REFERENCED_SOP_INSTANCE_UID) + { + // in RT-STRUCT, this ReferencedSOPInstanceUID is actually referencing a StudyInstanceUID !! + // (observed in many data sets including: https://wiki.cancerimagingarchive.net/display/Public/Lung+CT+Segmentation+Challenge+2017) + // tested in test_anonymize_relationships_5 + newValue = that_.MapDicomIdentifier(value, ResourceType_Study); + } + else + { + newValue = that_.MapDicomIdentifier(value, ResourceType_Instance); + } + return Action_Replace; } else @@ -186,18 +200,20 @@ void RemoveRelationships(ParsedDicomFile& dicom) const { - // Sequences containing the UID relationships + for (SetOfTags::const_iterator it = that_.uids_.begin(); it != that_.uids_.end(); ++it) + { + if (*it != DICOM_TAG_STUDY_INSTANCE_UID && + *it != DICOM_TAG_SERIES_INSTANCE_UID && + *it != DICOM_TAG_SOP_INSTANCE_UID) + { + RemoveIfEnabled(dicom, *it); + } + } + + // The only two sequences with to the "X/Z/U*" rule in the + // basic profile. They were already present in Orthanc 1.9.3. RemoveIfEnabled(dicom, DICOM_TAG_REFERENCED_IMAGE_SEQUENCE); RemoveIfEnabled(dicom, DICOM_TAG_SOURCE_IMAGE_SEQUENCE); - - // Individual tags - RemoveIfEnabled(dicom, DICOM_TAG_FRAME_OF_REFERENCE_UID); - - // The tags below should never occur at the first level of the - // hierarchy, but remove them anyway - RemoveIfEnabled(dicom, DICOM_TAG_REFERENCED_FRAME_OF_REFERENCE_UID); - RemoveIfEnabled(dicom, DICOM_TAG_REFERENCED_SOP_INSTANCE_UID); - RemoveIfEnabled(dicom, DICOM_TAG_RELATED_FRAME_OF_REFERENCE_UID); } }; @@ -278,9 +294,11 @@ std::string DicomModification::MapDicomIdentifier(const std::string& original, ResourceType level) { + const std::string stripped = Toolbox::StripSpaces(original); + std::string mapped; - UidMap::const_iterator previous = uidMap_.find(std::make_pair(level, original)); + UidMap::const_iterator previous = uidMap_.find(std::make_pair(level, stripped)); if (previous == uidMap_.end()) { @@ -290,14 +308,14 @@ } else { - if (!identifierGenerator_->Apply(mapped, original, level, currentSource_)) + if (!identifierGenerator_->Apply(mapped, stripped, level, currentSource_)) { throw OrthancException(ErrorCode_InternalError, "Unable to generate an anonymized ID"); } } - uidMap_.insert(std::make_pair(std::make_pair(level, original), mapped)); + uidMap_.insert(std::make_pair(std::make_pair(level, stripped), mapped)); } else { @@ -337,7 +355,7 @@ original = ""; } - std::string mapped = MapDicomIdentifier(Toolbox::StripSpaces(original), level); + std::string mapped = MapDicomIdentifier(original, level); dicom.Replace(*tag, mapped, false /* don't try and decode data URI scheme for UIDs */, @@ -371,6 +389,7 @@ removals_.erase(tag); clearings_.erase(tag); + uids_.erase(tag); bool wasReplaced = CancelReplacement(tag); @@ -404,6 +423,7 @@ { removals_.insert(tag); clearings_.erase(tag); + uids_.erase(tag); CancelReplacement(tag); privateTagsToKeep_.erase(tag); @@ -414,6 +434,7 @@ { removals_.erase(tag); clearings_.insert(tag); + uids_.erase(tag); CancelReplacement(tag); privateTagsToKeep_.erase(tag); @@ -422,7 +443,23 @@ bool DicomModification::IsRemoved(const DicomTag& tag) const { - return removals_.find(tag) != removals_.end(); + if (removals_.find(tag) != removals_.end()) + { + return true; + } + else + { + for (RemovedRanges::const_iterator it = removedRanges_.begin(); + it != removedRanges_.end(); it++) + { + if (it->Contains(tag)) + { + return true; + } + } + + return false; + } } bool DicomModification::IsCleared(const DicomTag& tag) const @@ -436,6 +473,7 @@ { clearings_.erase(tag); removals_.erase(tag); + uids_.erase(tag); privateTagsToKeep_.erase(tag); ReplaceInternal(tag, value); @@ -513,12 +551,44 @@ } + static void SetupUidsFromOrthancInternal(std::set& uids, + std::set& removals, + const DicomTag& tag) + { + uids.insert(tag); + removals.erase(tag); // Necessary if unserializing a job from 1.9.3 + } + + + void DicomModification::SetupUidsFromOrthanc_1_9_3() + { + /** + * 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 + **/ + uids_.clear(); + + SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0008, 0x0014)); // Instance Creator UID <= from SetupAnonymization2008() + SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0008, 0x1155)); // Referenced SOP Instance UID <= from VisitString() + RemoveRelationships() + SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0020, 0x0052)); // Frame of Reference UID <= from VisitString() + RemoveRelationships() + SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0020, 0x0200)); // Synchronization Frame of Reference UID <= from SetupAnonymization2008() + SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0040, 0xa124)); // UID <= from SetupAnonymization2008() + SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x0088, 0x0140)); // Storage Media File-set UID <= from SetupAnonymization2008() + SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x3006, 0x0024)); // Referenced Frame of Reference UID <= from VisitString() + RemoveRelationships() + SetupUidsFromOrthancInternal(uids_, removals_, DicomTag(0x3006, 0x00c2)); // Related Frame of Reference UID <= from VisitString() + RemoveRelationships() + } + + void DicomModification::SetupAnonymization2008() { // This is Table E.1-1 from PS 3.15-2008 - DICOM Part 15: Security and System Management Profiles // https://raw.githubusercontent.com/jodogne/dicom-specification/master/2008/08_15pu.pdf + + SetupUidsFromOrthanc_1_9_3(); - removals_.insert(DicomTag(0x0008, 0x0014)); // Instance Creator UID + //uids_.insert(DicomTag(0x0008, 0x0014)); // Instance Creator UID => set in SetupUidsFromOrthanc_1_9_3() //removals_.insert(DicomTag(0x0008, 0x0018)); // SOP Instance UID => set in Apply() removals_.insert(DicomTag(0x0008, 0x0050)); // Accession Number removals_.insert(DicomTag(0x0008, 0x0080)); // Institution Name @@ -535,7 +605,7 @@ removals_.insert(DicomTag(0x0008, 0x1060)); // Name of Physician(s) Reading Study removals_.insert(DicomTag(0x0008, 0x1070)); // Operators' Name removals_.insert(DicomTag(0x0008, 0x1080)); // Admitting Diagnoses Description - //removals_.insert(DicomTag(0x0008, 0x1155)); // Referenced SOP Instance UID => RelationshipsVisitor + //uids_.insert(DicomTag(0x0008, 0x1155)); // Referenced SOP Instance UID => set in SetupUidsFromOrthanc_1_9_3() removals_.insert(DicomTag(0x0008, 0x2111)); // Derivation Description //removals_.insert(DicomTag(0x0010, 0x0010)); // Patient's Name => cf. below (*) //removals_.insert(DicomTag(0x0010, 0x0020)); // Patient ID => cf. below (*) @@ -557,15 +627,15 @@ //removals_.insert(DicomTag(0x0020, 0x000d)); // Study Instance UID => set in Apply() //removals_.insert(DicomTag(0x0020, 0x000e)); // Series Instance UID => set in Apply() removals_.insert(DicomTag(0x0020, 0x0010)); // Study ID - //removals_.insert(DicomTag(0x0020, 0x0052)); // Frame of Reference UID => cf. RelationshipsVisitor - removals_.insert(DicomTag(0x0020, 0x0200)); // Synchronization Frame of Reference UID + //uids_.insert(DicomTag(0x0020, 0x0052)); // Frame of Reference UID => set in SetupUidsFromOrthanc_1_9_3() + //uids_.insert(DicomTag(0x0020, 0x0200)); // Synchronization Frame of Reference UID => set in SetupUidsFromOrthanc_1_9_3() removals_.insert(DicomTag(0x0020, 0x4000)); // Image Comments removals_.insert(DicomTag(0x0040, 0x0275)); // Request Attributes Sequence - removals_.insert(DicomTag(0x0040, 0xa124)); // UID + //uids_.insert(DicomTag(0x0040, 0xa124)); // UID => set in SetupUidsFromOrthanc_1_9_3() removals_.insert(DicomTag(0x0040, 0xa730)); // Content Sequence - removals_.insert(DicomTag(0x0088, 0x0140)); // Storage Media File-set UID - //removals_.insert(DicomTag(0x3006, 0x0024)); // Referenced Frame of Reference UID => RelationshipsVisitor - //removals_.insert(DicomTag(0x3006, 0x00c2)); // Related Frame of Reference UID => RelationshipsVisitor + //uids_.insert(DicomTag(0x0088, 0x0140)); // Storage Media File-set UID => set in SetupUidsFromOrthanc_1_9_3() + //uids_.insert(DicomTag(0x3006, 0x0024)); // Referenced Frame of Reference UID => set in SetupUidsFromOrthanc_1_9_3() + //uids_.insert(DicomTag(0x3006, 0x00c2)); // Related Frame of Reference UID => set in SetupUidsFromOrthanc_1_9_3() // Some more removals (from the experience of DICOM files at the CHU of Liege) removals_.insert(DicomTag(0x0010, 0x1040)); // Patient's Address @@ -621,6 +691,8 @@ removals_.clear(); clearings_.clear(); + removedRanges_.clear(); + uids_.clear(); ClearReplacements(); removePrivateTags_ = true; level_ = ResourceType_Patient; @@ -652,6 +724,17 @@ std::string patientId = FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType_Patient); ReplaceInternal(DICOM_TAG_PATIENT_ID, patientId); ReplaceInternal(DICOM_TAG_PATIENT_NAME, patientId); + + // Sanity check + for (SetOfTags::const_iterator it = uids_.begin(); it != uids_.end(); ++it) + { + ValueRepresentation vr = FromDcmtkBridge::LookupValueRepresentation(*it); + if (vr != ValueRepresentation_UniqueIdentifier && + vr != ValueRepresentation_NotSupported /* for older versions of DCMTK */) + { + throw OrthancException(ErrorCode_InternalError); + } + } } void DicomModification::Apply(ParsedDicomFile& toModify) @@ -1131,6 +1214,8 @@ static const char* MAP_SERIES = "MapSeries"; static const char* MAP_INSTANCES = "MapInstances"; static const char* PRIVATE_CREATOR = "PrivateCreator"; // New in Orthanc 1.6.0 + static const char* UIDS = "Uids"; // New in Orthanc 1.9.4 + static const char* REMOVED_RANGES = "RemovedRanges"; // New in Orthanc 1.9.4 void DicomModification::Serialize(Json::Value& value) const { @@ -1205,6 +1290,24 @@ assert(tmp2 != NULL); (*tmp2) [it->first.second] = it->second; } + + // New in Orthanc 1.9.4 + SerializationToolbox::WriteSetOfTags(value, uids_, UIDS); + + // New in Orthanc 1.9.4 + Json::Value ranges = Json::arrayValue; + + for (RemovedRanges::const_iterator it = removedRanges_.begin(); it != removedRanges_.end(); ++it) + { + Json::Value item = Json::arrayValue; + item.append(it->GetGroupFrom()); + item.append(it->GetGroupTo()); + item.append(it->GetElementFrom()); + item.append(it->GetElementTo()); + ranges.append(item); + } + + value[REMOVED_RANGES] = ranges; } void DicomModification::UnserializeUidMap(ResourceType level, @@ -1283,6 +1386,62 @@ UnserializeUidMap(ResourceType_Study, serialized, MAP_STUDIES); UnserializeUidMap(ResourceType_Series, serialized, MAP_SERIES); UnserializeUidMap(ResourceType_Instance, serialized, MAP_INSTANCES); + + // New in Orthanc 1.9.4 + if (serialized.isMember(UIDS)) // Backward compatibility with Orthanc <= 1.9.3 + { + SerializationToolbox::ReadSetOfTags(uids_, serialized, UIDS); + } + else + { + SetupUidsFromOrthanc_1_9_3(); + } + + // New in Orthanc 1.9.4 + removedRanges_.clear(); + if (serialized.isMember(REMOVED_RANGES)) // Backward compatibility with Orthanc <= 1.9.3 + { + const Json::Value& ranges = serialized[REMOVED_RANGES]; + + if (ranges.type() != Json::arrayValue) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + else + { + for (Json::Value::ArrayIndex i = 0; i < ranges.size(); i++) + { + if (ranges[i].type() != Json::arrayValue || + ranges[i].size() != 4 || + !ranges[i][0].isUInt() || + !ranges[i][1].isUInt() || + !ranges[i][2].isUInt() || + !ranges[i][3].isUInt()) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + else + { + Json::LargestUInt groupFrom = ranges[i][0].asUInt(); + Json::LargestUInt groupTo = ranges[i][1].asUInt(); + Json::LargestUInt elementFrom = ranges[i][2].asUInt(); + Json::LargestUInt elementTo = ranges[i][3].asUInt(); + + if (groupFrom > groupTo || + elementFrom > elementTo || + groupTo > 0xffffu || + elementTo > 0xffffu) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + else + { + removedRanges_.push_back(DicomTagRange(groupFrom, groupTo, elementFrom, elementTo)); + } + } + } + } + } } diff -r 521e39b3f2c0 -r 2e850edf03d6 OrthancFramework/Sources/DicomParsing/DicomModification.h --- a/OrthancFramework/Sources/DicomParsing/DicomModification.h Thu Jun 03 21:06:34 2021 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomModification.h Fri Jun 04 17:38:43 2021 +0200 @@ -58,13 +58,53 @@ private: class RelationshipsVisitor; + class DicomTagRange + { + private: + uint16_t groupFrom_; + uint16_t groupTo_; + uint16_t elementFrom_; + uint16_t elementTo_; + + public: + DicomTagRange(uint16_t groupFrom, + uint16_t groupTo, + uint16_t elementFrom, + uint16_t elementTo); + + uint16_t GetGroupFrom() const + { + return groupFrom_; + } + + uint16_t GetGroupTo() const + { + return groupTo_; + } + + uint16_t GetElementFrom() const + { + return elementFrom_; + } + + uint16_t GetElementTo() const + { + return elementTo_; + } + + bool Contains(const DicomTag& tag) const; + }; + typedef std::set SetOfTags; typedef std::map Replacements; typedef std::map< std::pair, std::string> UidMap; + typedef std::list RemovedRanges; SetOfTags removals_; SetOfTags clearings_; Replacements replacements_; + SetOfTags uids_; // New in Orthanc 1.9.4 + RemovedRanges removedRanges_; // New in Orthanc 1.9.4 bool removePrivateTags_; ResourceType level_; UidMap uidMap_; @@ -99,6 +139,8 @@ void ReplaceInternal(const DicomTag& tag, const Json::Value& value); + void SetupUidsFromOrthanc_1_9_3(); + void SetupAnonymization2008(); void SetupAnonymization2017c(); diff -r 521e39b3f2c0 -r 2e850edf03d6 OrthancFramework/Sources/DicomParsing/DicomModification_Anonymization2017c.impl.h --- a/OrthancFramework/Sources/DicomParsing/DicomModification_Anonymization2017c.impl.h Thu Jun 03 21:06:34 2021 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomModification_Anonymization2017c.impl.h Fri Jun 04 17:38:43 2021 +0200 @@ -1,17 +1,10 @@ -// TODO: (50xx,xxxx) with rule X // Curve Data -// TODO: (60xx,3000) with rule X // Overlay Data -// TODO: (60xx,4000) with rule X // Overlay Comments +// RelationshipsVisitor handles (0x0008, 0x1140) /* X/Z/U* */ // Referenced Image Sequence +// RelationshipsVisitor handles (0x0008, 0x2112) /* X/Z/U* */ // Source Image Sequence // Tag (0x0008, 0x0018) is set in Apply() /* U */ // SOP Instance UID -// Tag (0x0008, 0x1140) => RelationshipsVisitor /* X/Z/U* */ // Referenced Image Sequence -// Tag (0x0008, 0x1155) => RelationshipsVisitor /* U */ // Referenced SOP Instance UID -// Tag (0x0008, 0x2112) => RelationshipsVisitor /* X/Z/U* */ // Source Image Sequence // Tag (0x0010, 0x0010) is set below (*) /* Z */ // Patient's Name // Tag (0x0010, 0x0020) is set below (*) /* Z */ // Patient ID // Tag (0x0020, 0x000d) is set in Apply() /* U */ // Study Instance UID // Tag (0x0020, 0x000e) is set in Apply() /* U */ // Series Instance UID -// Tag (0x0020, 0x0052) => RelationshipsVisitor /* U */ // Frame of Reference UID -// Tag (0x3006, 0x0024) => RelationshipsVisitor /* U */ // Referenced Frame of Reference UID -// Tag (0x3006, 0x00c2) => RelationshipsVisitor /* U */ // Related Frame of Reference UID clearings_.insert(DicomTag(0x0008, 0x0020)); // Study Date clearings_.insert(DicomTag(0x0008, 0x0023)); /* Z/D */ // Content Date clearings_.insert(DicomTag(0x0008, 0x0030)); // Study Time @@ -33,10 +26,6 @@ clearings_.insert(DicomTag(0x0070, 0x0001)); /* D */ // Graphic Annotation Sequence clearings_.insert(DicomTag(0x0070, 0x0084)); // Content Creator's Name removals_.insert(DicomTag(0x0000, 0x1000)); // Affected SOP Instance UID -removals_.insert(DicomTag(0x0000, 0x1001)); /* TODO UID */ // Requested SOP Instance UID -removals_.insert(DicomTag(0x0002, 0x0003)); /* TODO UID */ // Media Storage SOP Instance UID -removals_.insert(DicomTag(0x0004, 0x1511)); /* TODO UID */ // Referenced SOP Instance UID in File -removals_.insert(DicomTag(0x0008, 0x0014)); /* TODO UID */ // Instance Creator UID removals_.insert(DicomTag(0x0008, 0x0015)); // Instance Coercion DateTime removals_.insert(DicomTag(0x0008, 0x0021)); /* X/D */ // Series Date removals_.insert(DicomTag(0x0008, 0x0022)); /* X/Z */ // Acquisition Date @@ -47,7 +36,6 @@ removals_.insert(DicomTag(0x0008, 0x0032)); /* X/Z */ // Acquisition Time removals_.insert(DicomTag(0x0008, 0x0034)); // Overlay Time removals_.insert(DicomTag(0x0008, 0x0035)); // Curve Time -removals_.insert(DicomTag(0x0008, 0x0058)); /* TODO UID */ // Failed SOP Instance UID List removals_.insert(DicomTag(0x0008, 0x0080)); /* X/Z/D */ // Institution Name removals_.insert(DicomTag(0x0008, 0x0081)); // Institution Address removals_.insert(DicomTag(0x0008, 0x0082)); /* X/Z/D */ // Institution Code Sequence @@ -73,9 +61,7 @@ removals_.insert(DicomTag(0x0008, 0x1110)); /* X/Z */ // Referenced Study Sequence removals_.insert(DicomTag(0x0008, 0x1111)); /* X/Z/D */ // Referenced Performed Procedure Step Sequence removals_.insert(DicomTag(0x0008, 0x1120)); // Referenced Patient Sequence -removals_.insert(DicomTag(0x0008, 0x1195)); /* TODO UID */ // Transaction UID removals_.insert(DicomTag(0x0008, 0x2111)); // Derivation Description -removals_.insert(DicomTag(0x0008, 0x3010)); /* TODO UID */ // Irradiation Event UID removals_.insert(DicomTag(0x0008, 0x4000)); // Identifying Comments removals_.insert(DicomTag(0x0010, 0x0021)); // Issuer of Patient ID removals_.insert(DicomTag(0x0010, 0x0032)); // Patient's Birth Time @@ -114,30 +100,23 @@ removals_.insert(DicomTag(0x0010, 0x2299)); // Responsible Organization removals_.insert(DicomTag(0x0010, 0x4000)); // Patient Comments removals_.insert(DicomTag(0x0018, 0x1000)); /* X/Z/D */ // Device Serial Number -removals_.insert(DicomTag(0x0018, 0x1002)); /* TODO UID */ // Device UID removals_.insert(DicomTag(0x0018, 0x1004)); // Plate ID removals_.insert(DicomTag(0x0018, 0x1005)); // Generator ID removals_.insert(DicomTag(0x0018, 0x1007)); // Cassette ID removals_.insert(DicomTag(0x0018, 0x1008)); // Gantry ID removals_.insert(DicomTag(0x0018, 0x1030)); /* X/D */ // Protocol Name removals_.insert(DicomTag(0x0018, 0x1400)); /* X/D */ // Acquisition Device Processing Description -removals_.insert(DicomTag(0x0018, 0x2042)); /* TODO UID */ // Target UID removals_.insert(DicomTag(0x0018, 0x4000)); // Acquisition Comments removals_.insert(DicomTag(0x0018, 0x700a)); /* X/D */ // Detector ID removals_.insert(DicomTag(0x0018, 0x9424)); // Acquisition Protocol Description removals_.insert(DicomTag(0x0018, 0x9516)); /* X/D */ // Start Acquisition DateTime removals_.insert(DicomTag(0x0018, 0x9517)); /* X/D */ // End Acquisition DateTime removals_.insert(DicomTag(0x0018, 0xa003)); // Contribution Description -removals_.insert(DicomTag(0x0020, 0x0200)); /* TODO UID */ // Synchronization Frame of Reference UID removals_.insert(DicomTag(0x0020, 0x3401)); // Modifying Device ID removals_.insert(DicomTag(0x0020, 0x3404)); // Modifying Device Manufacturer removals_.insert(DicomTag(0x0020, 0x3406)); // Modified Image Description removals_.insert(DicomTag(0x0020, 0x4000)); // Image Comments removals_.insert(DicomTag(0x0020, 0x9158)); // Frame Comments -removals_.insert(DicomTag(0x0020, 0x9161)); /* TODO UID */ // Concatenation UID -removals_.insert(DicomTag(0x0020, 0x9164)); /* TODO UID */ // Dimension Organization UID -removals_.insert(DicomTag(0x0028, 0x1199)); /* TODO UID */ // Palette Color Lookup Table UID -removals_.insert(DicomTag(0x0028, 0x1214)); /* TODO UID */ // Large Palette Color Lookup Table UID removals_.insert(DicomTag(0x0028, 0x4000)); // Image Presentation Comments removals_.insert(DicomTag(0x0032, 0x0012)); // Study ID Issuer removals_.insert(DicomTag(0x0032, 0x1020)); // Scheduled Study Location @@ -205,7 +184,6 @@ removals_.insert(DicomTag(0x0040, 0x4005)); // Scheduled Procedure Step Start DateTime removals_.insert(DicomTag(0x0040, 0x4010)); // Scheduled Procedure Step Modification DateTime removals_.insert(DicomTag(0x0040, 0x4011)); // Expected Completion DateTime -removals_.insert(DicomTag(0x0040, 0x4023)); /* TODO UID */ // Referenced General Purpose Scheduled Procedure Step Transaction UID removals_.insert(DicomTag(0x0040, 0x4025)); // Scheduled Station Name Code Sequence removals_.insert(DicomTag(0x0040, 0x4027)); // Scheduled Station Geographic Location Code Sequence removals_.insert(DicomTag(0x0040, 0x4028)); // Performed Station Name Code Sequence @@ -221,9 +199,6 @@ removals_.insert(DicomTag(0x0040, 0xa078)); // Author Observer Sequence removals_.insert(DicomTag(0x0040, 0xa07a)); // Participant Sequence removals_.insert(DicomTag(0x0040, 0xa07c)); // Custodial Organization Sequence -removals_.insert(DicomTag(0x0040, 0xa124)); /* TODO UID */ // UID -removals_.insert(DicomTag(0x0040, 0xa171)); /* TODO UID */ // Observation UID -removals_.insert(DicomTag(0x0040, 0xa172)); /* TODO UID */ // Referenced Observation UID (Trial) removals_.insert(DicomTag(0x0040, 0xa192)); // Observation Date (Trial) removals_.insert(DicomTag(0x0040, 0xa193)); // Observation Time (Trial) removals_.insert(DicomTag(0x0040, 0xa307)); // Current Observer (Trial) @@ -231,16 +206,8 @@ removals_.insert(DicomTag(0x0040, 0xa353)); // Address (Trial) removals_.insert(DicomTag(0x0040, 0xa354)); // Telephone Number (Trial) removals_.insert(DicomTag(0x0040, 0xa358)); // Verbal Source Identifier Code Sequence (Trial) -removals_.insert(DicomTag(0x0040, 0xa402)); /* TODO UID */ // Observation Subject UID (Trial) removals_.insert(DicomTag(0x0040, 0xa730)); // Content Sequence -removals_.insert(DicomTag(0x0040, 0xdb0c)); /* TODO UID */ // Template Extension Organization UID -removals_.insert(DicomTag(0x0040, 0xdb0d)); /* TODO UID */ // Template Extension Creator UID -removals_.insert(DicomTag(0x0062, 0x0021)); /* TODO UID */ // Tracking UID removals_.insert(DicomTag(0x0070, 0x0086)); // Content Creator's Identification Code Sequence -removals_.insert(DicomTag(0x0070, 0x031a)); /* TODO UID */ // Fiducial UID -removals_.insert(DicomTag(0x0070, 0x1101)); /* TODO UID */ // Presentation Display Collection UID -removals_.insert(DicomTag(0x0070, 0x1102)); /* TODO UID */ // Presentation Sequence Collection UID -removals_.insert(DicomTag(0x0088, 0x0140)); /* TODO UID */ // Storage Media File-set UID removals_.insert(DicomTag(0x0088, 0x0200)); // Icon Image Sequence(see Note 12) removals_.insert(DicomTag(0x0088, 0x0904)); // Topic Title removals_.insert(DicomTag(0x0088, 0x0906)); // Topic Subject @@ -254,7 +221,6 @@ removals_.insert(DicomTag(0x0400, 0x0561)); // Original Attributes Sequence removals_.insert(DicomTag(0x2030, 0x0020)); // Text String removals_.insert(DicomTag(0x3008, 0x0105)); // Source Serial Number -removals_.insert(DicomTag(0x300a, 0x0013)); /* TODO UID */ // Dose Reference UID removals_.insert(DicomTag(0x300c, 0x0113)); // Reason for Omission Description removals_.insert(DicomTag(0x300e, 0x0008)); /* X/Z */ // Reviewer Name removals_.insert(DicomTag(0x4000, 0x0010)); // Arbitrary @@ -275,3 +241,37 @@ removals_.insert(DicomTag(0x4008, 0x4000)); // Results Comments removals_.insert(DicomTag(0xfffa, 0xfffa)); // Digital Signatures Sequence removals_.insert(DicomTag(0xfffc, 0xfffc)); // Data Set Trailing Padding +removedRanges_.push_back(DicomTagRange(0x5000, 0x50ff, 0x0000, 0xffff)); // Curve Data +removedRanges_.push_back(DicomTagRange(0x6000, 0x60ff, 0x3000, 0x3000)); // Overlay Data +removedRanges_.push_back(DicomTagRange(0x6000, 0x60ff, 0x4000, 0x4000)); // Overlay Comments +uids_.insert(DicomTag(0x0000, 0x1001)); // Requested SOP Instance UID +uids_.insert(DicomTag(0x0002, 0x0003)); // Media Storage SOP Instance UID +uids_.insert(DicomTag(0x0004, 0x1511)); // Referenced SOP Instance UID in File +uids_.insert(DicomTag(0x0008, 0x0014)); // Instance Creator UID +uids_.insert(DicomTag(0x0008, 0x0058)); // Failed SOP Instance UID List +uids_.insert(DicomTag(0x0008, 0x1155)); // Referenced SOP Instance UID +uids_.insert(DicomTag(0x0008, 0x1195)); // Transaction UID +uids_.insert(DicomTag(0x0008, 0x3010)); // Irradiation Event UID +uids_.insert(DicomTag(0x0018, 0x1002)); // Device UID +uids_.insert(DicomTag(0x0018, 0x2042)); // Target UID +uids_.insert(DicomTag(0x0020, 0x0052)); // Frame of Reference UID +uids_.insert(DicomTag(0x0020, 0x0200)); // Synchronization Frame of Reference UID +uids_.insert(DicomTag(0x0020, 0x9161)); // Concatenation UID +uids_.insert(DicomTag(0x0020, 0x9164)); // Dimension Organization UID +uids_.insert(DicomTag(0x0028, 0x1199)); // Palette Color Lookup Table UID +uids_.insert(DicomTag(0x0028, 0x1214)); // Large Palette Color Lookup Table UID +uids_.insert(DicomTag(0x0040, 0x4023)); // Referenced General Purpose Scheduled Procedure Step Transaction UID +uids_.insert(DicomTag(0x0040, 0xa124)); // UID +uids_.insert(DicomTag(0x0040, 0xa171)); // Observation UID +uids_.insert(DicomTag(0x0040, 0xa172)); // Referenced Observation UID (Trial) +uids_.insert(DicomTag(0x0040, 0xa402)); // Observation Subject UID (Trial) +uids_.insert(DicomTag(0x0040, 0xdb0c)); // Template Extension Organization UID +uids_.insert(DicomTag(0x0040, 0xdb0d)); // Template Extension Creator UID +uids_.insert(DicomTag(0x0062, 0x0021)); // Tracking UID +uids_.insert(DicomTag(0x0070, 0x031a)); // Fiducial UID +uids_.insert(DicomTag(0x0070, 0x1101)); // Presentation Display Collection UID +uids_.insert(DicomTag(0x0070, 0x1102)); // Presentation Sequence Collection UID +uids_.insert(DicomTag(0x0088, 0x0140)); // Storage Media File-set UID +uids_.insert(DicomTag(0x3006, 0x0024)); // Referenced Frame of Reference UID +uids_.insert(DicomTag(0x3006, 0x00c2)); // Related Frame of Reference UID +uids_.insert(DicomTag(0x300a, 0x0013)); // Dose Reference UID diff -r 521e39b3f2c0 -r 2e850edf03d6 OrthancFramework/Sources/DicomParsing/DicomModification_Anonymization2021b.impl.h --- a/OrthancFramework/Sources/DicomParsing/DicomModification_Anonymization2021b.impl.h Thu Jun 03 21:06:34 2021 +0200 +++ b/OrthancFramework/Sources/DicomParsing/DicomModification_Anonymization2021b.impl.h Fri Jun 04 17:38:43 2021 +0200 @@ -1,17 +1,10 @@ -// TODO: (50xx,xxxx) with rule X // Curve Data -// TODO: (60xx,3000) with rule X // Overlay Data -// TODO: (60xx,4000) with rule X // Overlay Comments +// RelationshipsVisitor handles (0x0008, 0x1140) /* X/Z/U* */ // Referenced Image Sequence +// RelationshipsVisitor handles (0x0008, 0x2112) /* X/Z/U* */ // Source Image Sequence // Tag (0x0008, 0x0018) is set in Apply() /* U */ // SOP Instance UID -// Tag (0x0008, 0x1140) => RelationshipsVisitor /* X/Z/U* */ // Referenced Image Sequence -// Tag (0x0008, 0x1155) => RelationshipsVisitor /* U */ // Referenced SOP Instance UID -// Tag (0x0008, 0x2112) => RelationshipsVisitor /* X/Z/U* */ // Source Image Sequence // Tag (0x0010, 0x0010) is set below (*) /* Z */ // Patient's Name // Tag (0x0010, 0x0020) is set below (*) /* Z */ // Patient ID // Tag (0x0020, 0x000d) is set in Apply() /* U */ // Study Instance UID // Tag (0x0020, 0x000e) is set in Apply() /* U */ // Series Instance UID -// Tag (0x0020, 0x0052) => RelationshipsVisitor /* U */ // Frame of Reference UID -// Tag (0x3006, 0x0024) => RelationshipsVisitor /* U */ // Referenced Frame of Reference UID -// Tag (0x3006, 0x00c2) => RelationshipsVisitor /* U */ // Related Frame of Reference UID clearings_.insert(DicomTag(0x0008, 0x0020)); // Study Date clearings_.insert(DicomTag(0x0008, 0x0023)); /* Z/D */ // Content Date clearings_.insert(DicomTag(0x0008, 0x0030)); // Study Time @@ -98,10 +91,6 @@ clearings_.insert(DicomTag(0x3010, 0x007f)); // Fractionation Notes clearings_.insert(DicomTag(0x3010, 0x0081)); // Prescription Notes Sequence removals_.insert(DicomTag(0x0000, 0x1000)); // Affected SOP Instance UID -removals_.insert(DicomTag(0x0000, 0x1001)); /* TODO UID */ // Requested SOP Instance UID -removals_.insert(DicomTag(0x0002, 0x0003)); /* TODO UID */ // Media Storage SOP Instance UID -removals_.insert(DicomTag(0x0004, 0x1511)); /* TODO UID */ // Referenced SOP Instance UID in File -removals_.insert(DicomTag(0x0008, 0x0014)); /* TODO UID */ // Instance Creator UID removals_.insert(DicomTag(0x0008, 0x0015)); // Instance Coercion DateTime removals_.insert(DicomTag(0x0008, 0x0021)); /* X/D */ // Series Date removals_.insert(DicomTag(0x0008, 0x0022)); /* X/Z */ // Acquisition Date @@ -112,7 +101,6 @@ removals_.insert(DicomTag(0x0008, 0x0032)); /* X/Z */ // Acquisition Time removals_.insert(DicomTag(0x0008, 0x0034)); // Overlay Time removals_.insert(DicomTag(0x0008, 0x0035)); // Curve Time -removals_.insert(DicomTag(0x0008, 0x0058)); /* TODO UID */ // Failed SOP Instance UID List removals_.insert(DicomTag(0x0008, 0x0080)); /* X/Z/D */ // Institution Name removals_.insert(DicomTag(0x0008, 0x0081)); // Institution Address removals_.insert(DicomTag(0x0008, 0x0082)); /* X/Z/D */ // Institution Code Sequence @@ -139,9 +127,7 @@ removals_.insert(DicomTag(0x0008, 0x1110)); /* X/Z */ // Referenced Study Sequence removals_.insert(DicomTag(0x0008, 0x1111)); /* X/Z/D */ // Referenced Performed Procedure Step Sequence removals_.insert(DicomTag(0x0008, 0x1120)); // Referenced Patient Sequence -removals_.insert(DicomTag(0x0008, 0x1195)); /* TODO UID */ // Transaction UID removals_.insert(DicomTag(0x0008, 0x2111)); // Derivation Description -removals_.insert(DicomTag(0x0008, 0x3010)); /* TODO UID */ // Irradiation Event UID removals_.insert(DicomTag(0x0008, 0x4000)); // Identifying Comments removals_.insert(DicomTag(0x0010, 0x0021)); // Issuer of Patient ID removals_.insert(DicomTag(0x0010, 0x0032)); // Patient's Birth Time @@ -222,17 +208,14 @@ removals_.insert(DicomTag(0x0016, 0x008d)); // GPS Date Stamp removals_.insert(DicomTag(0x0016, 0x008e)); // GPS Differential removals_.insert(DicomTag(0x0018, 0x1000)); /* X/Z/D */ // Device Serial Number -removals_.insert(DicomTag(0x0018, 0x1002)); /* TODO UID */ // Device UID removals_.insert(DicomTag(0x0018, 0x1004)); // Plate ID removals_.insert(DicomTag(0x0018, 0x1005)); // Generator ID removals_.insert(DicomTag(0x0018, 0x1007)); // Cassette ID removals_.insert(DicomTag(0x0018, 0x1008)); // Gantry ID removals_.insert(DicomTag(0x0018, 0x1009)); // Unique Device Identifier removals_.insert(DicomTag(0x0018, 0x100a)); // UDI Sequence -removals_.insert(DicomTag(0x0018, 0x100b)); /* TODO UID */ // Manufacturer's Device Class UID removals_.insert(DicomTag(0x0018, 0x1030)); /* X/D */ // Protocol Name removals_.insert(DicomTag(0x0018, 0x1400)); /* X/D */ // Acquisition Device Processing Description -removals_.insert(DicomTag(0x0018, 0x2042)); /* TODO UID */ // Target UID removals_.insert(DicomTag(0x0018, 0x4000)); // Acquisition Comments removals_.insert(DicomTag(0x0018, 0x5011)); // Transducer Identification Sequence removals_.insert(DicomTag(0x0018, 0x700a)); /* X/D */ // Detector ID @@ -245,15 +228,10 @@ removals_.insert(DicomTag(0x0018, 0x9517)); /* X/D */ // End Acquisition DateTime removals_.insert(DicomTag(0x0018, 0x9937)); // Requested Series Description removals_.insert(DicomTag(0x0018, 0xa003)); // Contribution Description -removals_.insert(DicomTag(0x0020, 0x0200)); /* TODO UID */ // Synchronization Frame of Reference UID removals_.insert(DicomTag(0x0020, 0x3401)); // Modifying Device ID removals_.insert(DicomTag(0x0020, 0x3406)); // Modified Image Description removals_.insert(DicomTag(0x0020, 0x4000)); // Image Comments removals_.insert(DicomTag(0x0020, 0x9158)); // Frame Comments -removals_.insert(DicomTag(0x0020, 0x9161)); /* TODO UID */ // Concatenation UID -removals_.insert(DicomTag(0x0020, 0x9164)); /* TODO UID */ // Dimension Organization UID -removals_.insert(DicomTag(0x0028, 0x1199)); /* TODO UID */ // Palette Color Lookup Table UID -removals_.insert(DicomTag(0x0028, 0x1214)); /* TODO UID */ // Large Palette Color Lookup Table UID removals_.insert(DicomTag(0x0028, 0x4000)); // Image Presentation Comments removals_.insert(DicomTag(0x0032, 0x0012)); // Study ID Issuer removals_.insert(DicomTag(0x0032, 0x1020)); // Scheduled Study Location @@ -283,7 +261,6 @@ removals_.insert(DicomTag(0x0038, 0x0400)); // Patient's Institution Residence removals_.insert(DicomTag(0x0038, 0x0500)); // Patient State removals_.insert(DicomTag(0x0038, 0x4000)); // Visit Comments -removals_.insert(DicomTag(0x003a, 0x0310)); /* TODO UID */ // Multiplex Group UID removals_.insert(DicomTag(0x0040, 0x0001)); // Scheduled Station AE Title removals_.insert(DicomTag(0x0040, 0x0002)); // Scheduled Procedure Step Start Date removals_.insert(DicomTag(0x0040, 0x0003)); // Scheduled Procedure Step Start Time @@ -310,7 +287,6 @@ removals_.insert(DicomTag(0x0040, 0x0310)); // Comments on Radiation Dose removals_.insert(DicomTag(0x0040, 0x050a)); // Specimen Accession Number removals_.insert(DicomTag(0x0040, 0x051a)); // Container Description -removals_.insert(DicomTag(0x0040, 0x0554)); /* TODO UID */ // Specimen UID removals_.insert(DicomTag(0x0040, 0x0555)); /* X/Z */ // Acquisition Context Sequence removals_.insert(DicomTag(0x0040, 0x0600)); // Specimen Short Description removals_.insert(DicomTag(0x0040, 0x0602)); // Specimen Detailed Description @@ -337,7 +313,6 @@ removals_.insert(DicomTag(0x0040, 0x4008)); // Scheduled Procedure Step Expiration DateTime removals_.insert(DicomTag(0x0040, 0x4010)); // Scheduled Procedure Step Modification DateTime removals_.insert(DicomTag(0x0040, 0x4011)); // Expected Completion DateTime -removals_.insert(DicomTag(0x0040, 0x4023)); /* TODO UID */ // Referenced General Purpose Scheduled Procedure Step Transaction UID removals_.insert(DicomTag(0x0040, 0x4025)); // Scheduled Station Name Code Sequence removals_.insert(DicomTag(0x0040, 0x4027)); // Scheduled Station Geographic Location Code Sequence removals_.insert(DicomTag(0x0040, 0x4028)); // Performed Station Name Code Sequence @@ -352,9 +327,6 @@ removals_.insert(DicomTag(0x0040, 0xa078)); // Author Observer Sequence removals_.insert(DicomTag(0x0040, 0xa07a)); // Participant Sequence removals_.insert(DicomTag(0x0040, 0xa07c)); // Custodial Organization Sequence -removals_.insert(DicomTag(0x0040, 0xa124)); /* TODO UID */ // UID -removals_.insert(DicomTag(0x0040, 0xa171)); /* TODO UID */ // Observation UID -removals_.insert(DicomTag(0x0040, 0xa172)); /* TODO UID */ // Referenced Observation UID (Trial) removals_.insert(DicomTag(0x0040, 0xa192)); // Observation Date (Trial) removals_.insert(DicomTag(0x0040, 0xa193)); // Observation Time (Trial) removals_.insert(DicomTag(0x0040, 0xa307)); // Current Observer (Trial) @@ -362,24 +334,15 @@ removals_.insert(DicomTag(0x0040, 0xa353)); // Address (Trial) removals_.insert(DicomTag(0x0040, 0xa354)); // Telephone Number (Trial) removals_.insert(DicomTag(0x0040, 0xa358)); // Verbal Source Identifier Code Sequence (Trial) -removals_.insert(DicomTag(0x0040, 0xa402)); /* TODO UID */ // Observation Subject UID (Trial) -removals_.insert(DicomTag(0x0040, 0xdb0c)); /* TODO UID */ // Template Extension Organization UID -removals_.insert(DicomTag(0x0040, 0xdb0d)); /* TODO UID */ // Template Extension Creator UID removals_.insert(DicomTag(0x0050, 0x001b)); // Container Component ID removals_.insert(DicomTag(0x0050, 0x0020)); // Device Description removals_.insert(DicomTag(0x0050, 0x0021)); // Long Device Description -removals_.insert(DicomTag(0x0062, 0x0021)); /* TODO UID */ // Tracking UID removals_.insert(DicomTag(0x0070, 0x0086)); // Content Creator's Identification Code Sequence -removals_.insert(DicomTag(0x0070, 0x031a)); /* TODO UID */ // Fiducial UID -removals_.insert(DicomTag(0x0070, 0x1101)); /* TODO UID */ // Presentation Display Collection UID -removals_.insert(DicomTag(0x0070, 0x1102)); /* TODO UID */ // Presentation Sequence Collection UID -removals_.insert(DicomTag(0x0088, 0x0140)); /* TODO UID */ // Storage Media File-set UID removals_.insert(DicomTag(0x0088, 0x0200)); // Icon Image Sequence removals_.insert(DicomTag(0x0088, 0x0904)); // Topic Title removals_.insert(DicomTag(0x0088, 0x0906)); // Topic Subject removals_.insert(DicomTag(0x0088, 0x0910)); // Topic Author removals_.insert(DicomTag(0x0088, 0x0912)); // Topic Keywords -removals_.insert(DicomTag(0x0400, 0x0100)); /* TODO UID */ // Digital Signature UID removals_.insert(DicomTag(0x0400, 0x0402)); // Referenced Digital Signature Sequence removals_.insert(DicomTag(0x0400, 0x0403)); // Referenced SOP Instance MAC Sequence removals_.insert(DicomTag(0x0400, 0x0404)); // MAC @@ -407,10 +370,8 @@ removals_.insert(DicomTag(0x300a, 0x0006)); /* X/D */ // RT Plan Date removals_.insert(DicomTag(0x300a, 0x0007)); /* X/D */ // RT Plan Time removals_.insert(DicomTag(0x300a, 0x000e)); // Prescription Description -removals_.insert(DicomTag(0x300a, 0x0013)); /* TODO UID */ // Dose Reference UID removals_.insert(DicomTag(0x300a, 0x0016)); // Dose Reference Description removals_.insert(DicomTag(0x300a, 0x0072)); // Fraction Group Description -removals_.insert(DicomTag(0x300a, 0x0083)); /* TODO UID */ // Referenced Dose Reference UID removals_.insert(DicomTag(0x300a, 0x00b2)); /* X/Z */ // Treatment Machine Name removals_.insert(DicomTag(0x300a, 0x00c3)); // Beam Description removals_.insert(DicomTag(0x300a, 0x00dd)); // Bolus Description @@ -419,26 +380,15 @@ removals_.insert(DicomTag(0x300a, 0x01b2)); // Setup Technique Description removals_.insert(DicomTag(0x300a, 0x0216)); // Source Manufacturer removals_.insert(DicomTag(0x300a, 0x02eb)); // Compensator Description -removals_.insert(DicomTag(0x300a, 0x0609)); /* TODO UID */ // Treatment Position Group UID -removals_.insert(DicomTag(0x300a, 0x0650)); /* TODO UID */ // Patient Setup UID removals_.insert(DicomTag(0x300a, 0x0676)); // Equipment Frame of Reference Description -removals_.insert(DicomTag(0x300a, 0x0700)); /* TODO UID */ // Treatment Session UID removals_.insert(DicomTag(0x300c, 0x0113)); // Reason for Omission Description removals_.insert(DicomTag(0x300e, 0x0008)); /* X/Z */ // Reviewer Name -removals_.insert(DicomTag(0x3010, 0x0006)); /* TODO UID */ // Conceptual Volume UID -removals_.insert(DicomTag(0x3010, 0x000b)); /* TODO UID */ // Referenced Conceptual Volume UID -removals_.insert(DicomTag(0x3010, 0x0013)); /* TODO UID */ // Constituent Conceptual Volume UID -removals_.insert(DicomTag(0x3010, 0x0015)); /* TODO UID */ // Source Conceptual Volume UID -removals_.insert(DicomTag(0x3010, 0x0031)); /* TODO UID */ // Referenced Fiducials UID removals_.insert(DicomTag(0x3010, 0x0036)); // Entity Name removals_.insert(DicomTag(0x3010, 0x0037)); // Entity Description -removals_.insert(DicomTag(0x3010, 0x003b)); /* TODO UID */ // RT Treatment Phase UID removals_.insert(DicomTag(0x3010, 0x004c)); /* X/D */ // Intended Phase Start Date removals_.insert(DicomTag(0x3010, 0x004d)); /* X/D */ // Intended Phase End Date removals_.insert(DicomTag(0x3010, 0x0056)); /* X/D */ // RT Treatment Approach Label removals_.insert(DicomTag(0x3010, 0x0061)); // Prior Treatment Dose Description -removals_.insert(DicomTag(0x3010, 0x006e)); /* TODO UID */ // Dosimetric Objective UID -removals_.insert(DicomTag(0x3010, 0x006f)); /* TODO UID */ // Referenced Dosimetric Objective UID removals_.insert(DicomTag(0x4000, 0x0010)); // Arbitrary removals_.insert(DicomTag(0x4000, 0x4000)); // Text Comments removals_.insert(DicomTag(0x4008, 0x0042)); // Results ID Issuer @@ -457,3 +407,53 @@ removals_.insert(DicomTag(0x4008, 0x4000)); // Results Comments removals_.insert(DicomTag(0xfffa, 0xfffa)); // Digital Signatures Sequence removals_.insert(DicomTag(0xfffc, 0xfffc)); // Data Set Trailing Padding +removedRanges_.push_back(DicomTagRange(0x5000, 0x50ff, 0x0000, 0xffff)); // Curve Data +removedRanges_.push_back(DicomTagRange(0x6000, 0x60ff, 0x3000, 0x3000)); // Overlay Data +removedRanges_.push_back(DicomTagRange(0x6000, 0x60ff, 0x4000, 0x4000)); // Overlay Comments +uids_.insert(DicomTag(0x0000, 0x1001)); // Requested SOP Instance UID +uids_.insert(DicomTag(0x0002, 0x0003)); // Media Storage SOP Instance UID +uids_.insert(DicomTag(0x0004, 0x1511)); // Referenced SOP Instance UID in File +uids_.insert(DicomTag(0x0008, 0x0014)); // Instance Creator UID +uids_.insert(DicomTag(0x0008, 0x0058)); // Failed SOP Instance UID List +uids_.insert(DicomTag(0x0008, 0x1155)); // Referenced SOP Instance UID +uids_.insert(DicomTag(0x0008, 0x1195)); // Transaction UID +uids_.insert(DicomTag(0x0008, 0x3010)); // Irradiation Event UID +uids_.insert(DicomTag(0x0018, 0x1002)); // Device UID +uids_.insert(DicomTag(0x0018, 0x100b)); // Manufacturer's Device Class UID +uids_.insert(DicomTag(0x0018, 0x2042)); // Target UID +uids_.insert(DicomTag(0x0020, 0x0052)); // Frame of Reference UID +uids_.insert(DicomTag(0x0020, 0x0200)); // Synchronization Frame of Reference UID +uids_.insert(DicomTag(0x0020, 0x9161)); // Concatenation UID +uids_.insert(DicomTag(0x0020, 0x9164)); // Dimension Organization UID +uids_.insert(DicomTag(0x0028, 0x1199)); // Palette Color Lookup Table UID +uids_.insert(DicomTag(0x0028, 0x1214)); // Large Palette Color Lookup Table UID +uids_.insert(DicomTag(0x003a, 0x0310)); // Multiplex Group UID +uids_.insert(DicomTag(0x0040, 0x0554)); // Specimen UID +uids_.insert(DicomTag(0x0040, 0x4023)); // Referenced General Purpose Scheduled Procedure Step Transaction UID +uids_.insert(DicomTag(0x0040, 0xa124)); // UID +uids_.insert(DicomTag(0x0040, 0xa171)); // Observation UID +uids_.insert(DicomTag(0x0040, 0xa172)); // Referenced Observation UID (Trial) +uids_.insert(DicomTag(0x0040, 0xa402)); // Observation Subject UID (Trial) +uids_.insert(DicomTag(0x0040, 0xdb0c)); // Template Extension Organization UID +uids_.insert(DicomTag(0x0040, 0xdb0d)); // Template Extension Creator UID +uids_.insert(DicomTag(0x0062, 0x0021)); // Tracking UID +uids_.insert(DicomTag(0x0070, 0x031a)); // Fiducial UID +uids_.insert(DicomTag(0x0070, 0x1101)); // Presentation Display Collection UID +uids_.insert(DicomTag(0x0070, 0x1102)); // Presentation Sequence Collection UID +uids_.insert(DicomTag(0x0088, 0x0140)); // Storage Media File-set UID +uids_.insert(DicomTag(0x0400, 0x0100)); // Digital Signature UID +uids_.insert(DicomTag(0x3006, 0x0024)); // Referenced Frame of Reference UID +uids_.insert(DicomTag(0x3006, 0x00c2)); // Related Frame of Reference UID +uids_.insert(DicomTag(0x300a, 0x0013)); // Dose Reference UID +uids_.insert(DicomTag(0x300a, 0x0083)); // Referenced Dose Reference UID +uids_.insert(DicomTag(0x300a, 0x0609)); // Treatment Position Group UID +uids_.insert(DicomTag(0x300a, 0x0650)); // Patient Setup UID +uids_.insert(DicomTag(0x300a, 0x0700)); // Treatment Session UID +uids_.insert(DicomTag(0x3010, 0x0006)); // Conceptual Volume UID +uids_.insert(DicomTag(0x3010, 0x000b)); // Referenced Conceptual Volume UID +uids_.insert(DicomTag(0x3010, 0x0013)); // Constituent Conceptual Volume UID +uids_.insert(DicomTag(0x3010, 0x0015)); // Source Conceptual Volume UID +uids_.insert(DicomTag(0x3010, 0x0031)); // Referenced Fiducials UID +uids_.insert(DicomTag(0x3010, 0x003b)); // RT Treatment Phase UID +uids_.insert(DicomTag(0x3010, 0x006e)); // Dosimetric Objective UID +uids_.insert(DicomTag(0x3010, 0x006f)); // Referenced Dosimetric Objective UID diff -r 521e39b3f2c0 -r 2e850edf03d6 OrthancServer/Resources/GenerateAnonymizationProfile.py --- a/OrthancServer/Resources/GenerateAnonymizationProfile.py Thu Jun 03 21:06:34 2021 +0200 +++ b/OrthancServer/Resources/GenerateAnonymizationProfile.py Fri Jun 04 17:38:43 2021 +0200 @@ -62,7 +62,7 @@ indentation = 65 if len(command) > indentation: - raise Exception('Too long command') + indentation = len(command) + 2 line = command + (' ' * (indentation - len(command))) + '// ' + name LINES.append(line) @@ -71,7 +71,7 @@ FormatLine('// TODO: %s with rule %s' % (rawTag, profile), name) -RAW_TAG_RE = re.compile(r'^\(\s*([0-9A-F]{4})\s*,\s*([0-9A-F]{4})\s*\)$') +RAW_TAG_RE = re.compile(r'^\(\s*([0-9A-Fx]{4})\s*,\s*([0-9A-Fx]{4})\s*\)$') for table in root.iter('%stable' % br): @@ -86,30 +86,37 @@ match = RAW_TAG_RE.match(rawTag) if match == None: - FormatUnknown(rawTag, name, profile) + raise Exception('Unsupported rule: %s, %s, %s' % (rawTag, profile, name)) else: - tag = '0x%s, 0x%s' % (match.group(1).lower(), match.group(2).lower()) + group = match.group(1).lower() + element = match.group(2).lower() + tag = '0x%s, 0x%s' % (group, element) - if name in [ - 'SOP Instance UID', - 'Series Instance UID', - 'Study Instance UID', + if 'x' in group or 'x' in element: + if profile == 'X': + groupFrom = group.replace('x', '0') + groupTo = group.replace('x', 'f') + elementFrom = element.replace('x', '0') + elementTo = element.replace('x', 'f') + FormatLine('removedRanges_.push_back(DicomTagRange(0x%s, 0x%s, 0x%s, 0x%s));' % ( + groupFrom, groupTo, elementFrom, elementTo), name) + else: + raise Exception('Unsupported rule: %s, %s, %s' % (rawTag, profile, name)) + elif tag in [ + '0x0008, 0x0018', # SOP Instance UID + '0x0020, 0x000e', # Series Instance UID + '0x0020, 0x000d', # Study Instance UID ]: FormatLine('// Tag (%s) is set in Apply() /* %s */' % (tag, profile), name) - elif name in [ - 'Referenced Image Sequence', - 'Source Image Sequence', - 'Referenced SOP Instance UID', - 'Frame of Reference UID', - 'Referenced Frame of Reference UID', - 'Related Frame of Reference UID', - ]: - FormatLine('// Tag (%s) => RelationshipsVisitor /* %s */' % (tag, profile), name) - elif name in [ - 'Patient\'s Name', - 'Patient ID', + elif tag in [ + '0x0010, 0x0010', # Patient's Name + '0x0010, 0x0020', # Patient ID ]: FormatLine('// Tag (%s) is set below (*) /* %s */' % (tag, profile), name) + elif profile == 'U': + FormatLine('uids_.insert(DicomTag(%s));' % (tag), name) + elif profile == 'X/Z/U*': + FormatLine('// RelationshipsVisitor handles (%s) /* %s */' % (tag, profile), name) elif profile == 'X': FormatLine('removals_.insert(DicomTag(%s));' % tag, name) elif profile.startswith('X/'): @@ -118,10 +125,9 @@ FormatLine('clearings_.insert(DicomTag(%s));' % tag, name) elif profile == 'D' or profile.startswith('Z/'): FormatLine('clearings_.insert(DicomTag(%s)); /* %s */' % (tag, profile), name) - elif profile == 'U': - FormatLine('removals_.insert(DicomTag(%s)); /* TODO UID */' % (tag), name) else: - FormatUnknown(rawTag, name, profile) + # FormatUnknown(rawTag, name, profile) + raise Exception('Unsupported rule: %s, %s, %s' % (rawTag, profile, name)) for line in sorted(LINES): print(line.encode('ascii', 'ignore').decode('ascii')) diff -r 521e39b3f2c0 -r 2e850edf03d6 OrthancServer/UnitTestsSources/ServerJobsTests.cpp --- a/OrthancServer/UnitTestsSources/ServerJobsTests.cpp Thu Jun 03 21:06:34 2021 +0200 +++ b/OrthancServer/UnitTestsSources/ServerJobsTests.cpp Fri Jun 04 17:38:43 2021 +0200 @@ -698,6 +698,24 @@ ASSERT_EQ(RequestOrigin_Lua, tmp.GetRequestOrigin()); ASSERT_TRUE(tmp.GetModification().IsRemoved(DICOM_TAG_STUDY_DESCRIPTION)); } + + { + std::unique_ptr modification(new DicomModification); + modification->SetupAnonymization(DicomVersion_2021b); + + ModifyInstanceOperation operation(GetContext(), RequestOrigin_Lua, modification.release()); + + ASSERT_TRUE(CheckIdempotentSerialization(unserializer, operation)); + operation.Serialize(s); + } + + { + operation.reset(unserializer.UnserializeOperation(s)); + + const ModifyInstanceOperation& tmp = dynamic_cast(*operation); + ASSERT_EQ(RequestOrigin_Lua, tmp.GetRequestOrigin()); + ASSERT_TRUE(tmp.GetModification().IsRemoved(DICOM_TAG_STUDY_DESCRIPTION)); + } }