changeset 1307:f796207e3df1

Fix replacement and insertion of private DICOM tags
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 11 Feb 2015 10:26:17 +0100
parents 8cd5784a6d80
children f7966e9950e4 d1a430176401
files NEWS OrthancServer/FromDcmtkBridge.cpp OrthancServer/ParsedDicomFile.cpp Resources/Samples/Lua/AutoroutingModification.lua UnitTestsSources/FromDcmtkTests.cpp
diffstat 5 files changed, 109 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Tue Feb 10 17:17:25 2015 +0100
+++ b/NEWS	Wed Feb 11 10:26:17 2015 +0100
@@ -31,6 +31,7 @@
 
 * Code refactorings
 * Fix issue 25 (AET with underscore not allowed)
+* Fix replacement and insertion of private DICOM tags
 
 
 Version 0.8.5 (2014/11/04)
--- a/OrthancServer/FromDcmtkBridge.cpp	Tue Feb 10 17:17:25 2015 +0100
+++ b/OrthancServer/FromDcmtkBridge.cpp	Wed Feb 11 10:26:17 2015 +0100
@@ -186,15 +186,27 @@
 
   bool FromDcmtkBridge::IsPrivateTag(DcmTag& tag)
   {
+#if 1
+    DcmTagKey tmp(tag.getGTag(), tag.getETag());
+    return tmp.isPrivate();
+#else
+    // Implementation for Orthanc versions <= 0.8.5
     return (tag.getPrivateCreator() != NULL ||
             !strcmp("PrivateCreator", tag.getTagName()));  // TODO - This may change with future versions of DCMTK
+#endif
   }
 
 
   bool FromDcmtkBridge::IsPrivateTag(const DicomTag& tag)
   {
+#if 1
+    DcmTagKey tmp(tag.GetGroup(), tag.GetElement());
+    return tmp.isPrivate();
+#else
+    // Implementation for Orthanc versions <= 0.8.5
     DcmTag tmp(tag.GetGroup(), tag.GetElement());
     return IsPrivateTag(tmp);
+#endif
   }
 
 
--- a/OrthancServer/ParsedDicomFile.cpp	Tue Feb 10 17:17:25 2015 +0100
+++ b/OrthancServer/ParsedDicomFile.cpp	Wed Feb 11 10:26:17 2015 +0100
@@ -807,13 +807,30 @@
 
 
 
+
   void ParsedDicomFile::Insert(const DicomTag& tag,
                                const std::string& value)
   {
-    std::auto_ptr<DcmElement> element(CreateElementForTag(tag));
-    FillElementWithString(*element, tag, value);
+    OFCondition cond;
+
+    if (FromDcmtkBridge::IsPrivateTag(tag))
+    {
+      // This is a private tag
+      // http://support.dcmtk.org/redmine/projects/dcmtk/wiki/howto_addprivatedata
 
-    if (!pimpl_->file_->getDataset()->insert(element.release(), false, false).good())
+      DcmTag key(tag.GetGroup(), tag.GetElement(), EVR_OB);
+      cond = pimpl_->file_->getDataset()->putAndInsertUint8Array
+        (key, (const Uint8*) value.c_str(), value.size(), false);
+    }
+    else
+    {
+      std::auto_ptr<DcmElement> element(CreateElementForTag(tag));
+      FillElementWithString(*element, tag, value);
+
+      cond = pimpl_->file_->getDataset()->insert(element.release(), false, false);
+    }
+
+    if (!cond.good())
     {
       // This field already exists
       throw OrthancException(ErrorCode_InternalError);
@@ -847,7 +864,17 @@
     }
     else
     {
-      FillElementWithString(*element, tag, value);
+      if (FromDcmtkBridge::IsPrivateTag(tag))
+      {
+        if (!element->putUint8Array((const Uint8*) value.c_str(), value.size()).good())
+        {
+          throw OrthancException(ErrorCode_InternalError);
+        }
+      }
+      else
+      {
+        FillElementWithString(*element, tag, value);
+      }
     }
 
 
@@ -888,25 +915,53 @@
   {
     DcmTagKey k(tag.GetGroup(), tag.GetElement());
     DcmDataset& dataset = *pimpl_->file_->getDataset();
-    DcmElement* element = NULL;
-    if (!dataset.findAndGetElement(k, element).good() ||
-        element == NULL)
+
+    if (FromDcmtkBridge::IsPrivateTag(tag))
     {
-      return false;
-    }
+      const Uint8* data = NULL;   // This is freed in the destructor of the dataset
+      long unsigned int count = 0;
 
-    std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement(*element, pimpl_->encoding_));
+      if (dataset.findAndGetUint8Array(k, data, &count).good())
+      {
+        if (count > 0)
+        {
+          assert(data != NULL);
+          value.assign(reinterpret_cast<const char*>(data), count);
+        }
+        else
+        {
+          value.clear();
+        }
 
-    if (v.get() == NULL)
-    {
-      value = "";
+        return true;
+      }
+      else
+      {
+        return false;
+      }
     }
     else
     {
-      value = v->AsString();
+      DcmElement* element = NULL;
+      if (!dataset.findAndGetElement(k, element).good() ||
+          element == NULL)
+      {
+        return false;
+      }
+
+      std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement(*element, pimpl_->encoding_));
+
+      if (v.get() == NULL)
+      {
+        value = "";
+      }
+      else
+      {
+        value = v->AsString();
+      }
+
+      return true;
     }
-
-    return true;
   }
 
 
--- a/Resources/Samples/Lua/AutoroutingModification.lua	Tue Feb 10 17:17:25 2015 +0100
+++ b/Resources/Samples/Lua/AutoroutingModification.lua	Wed Feb 11 10:26:17 2015 +0100
@@ -7,6 +7,7 @@
       -- The tags to be replaced
       local replace = {}
       replace['StationName'] = 'My Medical Device'
+      replace['0031-1020'] = 'Some private tag'
 
       -- The tags to be removed
       local remove = { 'MilitaryRank' }
--- a/UnitTestsSources/FromDcmtkTests.cpp	Tue Feb 10 17:17:25 2015 +0100
+++ b/UnitTestsSources/FromDcmtkTests.cpp	Wed Feb 11 10:26:17 2015 +0100
@@ -89,14 +89,35 @@
 
 TEST(DicomModification, Anonymization)
 {
+  ASSERT_EQ(DICOM_TAG_PATIENT_NAME, FromDcmtkBridge::ParseTag("PatientName"));
+
   const DicomTag privateTag(0x0045, 0x0010);
+  const DicomTag privateTag2(FromDcmtkBridge::ParseTag("0031-1020"));
   ASSERT_TRUE(FromDcmtkBridge::IsPrivateTag(privateTag));
+  ASSERT_TRUE(FromDcmtkBridge::IsPrivateTag(privateTag2));
+  ASSERT_EQ(0x0031, privateTag2.GetGroup());
+  ASSERT_EQ(0x1020, privateTag2.GetElement());
 
+  std::string s;
   ParsedDicomFile o;
   o.Replace(DICOM_TAG_PATIENT_NAME, "coucou");
-  o.Replace(privateTag, "private tag");
+  ASSERT_FALSE(o.GetTagValue(s, privateTag));
+  o.Insert(privateTag, "private tag");
+  ASSERT_TRUE(o.GetTagValue(s, privateTag));
+  ASSERT_STREQ("private tag", s.c_str());
 
-  std::string s;
+  ASSERT_FALSE(o.GetTagValue(s, privateTag2));
+  ASSERT_THROW(o.Replace(privateTag2, "hello", DicomReplaceMode_ThrowIfAbsent), OrthancException);
+  ASSERT_FALSE(o.GetTagValue(s, privateTag2));
+  o.Replace(privateTag2, "hello", DicomReplaceMode_IgnoreIfAbsent);
+  ASSERT_FALSE(o.GetTagValue(s, privateTag2));
+  o.Replace(privateTag2, "hello", DicomReplaceMode_InsertIfAbsent);
+  ASSERT_TRUE(o.GetTagValue(s, privateTag2));
+  ASSERT_STREQ("hello", s.c_str());
+  o.Replace(privateTag2, "hello world");
+  ASSERT_TRUE(o.GetTagValue(s, privateTag2));
+  ASSERT_STREQ("hello world", s.c_str());
+
   ASSERT_TRUE(o.GetTagValue(s, DICOM_TAG_PATIENT_NAME));
   ASSERT_FALSE(Toolbox::IsUuid(s));
 
@@ -109,7 +130,7 @@
   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);
+  ASSERT_STREQ("private tag", s.c_str());
   
   m.SetupAnonymization();
   m.Apply(o);