changeset 3195:880e4161c312

cont
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 05 Feb 2019 20:44:26 +0100
parents 47ef29168698
children 763738c1f9f6
files Core/DicomParsing/DicomModification.cpp Core/DicomParsing/FromDcmtkBridge.cpp Core/DicomParsing/ITagVisitor.h UnitTestsSources/DicomMapTests.cpp
diffstat 4 files changed, 191 insertions(+), 120 deletions(-) [+]
line wrap: on
line diff
--- a/Core/DicomParsing/DicomModification.cpp	Tue Feb 05 18:34:27 2019 +0100
+++ b/Core/DicomParsing/DicomModification.cpp	Tue Feb 05 20:44:26 2019 +0100
@@ -79,10 +79,16 @@
     {
     }
 
-    virtual void VisitUnknown(const std::vector<DicomTag>& parentTags,
-                              const std::vector<size_t>& parentIndexes,
-                              const DicomTag& tag,
-                              ValueRepresentation vr)
+    virtual void VisitNotSupported(const std::vector<DicomTag>& parentTags,
+                                   const std::vector<size_t>& parentIndexes,
+                                   const DicomTag& tag,
+                                   ValueRepresentation vr)
+    {
+    }
+
+    virtual void VisitEmptySequence(const std::vector<DicomTag>& parentTags,
+                                    const std::vector<size_t>& parentIndexes,
+                                    const DicomTag& tag)
     {
     }
 
@@ -114,7 +120,6 @@
     virtual void VisitAttributes(const std::vector<DicomTag>& parentTags,
                                  const std::vector<size_t>& parentIndexes,
                                  const DicomTag& tag,
-                                 ValueRepresentation vr,
                                  const std::vector<DicomTag>& value)
     {
     }
--- a/Core/DicomParsing/FromDcmtkBridge.cpp	Tue Feb 05 18:34:27 2019 +0100
+++ b/Core/DicomParsing/FromDcmtkBridge.cpp	Tue Feb 05 20:44:26 2019 +0100
@@ -2253,7 +2253,7 @@
           }
           else
           {
-            visitor.VisitUnknown(parentTags, parentIndexes, tag, vr);
+            visitor.VisitNotSupported(parentTags, parentIndexes, tag, vr);
           }
 
           break;
@@ -2405,7 +2405,8 @@
             }
           }
 
-          visitor.VisitAttributes(parentTags, parentIndexes, tag, vr, values);
+          assert(vr == ValueRepresentation_AttributeTag);
+          visitor.VisitAttributes(parentTags, parentIndexes, tag, values);
           break;
         }
 
@@ -2437,7 +2438,7 @@
         case EVR_pixelItem:  // used internally for pixel items in a compressed image
         case EVR_PixelData:  // used internally for uncompressed pixeld data
         case EVR_OverlayData:  // used internally for overlay data
-          visitor.VisitUnknown(parentTags, parentIndexes, tag, vr);
+          visitor.VisitNotSupported(parentTags, parentIndexes, tag, vr);
           return;
 
 
@@ -2481,16 +2482,23 @@
       // etc. are not." The following dynamic_cast is thus OK.
       DcmSequenceOfItems& sequence = dynamic_cast<DcmSequenceOfItems&>(element);
 
-      std::vector<DicomTag> tags = parentTags;
-      std::vector<size_t> indexes = parentIndexes;
-      tags.push_back(tag);
-      indexes.push_back(0);
-
-      for (unsigned long i = 0; i < sequence.card(); i++)
+      if (sequence.card() == 0)
+      {
+        visitor.VisitEmptySequence(parentTags, parentIndexes, tag);
+      }
+      else
       {
-        indexes.back() = static_cast<size_t>(i);
-        DcmItem* child = sequence.getItem(i);
-        ApplyVisitorToDataset(*child, visitor, tags, indexes, encoding);
+        std::vector<DicomTag> tags = parentTags;
+        std::vector<size_t> indexes = parentIndexes;
+        tags.push_back(tag);
+        indexes.push_back(0);
+
+        for (unsigned long i = 0; i < sequence.card(); i++)
+        {
+          indexes.back() = static_cast<size_t>(i);
+          DcmItem* child = sequence.getItem(i);
+          ApplyVisitorToDataset(*child, visitor, tags, indexes, encoding);
+        }
       }
     }
   }
--- a/Core/DicomParsing/ITagVisitor.h	Tue Feb 05 18:34:27 2019 +0100
+++ b/Core/DicomParsing/ITagVisitor.h	Tue Feb 05 20:44:26 2019 +0100
@@ -53,11 +53,38 @@
     {
     }
 
-    virtual void VisitUnknown(const std::vector<DicomTag>& parentTags,
+    // Visiting a DICOM element that is internal to DCMTK
+    virtual void VisitNotSupported(const std::vector<DicomTag>& parentTags,
+                                   const std::vector<size_t>& parentIndexes,
+                                   const DicomTag& tag,
+                                   ValueRepresentation vr) = 0;
+
+    // SQ
+    virtual void VisitEmptySequence(const std::vector<DicomTag>& parentTags,
+                                    const std::vector<size_t>& parentIndexes,
+                                    const DicomTag& tag) = 0;
+
+    // SL, SS, UL, US
+    virtual void VisitIntegers(const std::vector<DicomTag>& parentTags,
+                               const std::vector<size_t>& parentIndexes,
+                               const DicomTag& tag,
+                               ValueRepresentation vr,
+                               const std::vector<int64_t>& values) = 0;
+
+    // FL, FD
+    virtual void VisitDoubles(const std::vector<DicomTag>& parentTags,
                               const std::vector<size_t>& parentIndexes,
                               const DicomTag& tag,
-                              ValueRepresentation vr) = 0;
+                              ValueRepresentation vr,
+                              const std::vector<double>& values) = 0;
 
+    // AT
+    virtual void VisitAttributes(const std::vector<DicomTag>& parentTags,
+                                 const std::vector<size_t>& parentIndexes,
+                                 const DicomTag& tag,
+                                 const std::vector<DicomTag>& values) = 0;
+
+    // Visiting a binary buffer
     virtual void VisitBinary(const std::vector<DicomTag>& parentTags,
                              const std::vector<size_t>& parentIndexes,
                              const DicomTag& tag,
@@ -65,24 +92,7 @@
                              const void* data,
                              size_t size) = 0;
 
-    virtual void VisitIntegers(const std::vector<DicomTag>& parentTags,
-                               const std::vector<size_t>& parentIndexes,
-                               const DicomTag& tag,
-                               ValueRepresentation vr,
-                               const std::vector<int64_t>& values) = 0;
-
-    virtual void VisitDoubles(const std::vector<DicomTag>& parentTags,
-                              const std::vector<size_t>& parentIndexes,
-                              const DicomTag& tag,
-                              ValueRepresentation vr,
-                              const std::vector<double>& values) = 0;
-
-    virtual void VisitAttributes(const std::vector<DicomTag>& parentTags,
-                                 const std::vector<size_t>& parentIndexes,
-                                 const DicomTag& tag,
-                                 ValueRepresentation vr,
-                                 const std::vector<DicomTag>& values) = 0;
-
+    // Visiting an UTF-8 string
     virtual Action VisitString(std::string& newValue,
                                const std::vector<DicomTag>& parentTags,
                                const std::vector<size_t>& parentIndexes,
--- a/UnitTestsSources/DicomMapTests.cpp	Tue Feb 05 18:34:27 2019 +0100
+++ b/UnitTestsSources/DicomMapTests.cpp	Tue Feb 05 20:44:26 2019 +0100
@@ -559,6 +559,13 @@
 
 #include <boost/math/special_functions/round.hpp>
 
+
+static const char* const KEY_ALPHABETIC = "Alphabetic";
+static const char* const KEY_INLINE_BINARY = "InlineBinary";
+static const char* const KEY_SQ = "SQ";
+static const char* const KEY_VALUE = "Value";
+static const char* const KEY_VR = "vr";
+
 namespace Orthanc
 {
   class DicomJsonVisitor : public ITagVisitor
@@ -589,25 +596,25 @@
         if (!node->isMember(t))
         {
           Json::Value item = Json::objectValue;
-          item["vr"] = "SQ";
-          item["Value"] = Json::arrayValue;
-          item["Value"].append(Json::objectValue);
+          item[KEY_VR] = KEY_SQ;
+          item[KEY_VALUE] = Json::arrayValue;
+          item[KEY_VALUE].append(Json::objectValue);
           (*node) [t] = item;
 
-          node = &(*node)[t]["Value"][0];
+          node = &(*node)[t][KEY_VALUE][0];
         }
         else if ((*node)  [t].type() != Json::objectValue ||
-                 !(*node) [t].isMember("vr") ||
-                 (*node)  [t]["vr"].type() != Json::stringValue ||
-                 (*node)  [t]["vr"].asString() != "SQ" ||
-                 !(*node) [t].isMember("Value") ||
-                 (*node)  [t]["Value"].type() != Json::arrayValue)
+                 !(*node) [t].isMember(KEY_VR) ||
+                 (*node)  [t][KEY_VR].type() != Json::stringValue ||
+                 (*node)  [t][KEY_VR].asString() != KEY_SQ ||
+                 !(*node) [t].isMember(KEY_VALUE) ||
+                 (*node)  [t][KEY_VALUE].type() != Json::arrayValue)
         {
           throw OrthancException(ErrorCode_InternalError);
         }
         else
         {
-          size_t currentSize = (*node) [t]["Value"].size();
+          size_t currentSize = (*node) [t][KEY_VALUE].size();
 
           if (parentIndexes[i] < currentSize)
           {
@@ -615,14 +622,14 @@
           }
           else if (parentIndexes[i] == currentSize)
           {
-            (*node) [t]["Value"].append(Json::objectValue);
+            (*node) [t][KEY_VALUE].append(Json::objectValue);
           }
           else
           {
             throw OrthancException(ErrorCode_InternalError);
           }
           
-          node = &(*node) [t]["Value"][Json::ArrayIndex(parentIndexes[i])];
+          node = &(*node) [t][KEY_VALUE][Json::ArrayIndex(parentIndexes[i])];
         }
       }
 
@@ -689,13 +696,22 @@
       return result_;
     }
 
-    virtual void VisitUnknown(const std::vector<DicomTag>& parentTags,
-                              const std::vector<size_t>& parentIndexes,
-                              const DicomTag& tag,
-                              ValueRepresentation vr) ORTHANC_OVERRIDE
+    virtual void VisitNotSupported(const std::vector<DicomTag>& parentTags,
+                                   const std::vector<size_t>& parentIndexes,
+                                   const DicomTag& tag,
+                                   ValueRepresentation vr) ORTHANC_OVERRIDE
     {
-      Json::Value& node = CreateNode(parentTags, parentIndexes, tag);
-      node["vr"] = EnumerationToString(vr);
+    }
+
+    virtual void VisitEmptySequence(const std::vector<DicomTag>& parentTags,
+                                    const std::vector<size_t>& parentIndexes,
+                                    const DicomTag& tag) ORTHANC_OVERRIDE
+    {
+      if (tag.GetElement() != 0x0000)
+      {
+        Json::Value& node = CreateNode(parentTags, parentIndexes, tag);
+        node[KEY_VR] = EnumerationToString(ValueRepresentation_Sequence);
+      }
     }
 
     virtual void VisitBinary(const std::vector<DicomTag>& parentTags,
@@ -705,11 +721,19 @@
                              const void* data,
                              size_t size) ORTHANC_OVERRIDE
     {
-      if (vr != ValueRepresentation_NotSupported &&
-          !bulkUriRoot_.empty())
+      if (tag.GetElement() != 0x0000 &&
+          vr != ValueRepresentation_NotSupported /*&&
+                                                   !bulkUriRoot_.empty()*/)
       {
         Json::Value& node = CreateNode(parentTags, parentIndexes, tag);
-        node["vr"] = EnumerationToString(vr);
+        node[KEY_VR] = EnumerationToString(vr);
+
+        std::string tmp(static_cast<const char*>(data), size);
+        
+        std::string base64;
+        Toolbox::EncodeBase64(base64, tmp);
+
+        node[KEY_INLINE_BINARY] = base64;
       }
     }
 
@@ -719,18 +743,22 @@
                                ValueRepresentation vr,
                                const std::vector<int64_t>& values) ORTHANC_OVERRIDE
     {
-      if (vr != ValueRepresentation_NotSupported)
+      if (tag.GetElement() != 0x0000 &&
+          vr != ValueRepresentation_NotSupported)
       {
         Json::Value& node = CreateNode(parentTags, parentIndexes, tag);
-        node["vr"] = EnumerationToString(vr);
+        node[KEY_VR] = EnumerationToString(vr);
 
-        Json::Value content = Json::arrayValue;
-        for (size_t i = 0; i < values.size(); i++)
+        if (!values.empty())
         {
-          content.append(FormatInteger(values[i]));
+          Json::Value content = Json::arrayValue;
+          for (size_t i = 0; i < values.size(); i++)
+          {
+            content.append(FormatInteger(values[i]));
+          }
+
+          node[KEY_VALUE] = content;
         }
-
-        node["Value"] = content;
       }
     }
 
@@ -740,32 +768,39 @@
                               ValueRepresentation vr,
                               const std::vector<double>& values) ORTHANC_OVERRIDE
     {
-      if (vr != ValueRepresentation_NotSupported)
+      if (tag.GetElement() != 0x0000 &&
+          vr != ValueRepresentation_NotSupported)
       {
         Json::Value& node = CreateNode(parentTags, parentIndexes, tag);
-        node["vr"] = EnumerationToString(vr);
+        node[KEY_VR] = EnumerationToString(vr);
 
-        Json::Value content = Json::arrayValue;
-        for (size_t i = 0; i < values.size(); i++)
+        if (!values.empty())
         {
-          content.append(FormatDouble(values[i]));
+          Json::Value content = Json::arrayValue;
+          for (size_t i = 0; i < values.size(); i++)
+          {
+            content.append(FormatDouble(values[i]));
+          }
+          
+          node[KEY_VALUE] = content;
         }
-        node["Value"] = content;
       }
     }
 
     virtual void VisitAttributes(const std::vector<DicomTag>& parentTags,
                                  const std::vector<size_t>& parentIndexes,
                                  const DicomTag& tag,
-                                 ValueRepresentation vr,
                                  const std::vector<DicomTag>& values) ORTHANC_OVERRIDE
     {
-      if (vr != ValueRepresentation_NotSupported)
+      if (tag.GetElement() != 0x0000)
       {
         Json::Value& node = CreateNode(parentTags, parentIndexes, tag);
-        node["vr"] = EnumerationToString(vr);
+        node[KEY_VR] = EnumerationToString(ValueRepresentation_AttributeTag);
 
-        
+        if (!values.empty())
+        {
+          // TODO
+        }
       }
     }
 
@@ -776,61 +811,68 @@
                                ValueRepresentation vr,
                                const std::string& value) ORTHANC_OVERRIDE
     {
-      if (vr != ValueRepresentation_NotSupported)
+      if (tag.GetElement() != 0x0000 &&
+          vr != ValueRepresentation_NotSupported)
       {
         Json::Value& node = CreateNode(parentTags, parentIndexes, tag);
-        node["vr"] = EnumerationToString(vr);
-
-        std::vector<std::string> tokens;
-        Toolbox::TokenizeString(tokens, value, '\\');
+        node[KEY_VR] = EnumerationToString(vr);
 
-        node["Value"] = Json::arrayValue;
-        for (size_t i = 0; i < tokens.size(); i++)
+        if (!value.empty())
         {
-          try
+          std::vector<std::string> tokens;
+          Toolbox::TokenizeString(tokens, value, '\\');
+
+          node[KEY_VALUE] = Json::arrayValue;
+          for (size_t i = 0; i < tokens.size(); i++)
           {
-            switch (vr)
+            try
             {
-              case ValueRepresentation_PersonName:
-              {
-                Json::Value value = Json::objectValue;
-                value["Alphabetic"] = tokens[i];
-                node["Value"].append(value);
-                break;
-              }
-                  
-              case ValueRepresentation_IntegerString:
+              switch (vr)
               {
-                int64_t value = boost::lexical_cast<int64_t>(tokens[i]);
-                node["Value"].append(FormatInteger(value));
-                break;
-              }
-              
-              case ValueRepresentation_DecimalString:
-              {
-                double value = boost::lexical_cast<double>(tokens[i]);
-                node["Value"].append(FormatDouble(value));
-                break;
-              }
+                case ValueRepresentation_PersonName:
+                {
+                  Json::Value value = Json::objectValue;
+                  if (!tokens[i].empty())
+                  {
+                    value[KEY_ALPHABETIC] = tokens[i];
+                  }
+                  node[KEY_VALUE].append(value);
+                  break;
+                }
+                  
+                case ValueRepresentation_IntegerString:
+                {
+                  int64_t value = boost::lexical_cast<int64_t>(tokens[i]);
+                  node[KEY_VALUE].append(FormatInteger(value));
+                  break;
+                }
               
-              default:
-              {
-                size_t l = tokens[i].size();
+                case ValueRepresentation_DecimalString:
+                {
+                  double value = boost::lexical_cast<double>(tokens[i]);
+                  node[KEY_VALUE].append(FormatDouble(value));
+                  break;
+                }
+              
+                default:
+                {
+                  size_t l = tokens[i].size();
 
-                if (l > 0 &&
-                    tokens[i][l - 1] == '\0')
-                {
-                  tokens[i] = tokens[i].substr(0, l - 1);
+                  if (l > 0 &&
+                      tokens[i][l - 1] == '\0')
+                  {
+                    tokens[i] = tokens[i].substr(0, l - 1);
+                  }
+
+                  node[KEY_VALUE].append(tokens[i]);
+                  break;
                 }
-
-                node["Value"].append(tokens[i]);
-                break;
               }
             }
-          }
-          catch (boost::bad_lexical_cast&)
-          {
-            throw OrthancException(ErrorCode_BadFileFormat);
+            catch (boost::bad_lexical_cast&)
+            {
+              throw OrthancException(ErrorCode_BadFileFormat);
+            }
           }
         }
       }
@@ -845,6 +887,12 @@
 
 /* 
 
+MarekLatin2.dcm 
+HierarchicalAnonymization/StructuredReports/IM0
+DummyCT.dcm
+Brainix/Epi/IM-0001-0018.dcm
+
+
 cat << EOF > /tmp/tutu.py
 import json
 import sys
@@ -852,7 +900,7 @@
 print(json.dumps(j, indent=4, sort_keys=True, ensure_ascii=False).encode('utf-8'))
 EOF
 
-DCMDICTPATH=/home/jodogne/Downloads/dcmtk-3.6.2/dcmdata/data/dicom.dic /home/jodogne/Downloads/dcmtk-3.6.2/i/bin/dcm2json ~/Subversion/orthanc-tests/Database/DummyCT.dcm | tr -d '\0' | sed 's/\\u0000//g' | sed 's/\.0$//' | python /tmp/tutu.py | grep -v 'InlineBinary' > /tmp/a.json
+DCMDICTPATH=/home/jodogne/Downloads/dcmtk-3.6.4/dcmdata/data/dicom.dic /home/jodogne/Downloads/dcmtk-3.6.4/i/bin/dcm2json ~/Subversion/orthanc-tests/Database/HierarchicalAnonymization/StructuredReports/IM0 | tr -d '\0' | sed 's/\\u0000//g' | sed 's/\.0$//' | python /tmp/tutu.py > /tmp/a.json
 
 make -j4 && ./UnitTests --gtest_filter=DicomWeb* && python /tmp/tutu.py < /tmp/tutu.json > /tmp/b.json && diff -i /tmp/a.json /tmp/b.json
 
@@ -861,7 +909,7 @@
 TEST(DicomWebJson, Basic)
 {
   std::string content;
-  Orthanc::SystemToolbox::ReadFile(content, "/home/jodogne/Subversion/orthanc-tests/Database/DummyCT.dcm");
+  Orthanc::SystemToolbox::ReadFile(content, "/home/jodogne/Subversion/orthanc-tests/Database/HierarchicalAnonymization/StructuredReports/IM0");
 
   Orthanc::ParsedDicomFile dicom(content);