changeset 3522:00b0f4ce84e2

merge
author Alain Mazy <alain@mazy.be>
date Mon, 23 Sep 2019 17:48:12 +0200
parents 793c141be598 (current diff) 77bede920d22 (diff)
children d96379a965de
files
diffstat 9 files changed, 161 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- a/Core/DicomFormat/DicomArray.h	Mon Sep 23 17:47:54 2019 +0200
+++ b/Core/DicomFormat/DicomArray.h	Mon Sep 23 17:48:12 2019 +0200
@@ -62,6 +62,6 @@
       return *elements_[i];
     }
 
-    void Print(FILE* fp) const;
+    void Print(FILE* fp) const;  // For debugging only
   };
 }
--- a/Core/DicomFormat/DicomImageInformation.cpp	Mon Sep 23 17:47:54 2019 +0200
+++ b/Core/DicomFormat/DicomImageInformation.cpp	Mon Sep 23 17:48:12 2019 +0200
@@ -116,8 +116,9 @@
         photometric_ = PhotometricInterpretation_Unknown;
       }
 
-      width_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_COLUMNS).GetContent());
-      height_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_ROWS).GetContent());
+      values.GetValue(DICOM_TAG_COLUMNS).ParseFirstUnsignedInteger(width_); // in some US images, we've seen tag values of "800\0"; that's why we parse the 'first' value
+      values.GetValue(DICOM_TAG_ROWS).ParseFirstUnsignedInteger(height_);
+
       bitsAllocated_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_BITS_ALLOCATED).GetContent());
 
       try
--- a/Core/DicomFormat/DicomMap.cpp	Mon Sep 23 17:47:54 2019 +0200
+++ b/Core/DicomFormat/DicomMap.cpp	Mon Sep 23 17:48:12 2019 +0200
@@ -41,6 +41,7 @@
 #include "../Logging.h"
 #include "../OrthancException.h"
 #include "../Toolbox.h"
+#include "DicomArray.h"
 
 
 namespace Orthanc
@@ -876,9 +877,9 @@
   }
 
 
-  bool DicomMap::CopyToString(std::string& result,
-                              const DicomTag& tag,
-                              bool allowBinary) const
+  bool DicomMap::LookupStringValue(std::string& result,
+                                   const DicomTag& tag,
+                                   bool allowBinary) const
   {
     const DicomValue* value = TestAndGetValue(tag);
 
@@ -1275,4 +1276,27 @@
       }
     }
   }
+
+
+  std::string DicomMap::GetStringValue(const DicomTag& tag,
+                                       const std::string& defaultValue,
+                                       bool allowBinary) const
+  {
+    std::string s;
+    if (LookupStringValue(s, tag, allowBinary))
+    {
+      return s;
+    }
+    else
+    {
+      return defaultValue;
+    }
+  }
+
+
+  void DicomMap::Print(FILE* fp) const
+  {
+    DicomArray a(*this);
+    a.Print(fp);
+  }
 }
--- a/Core/DicomFormat/DicomMap.h	Mon Sep 23 17:47:54 2019 +0200
+++ b/Core/DicomFormat/DicomMap.h	Mon Sep 23 17:48:12 2019 +0200
@@ -198,9 +198,9 @@
 
     void LogMissingTagsForStore() const;
 
-    bool CopyToString(std::string& result,
-                      const DicomTag& tag,
-                      bool allowBinary) const;
+    bool LookupStringValue(std::string& result,
+                           const DicomTag& tag,
+                           bool allowBinary) const;
     
     bool ParseInteger32(int32_t& result,
                         const DicomTag& tag) const;
@@ -233,5 +233,11 @@
     void Unserialize(const Json::Value& source);
 
     void FromDicomWeb(const Json::Value& source);
+
+    std::string GetStringValue(const DicomTag& tag,
+                               const std::string& defaultValue,
+                               bool allowBinary) const;
+
+    void Print(FILE* fp) const;  // For debugging only
   };
 }
--- a/Core/DicomFormat/DicomValue.cpp	Mon Sep 23 17:47:54 2019 +0200
+++ b/Core/DicomFormat/DicomValue.cpp	Mon Sep 23 17:48:12 2019 +0200
@@ -94,6 +94,60 @@
   }
 #endif
 
+  // same as ParseValue but in case the value actually contains a sequence,
+  // it will return the first value
+  // this has been introduced to support invalid "width/height" DICOM tags in some US
+  // images where the width is stored as "800\0" !
+  template <typename T,
+            bool allowSigned>
+  static bool ParseFirstValue(T& result,
+                              const DicomValue& source)
+  {
+    if (source.IsBinary() ||
+        source.IsNull())
+    {
+      return false;
+    }
+
+    try
+    {
+      std::string value = Toolbox::StripSpaces(source.GetContent());
+      if (value.empty())
+      {
+        return false;
+      }
+
+      if (!allowSigned &&
+          value[0] == '-')
+      {
+        return false;
+      }
+
+      if (value.find("\\") == std::string::npos)
+      {
+        result = boost::lexical_cast<T>(value);
+        return true;
+      }
+      else
+      {
+        std::vector<std::string> tokens;
+        Toolbox::TokenizeString(tokens, value, '\\');
+
+        if (tokens.size() >= 1)
+        {
+          result = boost::lexical_cast<T>(tokens[0]);
+          return true;
+        }
+
+        return false;
+      }
+    }
+    catch (boost::bad_lexical_cast&)
+    {
+      return false;
+    }
+  }
+
 
   template <typename T,
             bool allowSigned>
@@ -177,6 +231,11 @@
     return ParseValue<double, true>(result, *this);
   }
 
+  bool DicomValue::ParseFirstUnsignedInteger(unsigned int& result) const
+  {
+    return ParseFirstValue<unsigned int, true>(result, *this);
+  }
+
   bool DicomValue::CopyToString(std::string& result,
                                 bool allowBinary) const
   {
--- a/Core/DicomFormat/DicomValue.h	Mon Sep 23 17:47:54 2019 +0200
+++ b/Core/DicomFormat/DicomValue.h	Mon Sep 23 17:48:12 2019 +0200
@@ -112,6 +112,8 @@
 
     bool ParseDouble(double& result) const;
 
+    bool ParseFirstUnsignedInteger(unsigned int& result) const;
+
     void Serialize(Json::Value& target) const;
 
     void Unserialize(const Json::Value& source);
--- a/Core/HttpClient.cpp	Mon Sep 23 17:47:54 2019 +0200
+++ b/Core/HttpClient.cpp	Mon Sep 23 17:48:12 2019 +0200
@@ -933,6 +933,8 @@
 
     CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_WRITEDATA, &answer));
 
+    const boost::posix_time::ptime start = boost::posix_time::microsec_clock::universal_time();
+    
     if (boost::starts_with(url_, "https://"))
     {
       code = OrthancHttpClientPerformSSL(pimpl_->curl_, &status);
@@ -942,7 +944,10 @@
       code = GetHttpStatus(curl_easy_perform(pimpl_->curl_), pimpl_->curl_, &status);
     }
 
-    LOG(INFO) << "HTTP status code " << status << " after "
+    const boost::posix_time::ptime end = boost::posix_time::microsec_clock::universal_time();
+    
+    LOG(INFO) << "HTTP status code " << status << " in "
+              << ((end - start).total_milliseconds()) << " ms after "
               << EnumerationToString(method_) << " request on: " << url_;
 
     if (isVerbose_)
--- a/UnitTestsSources/DicomMapTests.cpp	Mon Sep 23 17:47:54 2019 +0200
+++ b/UnitTestsSources/DicomMapTests.cpp	Mon Sep 23 17:48:12 2019 +0200
@@ -239,6 +239,7 @@
   int64_t j;
   uint32_t k;
   uint64_t l;
+  unsigned int ui;
   std::string s;
   
   m.SetValue(DICOM_TAG_PATIENT_NAME, "      ", false);  // Empty value
@@ -257,8 +258,8 @@
   ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger32(k));
   ASSERT_FALSE(m.GetValue(DICOM_TAG_PATIENT_NAME).ParseUnsignedInteger64(l));
 
-  ASSERT_FALSE(m.CopyToString(s, DICOM_TAG_PATIENT_NAME, false));
-  ASSERT_TRUE(m.CopyToString(s, DICOM_TAG_PATIENT_NAME, true));
+  ASSERT_FALSE(m.LookupStringValue(s, DICOM_TAG_PATIENT_NAME, false));
+  ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_PATIENT_NAME, true));
   ASSERT_EQ("0", s);
                
 
@@ -292,9 +293,9 @@
   ASSERT_EQ(42u, k);
   ASSERT_EQ(42ull, l);
 
-  ASSERT_TRUE(m.CopyToString(s, DICOM_TAG_PATIENT_NAME, false));
+  ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_PATIENT_NAME, false));
   ASSERT_EQ("42", s);
-  ASSERT_TRUE(m.CopyToString(s, DICOM_TAG_PATIENT_NAME, true));
+  ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_PATIENT_NAME, true));
   ASSERT_EQ("42", s);
                
   
@@ -375,6 +376,15 @@
   ASSERT_FLOAT_EQ(-2147483649.0f, f);
   ASSERT_DOUBLE_EQ(-2147483649.0, d); 
   ASSERT_EQ(-2147483649ll, j);
+
+
+  // "800\0" in US COLMUNS tag
+  m.SetValue(DICOM_TAG_COLUMNS, "800\0", false);
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_COLUMNS).ParseFirstUnsignedInteger(ui));
+  ASSERT_EQ(800, ui);
+  m.SetValue(DICOM_TAG_COLUMNS, "800", false);
+  ASSERT_TRUE(m.GetValue(DICOM_TAG_COLUMNS).ParseFirstUnsignedInteger(ui));
+  ASSERT_EQ(800, ui);
 }
 
 
@@ -597,12 +607,12 @@
     ASSERT_EQ(3u, m.GetSize());
 
     std::string s;
-    ASSERT_TRUE(m.CopyToString(s, DICOM_TAG_PATIENT_NAME, false));
+    ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_PATIENT_NAME, false));
     ASSERT_EQ("SB1^SB2^SB3^SB4^SB5", s);
-    ASSERT_TRUE(m.CopyToString(s, DICOM_TAG_IMAGE_POSITION_PATIENT, false));
+    ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_IMAGE_POSITION_PATIENT, false));
     ASSERT_TRUE(s.empty());
 
-    ASSERT_TRUE(m.CopyToString(s, DICOM_TAG_IMAGE_ORIENTATION_PATIENT, false));
+    ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_IMAGE_ORIENTATION_PATIENT, false));
 
     std::vector<std::string> v;
     Orthanc::Toolbox::TokenizeString(v, s, '\\');
@@ -647,7 +657,7 @@
     ASSERT_EQ(1u, m.GetSize());
 
     std::string s;
-    ASSERT_TRUE(m.CopyToString(s, DICOM_TAG_IMAGE_ORIENTATION_PATIENT, false));
+    ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_IMAGE_ORIENTATION_PATIENT, false));
 
     std::vector<std::string> v;
     Orthanc::Toolbox::TokenizeString(v, s, '\\');
@@ -851,41 +861,41 @@
     ASSERT_EQ(31u, m.GetSize());
 
     std::string s;
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0002, 0x0002), false));  ASSERT_EQ("UI", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0040, 0x0241), false));  ASSERT_EQ("AE", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0010, 0x1010), false));  ASSERT_EQ("AS", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0020, 0x9165), false));  ASSERT_EQ("00100020", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0008, 0x0052), false));  ASSERT_EQ("CS", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0008, 0x0012), false));  ASSERT_EQ("DA", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0010, 0x1020), false));  ASSERT_EQ("42", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0008, 0x002a), false));  ASSERT_EQ("DT", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0010, 0x9431), false));  ASSERT_EQ("43", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0008, 0x1163), false));  ASSERT_EQ("44", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0008, 0x1160), false));  ASSERT_EQ("45", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0008, 0x0070), false));  ASSERT_EQ("LO", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0010, 0x4000), false));  ASSERT_EQ("LT", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0028, 0x2000), true));   ASSERT_EQ("OB", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x7fe0, 0x0009), true));   ASSERT_EQ("OD", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0064, 0x0009), true));   ASSERT_EQ("OF", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0028, 0x1201), true));   ASSERT_EQ("OWOW", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0010, 0x0010), false));  ASSERT_EQ("PN", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0008, 0x0050), false));  ASSERT_EQ("SH", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0018, 0x6020), false));  ASSERT_EQ("-15", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0018, 0x9219), false));  ASSERT_EQ("-16", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0008, 0x0081), false));  ASSERT_EQ("ST", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0008, 0x0013), false));  ASSERT_EQ("TM", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0008, 0x0119), false));  ASSERT_EQ("UC", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0008, 0x0016), false));  ASSERT_EQ("UI", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0008, 0x1161), false));  ASSERT_EQ("128", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x4342, 0x1234), true));   ASSERT_EQ("UN", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0008, 0x0120), false));  ASSERT_EQ("UR", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0008, 0x0301), false));  ASSERT_EQ("17", s);
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0040, 0x0031), false));  ASSERT_EQ("UT", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0002, 0x0002), false));  ASSERT_EQ("UI", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0040, 0x0241), false));  ASSERT_EQ("AE", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x1010), false));  ASSERT_EQ("AS", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0020, 0x9165), false));  ASSERT_EQ("00100020", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0052), false));  ASSERT_EQ("CS", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0012), false));  ASSERT_EQ("DA", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x1020), false));  ASSERT_EQ("42", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x002a), false));  ASSERT_EQ("DT", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x9431), false));  ASSERT_EQ("43", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x1163), false));  ASSERT_EQ("44", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x1160), false));  ASSERT_EQ("45", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0070), false));  ASSERT_EQ("LO", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x4000), false));  ASSERT_EQ("LT", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0028, 0x2000), true));   ASSERT_EQ("OB", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x7fe0, 0x0009), true));   ASSERT_EQ("OD", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0064, 0x0009), true));   ASSERT_EQ("OF", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0028, 0x1201), true));   ASSERT_EQ("OWOW", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0010, 0x0010), false));  ASSERT_EQ("PN", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0050), false));  ASSERT_EQ("SH", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0018, 0x6020), false));  ASSERT_EQ("-15", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0018, 0x9219), false));  ASSERT_EQ("-16", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0081), false));  ASSERT_EQ("ST", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0013), false));  ASSERT_EQ("TM", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0119), false));  ASSERT_EQ("UC", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0016), false));  ASSERT_EQ("UI", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x1161), false));  ASSERT_EQ("128", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x4342, 0x1234), true));   ASSERT_EQ("UN", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0120), false));  ASSERT_EQ("UR", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0008, 0x0301), false));  ASSERT_EQ("17", s);
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0040, 0x0031), false));  ASSERT_EQ("UT", s);
 
 #if DCMTK_VERSION_NUMBER == 361
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0066, 0x0040), false));
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0066, 0x0040), false));
 #else
-    ASSERT_TRUE(m.CopyToString(s, DicomTag(0x0066, 0x0040), true));
+    ASSERT_TRUE(m.LookupStringValue(s, DicomTag(0x0066, 0x0040), true));
 #endif
     ASSERT_EQ("46", s);
   }
--- a/UnitTestsSources/FromDcmtkTests.cpp	Mon Sep 23 17:47:54 2019 +0200
+++ b/UnitTestsSources/FromDcmtkTests.cpp	Mon Sep 23 17:48:12 2019 +0200
@@ -1615,10 +1615,10 @@
     ASSERT_EQ(2u, m.GetSize());
 
     std::string s;
-    ASSERT_TRUE(m.CopyToString(s, DICOM_TAG_SPECIFIC_CHARACTER_SET, false));
+    ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_SPECIFIC_CHARACTER_SET, false));
     ASSERT_EQ("ISO 2022 IR 149", s);
 
-    ASSERT_TRUE(m.CopyToString(s, DICOM_TAG_PATIENT_NAME, false));
+    ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_PATIENT_NAME, false));
     std::vector<std::string> v;
     Toolbox::TokenizeString(v, s, '=');
     ASSERT_EQ(3u, v.size());
@@ -1712,10 +1712,10 @@
     ASSERT_EQ(2u, m.GetSize());
 
     std::string s;
-    ASSERT_TRUE(m.CopyToString(s, DICOM_TAG_SPECIFIC_CHARACTER_SET, false));
+    ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_SPECIFIC_CHARACTER_SET, false));
     ASSERT_EQ("ISO 2022 IR 87", s);
 
-    ASSERT_TRUE(m.CopyToString(s, DICOM_TAG_PATIENT_NAME, false));
+    ASSERT_TRUE(m.LookupStringValue(s, DICOM_TAG_PATIENT_NAME, false));
     std::vector<std::string> v;
     Toolbox::TokenizeString(v, s, '=');
     ASSERT_EQ(3u, v.size());