# HG changeset patch # User Sebastien Jodogne # Date 1404294968 -7200 # Node ID 2f76b92addd4d02c4686db70fd48ce14d6019f20 # Parent 7cbcd580cd2124bcafe13f9527615d1c2c753996 keep private tags during anonymization diff -r 7cbcd580cd21 -r 2f76b92addd4 OrthancServer/DicomModification.cpp --- a/OrthancServer/DicomModification.cpp Tue Jul 01 17:17:45 2014 +0200 +++ b/OrthancServer/DicomModification.cpp Wed Jul 02 11:56:08 2014 +0200 @@ -96,12 +96,18 @@ { removals_.erase(tag); replacements_.erase(tag); + + if (FromDcmtkBridge::IsPrivateTag(tag)) + { + privateTagsToKeep_.insert(tag); + } } void DicomModification::Remove(const DicomTag& tag) { removals_.insert(tag); replacements_.erase(tag); + privateTagsToKeep_.erase(tag); } bool DicomModification::IsRemoved(const DicomTag& tag) const @@ -113,6 +119,7 @@ const std::string& value) { removals_.erase(tag); + privateTagsToKeep_.erase(tag); replacements_[tag] = value; } @@ -153,6 +160,7 @@ removePrivateTags_ = true; level_ = ResourceType_Patient; uidMap_.clear(); + privateTagsToKeep_.clear(); // This is Table E.1-1 from PS 3.15-2008 - DICOM Part 15: Security and System Management Profiles removals_.insert(DicomTag(0x0008, 0x0014)); // Instance Creator UID @@ -261,11 +269,11 @@ // (1) Remove the private tags, if need be if (removePrivateTags_) { - toModify.RemovePrivateTags(); + toModify.RemovePrivateTags(privateTagsToKeep_); } // (2) Remove the tags specified by the user - for (Removals::const_iterator it = removals_.begin(); + for (SetOfTags::const_iterator it = removals_.begin(); it != removals_.end(); ++it) { toModify.Remove(*it); diff -r 7cbcd580cd21 -r 2f76b92addd4 OrthancServer/DicomModification.h --- a/OrthancServer/DicomModification.h Tue Jul 01 17:17:45 2014 +0200 +++ b/OrthancServer/DicomModification.h Wed Jul 02 11:56:08 2014 +0200 @@ -46,15 +46,16 @@ **/ private: - typedef std::set Removals; + typedef std::set SetOfTags; typedef std::map Replacements; typedef std::map< std::pair, std::string> UidMap; - Removals removals_; + SetOfTags removals_; Replacements replacements_; bool removePrivateTags_; ResourceType level_; UidMap uidMap_; + SetOfTags privateTagsToKeep_; void MapDicomIdentifier(ParsedDicomFile& dicom, ResourceType level); diff -r 7cbcd580cd21 -r 2f76b92addd4 OrthancServer/FromDcmtkBridge.cpp --- a/OrthancServer/FromDcmtkBridge.cpp Tue Jul 01 17:17:45 2014 +0200 +++ b/OrthancServer/FromDcmtkBridge.cpp Wed Jul 02 11:56:08 2014 +0200 @@ -168,12 +168,32 @@ } + DicomTag FromDcmtkBridge::Convert(const DcmTag& tag) + { + return DicomTag(tag.getGTag(), tag.getETag()); + } + + DicomTag FromDcmtkBridge::GetTag(const DcmElement& element) { return DicomTag(element.getGTag(), element.getETag()); } + bool FromDcmtkBridge::IsPrivateTag(DcmTag& tag) + { + return (tag.getPrivateCreator() != NULL || + !strcmp("PrivateCreator", tag.getTagName())); // TODO - This may change with future versions of DCMTK + } + + + bool FromDcmtkBridge::IsPrivateTag(const DicomTag& tag) + { + DcmTag tmp(tag.GetGroup(), tag.GetElement()); + return IsPrivateTag(tmp); + } + + DicomValue* FromDcmtkBridge::ConvertLeafElement(DcmElement& element, Encoding encoding) { @@ -516,7 +536,7 @@ isxdigit(name[1]) && isxdigit(name[2]) && isxdigit(name[3]) && - name[4] == '-' && + (name[4] == '-' || name[4] == ',') && isxdigit(name[5]) && isxdigit(name[6]) && isxdigit(name[7]) && diff -r 7cbcd580cd21 -r 2f76b92addd4 OrthancServer/FromDcmtkBridge.h --- a/OrthancServer/FromDcmtkBridge.h Tue Jul 01 17:17:45 2014 +0200 +++ b/OrthancServer/FromDcmtkBridge.h Wed Jul 02 11:56:08 2014 +0200 @@ -48,8 +48,14 @@ static void Convert(DicomMap& target, DcmDataset& dataset); + static DicomTag Convert(const DcmTag& tag); + static DicomTag GetTag(const DcmElement& element); + static bool IsPrivateTag(DcmTag& tag); + + static bool IsPrivateTag(const DicomTag& tag); + static DicomValue* ConvertLeafElement(DcmElement& element, Encoding encoding); diff -r 7cbcd580cd21 -r 2f76b92addd4 OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp Tue Jul 01 17:17:45 2014 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp Wed Jul 02 11:56:08 2014 +0200 @@ -174,7 +174,8 @@ ParseListOfTags(target, request["Keep"], TagOperation_Keep); } - if (target.GetReplacement(DICOM_TAG_PATIENT_NAME) == patientName) + if (target.IsReplaced(DICOM_TAG_PATIENT_NAME) && + target.GetReplacement(DICOM_TAG_PATIENT_NAME) == patientName) { // Overwrite the random Patient's Name by one that is more // user-friendly (provided none was specified by the user) diff -r 7cbcd580cd21 -r 2f76b92addd4 OrthancServer/ParsedDicomFile.cpp --- a/OrthancServer/ParsedDicomFile.cpp Tue Jul 01 17:17:45 2014 +0200 +++ b/OrthancServer/ParsedDicomFile.cpp Wed Jul 02 11:56:08 2014 +0200 @@ -756,24 +756,42 @@ - void ParsedDicomFile::RemovePrivateTags() + void ParsedDicomFile::RemovePrivateTagsInternal(const std::set* toKeep) { + DcmDataset& dataset = *pimpl_->file_->getDataset(); + + // Loop over the dataset to detect its private tags typedef std::list Tags; - Tags privateTags; - DcmDataset& dataset = *pimpl_->file_->getDataset(); for (unsigned long i = 0; i < dataset.card(); i++) { DcmElement* element = dataset.getElement(i); DcmTag tag(element->getTag()); - if (!strcmp("PrivateCreator", tag.getTagName()) || // TODO - This may change with future versions of DCMTK - tag.getPrivateCreator() != NULL) + + // Is this a private tag? + if (FromDcmtkBridge::IsPrivateTag(tag)) { - privateTags.push_back(element); + bool remove = true; + + // Check whether this private tag is to be kept + if (toKeep != NULL) + { + DicomTag tmp = FromDcmtkBridge::Convert(tag); + if (toKeep->find(tmp) != toKeep->end()) + { + remove = false; // Keep it + } + } + + if (remove) + { + privateTags.push_back(element); + } } } + // Loop over the detected private tags to remove them for (Tags::iterator it = privateTags.begin(); it != privateTags.end(); ++it) { diff -r 7cbcd580cd21 -r 2f76b92addd4 OrthancServer/ParsedDicomFile.h --- a/OrthancServer/ParsedDicomFile.h Tue Jul 01 17:17:45 2014 +0200 +++ b/OrthancServer/ParsedDicomFile.h Wed Jul 02 11:56:08 2014 +0200 @@ -51,6 +51,8 @@ void Setup(const char* content, size_t size); + void RemovePrivateTagsInternal(const std::set* toKeep); + public: ParsedDicomFile(); // Create a minimal DICOM instance @@ -79,7 +81,15 @@ const std::string& value, DicomReplaceMode mode = DicomReplaceMode_InsertIfAbsent); - void RemovePrivateTags(); + void RemovePrivateTags() + { + RemovePrivateTagsInternal(NULL); + } + + void RemovePrivateTags(const std::set& toKeep) + { + RemovePrivateTagsInternal(&toKeep); + } bool GetTagValue(std::string& value, const DicomTag& tag); diff -r 7cbcd580cd21 -r 2f76b92addd4 UnitTestsSources/FromDcmtkTests.cpp --- a/UnitTestsSources/FromDcmtkTests.cpp Tue Jul 01 17:17:45 2014 +0200 +++ b/UnitTestsSources/FromDcmtkTests.cpp Wed Jul 02 11:56:08 2014 +0200 @@ -40,6 +40,7 @@ #include "../Core/ImageFormats/ImageBuffer.h" #include "../Core/ImageFormats/PngReader.h" #include "../Core/ImageFormats/PngWriter.h" +#include "../Core/Uuid.h" using namespace Orthanc; @@ -85,6 +86,36 @@ } +TEST(DicomModification, Anonymization) +{ + const DicomTag privateTag(0x0045, 0x0010); + ASSERT_TRUE(FromDcmtkBridge::IsPrivateTag(privateTag)); + + ParsedDicomFile o; + o.Replace(DICOM_TAG_PATIENT_NAME, "coucou"); + o.Replace(privateTag, "private tag"); + + std::string s; + ASSERT_TRUE(o.GetTagValue(s, DICOM_TAG_PATIENT_NAME)); + ASSERT_FALSE(Toolbox::IsUuid(s)); + + DicomModification m; + m.SetupAnonymization(); + m.Keep(privateTag); + + m.Apply(o); + + ASSERT_TRUE(o.GetTagValue(s, DICOM_TAG_PATIENT_NAME)); + ASSERT_TRUE(Toolbox::IsUuid(s)); + ASSERT_TRUE(o.GetTagValue(s, privateTag)); + ASSERT_EQ("private tag", s); + + m.SetupAnonymization(); + m.Apply(o); + ASSERT_FALSE(o.GetTagValue(s, privateTag)); +} + + #include TEST(DicomModification, Png)