changeset 131:3112e5edb8b6

sync
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sat, 24 Mar 2018 11:30:05 +0100
parents 4f3945a2b725
children de866753a5fa
files Resources/Orthanc/Core/DicomFormat/DicomTag.h Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.cpp Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.h Resources/Orthanc/Core/Enumerations.cpp Resources/Orthanc/Core/Enumerations.h Resources/Orthanc/Resources/CMake/DcmtkConfiguration.cmake Resources/Orthanc/Resources/Patches/dcmtk-3.6.2-cmath.patch Resources/SyncOrthancFolder.py
diffstat 8 files changed, 465 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/Resources/Orthanc/Core/DicomFormat/DicomTag.h	Thu Mar 22 17:32:05 2018 +0100
+++ b/Resources/Orthanc/Core/DicomFormat/DicomTag.h	Sat Mar 24 11:30:05 2018 +0100
@@ -123,6 +123,8 @@
   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);
+  static const DicomTag DICOM_TAG_REFERENCED_SOP_INSTANCE_UID(0x0008, 0x1155);
+  static const DicomTag DICOM_TAG_FRAME_OF_REFERENCE_UID(0x0020, 0x0052);
 
   // DICOM tags used for fMRI (thanks to Will Ryder)
   static const DicomTag DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS(0x0020, 0x0105);
--- a/Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.cpp	Thu Mar 22 17:32:05 2018 +0100
+++ b/Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.cpp	Sat Mar 24 11:30:05 2018 +0100
@@ -667,11 +667,11 @@
           return new DicomValue;
       }
     }
-    catch (boost::bad_lexical_cast)
+    catch (boost::bad_lexical_cast&)
     {
       return new DicomValue;
     }
-    catch (std::bad_cast)
+    catch (std::bad_cast&)
     {
       return new DicomValue;
     }
@@ -2096,4 +2096,322 @@
     DJDecoderRegistration::cleanup();
 #endif
   }
+
+
+
+  // Forward declaration
+  static void ApplyVisitorToElement(DcmElement& element,
+                                    ITagVisitor& visitor,
+                                    const std::vector<DicomTag>& parentTags,
+                                    const std::vector<size_t>& parentIndexes,
+                                    Encoding encoding);
+ 
+  static void ApplyVisitorToDataset(DcmItem& dataset,
+                                    ITagVisitor& visitor,
+                                    const std::vector<DicomTag>& parentTags,
+                                    const std::vector<size_t>& parentIndexes,
+                                    Encoding encoding)
+  {
+    assert(parentTags.size() == parentIndexes.size());
+
+    for (unsigned long i = 0; i < dataset.card(); i++)
+    {
+      DcmElement* element = dataset.getElement(i);
+      if (element == NULL)
+      {
+        throw OrthancException(ErrorCode_InternalError);
+      }
+      else
+      {
+        ApplyVisitorToElement(*element, visitor, parentTags, parentIndexes, encoding);
+      }      
+    }
+  }
+
+
+  static void ApplyVisitorToLeaf(DcmElement& element,
+                                 ITagVisitor& visitor,
+                                 const std::vector<DicomTag>& parentTags,
+                                 const std::vector<size_t>& parentIndexes,
+                                 const DicomTag& tag,
+                                 Encoding encoding)
+  {
+    // TODO - Merge this function with ConvertLeafElement()
+
+    assert(element.isLeaf());
+
+    DcmEVR evr = element.getTag().getEVR();
+    ValueRepresentation vr = FromDcmtkBridge::Convert(evr);
+
+    char *c = NULL;
+    if (element.isaString() &&
+        element.getString(c).good())
+    {
+      std::string utf8;
+
+      if (c != NULL)  // This case corresponds to the empty string
+      {
+        std::string s(c);
+        utf8 = Toolbox::ConvertToUtf8(s, encoding);
+      }
+
+      std::string newValue;
+      ITagVisitor::Action action = visitor.VisitString
+        (newValue, parentTags, parentIndexes, tag, vr, utf8);
+
+      switch (action)
+      {
+        case ITagVisitor::Action_None:
+          break;
+
+        case ITagVisitor::Action_Replace:
+        {
+          std::string s = Toolbox::ConvertFromUtf8(newValue, encoding);
+          if (element.putString(s.c_str(), s.size()) != EC_Normal)
+          {
+            LOG(ERROR) << "Cannot replace value of tag: " << tag.Format();
+            throw OrthancException(ErrorCode_InternalError);
+          }
+
+          break;
+        }
+
+        default:
+          throw OrthancException(ErrorCode_InternalError);
+      }
+
+      return;  // We're done
+    }
+
+
+    try
+    {
+      // http://support.dcmtk.org/docs/dcvr_8h-source.html
+      switch (element.getVR())
+      {
+
+        /**
+         * Deal with binary data (including PixelData).
+         **/
+
+        case EVR_OB:  // other byte
+        case EVR_OF:  // other float
+        case EVR_OW:  // other word
+        case EVR_UN:  // unknown value representation
+        case EVR_ox:  // OB or OW depending on context
+        case EVR_DS:  // decimal string
+        case EVR_IS:  // integer string
+        case EVR_AS:  // age string
+        case EVR_DA:  // date string
+        case EVR_DT:  // date time string
+        case EVR_TM:  // time string
+        case EVR_AE:  // application entity title
+        case EVR_CS:  // code string
+        case EVR_SH:  // short string
+        case EVR_LO:  // long string
+        case EVR_ST:  // short text
+        case EVR_LT:  // long text
+        case EVR_UT:  // unlimited text
+        case EVR_PN:  // person name
+        case EVR_UI:  // unique identifier
+        case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR)
+        case EVR_UNKNOWN2B:  // used internally for elements with unknown VR with 2-byte length field in explicit VR
+        {
+          Uint8* data = NULL;
+
+          if (element.getUint8Array(data) == EC_Normal)
+          {
+            visitor.VisitBinary(parentTags, parentIndexes, tag, vr, data, element.getLength());
+          }
+          else
+          {
+            visitor.VisitUnknown(parentTags, parentIndexes, tag, vr);
+          }
+
+          break;
+        }
+    
+        /**
+         * Numeric types
+         **/ 
+      
+        case EVR_SL:  // signed long
+        {
+          Sint32 f;
+          if (dynamic_cast<DcmSignedLong&>(element).getSint32(f).good())
+          {
+            visitor.VisitInteger(parentTags, parentIndexes, tag, vr, f);
+          }
+
+          break;
+        }
+
+        case EVR_SS:  // signed short
+        {
+          Sint16 f;
+          if (dynamic_cast<DcmSignedShort&>(element).getSint16(f).good())
+          {
+            visitor.VisitInteger(parentTags, parentIndexes, tag, vr, f);
+          }
+
+          break;
+        }
+
+        case EVR_UL:  // unsigned long
+        {
+          Uint32 f;
+          if (dynamic_cast<DcmUnsignedLong&>(element).getUint32(f).good())
+          {
+            visitor.VisitInteger(parentTags, parentIndexes, tag, vr, f);
+          }
+
+          break;
+        }
+
+        case EVR_US:  // unsigned short
+        {
+          Uint16 f;
+          if (dynamic_cast<DcmUnsignedShort&>(element).getUint16(f).good())
+          {
+            visitor.VisitInteger(parentTags, parentIndexes, tag, vr, f);
+          }
+
+          break;
+        }
+
+        case EVR_FL:  // float single-precision
+        {
+          Float32 f;
+          if (dynamic_cast<DcmFloatingPointSingle&>(element).getFloat32(f).good())
+          {
+            visitor.VisitDouble(parentTags, parentIndexes, tag, vr, f);
+          }
+
+          break;
+        }
+
+        case EVR_FD:  // float double-precision
+        {
+          Float64 f;
+          if (dynamic_cast<DcmFloatingPointDouble&>(element).getFloat64(f).good())
+          {
+            visitor.VisitDouble(parentTags, parentIndexes, tag, vr, f);
+          }
+
+          break;
+        }
+
+
+        /**
+         * Attribute tag.
+         **/
+
+        case EVR_AT:
+        {
+          DcmTagKey tagKey;
+          if (dynamic_cast<DcmAttributeTag&>(element).getTagVal(tagKey, 0).good())
+          {
+            DicomTag t(tagKey.getGroup(), tagKey.getElement());
+            visitor.VisitAttribute(parentTags, parentIndexes, tag, vr, t);
+          }
+
+          break;
+        }
+
+
+        /**
+         * Sequence types, should never occur at this point because of
+         * "element.isLeaf()".
+         **/
+
+        case EVR_SQ:  // sequence of items
+          return;
+
+
+          /**
+           * Internal to DCMTK.
+           **/ 
+
+        case EVR_xs:  // SS or US depending on context
+        case EVR_lt:  // US, SS or OW depending on context, used for LUT Data (thus the name)
+        case EVR_na:  // na="not applicable", for data which has no VR
+        case EVR_up:  // up="unsigned pointer", used internally for DICOMDIR suppor
+        case EVR_item:  // used internally for items
+        case EVR_metainfo:  // used internally for meta info datasets
+        case EVR_dataset:  // used internally for datasets
+        case EVR_fileFormat:  // used internally for DICOM files
+        case EVR_dicomDir:  // used internally for DICOMDIR objects
+        case EVR_dirRecord:  // used internally for DICOMDIR records
+        case EVR_pixelSQ:  // used internally for pixel sequences in a compressed image
+        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);
+          return;
+
+
+          /**
+           * Default case.
+           **/ 
+
+        default:
+          return;
+      }
+    }
+    catch (boost::bad_lexical_cast&)
+    {
+      return;
+    }
+    catch (std::bad_cast&)
+    {
+      return;
+    }
+  }
+
+
+  static void ApplyVisitorToElement(DcmElement& element,
+                                    ITagVisitor& visitor,
+                                    const std::vector<DicomTag>& parentTags,
+                                    const std::vector<size_t>& parentIndexes,
+                                    Encoding encoding)
+  {
+    assert(parentTags.size() == parentIndexes.size());
+
+    DicomTag tag(FromDcmtkBridge::Convert(element.getTag()));
+
+    if (element.isLeaf())
+    {
+      ApplyVisitorToLeaf(element, visitor, parentTags, parentIndexes, tag, encoding);
+    }
+    else
+    {
+      // "All subclasses of DcmElement except for DcmSequenceOfItems
+      // are leaf nodes, while DcmSequenceOfItems, DcmItem, DcmDataset
+      // 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++)
+      {
+        indexes.back() = static_cast<size_t>(i);
+        DcmItem* child = sequence.getItem(i);
+        ApplyVisitorToDataset(*child, visitor, tags, indexes, encoding);
+      }
+    }
+  }
+
+
+  void FromDcmtkBridge::Apply(DcmItem& dataset,
+                              ITagVisitor& visitor,
+                              Encoding defaultEncoding)
+  {
+    std::vector<DicomTag> parentTags;
+    std::vector<size_t> parentIndexes;
+    Encoding encoding = DetectEncoding(dataset, defaultEncoding);
+    ApplyVisitorToDataset(dataset, visitor, parentTags, parentIndexes, encoding);
+  }
 }
--- a/Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.h	Thu Mar 22 17:32:05 2018 +0100
+++ b/Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.h	Sat Mar 24 11:30:05 2018 +0100
@@ -33,6 +33,7 @@
 
 #pragma once
 
+#include "ITagVisitor.h"
 #include "../DicomFormat/DicomElement.h"
 #include "../DicomFormat/DicomMap.h"
 
@@ -240,5 +241,9 @@
     static void InitializeCodecs();
 
     static void FinalizeCodecs();
+
+    static void Apply(DcmItem& dataset,
+                      ITagVisitor& visitor,
+                      Encoding defaultEncoding);
   };
 }
--- a/Resources/Orthanc/Core/Enumerations.cpp	Thu Mar 22 17:32:05 2018 +0100
+++ b/Resources/Orthanc/Core/Enumerations.cpp	Sat Mar 24 11:30:05 2018 +0100
@@ -878,6 +878,112 @@
   }
 
 
+  const char* EnumerationToString(ValueRepresentation vr)
+  {
+    switch (vr)
+    {
+      case ValueRepresentation_ApplicationEntity:     // AE
+        return "AE";
+
+      case ValueRepresentation_AgeString:             // AS
+        return "AS";
+
+      case ValueRepresentation_AttributeTag:          // AT (2 x uint16_t)
+        return "AT";
+
+      case ValueRepresentation_CodeString:            // CS
+        return "CS";
+
+      case ValueRepresentation_Date:                  // DA
+        return "DA";
+
+      case ValueRepresentation_DecimalString:         // DS
+        return "DS";
+
+      case ValueRepresentation_DateTime:              // DT
+        return "DT";
+
+      case ValueRepresentation_FloatingPointSingle:   // FL (float)
+        return "FL";
+
+      case ValueRepresentation_FloatingPointDouble:   // FD (double)
+        return "FD";
+
+      case ValueRepresentation_IntegerString:         // IS
+        return "IS";
+
+      case ValueRepresentation_LongString:            // LO
+        return "LO";
+
+      case ValueRepresentation_LongText:              // LT
+        return "LT";
+
+      case ValueRepresentation_OtherByte:             // OB
+        return "OB";
+
+      case ValueRepresentation_OtherDouble:           // OD
+        return "OD";
+
+      case ValueRepresentation_OtherFloat:            // OF
+        return "OF";
+
+      case ValueRepresentation_OtherLong:             // OL
+        return "OL";
+
+      case ValueRepresentation_OtherWord:             // OW
+        return "OW";
+
+      case ValueRepresentation_PersonName:            // PN
+        return "PN";
+
+      case ValueRepresentation_ShortString:           // SH
+        return "SH";
+
+      case ValueRepresentation_SignedLong:            // SL (int32_t)
+        return "SL";
+
+      case ValueRepresentation_Sequence:              // SQ
+        return "SQ";
+
+      case ValueRepresentation_SignedShort:           // SS (int16_t)
+        return "SS";
+
+      case ValueRepresentation_ShortText:             // ST
+        return "ST";
+
+      case ValueRepresentation_Time:                  // TM
+        return "TM";
+
+      case ValueRepresentation_UnlimitedCharacters:   // UC
+        return "UC";
+
+      case ValueRepresentation_UniqueIdentifier:      // UI (UID)
+        return "UI";
+
+      case ValueRepresentation_UnsignedLong:          // UL (uint32_t)
+        return "UL";
+
+      case ValueRepresentation_Unknown:               // UN
+        return "UN";
+
+      case ValueRepresentation_UniversalResource:     // UR (URI or URL)
+        return "UR";
+
+      case ValueRepresentation_UnsignedShort:         // US (uint16_t)
+        return "US";
+
+      case ValueRepresentation_UnlimitedText:         // UT
+        return "UT";
+
+      case ValueRepresentation_NotSupported:
+        return "Not supported";
+
+      default: 
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
   Encoding StringToEncoding(const char* encoding)
   {
     std::string s(encoding);
--- a/Resources/Orthanc/Core/Enumerations.h	Thu Mar 22 17:32:05 2018 +0100
+++ b/Resources/Orthanc/Core/Enumerations.h	Sat Mar 24 11:30:05 2018 +0100
@@ -620,6 +620,8 @@
 
   const char* EnumerationToString(DicomVersion version);
 
+  const char* EnumerationToString(ValueRepresentation vr);
+
   Encoding StringToEncoding(const char* encoding);
 
   ResourceType StringToResourceType(const char* type);
--- a/Resources/Orthanc/Resources/CMake/DcmtkConfiguration.cmake	Thu Mar 22 17:32:05 2018 +0100
+++ b/Resources/Orthanc/Resources/CMake/DcmtkConfiguration.cmake	Sat Mar 24 11:30:05 2018 +0100
@@ -81,8 +81,18 @@
         message(FATAL_ERROR "Error while patching a file")
       endif()
 
-    else (FirstRun())
-      message("No need to apply a patch for speed in DCMTK")
+    else()
+      message("Applying patch to detect mathematic primitives in DCMTK 3.6.2")
+      execute_process(
+        COMMAND ${PATCH_EXECUTABLE} -p0 -N -i
+        ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.2-cmath.patch
+        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+        RESULT_VARIABLE Failure
+        )
+
+      if (Failure)
+        message(FATAL_ERROR "Error while patching a file")
+      endif()
     endif()
   else()
     message("The patches for DCMTK have already been applied")
@@ -99,8 +109,6 @@
   
   if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase")
     SET(DCMTK_ENABLE_CHARSET_CONVERSION "iconv" CACHE STRING "")
-    SET(HAVE_PROTOTYPE_STD__ISINF 1 CACHE INTERNAL "")
-    SET(HAVE_PROTOTYPE_STD__ISNAN 1 CACHE INTERNAL "")
     SET(HAVE_SYS_GETTID 0 CACHE INTERNAL "")
 
     execute_process(
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Resources/Orthanc/Resources/Patches/dcmtk-3.6.2-cmath.patch	Sat Mar 24 11:30:05 2018 +0100
@@ -0,0 +1,17 @@
+diff -urEb dcmtk-3.6.2.orig/CMake/GenerateDCMTKConfigure.cmake dcmtk-3.6.2/CMake/GenerateDCMTKConfigure.cmake
+--- dcmtk-3.6.2.orig/CMake/GenerateDCMTKConfigure.cmake	2018-03-24 11:19:13.705396611 +0100
++++ dcmtk-3.6.2/CMake/GenerateDCMTKConfigure.cmake	2018-03-24 11:19:33.429286501 +0100
+@@ -571,9 +571,9 @@
+   CHECK_FUNCTIONWITHHEADER_EXISTS(isinf "${HEADERS}" HAVE_PROTOTYPE_ISINF)
+   CHECK_FUNCTIONWITHHEADER_EXISTS(isnan "${HEADERS}" HAVE_PROTOTYPE_ISNAN)
+   CHECK_FUNCTIONWITHHEADER_EXISTS(finite "${HEADERS}" HAVE_PROTOTYPE_FINITE)
+-  CHECK_FUNCTIONWITHHEADER_EXISTS(std::isinf "${HEADERS}" HAVE_PROTOTYPE_STD__ISINF)
+-  CHECK_FUNCTIONWITHHEADER_EXISTS(std::isnan "${HEADERS}" HAVE_PROTOTYPE_STD__ISNAN)
+-  CHECK_FUNCTIONWITHHEADER_EXISTS(std::finite "${HEADERS}" HAVE_PROTOTYPE_STD__FINITE)
++  CHECK_FUNCTIONWITHHEADER_EXISTS(std::isinf<double> "${HEADERS}" HAVE_PROTOTYPE_STD__ISINF)
++  CHECK_FUNCTIONWITHHEADER_EXISTS(std::isnan<double> "${HEADERS}" HAVE_PROTOTYPE_STD__ISNAN)
++  CHECK_FUNCTIONWITHHEADER_EXISTS(std::finite<double> "${HEADERS}" HAVE_PROTOTYPE_STD__FINITE)
+   CHECK_FUNCTIONWITHHEADER_EXISTS(flock "${HEADERS}" HAVE_PROTOTYPE_FLOCK)
+   CHECK_FUNCTIONWITHHEADER_EXISTS(gethostbyname "${HEADERS}" HAVE_PROTOTYPE_GETHOSTBYNAME)
+   CHECK_FUNCTIONWITHHEADER_EXISTS(gethostbyname_r "${HEADERS}" HAVE_PROTOTYPE_GETHOSTBYNAME_R)
+Only in dcmtk-3.6.2/CMake: GenerateDCMTKConfigure.cmake~
--- a/Resources/SyncOrthancFolder.py	Thu Mar 22 17:32:05 2018 +0100
+++ b/Resources/SyncOrthancFolder.py	Sat Mar 24 11:30:05 2018 +0100
@@ -130,6 +130,7 @@
     'Resources/Patches/dcmtk-3.6.0-mingw64.patch',
     'Resources/Patches/dcmtk-3.6.0-speed.patch',
     'Resources/Patches/dcmtk-3.6.2-linux-standard-base.patch',
+    'Resources/Patches/dcmtk-3.6.2-cmath.patch',
     'Resources/ThirdParty/VisualStudio/stdint.h',
     'Resources/ThirdParty/base64/base64.cpp',
     'Resources/ThirdParty/base64/base64.h',