changeset 1765:57b9e6890482

New configuration option: "Dictionary" to declare custom DICOM tags
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 29 Oct 2015 16:49:25 +0100
parents 9ead18ef460a
children d178fab186dd
files NEWS OrthancServer/FromDcmtkBridge.cpp OrthancServer/FromDcmtkBridge.h OrthancServer/OrthancInitialization.cpp Plugins/Include/orthanc/OrthancCPlugin.h Resources/Configuration.json
diffstat 6 files changed, 146 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Thu Oct 29 16:08:59 2015 +0100
+++ b/NEWS	Thu Oct 29 16:49:25 2015 +0100
@@ -9,12 +9,13 @@
 * "/series/.../ordered-slices" to order the slices of a 2D+t or 3D image
 * New URI "/tools/shutdown" to stop Orthanc from the REST API
 * New URIs for attachments: ".../compress", ".../uncompress" and ".../is-compressed"
+* New configuration option: "Dictionary" to declare custom DICOM tags
 
 Plugins
 -------
 
 * New function "OrthancPluginRegisterErrorCode()" to declare custom error codes
-* New function "OrthancPluginRegisterDictionaryTag()" to declare DICOM tags
+* New function "OrthancPluginRegisterDictionaryTag()" to declare custom DICOM tags
 * New "OrthancStarted" and "OrthancStopped" events in change callbacks
 
 Lua
--- a/OrthancServer/FromDcmtkBridge.cpp	Thu Oct 29 16:08:59 2015 +0100
+++ b/OrthancServer/FromDcmtkBridge.cpp	Thu Oct 29 16:49:25 2015 +0100
@@ -255,15 +255,21 @@
       throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
 
+    bool arbitrary = false;
     if (maxMultiplicity == 0)
     {
       maxMultiplicity = DcmVariableVM;
+      arbitrary = true;
     }
     else if (maxMultiplicity < minMultiplicity)
     {
       throw OrthancException(ErrorCode_ParameterOutOfRange);
     }
     
+    LOG(INFO) << "Registering tag in dictionary: " << tag << " " << (DcmVR(vr).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(),
@@ -1448,4 +1454,91 @@
 
     return element.release();
   }
+
+
+  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);
+  }
 }
--- a/OrthancServer/FromDcmtkBridge.h	Thu Oct 29 16:08:59 2015 +0100
+++ b/OrthancServer/FromDcmtkBridge.h	Thu Oct 29 16:49:25 2015 +0100
@@ -132,5 +132,7 @@
                                 const Json::Value& element,  // Encoding using UTF-8
                                 bool interpretBinaryTags,
                                 Encoding dicomEncoding);
+
+    static DcmEVR ParseValueRepresentation(const std::string& s);
   };
 }
--- a/OrthancServer/OrthancInitialization.cpp	Thu Oct 29 16:08:59 2015 +0100
+++ b/OrthancServer/OrthancInitialization.cpp	Thu Oct 29 16:49:25 2015 +0100
@@ -311,6 +311,42 @@
   }
 
 
+  static void LoadCustomDictionary(const Json::Value& configuration)
+  {
+    if (configuration.type() != Json::objectValue ||
+        !configuration.isMember("Dictionary") ||
+        configuration["Dictionary"].type() != Json::objectValue)
+    {
+      return;
+    }
+
+    Json::Value::Members tags(configuration["Dictionary"].getMemberNames());
+
+    for (Json::Value::ArrayIndex i = 0; i < tags.size(); i++)
+    {
+      const Json::Value& content = configuration["Dictionary"][tags[i]];
+      if (content.type() != Json::arrayValue ||
+          content.size() < 2 ||
+          content.size() > 4 ||
+          content[0].type() != Json::stringValue ||
+          content[1].type() != Json::stringValue ||
+          (content.size() >= 3 && content[2].type() != Json::intValue) ||
+          (content.size() >= 4 && content[3].type() != Json::intValue))
+      {
+        throw OrthancException(ErrorCode_BadFileFormat);
+      }
+
+      DicomTag tag(FromDcmtkBridge::ParseTag(tags[i]));
+      DcmEVR vr = FromDcmtkBridge::ParseValueRepresentation(content[0].asString());
+      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;
+
+      FromDcmtkBridge::RegisterDictionaryTag(tag, vr, name, minMultiplicity, maxMultiplicity);
+    }
+  }
+
+
 
   void OrthancInitialize(const char* configurationFile)
   {
@@ -340,6 +376,7 @@
     RegisterUserContentType();
 
     FromDcmtkBridge::InitializeDictionary();
+    LoadCustomDictionary(configuration_);
 
 #if ORTHANC_JPEG_LOSSLESS_ENABLED == 1
     LOG(WARNING) << "Registering JPEG Lossless codecs";
--- a/Plugins/Include/orthanc/OrthancCPlugin.h	Thu Oct 29 16:08:59 2015 +0100
+++ b/Plugins/Include/orthanc/OrthancCPlugin.h	Thu Oct 29 16:49:25 2015 +0100
@@ -3791,7 +3791,7 @@
    * @brief Register a new tag into the DICOM dictionary.
    *
    * This function declares a new tag in the dictionary of DICOM tags
-   * that is known to Orthanc. This function should be used in the
+   * that are known to Orthanc. This function should be used in the
    * OrthancPluginInitialize() callback.
    *
    * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
--- a/Resources/Configuration.json	Thu Oct 29 16:08:59 2015 +0100
+++ b/Resources/Configuration.json	Thu Oct 29 16:49:25 2015 +0100
@@ -262,5 +262,15 @@
   // will enable case-sensitive match for PN value representation
   // (such as PatientName). By default, the search is
   // case-insensitive, which does not follow the DICOM standard.
-  "CaseSensitivePN" : false
+  "CaseSensitivePN" : false,
+  
+  // Register a new tag in the dictionary of DICOM tags that are known
+  // to Orthanc. Each line must contain the tag (formatted as 2
+  // hexadecimal numbers), the value representation (2 upcase
+  // characters), a nickname for the tag, possibly the minimum
+  // multiplicity (> 0 with defaults to 1), and possibly the maximum
+  // multiplicity (0 means arbitrary multiplicity, defaults to 1).
+  "Dictionary" : {
+    // "0014,1020" : [ "DA", "ValidationExpiryDate", 1, 1 ]
+  }
 }