changeset 2006:6301bbcbcaed

more generic support of value representations
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 09 Jun 2016 14:48:40 +0200
parents 9e021b2b348b
children 655489d9165d
files Core/Enumerations.cpp Core/Enumerations.h OrthancServer/DicomProtocol/DicomUserConnection.cpp OrthancServer/FromDcmtkBridge.cpp OrthancServer/FromDcmtkBridge.h OrthancServer/OrthancFindRequestHandler.cpp OrthancServer/OrthancInitialization.cpp OrthancServer/Search/HierarchicalMatcher.cpp OrthancServer/Search/IFindConstraint.cpp OrthancServer/ServerEnumerations.h OrthancServer/ToDcmtkBridge.cpp OrthancServer/ToDcmtkBridge.h Plugins/Engine/OrthancPlugins.cpp Plugins/Engine/PluginsEnumerations.cpp Plugins/Engine/PluginsEnumerations.h UnitTestsSources/FromDcmtkTests.cpp
diffstat 16 files changed, 609 insertions(+), 256 deletions(-) [+]
line wrap: on
line diff
--- a/Core/Enumerations.cpp	Wed Jun 08 12:36:21 2016 +0200
+++ b/Core/Enumerations.cpp	Thu Jun 09 14:48:40 2016 +0200
@@ -35,6 +35,7 @@
 
 #include "OrthancException.h"
 #include "Toolbox.h"
+#include "Logging.h"
 
 #include <string.h>
 #include <cassert>
@@ -900,6 +901,151 @@
   }
 
 
+  ValueRepresentation StringToValueRepresentation(const std::string& vr,
+                                                  bool throwIfUnsupported)
+  {
+    if (vr == "AE")
+    {
+      return ValueRepresentation_ApplicationEntity;
+    }
+    else if (vr == "AS")
+    {
+      return ValueRepresentation_AgeString;
+    }
+    else if (vr == "AT")
+    {
+      return ValueRepresentation_AttributeTag;
+    }
+    else if (vr == "CS")
+    {
+      return ValueRepresentation_CodeString;
+    }
+    else if (vr == "DA")
+    {
+      return ValueRepresentation_Date;
+    }
+    else if (vr == "DS")
+    {
+      return ValueRepresentation_DecimalString;
+    }
+    else if (vr == "DT")
+    {
+      return ValueRepresentation_DateTime;
+    }
+    else if (vr == "FL")
+    {
+      return ValueRepresentation_FloatingPointSingle;
+    }
+    else if (vr == "FD")
+    {
+      return ValueRepresentation_FloatingPointDouble;
+    }
+    else if (vr == "IS")
+    {
+      return ValueRepresentation_IntegerString;
+    }
+    else if (vr == "LO")
+    {
+      return ValueRepresentation_LongString;
+    }
+    else if (vr == "LT")
+    {
+      return ValueRepresentation_LongText;
+    }
+    else if (vr == "OB")
+    {
+      return ValueRepresentation_OtherByte;
+    }
+    else if (vr == "OD")
+    {
+      return ValueRepresentation_OtherDouble;
+    }
+    else if (vr == "OF")
+    {
+      return ValueRepresentation_OtherFloat;
+    }
+    else if (vr == "OL")
+    {
+      return ValueRepresentation_OtherLong;
+    }
+    else if (vr == "OW")
+    {
+      return ValueRepresentation_OtherWord;
+    }
+    else if (vr == "PN")
+    {
+      return ValueRepresentation_PatientName;
+    }
+    else if (vr == "SH")
+    {
+      return ValueRepresentation_ShortString;
+    }
+    else if (vr == "SL")
+    {
+      return ValueRepresentation_SignedLong;
+    }
+    else if (vr == "SQ")
+    {
+      return ValueRepresentation_Sequence;
+    }
+    else if (vr == "SS")
+    {
+      return ValueRepresentation_SignedShort;
+    }
+    else if (vr == "ST")
+    {
+      return ValueRepresentation_ShortText;
+    }
+    else if (vr == "TM")
+    {
+      return ValueRepresentation_Time;
+    }
+    else if (vr == "UC")
+    {
+      return ValueRepresentation_UnlimitedCharacters;
+    }
+    else if (vr == "UI")
+    {
+      return ValueRepresentation_UniqueIdentifier;
+    }
+    else if (vr == "UL")
+    {
+      return ValueRepresentation_UnsignedLong;
+    }
+    else if (vr == "UN")
+    {
+      return ValueRepresentation_Unknown;
+    }
+    else if (vr == "UR")
+    {
+      return ValueRepresentation_UniversalResource;
+    }
+    else if (vr == "US")
+    {
+      return ValueRepresentation_UnsignedShort;
+    }
+    else if (vr == "UT")
+    {
+      return ValueRepresentation_UnlimitedText;
+    }
+    else
+    {
+      std::string s = "Unsupported value representation encountered: " + vr;
+
+      if (throwIfUnsupported)
+      {
+        LOG(ERROR) << s;
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+      }
+      else
+      {
+        LOG(INFO) << s;
+        return ValueRepresentation_NotSupported;
+      }
+    }
+  }
+
+
   unsigned int GetBytesPerPixel(PixelFormat format)
   {
     switch (format)
--- a/Core/Enumerations.h	Wed Jun 08 12:36:21 2016 +0200
+++ b/Core/Enumerations.h	Thu Jun 09 14:48:40 2016 +0200
@@ -32,6 +32,8 @@
 
 #pragma once
 
+#include <string>
+
 namespace Orthanc
 {
   enum Endianness
@@ -385,6 +387,48 @@
 
 
   /**
+   * The value representations Orthanc knows about. They correspond to
+   * the DICOM 2016b version of the standard.
+   * http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_6.2.html
+   **/
+  enum ValueRepresentation
+  {
+    ValueRepresentation_ApplicationEntity = 1,     // AE
+    ValueRepresentation_AgeString = 2,             // AS
+    ValueRepresentation_AttributeTag = 3,          // AT (2 x uint16_t)
+    ValueRepresentation_CodeString = 4,            // CS
+    ValueRepresentation_Date = 5,                  // DA
+    ValueRepresentation_DecimalString = 6,         // DS
+    ValueRepresentation_DateTime = 7,              // DT
+    ValueRepresentation_FloatingPointSingle = 8,   // FL (float)
+    ValueRepresentation_FloatingPointDouble = 9,   // FD (double)
+    ValueRepresentation_IntegerString = 10,        // IS
+    ValueRepresentation_LongString = 11,           // LO
+    ValueRepresentation_LongText = 12,             // LT
+    ValueRepresentation_OtherByte = 13,            // OB
+    ValueRepresentation_OtherDouble = 14,          // OD
+    ValueRepresentation_OtherFloat = 15,           // OF
+    ValueRepresentation_OtherLong = 16,            // OL
+    ValueRepresentation_OtherWord = 17,            // OW
+    ValueRepresentation_PatientName = 18,          // PN
+    ValueRepresentation_ShortString = 19,          // SH
+    ValueRepresentation_SignedLong = 20,           // SL (int32_t)
+    ValueRepresentation_Sequence = 21,             // SQ
+    ValueRepresentation_SignedShort = 22,          // SS (int16_t)
+    ValueRepresentation_ShortText = 23,            // ST
+    ValueRepresentation_Time = 24,                 // TM
+    ValueRepresentation_UnlimitedCharacters = 25,  // UC
+    ValueRepresentation_UniqueIdentifier = 26,     // UI (UID)
+    ValueRepresentation_UnsignedLong = 27,         // UL (uint32_t)
+    ValueRepresentation_Unknown = 28,              // UN
+    ValueRepresentation_UniversalResource = 29,    // UR (URI or URL)
+    ValueRepresentation_UnsignedShort = 30,        // US (uint16_t)
+    ValueRepresentation_UnlimitedText = 31,        // UT
+    ValueRepresentation_NotSupported               // Not supported by Orthanc, or tag not in dictionary
+  };
+
+
+  /**
    * WARNING: Do not change the explicit values in the enumerations
    * below this point. This would result in incompatible databases
    * between versions of Orthanc!
@@ -459,7 +503,10 @@
 
   ImageFormat StringToImageFormat(const char* format);
 
-  LogLevel StringToLogLevel(const char* format);
+  LogLevel StringToLogLevel(const char* level);
+
+  ValueRepresentation StringToValueRepresentation(const std::string& vr,
+                                                  bool throwIfUnsupported);
 
   unsigned int GetBytesPerPixel(PixelFormat format);
 
--- a/OrthancServer/DicomProtocol/DicomUserConnection.cpp	Wed Jun 08 12:36:21 2016 +0200
+++ b/OrthancServer/DicomProtocol/DicomUserConnection.cpp	Thu Jun 09 14:48:40 2016 +0200
@@ -496,7 +496,7 @@
 
         for (std::set<DicomTag>::const_iterator it = tags.begin(); it != tags.end(); ++it)
         {
-          if (FromDcmtkBridge::GetValueRepresentation(*it) == ValueRepresentation_Date)
+          if (FromDcmtkBridge::LookupValueRepresentation(*it) == ValueRepresentation_Date)
           {
             // Replace a "*" query by an empty query ("") for "date"
             // value representations. Necessary to search over dates
--- a/OrthancServer/FromDcmtkBridge.cpp	Wed Jun 08 12:36:21 2016 +0200
+++ b/OrthancServer/FromDcmtkBridge.cpp	Thu Jun 09 14:48:40 2016 +0200
@@ -37,6 +37,7 @@
 #endif
 
 #include "FromDcmtkBridge.h"
+#include "ToDcmtkBridge.h"
 #include "../Core/Logging.h"
 #include "../Core/Toolbox.h"
 #include "../Core/Uuid.h"
@@ -232,7 +233,7 @@
 
 
   void FromDcmtkBridge::RegisterDictionaryTag(const DicomTag& tag,
-                                              const DcmEVR& vr,
+                                              ValueRepresentation vr,
                                               const std::string& name,
                                               unsigned int minMultiplicity,
                                               unsigned int maxMultiplicity)
@@ -253,13 +254,15 @@
       throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
     
-    LOG(INFO) << "Registering tag in dictionary: " << tag << " " << (DcmVR(vr).getValidVRName()) << " " 
+    DcmEVR evr = ToDcmtkBridge::Convert(vr);
+
+    LOG(INFO) << "Registering tag in dictionary: " << tag << " " << (DcmVR(evr).getValidVRName()) << " " 
               << name << " (multiplicity: " << minMultiplicity << "-" 
               << (arbitrary ? "n" : boost::lexical_cast<std::string>(maxMultiplicity)) << ")";
 
     std::auto_ptr<DcmDictEntry>  entry(new DcmDictEntry(tag.GetGroup(),
                                                         tag.GetElement(),
-                                                        vr, name.c_str(),
+                                                        evr, name.c_str(),
                                                         static_cast<int>(minMultiplicity),
                                                         static_cast<int>(maxMultiplicity),
                                                         NULL    /* version */,
@@ -1069,28 +1072,115 @@
   }
 
 
-  ValueRepresentation FromDcmtkBridge::GetValueRepresentation(const DicomTag& tag)
+  ValueRepresentation FromDcmtkBridge::LookupValueRepresentation(const DicomTag& tag)
   {
     DcmTag t(tag.GetGroup(), tag.GetElement());
-    switch (t.getEVR())
+    return Convert(t.getEVR());
+  }
+
+  ValueRepresentation FromDcmtkBridge::Convert(const DcmEVR vr)
+  {
+    switch (vr)
     {
-      case EVR_PN:
-        return ValueRepresentation_PatientName;
+      case EVR_AE:
+        return ValueRepresentation_ApplicationEntity;
+
+      case EVR_AS:
+        return ValueRepresentation_AgeString;
+
+      case EVR_AT:
+        return ValueRepresentation_AttributeTag;
+
+      case EVR_CS:
+        return ValueRepresentation_CodeString;
 
       case EVR_DA:
         return ValueRepresentation_Date;
 
+      case EVR_DS:
+        return ValueRepresentation_DecimalString;
+
       case EVR_DT:
         return ValueRepresentation_DateTime;
 
+      case EVR_FL:
+        return ValueRepresentation_FloatingPointSingle;
+
+      case EVR_FD:
+        return ValueRepresentation_FloatingPointDouble;
+
+      case EVR_IS:
+        return ValueRepresentation_IntegerString;
+
+      case EVR_LO:
+        return ValueRepresentation_LongString;
+
+      case EVR_LT:
+        return ValueRepresentation_LongText;
+
+      case EVR_OB:
+        return ValueRepresentation_OtherByte;
+
+        // Not supported as of DCMTK 3.6.0
+        /*case EVR_OD:
+          return ValueRepresentation_OtherDouble;*/
+
+      case EVR_OF:
+        return ValueRepresentation_OtherFloat;
+
+        // Not supported as of DCMTK 3.6.0
+        /*case EVR_OL:
+          return ValueRepresentation_OtherLong;*/
+
+      case EVR_OW:
+        return ValueRepresentation_OtherWord;
+
+      case EVR_PN:
+        return ValueRepresentation_PatientName;
+
+      case EVR_SH:
+        return ValueRepresentation_ShortString;
+
+      case EVR_SL:
+        return ValueRepresentation_SignedLong;
+
+      case EVR_SQ:
+        return ValueRepresentation_Sequence;
+
+      case EVR_SS:
+        return ValueRepresentation_SignedShort;
+
+      case EVR_ST:
+        return ValueRepresentation_ShortText;
+
       case EVR_TM:
         return ValueRepresentation_Time;
 
-      case EVR_SQ:
-        return ValueRepresentation_Sequence;
+        // Not supported as of DCMTK 3.6.0
+        /*case EVR_UC:
+          return ValueRepresentation_UnlimitedCharacters;*/
+
+      case EVR_UI:
+        return ValueRepresentation_UniqueIdentifier;
+
+      case EVR_UL:
+        return ValueRepresentation_UnsignedLong;
+
+      case EVR_UN:
+        return ValueRepresentation_Unknown;
+
+        // Not supported as of DCMTK 3.6.0
+        /*case EVR_UR:
+          return ValueRepresentation_UniversalResource;*/
+
+      case EVR_US:
+        return ValueRepresentation_UnsignedShort;
+
+      case EVR_UT:
+        return ValueRepresentation_UnlimitedText;
 
       default:
-        return ValueRepresentation_Other;
+        return ValueRepresentation_NotSupported;
     }
   }
 
@@ -1477,93 +1567,6 @@
   }
 
 
-  DcmEVR FromDcmtkBridge::ParseValueRepresentation(const std::string& s)
-  {
-    if (s == "AE")
-      return EVR_AE;
-
-    if (s == "AS")
-      return EVR_AS;
-
-    if (s == "AT")
-      return EVR_AT;
-
-    if (s == "CS")
-      return EVR_CS;
-
-    if (s == "DA")
-      return EVR_DA;
-
-    if (s == "DS")
-      return EVR_DS;
-
-    if (s == "DT")
-      return EVR_DT;
-
-    if (s == "FD")
-      return EVR_FD;
-
-    if (s == "FL")
-      return EVR_FL;
-
-    if (s == "IS")
-      return EVR_IS;
-
-    if (s == "LO")
-      return EVR_LO;
-
-    if (s == "LT")
-      return EVR_LT;
-
-    if (s == "OB")
-      return EVR_OB;
-
-    if (s == "OF")
-      return EVR_OF;
-
-    if (s == "OW")
-      return EVR_OW;
-
-    if (s == "PN")
-      return EVR_PN;
-
-    if (s == "SH")
-      return EVR_SH;
-
-    if (s == "SL")
-      return EVR_SL;
-
-    if (s == "SQ")
-      return EVR_SQ;
-
-    if (s == "SS")
-      return EVR_SS;
-
-    if (s == "ST")
-      return EVR_ST;
-
-    if (s == "TM")
-      return EVR_TM;
-
-    if (s == "UI")
-      return EVR_UI;
-
-    if (s == "UL")
-      return EVR_UL;
-
-    if (s == "UN")
-      return EVR_UN;
-
-    if (s == "US")
-      return EVR_US;
-
-    if (s == "UT")
-      return EVR_UT;
-
-    throw OrthancException(ErrorCode_ParameterOutOfRange);
-  }
-
-
   DcmPixelSequence* FromDcmtkBridge::GetPixelSequence(DcmDataset& dataset)
   {
     DcmElement *element = NULL;
--- a/OrthancServer/FromDcmtkBridge.h	Wed Jun 08 12:36:21 2016 +0200
+++ b/OrthancServer/FromDcmtkBridge.h	Thu Jun 09 14:48:40 2016 +0200
@@ -50,7 +50,7 @@
     static void InitializeDictionary();
 
     static void RegisterDictionaryTag(const DicomTag& tag,
-                                      const DcmEVR& vr,
+                                      ValueRepresentation vr,
                                       const std::string& name,
                                       unsigned int minMultiplicity,
                                       unsigned int maxMultiplicity);
@@ -131,7 +131,9 @@
     static bool SaveToMemoryBuffer(std::string& buffer,
                                    DcmDataset& dataSet);
 
-    static ValueRepresentation GetValueRepresentation(const DicomTag& tag);
+    static ValueRepresentation Convert(DcmEVR vr);
+
+    static ValueRepresentation LookupValueRepresentation(const DicomTag& tag);
 
     static DcmElement* CreateElementForTag(const DicomTag& tag);
     
@@ -146,8 +148,6 @@
                                 bool decodeDataUriScheme,
                                 Encoding dicomEncoding);
 
-    static DcmEVR ParseValueRepresentation(const std::string& s);
-
     static DcmPixelSequence* GetPixelSequence(DcmDataset& dataset);
 
     static Encoding ExtractEncoding(const Json::Value& json,
--- a/OrthancServer/OrthancFindRequestHandler.cpp	Wed Jun 08 12:36:21 2016 +0200
+++ b/OrthancServer/OrthancFindRequestHandler.cpp	Thu Jun 09 14:48:40 2016 +0200
@@ -610,7 +610,7 @@
 
       if (FilterQueryTag(value, level, tag, modality.GetManufacturer()))
       {
-        ValueRepresentation vr = FromDcmtkBridge::GetValueRepresentation(tag);
+        ValueRepresentation vr = FromDcmtkBridge::LookupValueRepresentation(tag);
 
         // DICOM specifies that searches must be case sensitive, except
         // for tags with a PN value representation
--- a/OrthancServer/OrthancInitialization.cpp	Wed Jun 08 12:36:21 2016 +0200
+++ b/OrthancServer/OrthancInitialization.cpp	Thu Jun 09 14:48:40 2016 +0200
@@ -42,6 +42,7 @@
 #include "ServerEnumerations.h"
 #include "DatabaseWrapper.h"
 #include "FromDcmtkBridge.h"
+#include "ToDcmtkBridge.h"
 
 #include <boost/lexical_cast.hpp>
 #include <boost/filesystem.hpp>
@@ -378,7 +379,7 @@
       }
 
       DicomTag tag(FromDcmtkBridge::ParseTag(tags[i]));
-      DcmEVR vr = FromDcmtkBridge::ParseValueRepresentation(content[0].asString());
+      ValueRepresentation vr = StringToValueRepresentation(content[0].asString(), true);
       std::string name = content[1].asString();
       unsigned int minMultiplicity = (content.size() >= 2) ? content[2].asUInt() : 1;
       unsigned int maxMultiplicity = (content.size() >= 3) ? content[3].asUInt() : 1;
--- a/OrthancServer/Search/HierarchicalMatcher.cpp	Wed Jun 08 12:36:21 2016 +0200
+++ b/OrthancServer/Search/HierarchicalMatcher.cpp	Thu Jun 09 14:48:40 2016 +0200
@@ -92,7 +92,7 @@
         continue;
       }
 
-      ValueRepresentation vr = FromDcmtkBridge::GetValueRepresentation(tag);
+      ValueRepresentation vr = FromDcmtkBridge::LookupValueRepresentation(tag);
 
       if (constraints_.find(tag) != constraints_.end() ||
           sequences_.find(tag) != sequences_.end())
--- a/OrthancServer/Search/IFindConstraint.cpp	Wed Jun 08 12:36:21 2016 +0200
+++ b/OrthancServer/Search/IFindConstraint.cpp	Thu Jun 09 14:48:40 2016 +0200
@@ -47,7 +47,7 @@
                                                          const std::string& dicomQuery,
                                                          bool caseSensitive)
   {
-    ValueRepresentation vr = FromDcmtkBridge::GetValueRepresentation(tag);
+    ValueRepresentation vr = FromDcmtkBridge::LookupValueRepresentation(tag);
 
     if (vr == ValueRepresentation_Sequence)
     {
--- a/OrthancServer/ServerEnumerations.h	Wed Jun 08 12:36:21 2016 +0200
+++ b/OrthancServer/ServerEnumerations.h	Thu Jun 09 14:48:40 2016 +0200
@@ -95,16 +95,6 @@
     TransferSyntax_Rle
   };
 
-  enum ValueRepresentation
-  {
-    ValueRepresentation_Other,
-    ValueRepresentation_PatientName,
-    ValueRepresentation_Date,
-    ValueRepresentation_DateTime,
-    ValueRepresentation_Time,
-    ValueRepresentation_Sequence
-  };
-
   enum DicomToJsonFormat
   {
     DicomToJsonFormat_Full,
--- a/OrthancServer/ToDcmtkBridge.cpp	Wed Jun 08 12:36:21 2016 +0200
+++ b/OrthancServer/ToDcmtkBridge.cpp	Thu Jun 09 14:48:40 2016 +0200
@@ -36,6 +36,8 @@
 #include <memory>
 #include <dcmtk/dcmnet/diutil.h>
 
+#include "../Core/OrthancException.h"
+
 
 namespace Orthanc
 {
@@ -55,4 +57,111 @@
 
     return result.release();
   }
+
+
+  DcmEVR ToDcmtkBridge::Convert(ValueRepresentation vr)
+  {
+    switch (vr)
+    {
+      case ValueRepresentation_ApplicationEntity:
+        return EVR_AE;
+
+      case ValueRepresentation_AgeString:
+        return EVR_AS;
+
+      case ValueRepresentation_AttributeTag:
+        return EVR_AT;
+
+      case ValueRepresentation_CodeString:
+        return EVR_CS;
+
+      case ValueRepresentation_Date:
+        return EVR_DA;
+
+      case ValueRepresentation_DecimalString:
+        return EVR_DS;
+
+      case ValueRepresentation_DateTime:
+        return EVR_DT;
+
+      case ValueRepresentation_FloatingPointSingle:
+        return EVR_FL;
+
+      case ValueRepresentation_FloatingPointDouble:
+        return EVR_FD;
+
+      case ValueRepresentation_IntegerString:
+        return EVR_IS;
+
+      case ValueRepresentation_LongString:
+        return EVR_LO;
+
+      case ValueRepresentation_LongText:
+        return EVR_LT;
+
+      case ValueRepresentation_OtherByte:
+        return EVR_OB;
+
+        // Not supported as of DCMTK 3.6.0
+        /*case ValueRepresentation_OtherDouble:
+          return EVR_OD;*/
+
+      case ValueRepresentation_OtherFloat:
+        return EVR_OF;
+
+        // Not supported as of DCMTK 3.6.0
+        /*case ValueRepresentation_OtherLong:
+          return EVR_OL;*/
+
+      case ValueRepresentation_OtherWord:
+        return EVR_OW;
+
+      case ValueRepresentation_PatientName:
+        return EVR_PN;
+
+      case ValueRepresentation_ShortString:
+        return EVR_SH;
+
+      case ValueRepresentation_SignedLong:
+        return EVR_SL;
+
+      case ValueRepresentation_Sequence:
+        return EVR_SQ;
+
+      case ValueRepresentation_SignedShort:
+        return EVR_SS;
+
+      case ValueRepresentation_ShortText:
+        return EVR_ST;
+
+      case ValueRepresentation_Time:
+        return EVR_TM;
+
+        // Not supported as of DCMTK 3.6.0
+        /*case ValueRepresentation_UnlimitedCharacters:
+          return EVR_UC;*/
+
+      case ValueRepresentation_UniqueIdentifier:
+        return EVR_UI;
+
+      case ValueRepresentation_UnsignedLong:
+        return EVR_UL;
+
+      case ValueRepresentation_Unknown:
+        return EVR_UN;
+
+        // Not supported as of DCMTK 3.6.0
+        /*case ValueRepresentation_UniversalResource:
+          return EVR_UR;*/
+
+      case ValueRepresentation_UnsignedShort:
+        return EVR_US;
+
+      case ValueRepresentation_UnlimitedText:
+        return EVR_UT;
+
+      default:
+        throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+  }
 }
--- a/OrthancServer/ToDcmtkBridge.h	Wed Jun 08 12:36:21 2016 +0200
+++ b/OrthancServer/ToDcmtkBridge.h	Thu Jun 09 14:48:40 2016 +0200
@@ -46,5 +46,7 @@
     }
 
     static DcmDataset* Convert(const DicomMap& map);
+
+    static DcmEVR Convert(ValueRepresentation vr);
   };
 }
--- a/Plugins/Engine/OrthancPlugins.cpp	Wed Jun 08 12:36:21 2016 +0200
+++ b/Plugins/Engine/OrthancPlugins.cpp	Thu Jun 09 14:48:40 2016 +0200
@@ -2126,7 +2126,7 @@
     {
       p.target->group = entry->getKey().getGroup();
       p.target->element = entry->getKey().getElement();
-      p.target->vr = Plugins::Convert(entry->getEVR());
+      p.target->vr = Plugins::Convert(FromDcmtkBridge::Convert(entry->getEVR()));
       p.target->minMultiplicity = static_cast<uint32_t>(entry->getVMMin());
       p.target->maxMultiplicity = (entry->getVMMax() == DcmVariableVM ? 0 : static_cast<uint32_t>(entry->getVMMax()));
     }
--- a/Plugins/Engine/PluginsEnumerations.cpp	Wed Jun 08 12:36:21 2016 +0200
+++ b/Plugins/Engine/PluginsEnumerations.cpp	Thu Jun 09 14:48:40 2016 +0200
@@ -326,185 +326,201 @@
     }
 
 
-#if !defined(ORTHANC_ENABLE_DCMTK) || ORTHANC_ENABLE_DCMTK != 0
-    DcmEVR Convert(OrthancPluginValueRepresentation vr)
+    ValueRepresentation Convert(OrthancPluginValueRepresentation vr)
     {
       switch (vr)
       {
         case OrthancPluginValueRepresentation_AE:
-          return EVR_AE;
+          return ValueRepresentation_ApplicationEntity;
 
         case OrthancPluginValueRepresentation_AS:
-          return EVR_AS;
+          return ValueRepresentation_AgeString;
 
         case OrthancPluginValueRepresentation_AT:
-          return EVR_AT;
+          return ValueRepresentation_AttributeTag;
 
         case OrthancPluginValueRepresentation_CS:
-          return EVR_CS;
+          return ValueRepresentation_CodeString;
 
         case OrthancPluginValueRepresentation_DA:
-          return EVR_DA;
+          return ValueRepresentation_Date;
 
         case OrthancPluginValueRepresentation_DS:
-          return EVR_DS;
+          return ValueRepresentation_DecimalString;
 
         case OrthancPluginValueRepresentation_DT:
-          return EVR_DT;
+          return ValueRepresentation_DateTime;
 
         case OrthancPluginValueRepresentation_FD:
-          return EVR_FD;
+          return ValueRepresentation_FloatingPointDouble;
 
         case OrthancPluginValueRepresentation_FL:
-          return EVR_FL;
+          return ValueRepresentation_FloatingPointSingle;
 
         case OrthancPluginValueRepresentation_IS:
-          return EVR_IS;
+          return ValueRepresentation_IntegerString;
 
         case OrthancPluginValueRepresentation_LO:
-          return EVR_LO;
+          return ValueRepresentation_LongString;
 
         case OrthancPluginValueRepresentation_LT:
-          return EVR_LT;
+          return ValueRepresentation_LongText;
 
         case OrthancPluginValueRepresentation_OB:
-          return EVR_OB;
+          return ValueRepresentation_OtherByte;
 
         case OrthancPluginValueRepresentation_OF:
-          return EVR_OF;
+          return ValueRepresentation_OtherFloat;
 
         case OrthancPluginValueRepresentation_OW:
-          return EVR_OW;
+          return ValueRepresentation_OtherWord;
 
         case OrthancPluginValueRepresentation_PN:
-          return EVR_PN;
+          return ValueRepresentation_PatientName;
 
         case OrthancPluginValueRepresentation_SH:
-          return EVR_SH;
+          return ValueRepresentation_ShortString;
 
         case OrthancPluginValueRepresentation_SL:
-          return EVR_SL;
+          return ValueRepresentation_SignedLong;
 
         case OrthancPluginValueRepresentation_SQ:
-          return EVR_SQ;
+          return ValueRepresentation_Sequence;
 
         case OrthancPluginValueRepresentation_SS:
-          return EVR_SS;
+          return ValueRepresentation_SignedShort;
 
         case OrthancPluginValueRepresentation_ST:
-          return EVR_ST;
+          return ValueRepresentation_ShortText;
 
         case OrthancPluginValueRepresentation_TM:
-          return EVR_TM;
+          return ValueRepresentation_Time;
 
         case OrthancPluginValueRepresentation_UI:
-          return EVR_UI;
+          return ValueRepresentation_UniqueIdentifier;
 
         case OrthancPluginValueRepresentation_UL:
-          return EVR_UL;
+          return ValueRepresentation_UnsignedLong;
 
         case OrthancPluginValueRepresentation_UN:
-          return EVR_UN;
+          return ValueRepresentation_Unknown;
 
         case OrthancPluginValueRepresentation_US:
-          return EVR_US;
+          return ValueRepresentation_UnsignedShort;
 
         case OrthancPluginValueRepresentation_UT:
-          return EVR_UT;
+          return ValueRepresentation_UnlimitedText;
+
+        default:
+          throw OrthancException(ErrorCode_ParameterOutOfRange);
+
+          /*
+          Not supported as of DCMTK 3.6.0:
+          return ValueRepresentation_OtherDouble
+          return ValueRepresentation_OtherLong
+          return ValueRepresentation_UniversalResource
+          return ValueRepresentation_UnlimitedCharacters
+          */
+      }
+    }
+
+
+    OrthancPluginValueRepresentation Convert(ValueRepresentation vr)
+    {
+      switch (vr)
+      {
+        case ValueRepresentation_ApplicationEntity:
+          return OrthancPluginValueRepresentation_AE;
+
+        case ValueRepresentation_AgeString:
+          return OrthancPluginValueRepresentation_AS;
+
+        case ValueRepresentation_AttributeTag:
+          return OrthancPluginValueRepresentation_AT;
+
+        case ValueRepresentation_CodeString:
+          return OrthancPluginValueRepresentation_CS;
+
+        case ValueRepresentation_Date:
+          return OrthancPluginValueRepresentation_DA;
+
+        case ValueRepresentation_DecimalString:
+          return OrthancPluginValueRepresentation_DS;
+
+        case ValueRepresentation_DateTime:
+          return OrthancPluginValueRepresentation_DT;
+
+        case ValueRepresentation_FloatingPointDouble:
+          return OrthancPluginValueRepresentation_FD;
+
+        case ValueRepresentation_FloatingPointSingle:
+          return OrthancPluginValueRepresentation_FL;
+
+        case ValueRepresentation_IntegerString:
+          return OrthancPluginValueRepresentation_IS;
+
+        case ValueRepresentation_LongString:
+          return OrthancPluginValueRepresentation_LO;
+
+        case ValueRepresentation_LongText:
+          return OrthancPluginValueRepresentation_LT;
+
+        case ValueRepresentation_OtherByte:
+          return OrthancPluginValueRepresentation_OB;
+
+        case ValueRepresentation_OtherFloat:
+          return OrthancPluginValueRepresentation_OF;
+
+        case ValueRepresentation_OtherWord:
+          return OrthancPluginValueRepresentation_OW;
+
+        case ValueRepresentation_PatientName:
+          return OrthancPluginValueRepresentation_PN;
+
+        case ValueRepresentation_ShortString:
+          return OrthancPluginValueRepresentation_SH;
+
+        case ValueRepresentation_SignedLong:
+          return OrthancPluginValueRepresentation_SL;
+
+        case ValueRepresentation_Sequence:
+          return OrthancPluginValueRepresentation_SQ;
+
+        case ValueRepresentation_SignedShort:
+          return OrthancPluginValueRepresentation_SS;
+
+        case ValueRepresentation_ShortText:
+          return OrthancPluginValueRepresentation_ST;
+
+        case ValueRepresentation_Time:
+          return OrthancPluginValueRepresentation_TM;
+
+        case ValueRepresentation_UniqueIdentifier:
+          return OrthancPluginValueRepresentation_UI;
+
+        case ValueRepresentation_UnsignedLong:
+          return OrthancPluginValueRepresentation_UL;
+
+        case ValueRepresentation_UnsignedShort:
+          return OrthancPluginValueRepresentation_US;
+
+        case ValueRepresentation_UnlimitedText:
+          return OrthancPluginValueRepresentation_UT;
+
+        case ValueRepresentation_Unknown:
+          return OrthancPluginValueRepresentation_UN;  // Unknown
+
+          // These VR are not supported as of DCMTK 3.6.0, so they are
+          // mapped to "UN" (unknown) VR in the plugins
+        case ValueRepresentation_OtherDouble:          
+        case ValueRepresentation_OtherLong:
+        case ValueRepresentation_UniversalResource:
+        case ValueRepresentation_UnlimitedCharacters:
+          return OrthancPluginValueRepresentation_UN;
 
         default:
           throw OrthancException(ErrorCode_ParameterOutOfRange);
       }
     }
-
-
-    OrthancPluginValueRepresentation Convert(DcmEVR vr)
-    {
-      switch (vr)
-      {
-        case EVR_AE:
-          return OrthancPluginValueRepresentation_AE;
-
-        case EVR_AS:
-          return OrthancPluginValueRepresentation_AS;
-
-        case EVR_AT:
-          return OrthancPluginValueRepresentation_AT;
-
-        case EVR_CS:
-          return OrthancPluginValueRepresentation_CS;
-
-        case EVR_DA:
-          return OrthancPluginValueRepresentation_DA;
-
-        case EVR_DS:
-          return OrthancPluginValueRepresentation_DS;
-
-        case EVR_DT:
-          return OrthancPluginValueRepresentation_DT;
-
-        case EVR_FD:
-          return OrthancPluginValueRepresentation_FD;
-
-        case EVR_FL:
-          return OrthancPluginValueRepresentation_FL;
-
-        case EVR_IS:
-          return OrthancPluginValueRepresentation_IS;
-
-        case EVR_LO:
-          return OrthancPluginValueRepresentation_LO;
-
-        case EVR_LT:
-          return OrthancPluginValueRepresentation_LT;
-
-        case EVR_OB:
-          return OrthancPluginValueRepresentation_OB;
-
-        case EVR_OF:
-          return OrthancPluginValueRepresentation_OF;
-
-        case EVR_OW:
-          return OrthancPluginValueRepresentation_OW;
-
-        case EVR_PN:
-          return OrthancPluginValueRepresentation_PN;
-
-        case EVR_SH:
-          return OrthancPluginValueRepresentation_SH;
-
-        case EVR_SL:
-          return OrthancPluginValueRepresentation_SL;
-
-        case EVR_SQ:
-          return OrthancPluginValueRepresentation_SQ;
-
-        case EVR_SS:
-          return OrthancPluginValueRepresentation_SS;
-
-        case EVR_ST:
-          return OrthancPluginValueRepresentation_ST;
-
-        case EVR_TM:
-          return OrthancPluginValueRepresentation_TM;
-
-        case EVR_UI:
-          return OrthancPluginValueRepresentation_UI;
-
-        case EVR_UL:
-          return OrthancPluginValueRepresentation_UL;
-
-        case EVR_US:
-          return OrthancPluginValueRepresentation_US;
-
-        case EVR_UT:
-          return OrthancPluginValueRepresentation_UT;
-
-        case EVR_UN:
-        default:
-          return OrthancPluginValueRepresentation_UN;  // Unknown
-      }
-    }
-#endif
   }
 }
--- a/Plugins/Engine/PluginsEnumerations.h	Wed Jun 08 12:36:21 2016 +0200
+++ b/Plugins/Engine/PluginsEnumerations.h	Thu Jun 09 14:48:40 2016 +0200
@@ -37,10 +37,6 @@
 #include "../Include/orthanc/OrthancCPlugin.h"
 #include "../../OrthancServer/ServerEnumerations.h"
 
-#if !defined(ORTHANC_ENABLE_DCMTK) || ORTHANC_ENABLE_DCMTK != 0
-#include <dcmtk/dcmdata/dcvr.h>
-#endif
-
 namespace Orthanc
 {
   namespace Plugins
@@ -69,11 +65,9 @@
 
     OrthancPluginHttpMethod Convert(HttpMethod method);
 
-#if !defined(ORTHANC_ENABLE_DCMTK) || ORTHANC_ENABLE_DCMTK != 0
-    DcmEVR Convert(OrthancPluginValueRepresentation vr);
+    ValueRepresentation Convert(OrthancPluginValueRepresentation vr);
 
-    OrthancPluginValueRepresentation Convert(DcmEVR vr);
-#endif
+    OrthancPluginValueRepresentation Convert(ValueRepresentation vr);
   }
 }
 
--- a/UnitTestsSources/FromDcmtkTests.cpp	Wed Jun 08 12:36:21 2016 +0200
+++ b/UnitTestsSources/FromDcmtkTests.cpp	Thu Jun 09 14:48:40 2016 +0200
@@ -34,6 +34,7 @@
 #include "gtest/gtest.h"
 
 #include "../OrthancServer/FromDcmtkBridge.h"
+#include "../OrthancServer/ToDcmtkBridge.h"
 #include "../OrthancServer/OrthancInitialization.h"
 #include "../OrthancServer/DicomModification.h"
 #include "../OrthancServer/ServerToolbox.h"
@@ -48,6 +49,7 @@
 #include "../Resources/EncodingTests.h"
 #include "../OrthancServer/DicomProtocol/DicomFindAnswers.h"
 #include "../OrthancServer/Internals/DicomImageDecoder.h"
+#include "../Plugins/Engine/PluginsEnumerations.h"
 
 #include <dcmtk/dcmdata/dcelem.h>
 
@@ -300,15 +302,58 @@
 TEST(FromDcmtkBridge, ValueRepresentation)
 {
   ASSERT_EQ(ValueRepresentation_PatientName, 
-            FromDcmtkBridge::GetValueRepresentation(DICOM_TAG_PATIENT_NAME));
+            FromDcmtkBridge::LookupValueRepresentation(DICOM_TAG_PATIENT_NAME));
   ASSERT_EQ(ValueRepresentation_Date, 
-            FromDcmtkBridge::GetValueRepresentation(DicomTag(0x0008, 0x0020) /* StudyDate */));
+            FromDcmtkBridge::LookupValueRepresentation(DicomTag(0x0008, 0x0020) /* StudyDate */));
   ASSERT_EQ(ValueRepresentation_Time, 
-            FromDcmtkBridge::GetValueRepresentation(DicomTag(0x0008, 0x0030) /* StudyTime */));
+            FromDcmtkBridge::LookupValueRepresentation(DicomTag(0x0008, 0x0030) /* StudyTime */));
   ASSERT_EQ(ValueRepresentation_DateTime, 
-            FromDcmtkBridge::GetValueRepresentation(DicomTag(0x0008, 0x002a) /* AcquisitionDateTime */));
-  ASSERT_EQ(ValueRepresentation_Other, 
-            FromDcmtkBridge::GetValueRepresentation(DICOM_TAG_PATIENT_ID));
+            FromDcmtkBridge::LookupValueRepresentation(DicomTag(0x0008, 0x002a) /* AcquisitionDateTime */));
+  ASSERT_EQ(ValueRepresentation_NotSupported, 
+            FromDcmtkBridge::LookupValueRepresentation(DicomTag(0x0001, 0x0001) /* some private tag */));
+}
+
+
+TEST(FromDcmtkBridge, ValueRepresentationConversions)
+{
+  ASSERT_EQ(1, ValueRepresentation_ApplicationEntity);
+  ASSERT_EQ(1, OrthancPluginValueRepresentation_AE);
+
+  for (int i = ValueRepresentation_ApplicationEntity;
+       i <= ValueRepresentation_NotSupported; i++)
+  {
+    ValueRepresentation vr = static_cast<ValueRepresentation>(i);
+
+    if (vr == ValueRepresentation_NotSupported)
+    {
+      ASSERT_THROW(ToDcmtkBridge::Convert(vr), OrthancException);
+      ASSERT_THROW(Plugins::Convert(vr), OrthancException);
+    }
+    else if (vr == ValueRepresentation_OtherDouble || 
+             vr == ValueRepresentation_OtherLong ||
+             vr == ValueRepresentation_UniversalResource ||
+             vr == ValueRepresentation_UnlimitedCharacters)
+    {
+      // These VR are not supported as of DCMTK 3.6.0
+      ASSERT_THROW(ToDcmtkBridge::Convert(vr), OrthancException);
+      ASSERT_EQ(OrthancPluginValueRepresentation_UN, Plugins::Convert(vr));
+    }
+    else
+    {
+      ASSERT_EQ(vr, FromDcmtkBridge::Convert(ToDcmtkBridge::Convert(vr)));
+
+      OrthancPluginValueRepresentation plugins = Plugins::Convert(vr);
+      ASSERT_EQ(vr, Plugins::Convert(plugins));
+    }
+  }
+
+  for (int i = OrthancPluginValueRepresentation_AE;
+       i <= OrthancPluginValueRepresentation_UT; i++)
+  {
+    OrthancPluginValueRepresentation plugins = static_cast<OrthancPluginValueRepresentation>(i);
+    ValueRepresentation orthanc = Plugins::Convert(plugins);
+    ASSERT_EQ(plugins, Plugins::Convert(orthanc));
+  }
 }
 
 
@@ -531,8 +576,8 @@
 
 TEST(ParsedDicomFile, ToJsonFlags1)
 {
-  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7053, 0x1000), EVR_PN, "MyPrivateTag", 1, 1);
-  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7050, 0x1000), EVR_PN, "Declared public tag", 1, 1);
+  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7053, 0x1000), ValueRepresentation_PatientName, "MyPrivateTag", 1, 1);
+  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7050, 0x1000), ValueRepresentation_PatientName, "Declared public tag", 1, 1);
 
   ParsedDicomFile f(true);
   f.Insert(DicomTag(0x7050, 0x1000), "Some public tag", false);  // Even group => public tag
@@ -672,9 +717,9 @@
 
 TEST(ParsedDicomFile, FromJson)
 {
-  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7057, 0x1000), EVR_OB, "MyPrivateTag", 1, 1);
-  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7059, 0x1000), EVR_OB, "MyPrivateTag", 1, 1);
-  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7050, 0x1000), EVR_PN, "Declared public tag", 1, 1);
+  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7057, 0x1000), ValueRepresentation_OtherByte, "MyPrivateTag", 1, 1);
+  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7059, 0x1000), ValueRepresentation_OtherByte, "MyPrivateTag", 1, 1);
+  FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7050, 0x1000), ValueRepresentation_PatientName, "Declared public tag", 1, 1);
 
   Json::Value v;
   const std::string sopClassUid = "1.2.840.10008.5.1.4.1.1.1";  // CR Image Storage: