changeset 1279:7f3a65e84d4b

More flexible /modify and /anonymize for single instance
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 02 Feb 2015 16:14:29 +0100
parents 7aa0630a958e
children d6a65dc6d0ac
files Core/DicomFormat/DicomTag.h NEWS OrthancServer/DicomModification.cpp OrthancServer/DicomModification.h OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp
diffstat 5 files changed, 106 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/Core/DicomFormat/DicomTag.h	Tue Jan 27 14:17:07 2015 +0100
+++ b/Core/DicomFormat/DicomTag.h	Mon Feb 02 16:14:29 2015 +0100
@@ -109,10 +109,11 @@
 
   static const DicomTag DICOM_TAG_PATIENT_NAME(0x0010, 0x0010);
 
-  // The following is used for "modify" operations
+  // The following is used for "modify/anonymize" operations
   static const DicomTag DICOM_TAG_SOP_CLASS_UID(0x0008, 0x0016);
   static const DicomTag DICOM_TAG_MEDIA_STORAGE_SOP_CLASS_UID(0x0002, 0x0002);
   static const DicomTag DICOM_TAG_MEDIA_STORAGE_SOP_INSTANCE_UID(0x0002, 0x0003);
+  static const DicomTag DICOM_TAG_DEIDENTIFICATION_METHOD(0x0012, 0x0063);
 
   // DICOM tags used for fMRI (thanks to Will Ryder)
   static const DicomTag DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS(0x0020, 0x0105);
--- a/NEWS	Tue Jan 27 14:17:07 2015 +0100
+++ b/NEWS	Mon Feb 02 16:14:29 2015 +0100
@@ -9,6 +9,7 @@
 * Support of Tudor DICOM in Query/Retrieve
 * Fix issue 25 (AET with underscore not allowed)
 * Code refactorings
+* More flexible "/modify" and "/anonymize" for single instance
 
 Plugins
 -------
--- a/OrthancServer/DicomModification.cpp	Tue Jan 27 14:17:07 2015 +0100
+++ b/OrthancServer/DicomModification.cpp	Mon Feb 02 16:14:29 2015 +0100
@@ -39,8 +39,23 @@
 #include <memory>   // For std::auto_ptr
 #include <glog/logging.h>
 
+
+static const std::string ORTHANC_DEIDENTIFICATION_METHOD = "Orthanc " ORTHANC_VERSION " - PS 3.15-2008 Table E.1-1";
+
 namespace Orthanc
 {
+  void DicomModification::MarkNotOrthancAnonymization()
+  {
+    Replacements::iterator it = replacements_.find(DICOM_TAG_DEIDENTIFICATION_METHOD);
+
+    if (it != replacements_.end() &&
+        it->second == ORTHANC_DEIDENTIFICATION_METHOD)
+    {
+      replacements_.erase(it);
+    }
+  }
+
+
   void DicomModification::MapDicomIdentifier(ParsedDicomFile& dicom,
                                              ResourceType level)
   {
@@ -90,6 +105,7 @@
   {
     removePrivateTags_ = false;
     level_ = ResourceType_Instance;
+    allowManualIdentifiers_ = true;
   }
 
   void DicomModification::Keep(const DicomTag& tag)
@@ -101,6 +117,8 @@
     {
       privateTagsToKeep_.insert(tag);
     }
+
+    MarkNotOrthancAnonymization();
   }
 
   void DicomModification::Remove(const DicomTag& tag)
@@ -108,6 +126,8 @@
     removals_.insert(tag);
     replacements_.erase(tag);
     privateTagsToKeep_.erase(tag);
+
+    MarkNotOrthancAnonymization();
   }
 
   bool DicomModification::IsRemoved(const DicomTag& tag) const
@@ -116,11 +136,17 @@
   }
 
   void DicomModification::Replace(const DicomTag& tag,
-                                  const std::string& value)
+                                  const std::string& value,
+                                  bool safeForAnonymization)
   {
     removals_.erase(tag);
     privateTagsToKeep_.erase(tag);
     replacements_[tag] = value;
+
+    if (!safeForAnonymization)
+    {
+      MarkNotOrthancAnonymization();
+    }
   }
 
   bool DicomModification::IsReplaced(const DicomTag& tag) const
@@ -145,12 +171,22 @@
   void DicomModification::SetRemovePrivateTags(bool removed)
   {
     removePrivateTags_ = removed;
+
+    if (!removed)
+    {
+      MarkNotOrthancAnonymization();
+    }
   }
 
   void DicomModification::SetLevel(ResourceType level)
   {
     uidMap_.clear();
     level_ = level;
+
+    if (level != ResourceType_Patient)
+    {
+      MarkNotOrthancAnonymization();
+    }
   }
 
   void DicomModification::SetupAnonymization()
@@ -219,7 +255,7 @@
     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"));
+    replacements_.insert(std::make_pair(DICOM_TAG_DEIDENTIFICATION_METHOD, ORTHANC_DEIDENTIFICATION_METHOD));
 
     // Set the PatientIdentityRemoved tag
     replacements_.insert(std::make_pair(DicomTag(0x0012, 0x0062), "YES"));
@@ -246,49 +282,59 @@
     }
     
 
-    // Sanity checks
+    // Sanity checks at the patient level
     if (level_ == ResourceType_Patient && !IsReplaced(DICOM_TAG_PATIENT_ID))
     {
       LOG(ERROR) << "When modifying a patient, her PatientID is required to be modified";
       throw OrthancException(ErrorCode_BadRequest);
     }
 
-    if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID))
+    if (!allowManualIdentifiers_)
     {
-      LOG(ERROR) << "When modifying a patient, the StudyInstanceUID cannot be manually modified";
-      throw OrthancException(ErrorCode_BadRequest);
+      if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID))
+      {
+        LOG(ERROR) << "When modifying a patient, the StudyInstanceUID cannot be manually modified";
+        throw OrthancException(ErrorCode_BadRequest);
+      }
+
+      if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID))
+      {
+        LOG(ERROR) << "When modifying a patient, the SeriesInstanceUID cannot be manually modified";
+        throw OrthancException(ErrorCode_BadRequest);
+      }
+
+      if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID))
+      {
+        LOG(ERROR) << "When modifying a patient, the SopInstanceUID cannot be manually modified";
+        throw OrthancException(ErrorCode_BadRequest);
+      }
     }
 
-    if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID))
-    {
-      LOG(ERROR) << "When modifying a patient, the SeriesInstanceUID cannot be manually modified";
-      throw OrthancException(ErrorCode_BadRequest);
-    }
 
-    if (level_ == ResourceType_Patient && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID))
-    {
-      LOG(ERROR) << "When modifying a patient, the SopInstanceUID cannot be manually modified";
-      throw OrthancException(ErrorCode_BadRequest);
-    }
-
+    // Sanity checks at the study level
     if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_PATIENT_ID))
     {
       LOG(ERROR) << "When modifying a study, the parent PatientID cannot be manually modified";
       throw OrthancException(ErrorCode_BadRequest);
     }
 
-    if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID))
+    if (!allowManualIdentifiers_)
     {
-      LOG(ERROR) << "When modifying a study, the SeriesInstanceUID cannot be manually modified";
-      throw OrthancException(ErrorCode_BadRequest);
+      if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID))
+      {
+        LOG(ERROR) << "When modifying a study, the SeriesInstanceUID cannot be manually modified";
+        throw OrthancException(ErrorCode_BadRequest);
+      }
+
+      if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID))
+      {
+        LOG(ERROR) << "When modifying a study, the SopInstanceUID cannot be manually modified";
+        throw OrthancException(ErrorCode_BadRequest);
+      }
     }
 
-    if (level_ == ResourceType_Study && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID))
-    {
-      LOG(ERROR) << "When modifying a study, the SopInstanceUID cannot be manually modified";
-      throw OrthancException(ErrorCode_BadRequest);
-    }
 
+    // Sanity checks at the series level
     if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_PATIENT_ID))
     {
       LOG(ERROR) << "When modifying a series, the parent PatientID cannot be manually modified";
@@ -301,12 +347,17 @@
       throw OrthancException(ErrorCode_BadRequest);
     }
 
-    if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID))
+    if (!allowManualIdentifiers_)
     {
-      LOG(ERROR) << "When modifying a series, the SopInstanceUID cannot be manually modified";
-      throw OrthancException(ErrorCode_BadRequest);
+      if (level_ == ResourceType_Series && IsReplaced(DICOM_TAG_SOP_INSTANCE_UID))
+      {
+        LOG(ERROR) << "When modifying a series, the SopInstanceUID cannot be manually modified";
+        throw OrthancException(ErrorCode_BadRequest);
+      }
     }
 
+
+    // Sanity checks at the instance level
     if (level_ == ResourceType_Instance && IsReplaced(DICOM_TAG_PATIENT_ID))
     {
       LOG(ERROR) << "When modifying an instance, the parent PatientID cannot be manually modified";
@@ -347,17 +398,20 @@
     }
 
     // (4) Update the DICOM identifiers
-    if (level_ <= ResourceType_Study)
+    if (level_ <= ResourceType_Study &&
+        !IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID))
     {
       MapDicomIdentifier(toModify, ResourceType_Study);
     }
 
-    if (level_ <= ResourceType_Series)
+    if (level_ <= ResourceType_Series &&
+        !IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID))
     {
       MapDicomIdentifier(toModify, ResourceType_Series);
     }
 
-    if (level_ <= ResourceType_Instance)  // Always true
+    if (level_ <= ResourceType_Instance &&  // Always true
+        !IsReplaced(DICOM_TAG_SOP_INSTANCE_UID))
     {
       MapDicomIdentifier(toModify, ResourceType_Instance);
     }
--- a/OrthancServer/DicomModification.h	Tue Jan 27 14:17:07 2015 +0100
+++ b/OrthancServer/DicomModification.h	Mon Feb 02 16:14:29 2015 +0100
@@ -56,10 +56,13 @@
     ResourceType level_;
     UidMap uidMap_;
     SetOfTags privateTagsToKeep_;
+    bool allowManualIdentifiers_;
 
     void MapDicomIdentifier(ParsedDicomFile& dicom,
                             ResourceType level);
 
+    void MarkNotOrthancAnonymization();
+
   public:
     DicomModification();
 
@@ -70,7 +73,8 @@
     bool IsRemoved(const DicomTag& tag) const;
 
     void Replace(const DicomTag& tag,
-                 const std::string& value);
+                 const std::string& value,
+                 bool safeForAnonymization = false);
 
     bool IsReplaced(const DicomTag& tag) const;
 
@@ -93,5 +97,15 @@
     void SetupAnonymization();
 
     void Apply(ParsedDicomFile& toModify);
+
+    void SetAllowManualIdentifiers(bool check)
+    {
+      allowManualIdentifiers_ = check;
+    }
+
+    bool AreAllowManualIdentifiers() const
+    {
+      return allowManualIdentifiers_;
+    }
   };
 }
--- a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp	Tue Jan 27 14:17:07 2015 +0100
+++ b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp	Mon Feb 02 16:14:29 2015 +0100
@@ -194,7 +194,7 @@
       {
         // Overwrite the random Patient's Name by one that is more
         // user-friendly (provided none was specified by the user)
-        target.Replace(DICOM_TAG_PATIENT_NAME, GeneratePatientName(OrthancRestApi::GetContext(call)));
+        target.Replace(DICOM_TAG_PATIENT_NAME, GeneratePatientName(OrthancRestApi::GetContext(call)), true);
       }
 
       return true;
@@ -361,6 +361,7 @@
   static void ModifyInstance(RestApiPostCall& call)
   {
     DicomModification modification;
+    modification.SetAllowManualIdentifiers(true);
 
     if (ParseModifyRequest(modification, call))
     {
@@ -389,6 +390,7 @@
   static void AnonymizeInstance(RestApiPostCall& call)
   {
     DicomModification modification;
+    modification.SetAllowManualIdentifiers(true);
 
     if (ParseAnonymizationRequest(modification, call))
     {