# HG changeset patch # User Sebastien Jodogne # Date 1446133765 -3600 # Node ID 57b9e6890482b53bcd4913eaea0082fe4c802fbc # Parent 9ead18ef460a09b2c16b52b9133160a5476a607e New configuration option: "Dictionary" to declare custom DICOM tags diff -r 9ead18ef460a -r 57b9e6890482 NEWS --- 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 diff -r 9ead18ef460a -r 57b9e6890482 OrthancServer/FromDcmtkBridge.cpp --- 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(maxMultiplicity)) << ")"; + std::auto_ptr 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); + } } diff -r 9ead18ef460a -r 57b9e6890482 OrthancServer/FromDcmtkBridge.h --- 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); }; } diff -r 9ead18ef460a -r 57b9e6890482 OrthancServer/OrthancInitialization.cpp --- 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"; diff -r 9ead18ef460a -r 57b9e6890482 Plugins/Include/orthanc/OrthancCPlugin.h --- 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(). diff -r 9ead18ef460a -r 57b9e6890482 Resources/Configuration.json --- 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 ] + } }