# HG changeset patch # User Sebastien Jodogne # Date 1399288030 -7200 # Node ID b6d6b65142e8786ac6d7ca0a11d78d0d5dfd9fbe # Parent 7cbed653476fe80871a6ff5ab6de68747b78e500 DicomModification diff -r 7cbed653476f -r b6d6b65142e8 CMakeLists.txt --- a/CMakeLists.txt Fri May 02 15:12:09 2014 +0200 +++ b/CMakeLists.txt Mon May 05 13:07:10 2014 +0200 @@ -204,6 +204,7 @@ OrthancServer/DicomProtocol/DicomServer.cpp OrthancServer/DicomProtocol/DicomUserConnection.cpp OrthancServer/DicomProtocol/ReusableDicomUserConnection.cpp + OrthancServer/DicomModification.cpp OrthancServer/FromDcmtkBridge.cpp OrthancServer/Internals/CommandDispatcher.cpp OrthancServer/Internals/FindScp.cpp diff -r 7cbed653476f -r b6d6b65142e8 NEWS --- a/NEWS Fri May 02 15:12:09 2014 +0200 +++ b/NEWS Mon May 05 13:07:10 2014 +0200 @@ -4,7 +4,7 @@ * Dynamic negotiation of SOP classes for C-Store SCU * Reuse of the previous SCU connection to avoid unecessary handshakes * Fix missing licensing terms about reuse of some DCMTK code -* Some refactorings +* Refactorings Version 0.7.4 (2014/04/16) diff -r 7cbed653476f -r b6d6b65142e8 OrthancServer/DicomModification.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/DicomModification.cpp Mon May 05 13:07:10 2014 +0200 @@ -0,0 +1,291 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2014 Medical Physics Department, CHU of Liege, + * Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#include "DicomModification.h" + +#include "../Core/OrthancException.h" + +namespace Orthanc +{ + void DicomModification::MapDicomIdentifier(ParsedDicomFile& dicom, + DicomRootLevel level) + { + std::auto_ptr tag; + + switch (level) + { + case DicomRootLevel_Study: + tag.reset(new DicomTag(DICOM_TAG_STUDY_INSTANCE_UID)); + break; + + case DicomRootLevel_Series: + tag.reset(new DicomTag(DICOM_TAG_SERIES_INSTANCE_UID)); + break; + + case DicomRootLevel_Instance: + tag.reset(new DicomTag(DICOM_TAG_SOP_INSTANCE_UID)); + break; + + default: + throw OrthancException(ErrorCode_InternalError); + } + + std::string original; + if (!dicom.GetTagValue(original, *tag)) + { + original = ""; + } + + std::string mapped; + + UidMap::const_iterator previous = uidMap_.find(std::make_pair(level, original)); + if (previous == uidMap_.end()) + { + mapped = FromDcmtkBridge::GenerateUniqueIdentifier(level); + uidMap_.insert(std::make_pair(std::make_pair(level, original), mapped)); + } + else + { + mapped = previous->second; + } + + dicom.Replace(*tag, mapped); + } + + DicomModification::DicomModification() + { + removePrivateTags_ = false; + level_ = DicomRootLevel_Instance; + } + + void DicomModification::Reset(const DicomTag& tag) + { + removals_.erase(tag); + replacements_.erase(tag); + } + + void DicomModification::Remove(const DicomTag& tag) + { + removals_.insert(tag); + replacements_.erase(tag); + } + + bool DicomModification::IsRemoved(const DicomTag& tag) const + { + return removals_.find(tag) != removals_.end(); + } + + void DicomModification::Replace(const DicomTag& tag, + const std::string& value) + { + removals_.erase(tag); + replacements_[tag] = value; + } + + bool DicomModification::IsReplaced(const DicomTag& tag) const + { + return replacements_.find(tag) != replacements_.end(); + } + + const std::string& DicomModification::GetReplacement(const DicomTag& tag) const + { + Replacements::const_iterator it = replacements_.find(tag); + + if (it == replacements_.end()) + { + throw OrthancException(ErrorCode_InexistentItem); + } + else + { + return it->second; + } + } + + void DicomModification::SetRemovePrivateTags(bool removed) + { + removePrivateTags_ = removed; + } + + void DicomModification::SetLevel(DicomRootLevel level) + { + uidMap_.clear(); + level_ = level; + } + + void DicomModification::SetupAnonymization() + { + removals_.clear(); + replacements_.clear(); + removePrivateTags_ = true; + level_ = DicomRootLevel_Patient; + uidMap_.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 + //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 + removals_.insert(DicomTag(0x0008, 0x0081)); // Institution Address + removals_.insert(DicomTag(0x0008, 0x0090)); // Referring Physician's Name + removals_.insert(DicomTag(0x0008, 0x0092)); // Referring Physician's Address + removals_.insert(DicomTag(0x0008, 0x0094)); // Referring Physician's Telephone Numbers + removals_.insert(DicomTag(0x0008, 0x1010)); // Station Name + removals_.insert(DicomTag(0x0008, 0x1030)); // Study Description + removals_.insert(DicomTag(0x0008, 0x103e)); // Series Description + removals_.insert(DicomTag(0x0008, 0x1040)); // Institutional Department Name + removals_.insert(DicomTag(0x0008, 0x1048)); // Physician(s) of Record + removals_.insert(DicomTag(0x0008, 0x1050)); // Performing Physicians' Name + 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 + 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 (*) + removals_.insert(DicomTag(0x0010, 0x0030)); // Patient's Birth Date + removals_.insert(DicomTag(0x0010, 0x0032)); // Patient's Birth Time + removals_.insert(DicomTag(0x0010, 0x0040)); // Patient's Sex + removals_.insert(DicomTag(0x0010, 0x1000)); // Other Patient Ids + removals_.insert(DicomTag(0x0010, 0x1001)); // Other Patient Names + removals_.insert(DicomTag(0x0010, 0x1010)); // Patient's Age + removals_.insert(DicomTag(0x0010, 0x1020)); // Patient's Size + removals_.insert(DicomTag(0x0010, 0x1030)); // Patient's Weight + removals_.insert(DicomTag(0x0010, 0x1090)); // Medical Record Locator + removals_.insert(DicomTag(0x0010, 0x2160)); // Ethnic Group + removals_.insert(DicomTag(0x0010, 0x2180)); // Occupation + removals_.insert(DicomTag(0x0010, 0x21b0)); // Additional Patient's History + removals_.insert(DicomTag(0x0010, 0x4000)); // Patient Comments + removals_.insert(DicomTag(0x0018, 0x1000)); // Device Serial Number + removals_.insert(DicomTag(0x0018, 0x1030)); // Protocol Name + //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 + removals_.insert(DicomTag(0x0020, 0x0200)); // Synchronization Frame of Reference UID + removals_.insert(DicomTag(0x0020, 0x4000)); // Image Comments + removals_.insert(DicomTag(0x0040, 0x0275)); // Request Attributes Sequence + removals_.insert(DicomTag(0x0040, 0xa124)); // UID + 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 + removals_.insert(DicomTag(0x3006, 0x00c2)); // Related Frame of Reference UID + + // Some more removals (from the experience of DICOM files at the CHU of Liege) + removals_.insert(DicomTag(0x0010, 0x1040)); // Patient's Address + removals_.insert(DicomTag(0x0032, 0x1032)); // Requesting Physician + removals_.insert(DicomTag(0x0010, 0x2154)); // PatientTelephoneNumbers + removals_.insert(DicomTag(0x0010, 0x2000)); // Medical Alerts + + // Set the DeidentificationMethod tag + replacements_.insert(std::make_pair(DicomTag(0x0012, 0x0063), "Orthanc " ORTHANC_VERSION " - PS 3.15-2008 Table E.1-1")); + + // Set the PatientIdentityRemoved tag + replacements_.insert(std::make_pair(DicomTag(0x0012, 0x0062), "YES")); + + // (*) Choose a random patient name and ID + std::string patientId = FromDcmtkBridge::GenerateUniqueIdentifier(DicomRootLevel_Patient); + replacements_[DICOM_TAG_PATIENT_ID] = patientId; + replacements_[DICOM_TAG_PATIENT_NAME] = patientId; + } + + void DicomModification::Apply(ParsedDicomFile& toModify) + { + // Check the request + assert(DicomRootLevel_Patient + 1 == DicomRootLevel_Study && + DicomRootLevel_Study + 1 == DicomRootLevel_Series && + DicomRootLevel_Series + 1 == DicomRootLevel_Instance); + + if (IsRemoved(DICOM_TAG_PATIENT_ID) || + IsRemoved(DICOM_TAG_STUDY_INSTANCE_UID) || + IsRemoved(DICOM_TAG_SERIES_INSTANCE_UID) || + IsRemoved(DICOM_TAG_SOP_INSTANCE_UID)) + { + throw OrthancException(ErrorCode_BadRequest); + } + + if (level_ == DicomRootLevel_Patient && !IsReplaced(DICOM_TAG_PATIENT_ID)) + { + throw OrthancException(ErrorCode_BadRequest); + } + + if (level_ > DicomRootLevel_Patient && IsReplaced(DICOM_TAG_PATIENT_ID)) + { + throw OrthancException(ErrorCode_BadRequest); + } + + if (level_ > DicomRootLevel_Study && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) + { + throw OrthancException(ErrorCode_BadRequest); + } + + if (level_ > DicomRootLevel_Series && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) + { + throw OrthancException(ErrorCode_BadRequest); + } + + // (1) Remove the private tags, if need be + if (removePrivateTags_) + { + toModify.RemovePrivateTags(); + } + + // (2) Remove the tags specified by the user + for (Removals::const_iterator it = removals_.begin(); + it != removals_.end(); ++it) + { + toModify.Remove(*it); + } + + // (3) Replace the tags + for (Replacements::const_iterator it = replacements_.begin(); + it != replacements_.end(); ++it) + { + toModify.Replace(it->first, it->second, DicomReplaceMode_InsertIfAbsent); + } + + // (4) Update the DICOM identifiers + if (level_ <= DicomRootLevel_Study) + { + MapDicomIdentifier(toModify, DicomRootLevel_Study); + } + + if (level_ <= DicomRootLevel_Series) + { + MapDicomIdentifier(toModify, DicomRootLevel_Series); + } + + if (level_ <= DicomRootLevel_Instance) // Always true + { + MapDicomIdentifier(toModify, DicomRootLevel_Instance); + } + } +} diff -r 7cbed653476f -r b6d6b65142e8 OrthancServer/DicomModification.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OrthancServer/DicomModification.h Mon May 05 13:07:10 2014 +0200 @@ -0,0 +1,96 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2014 Medical Physics Department, CHU of Liege, + * Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * In addition, as a special exception, the copyright holders of this + * program give permission to link the code of its release with the + * OpenSSL project's "OpenSSL" library (or with modified versions of it + * that use the same license as the "OpenSSL" library), and distribute + * the linked executables. You must obey the GNU General Public License + * in all respects for all of the code used other than "OpenSSL". If you + * modify file(s) with this exception, you may extend this exception to + * your version of the file(s), but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. If you delete this exception statement from all source files + * in the program, then also delete it here. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "FromDcmtkBridge.h" + +namespace Orthanc +{ + class DicomModification + { + /** + * Process: + * (1) Remove private tags + * (2) Remove tags specified by the user + * (3) Replace tags + **/ + + private: + typedef std::set Removals; + typedef std::map Replacements; + typedef std::map< std::pair, std::string> UidMap; + + Removals removals_; + Replacements replacements_; + bool removePrivateTags_; + DicomRootLevel level_; + UidMap uidMap_; + + void MapDicomIdentifier(ParsedDicomFile& dicom, + DicomRootLevel level); + + public: + DicomModification(); + + void Reset(const DicomTag& tag); + + void Remove(const DicomTag& tag); + + bool IsRemoved(const DicomTag& tag) const; + + void Replace(const DicomTag& tag, + const std::string& value); + + bool IsReplaced(const DicomTag& tag) const; + + const std::string& GetReplacement(const DicomTag& tag) const; + + void SetRemovePrivateTags(bool removed); + + bool ArePrivateTagsRemoved() const + { + return removePrivateTags_; + } + + void SetLevel(DicomRootLevel level); + + DicomRootLevel GetLevel() const + { + return level_; + } + + void SetupAnonymization(); + + void Apply(ParsedDicomFile& toModify); + }; +} diff -r 7cbed653476f -r b6d6b65142e8 UnitTestsSources/FromDcmtk.cpp --- a/UnitTestsSources/FromDcmtk.cpp Fri May 02 15:12:09 2014 +0200 +++ b/UnitTestsSources/FromDcmtk.cpp Mon May 05 13:07:10 2014 +0200 @@ -2,6 +2,7 @@ #include "../OrthancServer/FromDcmtkBridge.h" #include "../OrthancServer/OrthancInitialization.h" +#include "../OrthancServer/DicomModification.h" #include "../Core/OrthancException.h" using namespace Orthanc; @@ -24,300 +25,6 @@ } -namespace Orthanc -{ - class DicomModification - { - /** - * Process: - * (1) Remove private tags - * (2) Remove tags specified by the user - * (3) Replace tags - **/ - - private: - typedef std::set Removals; - typedef std::map Replacements; - typedef std::map< std::pair, std::string> UidMap; - - Removals removals_; - Replacements replacements_; - bool removePrivateTags_; - DicomRootLevel level_; - UidMap uidMap_; - - void MapDicomIdentifier(ParsedDicomFile& dicom, - DicomRootLevel level) - { - std::auto_ptr tag; - - switch (level) - { - case DicomRootLevel_Study: - tag.reset(new DicomTag(DICOM_TAG_STUDY_INSTANCE_UID)); - break; - - case DicomRootLevel_Series: - tag.reset(new DicomTag(DICOM_TAG_SERIES_INSTANCE_UID)); - break; - - case DicomRootLevel_Instance: - tag.reset(new DicomTag(DICOM_TAG_SOP_INSTANCE_UID)); - break; - - default: - throw OrthancException(ErrorCode_InternalError); - } - - std::string original; - if (!dicom.GetTagValue(original, *tag)) - { - original = ""; - } - - std::string mapped; - //bool isNew; - - UidMap::const_iterator previous = uidMap_.find(std::make_pair(level, original)); - if (previous == uidMap_.end()) - { - mapped = FromDcmtkBridge::GenerateUniqueIdentifier(level); - uidMap_.insert(std::make_pair(std::make_pair(level, original), mapped)); - //isNew = true; - } - else - { - mapped = previous->second; - //isNew = false; - } - - dicom.Replace(*tag, mapped); - - //return isNew; - } - - public: - DicomModification() - { - removePrivateTags_ = false; - level_ = DicomRootLevel_Instance; - } - - void Keep(const DicomTag& tag) - { - removals_.erase(tag); - } - - void Remove(const DicomTag& tag) - { - removals_.insert(tag); - replacements_.erase(tag); - } - - bool IsRemoved(const DicomTag& tag) const - { - return removals_.find(tag) != removals_.end(); - } - - void Replace(const DicomTag& tag, - const std::string& value) - { - removals_.erase(tag); - replacements_[tag] = value; - } - - bool IsReplaced(const DicomTag& tag) const - { - return replacements_.find(tag) != replacements_.end(); - } - - const std::string& GetReplacement(const DicomTag& tag) const - { - Replacements::const_iterator it = replacements_.find(tag); - - if (it == replacements_.end()) - { - throw OrthancException(ErrorCode_InexistentItem); - } - else - { - return it->second; - } - } - - void SetRemovePrivateTags(bool removed) - { - removePrivateTags_ = removed; - } - - bool ArePrivateTagsRemoved() const - { - return removePrivateTags_; - } - - void SetLevel(DicomRootLevel level) - { - uidMap_.clear(); - level_ = level; - } - - DicomRootLevel GetLevel() const - { - return level_; - } - - void SetupAnonymization() - { - removals_.clear(); - replacements_.clear(); - removePrivateTags_ = true; - level_ = DicomRootLevel_Patient; - uidMap_.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 - //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 - removals_.insert(DicomTag(0x0008, 0x0081)); // Institution Address - removals_.insert(DicomTag(0x0008, 0x0090)); // Referring Physician's Name - removals_.insert(DicomTag(0x0008, 0x0092)); // Referring Physician's Address - removals_.insert(DicomTag(0x0008, 0x0094)); // Referring Physician's Telephone Numbers - removals_.insert(DicomTag(0x0008, 0x1010)); // Station Name - removals_.insert(DicomTag(0x0008, 0x1030)); // Study Description - removals_.insert(DicomTag(0x0008, 0x103e)); // Series Description - removals_.insert(DicomTag(0x0008, 0x1040)); // Institutional Department Name - removals_.insert(DicomTag(0x0008, 0x1048)); // Physician(s) of Record - removals_.insert(DicomTag(0x0008, 0x1050)); // Performing Physicians' Name - 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 - 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 (*) - removals_.insert(DicomTag(0x0010, 0x0030)); // Patient's Birth Date - removals_.insert(DicomTag(0x0010, 0x0032)); // Patient's Birth Time - removals_.insert(DicomTag(0x0010, 0x0040)); // Patient's Sex - removals_.insert(DicomTag(0x0010, 0x1000)); // Other Patient Ids - removals_.insert(DicomTag(0x0010, 0x1001)); // Other Patient Names - removals_.insert(DicomTag(0x0010, 0x1010)); // Patient's Age - removals_.insert(DicomTag(0x0010, 0x1020)); // Patient's Size - removals_.insert(DicomTag(0x0010, 0x1030)); // Patient's Weight - removals_.insert(DicomTag(0x0010, 0x1090)); // Medical Record Locator - removals_.insert(DicomTag(0x0010, 0x2160)); // Ethnic Group - removals_.insert(DicomTag(0x0010, 0x2180)); // Occupation - removals_.insert(DicomTag(0x0010, 0x21b0)); // Additional Patient's History - removals_.insert(DicomTag(0x0010, 0x4000)); // Patient Comments - removals_.insert(DicomTag(0x0018, 0x1000)); // Device Serial Number - removals_.insert(DicomTag(0x0018, 0x1030)); // Protocol Name - //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 - removals_.insert(DicomTag(0x0020, 0x0200)); // Synchronization Frame of Reference UID - removals_.insert(DicomTag(0x0020, 0x4000)); // Image Comments - removals_.insert(DicomTag(0x0040, 0x0275)); // Request Attributes Sequence - removals_.insert(DicomTag(0x0040, 0xa124)); // UID - 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 - removals_.insert(DicomTag(0x3006, 0x00c2)); // Related Frame of Reference UID - - // Some more removals (from the experience of DICOM files at the CHU of Liege) - removals_.insert(DicomTag(0x0010, 0x1040)); // Patient's Address - removals_.insert(DicomTag(0x0032, 0x1032)); // Requesting Physician - removals_.insert(DicomTag(0x0010, 0x2154)); // PatientTelephoneNumbers - removals_.insert(DicomTag(0x0010, 0x2000)); // Medical Alerts - - // Set the DeidentificationMethod tag - replacements_.insert(std::make_pair(DicomTag(0x0012, 0x0063), "Orthanc " ORTHANC_VERSION " - PS 3.15-2008 Table E.1-1")); - - // Set the PatientIdentityRemoved tag - replacements_.insert(std::make_pair(DicomTag(0x0012, 0x0062), "YES")); - - // (*) Choose a random patient name and ID - std::string patientId = FromDcmtkBridge::GenerateUniqueIdentifier(DicomRootLevel_Patient); - replacements_[DICOM_TAG_PATIENT_ID] = patientId; - replacements_[DICOM_TAG_PATIENT_NAME] = patientId; - } - - void Apply(ParsedDicomFile& toModify) - { - // Check the request - assert(DicomRootLevel_Patient + 1 == DicomRootLevel_Study && - DicomRootLevel_Study + 1 == DicomRootLevel_Series && - DicomRootLevel_Series + 1 == DicomRootLevel_Instance); - - if (IsRemoved(DICOM_TAG_PATIENT_ID) || - IsRemoved(DICOM_TAG_STUDY_INSTANCE_UID) || - IsRemoved(DICOM_TAG_SERIES_INSTANCE_UID) || - IsRemoved(DICOM_TAG_SOP_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest); - } - - if (level_ == DicomRootLevel_Patient && !IsReplaced(DICOM_TAG_PATIENT_ID)) - { - throw OrthancException(ErrorCode_BadRequest); - } - - if (level_ > DicomRootLevel_Patient && IsReplaced(DICOM_TAG_PATIENT_ID)) - { - throw OrthancException(ErrorCode_BadRequest); - } - - if (level_ > DicomRootLevel_Study && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest); - } - - if (level_ > DicomRootLevel_Series && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID)) - { - throw OrthancException(ErrorCode_BadRequest); - } - - // (1) Remove the private tags, if need be - if (removePrivateTags_) - { - toModify.RemovePrivateTags(); - } - - // (2) Remove the tags specified by the user - for (Removals::const_iterator it = removals_.begin(); - it != removals_.end(); ++it) - { - toModify.Remove(*it); - } - - // (3) Replace the tags - for (Replacements::const_iterator it = replacements_.begin(); - it != replacements_.end(); ++it) - { - toModify.Replace(it->first, it->second, DicomReplaceMode_InsertIfAbsent); - } - - // (4) Update the DICOM identifiers - if (level_ <= DicomRootLevel_Study) - { - MapDicomIdentifier(toModify, DicomRootLevel_Study); - } - - if (level_ <= DicomRootLevel_Series) - { - MapDicomIdentifier(toModify, DicomRootLevel_Series); - } - - if (level_ <= DicomRootLevel_Instance) // Always true - { - MapDicomIdentifier(toModify, DicomRootLevel_Instance); - } - } - }; -} - - - TEST(DicomModification, Basic) { DicomModification m;