changeset 2409:e4045b3c9772

ignore-length argument if retrieving DICOM tags
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 27 Sep 2017 17:36:13 +0200
parents 26a0cc24d48d
children 3590c936e56f
files Core/DicomNetworking/Internals/StoreScp.cpp Core/DicomParsing/FromDcmtkBridge.cpp Core/DicomParsing/FromDcmtkBridge.h Core/DicomParsing/ParsedDicomFile.cpp Core/DicomParsing/ParsedDicomFile.h NEWS OrthancServer/DicomInstanceToStore.cpp OrthancServer/OrthancRestApi/OrthancRestResources.cpp OrthancServer/Search/HierarchicalMatcher.cpp OrthancServer/ServerContext.cpp OrthancServer/ServerContext.h OrthancServer/ServerToolbox.cpp UnitTestsSources/FromDcmtkTests.cpp
diffstat 13 files changed, 268 insertions(+), 104 deletions(-) [+]
line wrap: on
line diff
--- a/Core/DicomNetworking/Internals/StoreScp.cpp	Mon Sep 25 14:50:13 2017 +0200
+++ b/Core/DicomNetworking/Internals/StoreScp.cpp	Wed Sep 27 17:36:13 2017 +0200
@@ -167,8 +167,10 @@
 
           try
           {
+            std::set<DicomTag> ignoreTagLength;
+            
             FromDcmtkBridge::ExtractDicomSummary(summary, **imageDataSet);
-            FromDcmtkBridge::ExtractDicomAsJson(dicomJson, **imageDataSet);
+            FromDcmtkBridge::ExtractDicomAsJson(dicomJson, **imageDataSet, ignoreTagLength);
 
             if (!FromDcmtkBridge::SaveToMemoryBuffer(buffer, **imageDataSet))
             {
--- a/Core/DicomParsing/FromDcmtkBridge.cpp	Mon Sep 25 14:50:13 2017 +0200
+++ b/Core/DicomParsing/FromDcmtkBridge.cpp	Wed Sep 27 17:36:13 2017 +0200
@@ -395,6 +395,8 @@
                                             unsigned int maxStringLength,
                                             Encoding defaultEncoding)
   {
+    std::set<DicomTag> ignoreTagLength;
+    
     Encoding encoding = DetectEncoding(dataset, defaultEncoding);
 
     target.Clear();
@@ -405,7 +407,8 @@
       {
         target.SetValue(element->getTag().getGTag(),
                         element->getTag().getETag(),
-                        ConvertLeafElement(*element, DicomToJsonFlags_Default, maxStringLength, encoding));
+                        ConvertLeafElement(*element, DicomToJsonFlags_Default,
+                                           maxStringLength, encoding, ignoreTagLength));
       }
     }
   }
@@ -426,7 +429,8 @@
   DicomValue* FromDcmtkBridge::ConvertLeafElement(DcmElement& element,
                                                   DicomToJsonFlags flags,
                                                   unsigned int maxStringLength,
-                                                  Encoding encoding)
+                                                  Encoding encoding,
+                                                  const std::set<DicomTag>& ignoreTagLength)
   {
     if (!element.isLeaf())
     {
@@ -448,7 +452,8 @@
         std::string utf8 = Toolbox::ConvertToUtf8(s, encoding);
 
         if (maxStringLength != 0 &&
-            utf8.size() > maxStringLength)
+            utf8.size() > maxStringLength &&
+            ignoreTagLength.find(GetTag(element)) == ignoreTagLength.end())
         {
           return new DicomValue;  // Too long, create a NULL value
         }
@@ -486,7 +491,8 @@
             return new DicomValue("", false);   // Empty string
           }
           else if (maxStringLength != 0 &&
-                   element.getLength() > maxStringLength)
+                   element.getLength() > maxStringLength &&
+                   ignoreTagLength.find(GetTag(element)) == ignoreTagLength.end())
           {
             return new DicomValue;  // Too long, create a NULL value
           }
@@ -499,7 +505,7 @@
       }
     }
 
-
+    
     try
     {
       // http://support.dcmtk.org/docs/dcvr_8h-source.html
@@ -814,7 +820,8 @@
                                       DicomToJsonFormat format,
                                       DicomToJsonFlags flags,
                                       unsigned int maxStringLength,
-                                      Encoding encoding)
+                                      Encoding encoding,
+                                      const std::set<DicomTag>& ignoreTagLength)
   {
     if (parent.type() == Json::nullValue)
     {
@@ -827,8 +834,17 @@
     if (element.isLeaf())
     {
       // The "0" below lets "LeafValueToJson()" take care of "TooLong" values
-      std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement(element, flags, 0, encoding));
-      LeafValueToJson(target, *v, format, flags, maxStringLength);
+      std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement
+                                  (element, flags, 0, encoding, ignoreTagLength));
+
+      if (ignoreTagLength.find(GetTag(element)) == ignoreTagLength.end())
+      {
+        LeafValueToJson(target, *v, format, flags, maxStringLength);
+      }
+      else
+      {
+        LeafValueToJson(target, *v, format, flags, 0);
+      }
     }
     else
     {
@@ -844,7 +860,7 @@
       {
         DcmItem* child = sequence.getItem(i);
         Json::Value& v = target.append(Json::objectValue);
-        DatasetToJson(v, *child, format, flags, maxStringLength, encoding);
+        DatasetToJson(v, *child, format, flags, maxStringLength, encoding, ignoreTagLength);
       }
     }
   }
@@ -855,7 +871,8 @@
                                       DicomToJsonFormat format,
                                       DicomToJsonFlags flags,
                                       unsigned int maxStringLength,
-                                      Encoding encoding)
+                                      Encoding encoding,
+                                      const std::set<DicomTag>& ignoreTagLength)
   {
     assert(parent.type() == Json::objectValue);
 
@@ -900,7 +917,8 @@
         }
       }
 
-      FromDcmtkBridge::ElementToJson(parent, *element, format, flags, maxStringLength, encoding);
+      FromDcmtkBridge::ElementToJson(parent, *element, format, flags,
+                                     maxStringLength, encoding, ignoreTagLength);
     }
   }
 
@@ -910,12 +928,13 @@
                                            DicomToJsonFormat format,
                                            DicomToJsonFlags flags,
                                            unsigned int maxStringLength,
-                                           Encoding defaultEncoding)
+                                           Encoding defaultEncoding,
+                                           const std::set<DicomTag>& ignoreTagLength)
   {
     Encoding encoding = DetectEncoding(dataset, defaultEncoding);
 
     target = Json::objectValue;
-    DatasetToJson(target, dataset, format, flags, maxStringLength, encoding);
+    DatasetToJson(target, dataset, format, flags, maxStringLength, encoding, ignoreTagLength);
   }
 
 
@@ -925,8 +944,9 @@
                                             DicomToJsonFlags flags,
                                             unsigned int maxStringLength)
   {
+    std::set<DicomTag> ignoreTagLength;
     target = Json::objectValue;
-    DatasetToJson(target, dataset, format, flags, maxStringLength, Encoding_Ascii);
+    DatasetToJson(target, dataset, format, flags, maxStringLength, Encoding_Ascii, ignoreTagLength);
   }
 
 
@@ -2036,13 +2056,15 @@
 
   
   void FromDcmtkBridge::ExtractDicomAsJson(Json::Value& target, 
-                                           DcmDataset& dataset)
+                                           DcmDataset& dataset,
+                                           const std::set<DicomTag>& ignoreTagLength)
   {
     ExtractDicomAsJson(target, dataset, 
                        DicomToJsonFormat_Full,
                        DicomToJsonFlags_Default, 
                        ORTHANC_MAXIMUM_TAG_LENGTH,
-                       GetDefaultDicomEncoding());
+                       GetDefaultDicomEncoding(),
+                       ignoreTagLength);
   }
 
 
--- a/Core/DicomParsing/FromDcmtkBridge.h	Mon Sep 25 14:50:13 2017 +0200
+++ b/Core/DicomParsing/FromDcmtkBridge.h	Wed Sep 27 17:36:13 2017 +0200
@@ -90,21 +90,24 @@
                               DicomToJsonFormat format,
                               DicomToJsonFlags flags,
                               unsigned int maxStringLength,
-                              Encoding encoding);
+                              Encoding encoding,
+                              const std::set<DicomTag>& ignoreTagLength);
 
     static void ElementToJson(Json::Value& parent,
                               DcmElement& element,
                               DicomToJsonFormat format,
                               DicomToJsonFlags flags,
                               unsigned int maxStringLength,
-                              Encoding dicomEncoding);
+                              Encoding dicomEncoding,
+                              const std::set<DicomTag>& ignoreTagLength);
 
     static void ExtractDicomAsJson(Json::Value& target, 
                                    DcmDataset& dataset,
                                    DicomToJsonFormat format,
                                    DicomToJsonFlags flags,
                                    unsigned int maxStringLength,
-                                   Encoding defaultEncoding);
+                                   Encoding defaultEncoding,
+                                   const std::set<DicomTag>& ignoreTagLength);
 
     static void ChangeStringEncoding(DcmItem& dataset,
                                      Encoding source,
@@ -132,7 +135,8 @@
     static DicomValue* ConvertLeafElement(DcmElement& element,
                                           DicomToJsonFlags flags,
                                           unsigned int maxStringLength,
-                                          Encoding encoding);
+                                          Encoding encoding,
+                                          const std::set<DicomTag>& ignoreTagLength);
 
     static void ExtractHeaderAsJson(Json::Value& target, 
                                     DcmMetaInfo& header,
@@ -230,7 +234,8 @@
                                     DcmItem& dataset);
 
     static void ExtractDicomAsJson(Json::Value& target, 
-                                   DcmDataset& dataset);
+                                   DcmDataset& dataset,
+                                   const std::set<DicomTag>& ignoreTagLength);
 
     static void InitializeCodecs();
 
--- a/Core/DicomParsing/ParsedDicomFile.cpp	Mon Sep 25 14:50:13 2017 +0200
+++ b/Core/DicomParsing/ParsedDicomFile.cpp	Wed Sep 27 17:36:13 2017 +0200
@@ -842,9 +842,10 @@
         return false;
       }
 
+      std::set<DicomTag> tmp;
       std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement
                                   (*element, DicomToJsonFlags_Default, 
-                                   ORTHANC_MAXIMUM_TAG_LENGTH, GetEncoding()));
+                                   0, GetEncoding(), tmp));
       
       if (v.get() == NULL ||
           v->IsNull())
@@ -1241,14 +1242,36 @@
                                       DicomToJsonFlags flags,
                                       unsigned int maxStringLength)
   {
+    std::set<DicomTag> ignoreTagLength;
     FromDcmtkBridge::ExtractDicomAsJson(target, *pimpl_->file_->getDataset(),
-                                        format, flags, maxStringLength, GetDefaultDicomEncoding());
+                                        format, flags, maxStringLength,
+                                        GetDefaultDicomEncoding(), ignoreTagLength);
+  }
+
+
+  void ParsedDicomFile::DatasetToJson(Json::Value& target, 
+                                      DicomToJsonFormat format,
+                                      DicomToJsonFlags flags,
+                                      unsigned int maxStringLength,
+                                      const std::set<DicomTag>& ignoreTagLength)
+  {
+    FromDcmtkBridge::ExtractDicomAsJson(target, *pimpl_->file_->getDataset(),
+                                        format, flags, maxStringLength,
+                                        GetDefaultDicomEncoding(), ignoreTagLength);
+  }
+
+
+  void ParsedDicomFile::DatasetToJson(Json::Value& target,
+                                      const std::set<DicomTag>& ignoreTagLength)
+  {
+    FromDcmtkBridge::ExtractDicomAsJson(target, *pimpl_->file_->getDataset(), ignoreTagLength);
   }
 
 
   void ParsedDicomFile::DatasetToJson(Json::Value& target)
   {
-    FromDcmtkBridge::ExtractDicomAsJson(target, *pimpl_->file_->getDataset());
+    const std::set<DicomTag> ignoreTagLength;
+    FromDcmtkBridge::ExtractDicomAsJson(target, *pimpl_->file_->getDataset(), ignoreTagLength);
   }
 
 
@@ -1449,12 +1472,6 @@
   }
 
 
-  void ParsedDicomFile::ExtractDicomAsJson(Json::Value& target) const
-  {
-    FromDcmtkBridge::ExtractDicomAsJson(target, *pimpl_->file_->getDataset());
-  }
-
-
   bool ParsedDicomFile::LookupTransferSyntax(std::string& result)
   {
     return FromDcmtkBridge::LookupTransferSyntax(result, *pimpl_->file_);
--- a/Core/DicomParsing/ParsedDicomFile.h	Mon Sep 25 14:50:13 2017 +0200
+++ b/Core/DicomParsing/ParsedDicomFile.h	Wed Sep 27 17:36:13 2017 +0200
@@ -182,8 +182,17 @@
                        DicomToJsonFlags flags,
                        unsigned int maxStringLength);
 
+    void DatasetToJson(Json::Value& target, 
+                       DicomToJsonFormat format,
+                       DicomToJsonFlags flags,
+                       unsigned int maxStringLength,
+                       const std::set<DicomTag>& ignoreTagLength);
+      
     // This version uses the default parameters for
     // FileContentType_DicomAsJson
+    void DatasetToJson(Json::Value& target,
+                       const std::set<DicomTag>& ignoreTagLength);
+
     void DatasetToJson(Json::Value& target);
 
     void HeaderToJson(Json::Value& target, 
@@ -208,8 +217,6 @@
 
     void ExtractDicomSummary(DicomMap& target) const;
 
-    void ExtractDicomAsJson(Json::Value& target) const;
-
     bool LookupTransferSyntax(std::string& result);
 
     bool LookupPhotometricInterpretation(PhotometricInterpretation& result) const;
--- a/NEWS	Mon Sep 25 14:50:13 2017 +0200
+++ b/NEWS	Wed Sep 27 17:36:13 2017 +0200
@@ -1,8 +1,16 @@
 Pending changes in the mainline
 ===============================
 
+REST API
+--------
+
+* New URI: "/instances/.../frames/.../raw.gz" to compress raw frames using gzip
+* New argument "ignore-length" to force the inclusion of too long tags in JSON
+
+Maintenance
+-----------
+
 * New security-related options: "DicomAlwaysAllowEcho"
-* New URI: "/instances/.../frames/.../raw.gz" to compress raw frames using gzip
 * Use "GBK" (frequently used in China) as an alias for "GB18030"
 * Experimental support of actively maintained Civetweb to replace Mongoose 3.8
 * Fix issue 64 (OpenBSD support)
--- a/OrthancServer/DicomInstanceToStore.cpp	Mon Sep 25 14:50:13 2017 +0200
+++ b/OrthancServer/DicomInstanceToStore.cpp	Wed Sep 27 17:36:13 2017 +0200
@@ -112,8 +112,11 @@
     if (!json_.HasContent())
     {
       json_.Allocate();
+
+      std::set<DicomTag> ignoreTagLength;
       FromDcmtkBridge::ExtractDicomAsJson(json_.GetContent(), 
-                                          *parsed_.GetContent().GetDcmtkObject().getDataset());
+                                          *parsed_.GetContent().GetDcmtkObject().getDataset(),
+                                          ignoreTagLength);
     }
   }
 
--- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp	Mon Sep 25 14:50:13 2017 +0200
+++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp	Wed Sep 27 17:36:13 2017 +0200
@@ -48,6 +48,42 @@
 
 namespace Orthanc
 {
+  static void AnswerDicomAsJson(RestApiCall& call,
+                                const Json::Value& dicom,
+                                bool simplify)
+  {
+    if (simplify)
+    {
+      Json::Value simplified;
+      ServerToolbox::SimplifyTags(simplified, dicom, DicomToJsonFormat_Human);
+      call.GetOutput().AnswerJson(simplified);
+    }
+    else
+    {
+      call.GetOutput().AnswerJson(dicom);
+    }
+  }
+
+
+  static void ParseSetOfTags(std::set<DicomTag>& target,
+                             const RestApiGetCall& call,
+                             const std::string& argument)
+  {
+    target.clear();
+
+    if (call.HasArgument(argument))
+    {
+      std::vector<std::string> tags;
+      Toolbox::TokenizeString(tags, call.GetArgument(argument, ""), ',');
+
+      for (size_t i = 0; i < tags.size(); i++)
+      {
+        target.insert(FromDcmtkBridge::ParseTag(tags[i]));
+      }
+    }
+  }
+
+
   // List all the patients, studies, series or instances ----------------------
  
   static void AnswerListOfResources(RestApiOutput& output,
@@ -206,18 +242,22 @@
     ServerContext& context = OrthancRestApi::GetContext(call);
 
     std::string publicId = call.GetUriComponent("id", "");
+
+    std::set<DicomTag> ignoreTagLength;
+    ParseSetOfTags(ignoreTagLength, call, "ignore-length");
     
-    if (simplify)
+    if (simplify ||
+        !ignoreTagLength.empty())
     {
       Json::Value full;
-      context.ReadDicomAsJson(full, publicId);
-
-      Json::Value simplified;
-      ServerToolbox::SimplifyTags(simplified, full, DicomToJsonFormat_Human);
-      call.GetOutput().AnswerJson(simplified);
+      context.ReadDicomAsJson(full, publicId, ignoreTagLength);
+      AnswerDicomAsJson(call, full, simplify);
     }
     else
     {
+      // This path allows to avoid the JSON decoding if no
+      // simplification is asked, or if no "ignore-length" argument is
+      // present
       std::string full;
       context.ReadDicomAsJson(full, publicId);
       call.GetOutput().AnswerBuffer(full, "application/json");
@@ -1010,16 +1050,7 @@
     if (ExtractSharedTags(sharedTags, context, publicId))
     {
       // Success: Send the value of the shared tags
-      if (simplify)
-      {
-        Json::Value simplified;
-        ServerToolbox::SimplifyTags(simplified, sharedTags, DicomToJsonFormat_Human);
-        call.GetOutput().AnswerJson(simplified);
-      }
-      else
-      {
-        call.GetOutput().AnswerJson(sharedTags);
-      }
+      AnswerDicomAsJson(call, sharedTags, simplify);
     }
   }
 
@@ -1042,6 +1073,9 @@
     std::string publicId = call.GetUriComponent("id", "");
     bool simplify = call.HasArgument("simplify");
 
+    std::set<DicomTag> ignoreTagLength;
+    ParseSetOfTags(ignoreTagLength, call, "ignore-length");
+
     typedef std::set<DicomTag> ModuleTags;
     ModuleTags moduleTags;
     DicomTag::AddTagsForModule(moduleTags, module);
@@ -1064,7 +1098,7 @@
       publicId = instances.front();
     }
 
-    context.ReadDicomAsJson(tags, publicId);
+    context.ReadDicomAsJson(tags, publicId, ignoreTagLength);
     
     // Filter the tags of the instance according to the module
     Json::Value result = Json::objectValue;
@@ -1077,16 +1111,7 @@
       }      
     }
 
-    if (simplify)
-    {
-      Json::Value simplified;
-      ServerToolbox::SimplifyTags(simplified, result, DicomToJsonFormat_Human);
-      call.GetOutput().AnswerJson(simplified);
-    }
-    else
-    {
-      call.GetOutput().AnswerJson(result);
-    }    
+    AnswerDicomAsJson(call, result, simplify);
   }
     
 
@@ -1283,6 +1308,9 @@
     std::string publicId = call.GetUriComponent("id", "");
     bool simplify = call.HasArgument("simplify");
 
+    std::set<DicomTag> ignoreTagLength;
+    ParseSetOfTags(ignoreTagLength, call, "ignore-length");
+
     // Retrieve all the instances of this patient/study/series
     typedef std::list<std::string> Instances;
     Instances instances;
@@ -1295,7 +1323,7 @@
          it != instances.end(); ++it)
     {
       Json::Value full;
-      context.ReadDicomAsJson(full, *it);
+      context.ReadDicomAsJson(full, *it, ignoreTagLength);
 
       if (simplify)
       {
@@ -1394,16 +1422,7 @@
     Json::Value header;
     dicom.HeaderToJson(header, DicomToJsonFormat_Full);
 
-    if (simplify)
-    {
-      Json::Value simplified;
-      ServerToolbox::SimplifyTags(simplified, header, DicomToJsonFormat_Human);
-      call.GetOutput().AnswerJson(simplified);
-    }
-    else
-    {
-      call.GetOutput().AnswerJson(header);
-    }
+    AnswerDicomAsJson(call, header, simplify);
   }
 
 
--- a/OrthancServer/Search/HierarchicalMatcher.cpp	Mon Sep 25 14:50:13 2017 +0200
+++ b/OrthancServer/Search/HierarchicalMatcher.cpp	Wed Sep 27 17:36:13 2017 +0200
@@ -122,9 +122,10 @@
       }
       else
       {
+        std::set<DicomTag> ignoreTagLength;
         std::auto_ptr<DicomValue> value(FromDcmtkBridge::ConvertLeafElement
                                         (*element, DicomToJsonFlags_None, 
-                                         ORTHANC_MAXIMUM_TAG_LENGTH, encoding));
+                                         ORTHANC_MAXIMUM_TAG_LENGTH, encoding, ignoreTagLength));
 
         if (value->IsBinary())
         {
@@ -222,9 +223,10 @@
           return false;
         }
 
+        std::set<DicomTag> ignoreTagLength;
         std::auto_ptr<DicomValue> value(FromDcmtkBridge::ConvertLeafElement
                                         (*element, DicomToJsonFlags_None, 
-                                         ORTHANC_MAXIMUM_TAG_LENGTH, encoding));
+                                         ORTHANC_MAXIMUM_TAG_LENGTH, encoding, ignoreTagLength));
 
         if (value->IsNull() ||
             value->IsBinary() ||
--- a/OrthancServer/ServerContext.cpp	Mon Sep 25 14:50:13 2017 +0200
+++ b/OrthancServer/ServerContext.cpp	Wed Sep 27 17:36:13 2017 +0200
@@ -383,48 +383,82 @@
   }
 
 
-  void ServerContext::ReadDicomAsJson(std::string& result,
-                                      const std::string& instancePublicId)
+  void ServerContext::ReadDicomAsJsonInternal(std::string& result,
+                                              const std::string& instancePublicId)
   {
     FileInfo attachment;
     if (index_.LookupAttachment(attachment, instancePublicId, FileContentType_DicomAsJson))
     {
       ReadAttachment(result, attachment);
-      return;
     }
+    else
+    {
+      // The "DICOM as JSON" summary is not available from the Orthanc
+      // store (most probably deleted), reconstruct it from the DICOM file
+      std::string dicom;
+      ReadDicom(dicom, instancePublicId);
 
-    // The "DICOM as JSON" summary is not available from the Orthanc
-    // store (most probably deleted), reconstruct it from the DICOM file
-    std::string dicom;
-    ReadDicom(dicom, instancePublicId);
-
-    LOG(INFO) << "Reconstructing the missing DICOM-as-JSON summary for instance: " << instancePublicId;
+      LOG(INFO) << "Reconstructing the missing DICOM-as-JSON summary for instance: "
+                << instancePublicId;
     
-    ParsedDicomFile parsed(dicom);
+      ParsedDicomFile parsed(dicom);
 
-    Json::Value summary;
-    parsed.DatasetToJson(summary);
+      Json::Value summary;
+      parsed.DatasetToJson(summary);
+
+      result = summary.toStyledString();
 
-    result = summary.toStyledString();
+      if (!AddAttachment(instancePublicId, FileContentType_DicomAsJson,
+                         result.c_str(), result.size()))
+      {
+        LOG(WARNING) << "Cannot associate the DICOM-as-JSON summary to instance: " << instancePublicId;
+        throw OrthancException(ErrorCode_InternalError);
+      }
+    }
+  }
+
 
-    if (!AddAttachment(instancePublicId, FileContentType_DicomAsJson, result.c_str(), result.size()))
+  void ServerContext::ReadDicomAsJson(std::string& result,
+                                      const std::string& instancePublicId,
+                                      const std::set<DicomTag>& ignoreTagLength)
+  {
+    if (ignoreTagLength.empty())
     {
-      LOG(WARNING) << "Cannot associate the DICOM-as-JSON summary to instance: " << instancePublicId;
-      throw OrthancException(ErrorCode_InternalError);
+      ReadDicomAsJsonInternal(result, instancePublicId);
+    }
+    else
+    {
+      Json::Value tmp;
+      ReadDicomAsJson(tmp, instancePublicId, ignoreTagLength);
+      result = tmp.toStyledString();
     }
   }
 
 
   void ServerContext::ReadDicomAsJson(Json::Value& result,
-                                      const std::string& instancePublicId)
+                                      const std::string& instancePublicId,
+                                      const std::set<DicomTag>& ignoreTagLength)
   {
-    std::string tmp;
-    ReadDicomAsJson(tmp, instancePublicId);
+    if (ignoreTagLength.empty())
+    {
+      std::string tmp;
+      ReadDicomAsJsonInternal(tmp, instancePublicId);
 
-    Json::Reader reader;
-    if (!reader.parse(tmp, result))
+      Json::Reader reader;
+      if (!reader.parse(tmp, result))
+      {
+        throw OrthancException(ErrorCode_CorruptedFile);
+      }
+    }
+    else
     {
-      throw OrthancException(ErrorCode_CorruptedFile);
+      // The "DicomAsJson" attachment might have stored some tags as
+      // "too long". We are forced to re-parse the DICOM file.
+      std::string dicom;
+      ReadDicom(dicom, instancePublicId);
+
+      ParsedDicomFile parsed(dicom);
+      parsed.DatasetToJson(result, ignoreTagLength);
     }
   }
 
--- a/OrthancServer/ServerContext.h	Mon Sep 25 14:50:13 2017 +0200
+++ b/OrthancServer/ServerContext.h	Wed Sep 27 17:36:13 2017 +0200
@@ -106,6 +106,8 @@
 
     static void ChangeThread(ServerContext* that);
 
+    void ReadDicomAsJsonInternal(std::string& result,
+                                 const std::string& instancePublicId);
 
     ServerIndex index_;
     IStorageArea& area_;
@@ -193,10 +195,26 @@
                                      CompressionType compression);
 
     void ReadDicomAsJson(std::string& result,
-                         const std::string& instancePublicId);
+                         const std::string& instancePublicId,
+                         const std::set<DicomTag>& ignoreTagLength);
 
     void ReadDicomAsJson(Json::Value& result,
-                         const std::string& instancePublicId);
+                         const std::string& instancePublicId,
+                         const std::set<DicomTag>& ignoreTagLength);
+
+    void ReadDicomAsJson(std::string& result,
+                         const std::string& instancePublicId)
+    {
+      std::set<DicomTag> ignoreTagLength;
+      ReadDicomAsJson(result, instancePublicId, ignoreTagLength);
+    }
+
+    void ReadDicomAsJson(Json::Value& result,
+                         const std::string& instancePublicId)
+    {
+      std::set<DicomTag> ignoreTagLength;
+      ReadDicomAsJson(result, instancePublicId, ignoreTagLength);
+    }
 
     void ReadDicom(std::string& dicom,
                    const std::string& instancePublicId)
--- a/OrthancServer/ServerToolbox.cpp	Mon Sep 25 14:50:13 2017 +0200
+++ b/OrthancServer/ServerToolbox.cpp	Wed Sep 27 17:36:13 2017 +0200
@@ -431,7 +431,7 @@
         ServerContext::DicomCacheLocker locker(context, *it);
 
         Json::Value dicomAsJson;
-        locker.GetDicom().ExtractDicomAsJson(dicomAsJson);
+        locker.GetDicom().DatasetToJson(dicomAsJson);
 
         std::string s = dicomAsJson.toStyledString();
         context.AddAttachment(*it, FileContentType_DicomAsJson, s.c_str(), s.size());
--- a/UnitTestsSources/FromDcmtkTests.cpp	Mon Sep 25 14:50:13 2017 +0200
+++ b/UnitTestsSources/FromDcmtkTests.cpp	Wed Sep 27 17:36:13 2017 +0200
@@ -395,7 +395,28 @@
       element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, false, Encoding_Utf8));
 
       Json::Value b;
-      FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
+      std::set<DicomTag> ignoreTagLength;
+      ignoreTagLength.insert(DICOM_TAG_PATIENT_ID);
+
+      FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short,
+                                     DicomToJsonFlags_Default, 0, Encoding_Ascii, ignoreTagLength);
+      ASSERT_TRUE(b.isMember("0010,0010"));
+      ASSERT_EQ("Hello", b["0010,0010"].asString());
+
+      FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short,
+                                     DicomToJsonFlags_Default, 3, Encoding_Ascii, ignoreTagLength);
+      ASSERT_TRUE(b["0010,0010"].isNull()); // "Hello" has more than 3 characters
+
+      FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Full,
+                                     DicomToJsonFlags_Default, 3, Encoding_Ascii, ignoreTagLength);
+      ASSERT_TRUE(b["0010,0010"].isObject());
+      ASSERT_EQ("PatientName", b["0010,0010"]["Name"].asString());
+      ASSERT_EQ("TooLong", b["0010,0010"]["Type"].asString());
+      ASSERT_TRUE(b["0010,0010"]["Value"].isNull());
+
+      ignoreTagLength.insert(DICOM_TAG_PATIENT_NAME);
+      FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short,
+                                     DicomToJsonFlags_Default, 3, Encoding_Ascii, ignoreTagLength);
       ASSERT_EQ("Hello", b["0010,0010"].asString());
     }
 
@@ -419,7 +440,9 @@
       element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, true, Encoding_Utf8));
 
       Json::Value b;
-      FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
+      std::set<DicomTag> ignoreTagLength;
+      FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short,
+                                     DicomToJsonFlags_Default, 0, Encoding_Ascii, ignoreTagLength);
       ASSERT_EQ("Hello", b["0010,0010"].asString());
     }
 
@@ -430,7 +453,9 @@
 
       {
         Json::Value b;
-        FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
+        std::set<DicomTag> ignoreTagLength;
+        FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short,
+                                       DicomToJsonFlags_Default, 0, Encoding_Ascii, ignoreTagLength);
         ASSERT_EQ(Json::arrayValue, b["0008,1110"].type());
         ASSERT_EQ(2u, b["0008,1110"].size());
       
@@ -447,7 +472,9 @@
 
       {
         Json::Value b;
-        FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Full, DicomToJsonFlags_Default, 0, Encoding_Ascii);
+        std::set<DicomTag> ignoreTagLength;
+        FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Full,
+                                       DicomToJsonFlags_Default, 0, Encoding_Ascii, ignoreTagLength);
 
         Json::Value c;
         ServerToolbox::SimplifyTags(c, b, DicomToJsonFormat_Human);