changeset 4697:569d9ef165b1

Added "short", "simplify" and/or "full" options to control the format of DICOM tags wherever possible
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 18 Jun 2021 16:08:35 +0200
parents dd6274412ff4
children d16c3c7f11ef
files NEWS OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h OrthancServer/OrthancExplorer/explorer.js OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp OrthancServer/Sources/Database/StatelessDatabaseOperations.h OrthancServer/Sources/LuaScripting.cpp OrthancServer/Sources/OrthancRestApi/OrthancRestApi.cpp OrthancServer/Sources/OrthancRestApi/OrthancRestApi.h OrthancServer/Sources/OrthancRestApi/OrthancRestModalities.cpp OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp OrthancServer/Sources/OrthancWebDav.cpp
diffstat 12 files changed, 457 insertions(+), 252 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Thu Jun 17 15:47:21 2021 +0200
+++ b/NEWS	Fri Jun 18 16:08:35 2021 +0200
@@ -9,6 +9,11 @@
   - "ExternalDictionaries" to load external DICOM dictionaries (useful for DICONDE)
   - "SynchronousZipStream" to disable streaming of ZIP
 
+Orthanc Explorer
+----------------
+
+* Orthanc Explorer supports the DICONDE dictionary
+
 REST API
 --------
 
@@ -22,6 +27,19 @@
 * "/jobs/..." has new field "ErrorDetails" to help identify the cause of an error
 * "Replace", "Keep" and "Remove" in "/modify" and "/anonymize" accept paths to subsequences
   using the syntax of the dcmodify command-line tool (wildcards are supported as well)
+* Added "short", "simplify" and/or "full" options to control the format of DICOM tags in:
+  - GET /patients, GET /studies, GET /series, GET /instances (together with "&expand")
+  - GET /patients/{id}, GET /studies/{id}, GET /series/{id}, GET /instances/{id}
+  - GET /patients/{id}/studies, GET /patients/{id}/series, GET /patients/{id}/instances
+  - GET /studies/{id}/patient, GET /studies/{id}/series, GET /studies/{id}/instances
+  - GET /series/{id}/patient, GET /series/{id}/study, GET /series/{id}/instances
+  - GET /instances/{id}/patient, GET /instances/{id}/study, GET /instances/{id}/series
+  - GET /patients/{id}/instances-tags, GET /patients/{id}/shared-tags
+  - GET /studies/{id}/instances-tags, GET /series/{id}/shared-tags
+  - GET /series/{id}/instances-tags, GET /studies/{id}/shared-tags
+  - GET /patients/{id}/module, GET /patients/{id}/patient-module
+  - GET /series/{id}/module, GET /studies/{id}/module, GET /instances/{id}/module
+  - POST /tools/find
 
 Maintenance
 -----------
--- a/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp	Thu Jun 17 15:47:21 2021 +0200
+++ b/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp	Fri Jun 18 16:08:35 2021 +0200
@@ -1329,7 +1329,7 @@
 
   void FromDcmtkBridge::ToJson(Json::Value& result,
                                const DicomMap& values,
-                               bool simplify)
+                               DicomToJsonFormat format)
   {
     if (result.type() != Json::objectValue)
     {
@@ -1341,40 +1341,69 @@
     for (DicomMap::Content::const_iterator 
            it = values.content_.begin(); it != values.content_.end(); ++it)
     {
-      // TODO Inject PrivateCreator if some is available in the DicomMap?
-      const std::string tagName = GetTagName(it->first, "");
-
-      if (simplify)
-      {
-        if (it->second->IsNull())
-        {
-          result[tagName] = Json::nullValue;
-        }
-        else
-        {
-          // TODO IsBinary
-          result[tagName] = it->second->GetContent();
-        }
-      }
-      else
+      switch (format)
       {
-        Json::Value value = Json::objectValue;
-
-        value["Name"] = tagName;
-
-        if (it->second->IsNull())
+        case DicomToJsonFormat_Human:
         {
-          value["Type"] = "Null";
-          value["Value"] = Json::nullValue;
+          // TODO Inject PrivateCreator if some is available in the DicomMap?
+          const std::string tagName = GetTagName(it->first, "");
+
+          if (it->second->IsNull())
+          {
+            result[tagName] = Json::nullValue;
+          }
+          else
+          {
+            // TODO IsBinary
+            result[tagName] = it->second->GetContent();
+          }
+          break;
         }
-        else
+
+        case DicomToJsonFormat_Full:
         {
-          // TODO IsBinary
-          value["Type"] = "String";
-          value["Value"] = it->second->GetContent();
+          // TODO Inject PrivateCreator if some is available in the DicomMap?
+          const std::string tagName = GetTagName(it->first, "");
+
+          Json::Value value = Json::objectValue;
+
+          value["Name"] = tagName;
+
+          if (it->second->IsNull())
+          {
+            value["Type"] = "Null";
+            value["Value"] = Json::nullValue;
+          }
+          else
+          {
+            // TODO IsBinary
+            value["Type"] = "String";
+            value["Value"] = it->second->GetContent();
+          }
+
+          result[it->first.Format()] = value;
+          break;
         }
 
-        result[it->first.Format()] = value;
+        case DicomToJsonFormat_Short:
+        {
+          const std::string hex = it->first.Format();
+
+          if (it->second->IsNull())
+          {
+            result[hex] = Json::nullValue;
+          }
+          else
+          {
+            // TODO IsBinary
+            result[hex] = it->second->GetContent();
+          }
+
+          break;
+        }
+
+        default:
+          throw OrthancException(ErrorCode_ParameterOutOfRange);
       }
     }
   }
--- a/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h	Thu Jun 17 15:47:21 2021 +0200
+++ b/OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.h	Fri Jun 18 16:08:35 2021 +0200
@@ -176,7 +176,7 @@
 
     static void ToJson(Json::Value& result,
                        const DicomMap& values,
-                       bool simplify);
+                       DicomToJsonFormat format);
 
     static std::string GenerateUniqueIdentifier(ResourceType level);
 
--- a/OrthancServer/OrthancExplorer/explorer.js	Thu Jun 17 15:47:21 2021 +0200
+++ b/OrthancServer/OrthancExplorer/explorer.js	Fri Jun 18 16:08:35 2021 +0200
@@ -51,6 +51,30 @@
 var currentPage = '';
 var currentUuid = '';
 
+var ACQUISITION_NUMBER = '0020,0012';
+var IMAGES_IN_ACQUISITION = '0020,1002';
+var IMAGE_ORIENTATION_PATIENT = '0020,0037';
+var IMAGE_POSITION_PATIENT = '0020,0032';
+var INSTANCE_CREATION_DATE = '0008,0012';
+var INSTANCE_CREATION_TIME = '0008,0013';
+var INSTANCE_NUMBER = '0020,0013';
+var MANUFACTURER = '0008,0070';
+var OTHER_PATIENT_IDS = '0010,1000';
+var PATIENT_BIRTH_DATE = '0010,0030';
+var PATIENT_NAME = '0010,0010';
+var SERIES_DATE = '0008,0021';
+var SERIES_DESCRIPTION = '0008,103e';
+var SERIES_INSTANCE_UID = '0020,000e';
+var SERIES_TIME = '0008,0031';
+var SOP_INSTANCE_UID = '0008,0018';
+var STUDY_DATE = '0008,0020';
+var STUDY_DESCRIPTION = '0008,1030';
+var STUDY_INSTANCE_UID = '0020,000d';
+var STUDY_TIME = '0008,0030';
+
+var ANONYMIZED_FROM = 'AnonymizedFrom';
+var MODIFIED_FROM = 'ModifiedFrom';
+
 
 function DeepCopy(obj)
 {
@@ -158,12 +182,6 @@
 );
 
 
-function SplitLongUid(s)
-{
-  return '<span>' + s.substr(0, s.length / 2) + '</span> <span>' + s.substr(s.length / 2, s.length - s.length / 2) + '</span>';
-}
-
-
 function ParseDicomDate(s)
 {
   y = parseInt(s.substr(0, 4), 10);
@@ -259,10 +277,20 @@
 }
 
 
+function GetMainDicomTag(mainDicomTags, tag)
+{
+  if (tag in mainDicomTags) {
+    return mainDicomTags[tag].Value;
+  } else {
+    return '';
+  }
+}
+
+
 function SortOnDicomTag(arr, tag, isInteger, reverse)
 {
   return Sort(arr, function(a) { 
-    return a.MainDicomTags[tag];
+    return GetMainDicomTag(a.MainDicomTags, tag);
   }, isInteger, reverse);
 }
 
@@ -291,7 +319,8 @@
                     .text(count));
   }
   
-  if (link != null)
+  if (link != null &&
+      link)
   {
     node = $('<a>').attr('href', link).append(node);
 
@@ -316,28 +345,31 @@
   {
     if (tagsToIgnore.indexOf(i) == -1)
     {
-      v = tags[i];
+      v = GetMainDicomTag(tags, i);
 
-      if (i == "PatientBirthDate" ||
-          i == "StudyDate" ||
-          i == "SeriesDate")
+      if (i == PATIENT_BIRTH_DATE ||
+          i == STUDY_DATE ||
+          i == SERIES_DATE ||
+          i == INSTANCE_CREATION_DATE)
       {
         v = FormatDicomDate(v);
       }
-      else if (i == "DicomStudyInstanceUID" ||
-               i == "DicomSeriesInstanceUID")
+      else if (i == STUDY_INSTANCE_UID ||
+               i == SERIES_INSTANCE_UID ||
+               i == SOP_INSTANCE_UID)
       {
-        v = SplitLongUid(v);
+        // Possibly split a long UID
+        // v = '<span>' + s.substr(0, s.length / 2) + '</span><span>' + s.substr(s.length / 2, s.length - s.length / 2) + '</span>';
       }
-      else if (i == "ImagePositionPatient" ||
-               i == "ImageOrientationPatient")
+      else if (i == IMAGE_POSITION_PATIENT ||
+               i == IMAGE_ORIENTATION_PATIENT)
       {
         v = FormatFloatSequence(v);
       }
       
       target.append($('<p>')
-                    .text(i + ': ')
-                    .append($('<strong>').text(v)));
+                    .text(tags[i].Name + ': ')
+                    .append($('<strong>').html(v)));
     }
   }
 }
@@ -345,11 +377,11 @@
 
 function FormatPatient(patient, link, isReverse)
 {
-  var node = $('<div>').append($('<h3>').text(patient.MainDicomTags.PatientName));
+  var node = $('<div>').append($('<h3>').text(GetMainDicomTag(patient.MainDicomTags, PATIENT_NAME)));
 
   FormatMainDicomTags(node, patient.MainDicomTags, [ 
-    "PatientName"
-    // "OtherPatientIDs"
+    PATIENT_NAME
+    //,  OTHER_PATIENT_IDS
   ]);
     
   return CompleteFormatting(node, link, isReverse, patient.Studies.length);
@@ -365,20 +397,20 @@
   if (includePatient) {
     label = study.Label;
   } else {
-    label = study.MainDicomTags.StudyDescription;
+    label = GetMainDicomTag(study.MainDicomTags, STUDY_DESCRIPTION);
   }
 
   node = $('<div>').append($('<h3>').text(label));
 
   if (includePatient) {
     FormatMainDicomTags(node, study.PatientMainDicomTags, [ 
-      'PatientName'
+      PATIENT_NAME
     ]);
   }
     
   FormatMainDicomTags(node, study.MainDicomTags, [ 
-     'StudyDescription', 
-     'StudyTime' 
+    STUDY_DESCRIPTION, 
+    STUDY_TIME
   ]);
 
   return CompleteFormatting(node, link, isReverse, study.Series.length);
@@ -402,18 +434,18 @@
   }
   
   node = $('<div>')
-      .append($('<h3>').text(series.MainDicomTags.SeriesDescription))
-      .append($('<p>').append($('<em>')
-                           .text('Status: ')
-                           .append($('<strong>').text(series.Status))));
-
+    .append($('<h3>').text(GetMainDicomTag(series.MainDicomTags, SERIES_DESCRIPTION)))
+    .append($('<p>').append($('<em>')
+                            .text('Status: ')
+                            .append($('<strong>').text(series.Status))));
+  
   FormatMainDicomTags(node, series.MainDicomTags, [ 
-     "SeriesDescription", 
-     "SeriesTime", 
-     "Manufacturer",
-     "ImagesInAcquisition",
-     "SeriesDate",
-     "ImageOrientationPatient"
+    SERIES_DESCRIPTION,
+    SERIES_TIME,
+    MANUFACTURER,
+    IMAGES_IN_ACQUISITION,
+    SERIES_DATE,
+    IMAGE_ORIENTATION_PATIENT
   ]);
     
   return CompleteFormatting(node, link, isReverse, c);
@@ -425,10 +457,10 @@
   var node = $('<div>').append($('<h3>').text('Instance: ' + instance.IndexInSeries));
 
   FormatMainDicomTags(node, instance.MainDicomTags, [
-    "AcquisitionNumber", 
-    "InstanceNumber", 
-    "InstanceCreationDate", 
-    "InstanceCreationTime"
+    ACQUISITION_NUMBER,
+    INSTANCE_NUMBER,
+    INSTANCE_CREATION_DATE,
+    INSTANCE_CREATION_TIME,
   ]);
     
   return CompleteFormatting(node, link, isReverse);
@@ -534,14 +566,14 @@
 
 
 $('#find-patients').live('pagebeforeshow', function() {
-  GetResource('/patients?expand&since=0&limit=' + (LIMIT_RESOURCES + 1), function(patients) {
+  GetResource('/patients?expand&since=0&limit=' + (LIMIT_RESOURCES + 1) + '&full', function(patients) {
     var target = $('#all-patients');
     var count, showAlert, p;
 
 
     $('li', target).remove();
     
-    SortOnDicomTag(patients, 'PatientName', false, false);
+    SortOnDicomTag(patients, PATIENT_NAME, false, false);
 
     if (patients.length <= LIMIT_RESOURCES) {
       count = patients.length;
@@ -579,8 +611,8 @@
   $('li', target).remove();
 
   for (var i = 0; i < studies.length; i++) {
-    patient = studies[i].PatientMainDicomTags.PatientName;
-    study = studies[i].MainDicomTags.StudyDescription;
+    patient = GetMainDicomTag(studies[i].PatientMainDicomTags, PATIENT_NAME);
+    study = GetMainDicomTag(studies[i].MainDicomTags, STUDY_DESCRIPTION);
 
     s = "";
     if (typeof patient === 'string') {
@@ -626,7 +658,7 @@
 
 
 $('#find-studies').live('pagebeforeshow', function() {
-  GetResource('/studies?expand&since=0&limit=' + (LIMIT_RESOURCES + 1), function(studies) {
+  GetResource('/studies?expand&since=0&limit=' + (LIMIT_RESOURCES + 1) + '&full', function(studies) {
     FormatListOfStudies('#all-studies', '#alert-studies', '#count-studies', studies);
   });
 });
@@ -657,9 +689,9 @@
   if ($.mobile.pageData) {
     pageData = DeepCopy($.mobile.pageData);
 
-    GetResource('/patients/' + pageData.uuid, function(patient) {
-      GetResource('/patients/' + pageData.uuid + '/studies', function(studies) {
-        SortOnDicomTag(studies, 'StudyDate', false, true);
+    GetResource('/patients/' + pageData.uuid + '?full', function(patient) {
+      GetResource('/patients/' + pageData.uuid + '/studies?full', function(studies) {
+        SortOnDicomTag(studies, STUDY_DATE, false, true);
 
         $('#patient-info li').remove();
         $('#patient-info')
@@ -671,18 +703,20 @@
         $('li', target).remove();
         
         for (var i = 0; i < studies.length; i++) {
-          if (i == 0 || studies[i].MainDicomTags.StudyDate != studies[i - 1].MainDicomTags.StudyDate)
+          if (i == 0 ||
+              GetMainDicomTag(studies[i].MainDicomTags, STUDY_DATE) !=
+              GetMainDicomTag(studies[i - 1].MainDicomTags, STUDY_DATE))
           {
             target.append($('<li>')
                           .attr('data-role', 'list-divider')
-                          .text(FormatDicomDate(studies[i].MainDicomTags.StudyDate)));
+                          .text(FormatDicomDate(GetMainDicomTag(studies[i].MainDicomTags, STUDY_DATE))));
           }
 
           target.append(FormatStudy(studies[i], '#study?uuid=' + studies[i].ID));
         }
 
-        SetupAnonymizedOrModifiedFrom('#patient-anonymized-from', patient, 'patient', 'AnonymizedFrom');
-        SetupAnonymizedOrModifiedFrom('#patient-modified-from', patient, 'patient', 'ModifiedFrom');
+        SetupAnonymizedOrModifiedFrom('#patient-anonymized-from', patient, 'patient', ANONYMIZED_FROM);
+        SetupAnonymizedOrModifiedFrom('#patient-modified-from', patient, 'patient', MODIFIED_FROM);
 
         target.listview('refresh');
 
@@ -714,10 +748,10 @@
   if ($.mobile.pageData) {
     pageData = DeepCopy($.mobile.pageData);
 
-    GetResource('/studies/' + pageData.uuid, function(study) {
-      GetResource('/patients/' + study.ParentPatient, function(patient) {
-        GetResource('/studies/' + pageData.uuid + '/series', function(series) {
-          SortOnDicomTag(series, 'SeriesDate', false, true);
+    GetResource('/studies/' + pageData.uuid + '?full', function(study) {
+      GetResource('/patients/' + study.ParentPatient + '?full', function(patient) {
+        GetResource('/studies/' + pageData.uuid + '/series?full', function(series) {
+          SortOnDicomTag(series, SERIES_DATE, false, true);
 
           $('#study .patient-link').attr('href', '#patient?uuid=' + patient.ID);
           $('#study-info li').remove();
@@ -728,17 +762,19 @@
             .append(FormatStudy(study))
             .listview('refresh');
 
-          SetupAnonymizedOrModifiedFrom('#study-anonymized-from', study, 'study', 'AnonymizedFrom');
-          SetupAnonymizedOrModifiedFrom('#study-modified-from', study, 'study', 'ModifiedFrom');
+          SetupAnonymizedOrModifiedFrom('#study-anonymized-from', study, 'study', ANONYMIZED_FROM);
+          SetupAnonymizedOrModifiedFrom('#study-modified-from', study, 'study', MODIFIED_FROM);
 
           target = $('#list-series');
           $('li', target).remove();
           for (var i = 0; i < series.length; i++) {
-            if (i == 0 || series[i].MainDicomTags.SeriesDate != series[i - 1].MainDicomTags.SeriesDate)
+            if (i == 0 ||
+                GetMainDicomTag(series[i].MainDicomTags, SERIES_DATE) !=
+                GetMainDicomTag(series[i - 1].MainDicomTags, SERIES_DATE))
             {
               target.append($('<li>')
                             .attr('data-role', 'list-divider')
-                            .text(FormatDicomDate(series[i].MainDicomTags.SeriesDate)));
+                            .text(FormatDicomDate(GetMainDicomTag(series[i].MainDicomTags, SERIES_DATE))));
             }
             
             target.append(FormatSeries(series[i], '#series?uuid=' + series[i].ID));
@@ -761,10 +797,10 @@
   if ($.mobile.pageData) {
     pageData = DeepCopy($.mobile.pageData);
 
-    GetResource('/series/' + pageData.uuid, function(series) {
-      GetResource('/studies/' + series.ParentStudy, function(study) {
-        GetResource('/patients/' + study.ParentPatient, function(patient) {
-          GetResource('/series/' + pageData.uuid + '/instances', function(instances) {
+    GetResource('/series/' + pageData.uuid + '?full', function(series) {
+      GetResource('/studies/' + series.ParentStudy + '?full', function(study) {
+        GetResource('/patients/' + study.ParentPatient + '?full', function(patient) {
+          GetResource('/series/' + pageData.uuid + '/instances?full', function(instances) {
             Sort(instances, function(x) { return x.IndexInSeries; }, true, false);
 
             $('#series .patient-link').attr('href', '#patient?uuid=' + patient.ID);
@@ -780,8 +816,8 @@
               .append(FormatSeries(series))
               .listview('refresh');
 
-            SetupAnonymizedOrModifiedFrom('#series-anonymized-from', series, 'series', 'AnonymizedFrom');
-            SetupAnonymizedOrModifiedFrom('#series-modified-from', series, 'series', 'ModifiedFrom');
+            SetupAnonymizedOrModifiedFrom('#series-anonymized-from', series, 'series', ANONYMIZED_FROM);
+            SetupAnonymizedOrModifiedFrom('#series-modified-from', series, 'series', MODIFIED_FROM);
 
             target = $('#list-instances');
             $('li', target).remove();
@@ -880,10 +916,10 @@
   if ($.mobile.pageData) {
     pageData = DeepCopy($.mobile.pageData);
 
-    GetResource('/instances/' + pageData.uuid, function(instance) {
-      GetResource('/series/' + instance.ParentSeries, function(series) {
-        GetResource('/studies/' + series.ParentStudy, function(study) {
-          GetResource('/patients/' + study.ParentPatient, function(patient) {
+    GetResource('/instances/' + pageData.uuid + '?full', function(instance) {
+      GetResource('/series/' + instance.ParentSeries + '?full', function(series) {
+        GetResource('/studies/' + series.ParentStudy + '?full', function(study) {
+          GetResource('/patients/' + study.ParentPatient + '?full', function(patient) {
 
             $('#instance .patient-link').attr('href', '#patient?uuid=' + patient.ID);
             $('#instance .study-link').attr('href', '#study?uuid=' + study.ID);
@@ -918,8 +954,8 @@
               }
             });
 
-            SetupAnonymizedOrModifiedFrom('#instance-anonymized-from', instance, 'instance', 'AnonymizedFrom');
-            SetupAnonymizedOrModifiedFrom('#instance-modified-from', instance, 'instance', 'ModifiedFrom');
+            SetupAnonymizedOrModifiedFrom('#instance-anonymized-from', instance, 'instance', ANONYMIZED_FROM);
+            SetupAnonymizedOrModifiedFrom('#instance-modified-from', instance, 'instance', MODIFIED_FROM);
 
             currentPage = 'instance';
             currentUuid = pageData.uuid;
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp	Thu Jun 17 15:47:21 2021 +0200
+++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.cpp	Fri Jun 18 16:08:35 2021 +0200
@@ -724,16 +724,22 @@
 
   bool StatelessDatabaseOperations::ExpandResource(Json::Value& target,
                                                    const std::string& publicId,
-                                                   ResourceType level)
+                                                   ResourceType level,
+                                                   DicomToJsonFormat format)
   {    
-    class Operations : public ReadOnlyOperationsT4<bool&, Json::Value&, const std::string&, ResourceType>
+    class Operations : public ReadOnlyOperationsT5<
+      bool&, Json::Value&, const std::string&, ResourceType, DicomToJsonFormat>
     {
     private:
       static void MainDicomTagsToJson(ReadOnlyTransaction& transaction,
                                       Json::Value& target,
                                       int64_t resourceId,
-                                      ResourceType resourceType)
+                                      ResourceType resourceType,
+                                      DicomToJsonFormat format)
       {
+        static const char* const MAIN_DICOM_TAGS = "MainDicomTags";
+        static const char* const PATIENT_MAIN_DICOM_TAGS = "PatientMainDicomTags";
+        
         DicomMap tags;
         transaction.GetMainDicomTags(tags, resourceId);
 
@@ -743,16 +749,16 @@
           tags.ExtractStudyInformation(t1);
           tags.ExtractPatientInformation(t2);
 
-          target["MainDicomTags"] = Json::objectValue;
-          FromDcmtkBridge::ToJson(target["MainDicomTags"], t1, true);
-
-          target["PatientMainDicomTags"] = Json::objectValue;
-          FromDcmtkBridge::ToJson(target["PatientMainDicomTags"], t2, true);
+          target[MAIN_DICOM_TAGS] = Json::objectValue;
+          FromDcmtkBridge::ToJson(target[MAIN_DICOM_TAGS], t1, format);
+
+          target[PATIENT_MAIN_DICOM_TAGS] = Json::objectValue;
+          FromDcmtkBridge::ToJson(target[PATIENT_MAIN_DICOM_TAGS], t2, format);
         }
         else
         {
-          target["MainDicomTags"] = Json::objectValue;
-          FromDcmtkBridge::ToJson(target["MainDicomTags"], tags, true);
+          target[MAIN_DICOM_TAGS] = Json::objectValue;
+          FromDcmtkBridge::ToJson(target[MAIN_DICOM_TAGS], tags, format);
         }
       }
 
@@ -949,7 +955,7 @@
 
           // Record the remaining information
           target["ID"] = tuple.get<2>();
-          MainDicomTagsToJson(transaction, target, internalId, type);
+          MainDicomTagsToJson(transaction, target, internalId, type, tuple.get<4>());
 
           std::string tmp;
 
@@ -982,7 +988,7 @@
 
     bool found;
     Operations operations;
-    operations.Apply(*this, found, target, publicId, level);
+    operations.Apply(*this, found, target, publicId, level, format);
     return found;
   }
 
--- a/OrthancServer/Sources/Database/StatelessDatabaseOperations.h	Thu Jun 17 15:47:21 2021 +0200
+++ b/OrthancServer/Sources/Database/StatelessDatabaseOperations.h	Fri Jun 18 16:08:35 2021 +0200
@@ -461,7 +461,8 @@
 
     bool ExpandResource(Json::Value& target,
                         const std::string& publicId,
-                        ResourceType level);
+                        ResourceType level,
+                        DicomToJsonFormat format);
 
     void GetAllMetadata(std::map<MetadataType, std::string>& target,
                         const std::string& publicId,
--- a/OrthancServer/Sources/LuaScripting.cpp	Thu Jun 17 15:47:21 2021 +0200
+++ b/OrthancServer/Sources/LuaScripting.cpp	Fri Jun 18 16:08:35 2021 +0200
@@ -182,11 +182,11 @@
               {
                 DicomMap t;
                 tags_.ExtractStudyInformation(t);  // Discard patient-related tags
-                FromDcmtkBridge::ToJson(json, t, true);
+                FromDcmtkBridge::ToJson(json, t, DicomToJsonFormat_Human);
               }
               else
               {
-                FromDcmtkBridge::ToJson(json, tags_, true);
+                FromDcmtkBridge::ToJson(json, tags_, DicomToJsonFormat_Human);
               }
 
               LuaFunctionCall call(lock.GetLua(), name);
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestApi.cpp	Thu Jun 17 15:47:21 2021 +0200
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestApi.cpp	Fri Jun 18 16:08:35 2021 +0200
@@ -460,4 +460,117 @@
       .SetRequestField(KEY_PERMISSIVE, RestApiCallDocumentation::Type_Boolean,
                        "If `true`, ignore errors during the individual steps of the job.", false);
   }
+
+
+  static const std::string GET_SIMPLIFY = "simplify";
+  static const std::string GET_FULL = "full";
+  static const std::string GET_SHORT = "short";
+
+  static const std::string POST_SIMPLIFY = "Simplify";
+  static const std::string POST_FULL = "Full";
+  static const std::string POST_SHORT = "Short";
+
+  static const std::string DOCUMENT_SIMPLIFY =
+    "report the DICOM tags indexed in human-readable format "
+    "(using the symbolic name of the tags)";
+
+  static const std::string DOCUMENT_SHORT =
+    "report the DICOM tags indexed in hexadecimal format";
+
+  static const std::string DOCUMENT_FULL =
+    "report the DICOM tags in full format (tags indexed by their hexadecimal "
+    "format, associated with their symbolic name and their value)";
+
+
+  DicomToJsonFormat OrthancRestApi::GetDicomFormat(const RestApiGetCall& call,
+                                                   DicomToJsonFormat defaultFormat)
+  {
+    if (call.HasArgument(GET_SIMPLIFY))
+    {
+      return DicomToJsonFormat_Human;
+    }
+    else if (call.HasArgument(GET_SHORT))
+    {
+      return DicomToJsonFormat_Short;
+    }
+    else if (call.HasArgument(GET_FULL))
+    {
+      return DicomToJsonFormat_Full;
+    }
+    else
+    {
+      return defaultFormat;
+    }
+  }
+
+
+  DicomToJsonFormat OrthancRestApi::GetDicomFormat(const Json::Value& body,
+                                                   DicomToJsonFormat defaultFormat)
+  {
+    if (body.isMember(POST_SIMPLIFY) &&
+        SerializationToolbox::ReadBoolean(body, POST_SIMPLIFY))
+    {
+      return DicomToJsonFormat_Human;
+    }
+    else if (body.isMember(POST_SHORT) &&
+             SerializationToolbox::ReadBoolean(body, POST_SHORT))
+    {
+      return DicomToJsonFormat_Short;
+    }
+    else if (body.isMember(POST_FULL) &&
+             SerializationToolbox::ReadBoolean(body, POST_FULL))
+    {
+      return DicomToJsonFormat_Full;
+    }
+    else
+    {
+      return defaultFormat;
+    }
+  }
+
+
+  void OrthancRestApi::DocumentDicomFormat(RestApiGetCall& call,
+                                           DicomToJsonFormat defaultFormat)
+  {
+    if (defaultFormat != DicomToJsonFormat_Human)
+    {
+      call.GetDocumentation().SetHttpGetArgument(
+        GET_SIMPLIFY, RestApiCallDocumentation::Type_Boolean, "If present, " + DOCUMENT_SIMPLIFY, false);
+    }
+    
+    if (defaultFormat != DicomToJsonFormat_Short)
+    {
+      call.GetDocumentation().SetHttpGetArgument(
+        GET_SHORT, RestApiCallDocumentation::Type_Boolean, "If present, " + DOCUMENT_SHORT, false);
+    }
+    
+    if (defaultFormat != DicomToJsonFormat_Full)
+    {
+      call.GetDocumentation().SetHttpGetArgument(
+        GET_FULL, RestApiCallDocumentation::Type_Boolean, "If present, " + DOCUMENT_FULL, false);
+    }    
+  }
+  
+  
+  void OrthancRestApi::DocumentDicomFormat(RestApiPostCall& call,
+                                           DicomToJsonFormat defaultFormat)
+  {
+    if (defaultFormat != DicomToJsonFormat_Human)
+    {
+      call.GetDocumentation().SetRequestField(POST_SIMPLIFY, RestApiCallDocumentation::Type_Boolean,
+                                              "If set to `true`, " + DOCUMENT_SIMPLIFY, false);
+    }
+    
+    if (defaultFormat != DicomToJsonFormat_Short)
+    {
+      call.GetDocumentation().SetRequestField(POST_SHORT, RestApiCallDocumentation::Type_Boolean,
+                                              "If set to `true`, " + DOCUMENT_SIMPLIFY, false);
+    }
+    
+    if (defaultFormat != DicomToJsonFormat_Full)
+    {
+      call.GetDocumentation().SetRequestField(POST_FULL, RestApiCallDocumentation::Type_Boolean,
+                                              "If set to `true`, " + DOCUMENT_SIMPLIFY, false);
+    }
+  }
 }
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestApi.h	Thu Jun 17 15:47:21 2021 +0200
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestApi.h	Fri Jun 18 16:08:35 2021 +0200
@@ -144,5 +144,17 @@
     static void DocumentSubmitGenericJob(RestApiPostCall& call);
 
     static void DocumentSubmitCommandsJob(RestApiPostCall& call);
+
+    static DicomToJsonFormat GetDicomFormat(const RestApiGetCall& call,
+                                            DicomToJsonFormat defaultFormat);
+
+    static DicomToJsonFormat GetDicomFormat(const Json::Value& body,
+                                            DicomToJsonFormat defaultFormat);
+
+    static void DocumentDicomFormat(RestApiGetCall& call,
+                                    DicomToJsonFormat defaultFormat);
+
+    static void DocumentDicomFormat(RestApiPostCall& call,
+                                    DicomToJsonFormat defaultFormat);
   };
 }
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestModalities.cpp	Thu Jun 17 15:47:21 2021 +0200
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestModalities.cpp	Fri Jun 18 16:08:35 2021 +0200
@@ -819,12 +819,12 @@
       }
     };
 
-    static void AnswerDicomMap(RestApiCall& call,
+    static void AnswerDicomMap(RestApiGetCall& call,
                                const DicomMap& value,
-                               bool simplify)
+                               DicomToJsonFormat format)
     {
       Json::Value full = Json::objectValue;
-      FromDcmtkBridge::ToJson(full, value, simplify);
+      FromDcmtkBridge::ToJson(full, value, format);
       call.GetOutput().AnswerJson(full);
     }
   }
@@ -834,6 +834,8 @@
   {
     if (call.IsDocumentation())
     {
+      OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Full);
+      
       call.GetDocumentation()
         .SetTag("Networking")
         .SetSummary("List answers to a query")
@@ -842,15 +844,13 @@
         .SetUriArgument("id", "Identifier of the query of interest")
         .SetHttpGetArgument("expand", RestApiCallDocumentation::Type_String,
                             "If present, retrieve detailed information about the individual answers", false)        
-        .SetHttpGetArgument("simplify", RestApiCallDocumentation::Type_String,
-                            "If present and if `expand` is present, format the tags of the answers in human-readable format", false)
         .AddAnswerType(MimeType_Json, "JSON array containing the indices of the answers, or detailed information "
                        "about the reported answers (if `expand` argument is provided)");
       return;
     }
 
     const bool expand = call.HasArgument("expand");
-    const bool simplify = call.HasArgument("simplify");
+    const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Full);
     
     QueryAccessor query(call);
     size_t count = query.GetHandler().GetAnswersCount();
@@ -865,7 +865,7 @@
         query.GetHandler().GetAnswer(value, i);
         
         Json::Value json = Json::objectValue;
-        FromDcmtkBridge::ToJson(json, value, simplify);
+        FromDcmtkBridge::ToJson(json, value, format);
 
         result.append(json);
       }
@@ -883,6 +883,8 @@
   {
     if (call.IsDocumentation())
     {
+      OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Full);
+
       call.GetDocumentation()
         .SetTag("Networking")
         .SetSummary("Get one answer")
@@ -890,8 +892,6 @@
                         "query/retrieve operation whose identifier is provided in the URL")
         .SetUriArgument("id", "Identifier of the query of interest")
         .SetUriArgument("index", "Index of the answer")
-        .SetHttpGetArgument("simplify", RestApiCallDocumentation::Type_String,
-                            "If present, format the tags of the answer in human-readable format", false)
         .AddAnswerType(MimeType_Json, "JSON object containing the DICOM tags of the answer");
       return;
     }
@@ -903,7 +903,7 @@
     DicomMap map;
     query.GetHandler().GetAnswer(map, index);
 
-    AnswerDicomMap(call, map, call.HasArgument("simplify"));
+    AnswerDicomMap(call, map, OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Full));
   }
 
 
@@ -1031,6 +1031,8 @@
   {
     if (call.IsDocumentation())
     {
+      OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Full);
+
       call.GetDocumentation()
         .SetTag("Networking")
         .SetSummary("Get original query arguments")
@@ -1044,7 +1046,7 @@
     }
 
     QueryAccessor query(call);
-    AnswerDicomMap(call, query.GetHandler().GetQuery(), call.HasArgument("simplify"));
+    AnswerDicomMap(call, query.GetHandler().GetQuery(), OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Full));
   }
 
 
--- a/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Thu Jun 17 15:47:21 2021 +0200
+++ b/OrthancServer/Sources/OrthancRestApi/OrthancRestResources.cpp	Fri Jun 18 16:08:35 2021 +0200
@@ -112,30 +112,6 @@
   }
 
 
-  static DicomToJsonFormat GetDicomFormat(const RestApiGetCall& call)
-  {
-    if (call.HasArgument("simplify"))
-    {
-      return DicomToJsonFormat_Human;
-    }
-    else if (call.HasArgument("short"))
-    {
-      return DicomToJsonFormat_Short;
-    }
-    else
-    {
-      return DicomToJsonFormat_Full;
-    }
-  }
-
-
-  static void AnswerDicomAsJson(RestApiGetCall& call,
-                                const Json::Value& dicom)
-  {
-    AnswerDicomAsJson(call, dicom, GetDicomFormat(call));
-  }
-
-
   static void ParseSetOfTags(std::set<DicomTag>& target,
                              const RestApiGetCall& call,
                              const std::string& argument)
@@ -161,7 +137,8 @@
                                     ServerIndex& index,
                                     const std::list<std::string>& resources,
                                     ResourceType level,
-                                    bool expand)
+                                    bool expand,
+                                    DicomToJsonFormat format)
   {
     Json::Value answer = Json::arrayValue;
 
@@ -171,7 +148,7 @@
       if (expand)
       {
         Json::Value expanded;
-        if (index.ExpandResource(expanded, *resource, level))
+        if (index.ExpandResource(expanded, *resource, level, format))
         {
           answer.append(expanded);
         }
@@ -191,6 +168,8 @@
   {
     if (call.IsDocumentation())
     {
+      OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Human);
+
       const std::string resources = GetResourceTypeText(resourceType, true /* plural */, false /* lower case */);
       call.GetDocumentation()
         .SetTag(GetResourceTypeText(resourceType, true /* plural */, true /* upper case */))
@@ -236,8 +215,8 @@
       index.GetAllUuids(result, resourceType);
     }
 
-
-    AnswerListOfResources(call.GetOutput(), index, result, resourceType, call.HasArgument("expand"));
+    AnswerListOfResources(call.GetOutput(), index, result, resourceType, call.HasArgument("expand"),
+                          OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human));
   }
 
 
@@ -247,6 +226,8 @@
   {
     if (call.IsDocumentation())
     {
+      OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Human);
+
       const std::string resource = GetResourceTypeText(resourceType, false /* plural */, false /* lower case */);
       call.GetDocumentation()
         .SetTag(GetResourceTypeText(resourceType, true /* plural */, true /* upper case */))
@@ -258,8 +239,11 @@
       return;
     }
 
+    const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human);
+
     Json::Value json;
-    if (OrthancRestApi::GetIndex(call).ExpandResource(json, call.GetUriComponent("id", ""), resourceType))
+    if (OrthancRestApi::GetIndex(call).ExpandResource(
+          json, call.GetUriComponent("id", ""), resourceType, format))
     {
       call.GetOutput().AnswerJson(json);
     }
@@ -421,29 +405,8 @@
 
 
   template <DicomToJsonFormat format>
-  static void GetInstanceTags(RestApiGetCall& call)
+  static void GetInstanceTagsInternal(RestApiGetCall& call)
   {
-    if (call.IsDocumentation())
-    {
-      if (format == DicomToJsonFormat_Human)
-      {
-        call.GetDocumentation()
-          .SetTag("Instances")
-          .SetSummary("Get human-readable tags")
-          .SetDescription("Get the DICOM tags in human-readable format")
-          .SetUriArgument("id", "Orthanc identifier of the DICOM instance of interest")
-          .SetHttpGetArgument("ignore-length", RestApiCallDocumentation::Type_JsonListOfStrings,
-                              "Also include the DICOM tags that are provided in this list, even if their associated value is long", false)
-          .AddAnswerType(MimeType_Json, "JSON object containing the DICOM tags and their associated value")
-          .SetTruncatedJsonHttpGetSample("https://demo.orthanc-server.com/instances/7c92ce8e-bbf67ed2-ffa3b8c1-a3b35d94-7ff3ae26/simplified-tags", 10);
-        return;
-      }
-      else
-      {
-        throw OrthancException(ErrorCode_NotImplemented);
-      }
-    }
-
     ServerContext& context = OrthancRestApi::GetContext(call);
 
     std::string publicId = call.GetUriComponent("id", "");
@@ -470,38 +433,34 @@
   }
 
 
-  static void GetInstanceTagsBis(RestApiGetCall& call)
+  static void GetInstanceTags(RestApiGetCall& call)
   {
     if (call.IsDocumentation())
     {
+      OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Full);
       call.GetDocumentation()
         .SetTag("Instances")
         .SetSummary("Get DICOM tags")
         .SetDescription("Get the DICOM tags in the specified format. By default, the `full` format is used, which "
                         "combines hexadecimal tags with human-readable description.")
         .SetUriArgument("id", "Orthanc identifier of the DICOM instance of interest")
-        .SetHttpGetArgument("simplify", RestApiCallDocumentation::Type_String,
-                            "If present, report the DICOM tags in human-readable format "
-                            "(same as the `/instances/{id}/simplified-tags` route)", false)
-        .SetHttpGetArgument("short", RestApiCallDocumentation::Type_String,
-                            "If present, report the DICOM tags indexed in hexadecimal format", false)
         .AddAnswerType(MimeType_Json, "JSON object containing the DICOM tags and their associated value")
         .SetTruncatedJsonHttpGetSample("https://demo.orthanc-server.com/instances/7c92ce8e-bbf67ed2-ffa3b8c1-a3b35d94-7ff3ae26/tags", 10);
       return;
     }
 
-    switch (GetDicomFormat(call))
+    switch (OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Full))
     {
       case DicomToJsonFormat_Human:
-        GetInstanceTags<DicomToJsonFormat_Human>(call);
+        GetInstanceTagsInternal<DicomToJsonFormat_Human>(call);
         break;
 
       case DicomToJsonFormat_Short:
-        GetInstanceTags<DicomToJsonFormat_Short>(call);
+        GetInstanceTagsInternal<DicomToJsonFormat_Short>(call);
         break;
 
       case DicomToJsonFormat_Full:
-        GetInstanceTags<DicomToJsonFormat_Full>(call);
+        GetInstanceTagsInternal<DicomToJsonFormat_Full>(call);
         break;
 
       default:
@@ -510,6 +469,28 @@
   }
 
   
+  static void GetInstanceSimplifiedTags(RestApiGetCall& call)
+  {
+    if (call.IsDocumentation())
+    {
+      call.GetDocumentation()
+        .SetTag("Instances")
+        .SetSummary("Get human-readable tags")
+        .SetDescription("Get the DICOM tags in human-readable format (same as the `/instances/{id}/tags?simplify` route)")
+        .SetUriArgument("id", "Orthanc identifier of the DICOM instance of interest")
+        .SetHttpGetArgument("ignore-length", RestApiCallDocumentation::Type_JsonListOfStrings,
+                            "Also include the DICOM tags that are provided in this list, even if their associated value is long", false)
+        .AddAnswerType(MimeType_Json, "JSON object containing the DICOM tags and their associated value")
+        .SetTruncatedJsonHttpGetSample("https://demo.orthanc-server.com/instances/7c92ce8e-bbf67ed2-ffa3b8c1-a3b35d94-7ff3ae26/simplified-tags", 10);
+      return;
+    }
+    else
+    {
+      GetInstanceTagsInternal<DicomToJsonFormat_Human>(call);
+    }
+  }
+
+    
   static void ListFrames(RestApiGetCall& call)
   {
     if (call.IsDocumentation())
@@ -2367,6 +2348,8 @@
   {
     if (call.IsDocumentation())
     {
+      OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Full);
+
       ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str());
       std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */);
       call.GetDocumentation()
@@ -2387,15 +2370,51 @@
     if (ExtractSharedTags(sharedTags, context, publicId))
     {
       // Success: Send the value of the shared tags
-      AnswerDicomAsJson(call, sharedTags);
+      AnswerDicomAsJson(call, sharedTags, OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Full));
     }
   }
 
 
-  static void GetModuleInternal(RestApiGetCall& call,
-                                ResourceType resourceType,
-                                DicomModule module)
+  template <enum ResourceType resourceType, 
+            enum DicomModule module>
+  static void GetModule(RestApiGetCall& call)
   {
+    if (call.IsDocumentation())
+    {
+      const std::string resource = GetResourceTypeText(resourceType, false /* plural */, false /* lower case */);
+      std::string m;
+      switch (module)
+      {
+        case DicomModule_Patient:
+          m = "patient";
+          break;
+        case DicomModule_Study:
+          m = "study";
+          break;
+        case DicomModule_Series:
+          m = "series";
+          break;
+        case DicomModule_Instance:
+          m = "instance";
+          break;
+        default:
+          throw OrthancException(ErrorCode_ParameterOutOfRange);
+      }
+      
+      OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Full);
+
+      call.GetDocumentation()
+        .SetTag(GetResourceTypeText(resourceType, true /* plural */, true /* upper case */))
+        .SetSummary("Get " + m + " module" + std::string(resource == m ? "" : " of " + resource))
+        .SetDescription("Get the " + m + " module of the DICOM " + resource + " whose Orthanc identifier is provided in the URL")
+        .SetUriArgument("id", "Orthanc identifier of the " + resource + " of interest")
+        .SetHttpGetArgument("ignore-length", RestApiCallDocumentation::Type_JsonListOfStrings,
+                            "Also include the DICOM tags that are provided in this list, even if their associated value is long", false)
+        .AddAnswerType(MimeType_Json, "Information about the DICOM " + resource)
+        .SetHttpGetSample(GetDocumentationSampleResource(resourceType) + "/" + (*call.GetFullUri().rbegin()), true);
+      return;
+    }
+
     if (!((resourceType == ResourceType_Patient && module == DicomModule_Patient) ||
           (resourceType == ResourceType_Study && module == DicomModule_Patient) ||
           (resourceType == ResourceType_Study && module == DicomModule_Study) ||
@@ -2447,49 +2466,7 @@
       }      
     }
 
-    AnswerDicomAsJson(call, result);
-  }
-    
-
-
-  template <enum ResourceType resourceType, 
-            enum DicomModule module>
-  static void GetModule(RestApiGetCall& call)
-  {
-    if (call.IsDocumentation())
-    {
-      const std::string resource = GetResourceTypeText(resourceType, false /* plural */, false /* lower case */);
-      std::string m;
-      switch (module)
-      {
-        case DicomModule_Patient:
-          m = "patient";
-          break;
-        case DicomModule_Study:
-          m = "study";
-          break;
-        case DicomModule_Series:
-          m = "series";
-          break;
-        case DicomModule_Instance:
-          m = "instance";
-          break;
-        default:
-          throw OrthancException(ErrorCode_ParameterOutOfRange);
-      }
-      call.GetDocumentation()
-        .SetTag(GetResourceTypeText(resourceType, true /* plural */, true /* upper case */))
-        .SetSummary("Get " + m + " module" + std::string(resource == m ? "" : " of " + resource))
-        .SetDescription("Get the " + m + " module of the DICOM " + resource + " whose Orthanc identifier is provided in the URL")
-        .SetUriArgument("id", "Orthanc identifier of the " + resource + " of interest")
-        .SetHttpGetArgument("ignore-length", RestApiCallDocumentation::Type_JsonListOfStrings,
-                            "Also include the DICOM tags that are provided in this list, even if their associated value is long", false)
-        .AddAnswerType(MimeType_Json, "Information about the DICOM " + resource)
-        .SetHttpGetSample(GetDocumentationSampleResource(resourceType) + "/" + (*call.GetFullUri().rbegin()), true);
-      return;
-    }
-
-    GetModuleInternal(call, resourceType, module);
+    AnswerDicomAsJson(call, result, OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Full));
   }
 
 
@@ -2567,10 +2544,12 @@
     private:
       bool                    isComplete_;
       std::list<std::string>  resources_;
+      DicomToJsonFormat       format_;
 
     public:
-      FindVisitor() :
-        isComplete_(false)
+      FindVisitor(DicomToJsonFormat format) :
+        isComplete_(false),
+        format_(format)
       {
       }
       
@@ -2597,7 +2576,7 @@
                   ResourceType level,
                   bool expand) const
       {
-        AnswerListOfResources(output, index, resources_, level, expand);
+        AnswerListOfResources(output, index, resources_, level, expand, format_);
       }
     };
   }
@@ -2614,6 +2593,8 @@
 
     if (call.IsDocumentation())
     {
+      OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Human);
+
       call.GetDocumentation()
         .SetTag("System")
         .SetSummary("Look for local resources")
@@ -2741,7 +2722,7 @@
         }
       }
 
-      FindVisitor visitor;
+      FindVisitor visitor(OrthancRestApi::GetDicomFormat(request, DicomToJsonFormat_Human));
       context.Apply(visitor, query, level, since, limit);
       visitor.Answer(call.GetOutput(), context.GetIndex(), level, expand);
     }
@@ -2754,6 +2735,8 @@
   {
     if (call.IsDocumentation())
     {
+      OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Human);
+
       const std::string children = GetResourceTypeText(end, true /* plural */, false /* lower case */);
       const std::string resource = GetResourceTypeText(start, false /* plural */, false /* lower case */);
       call.GetDocumentation()
@@ -2792,11 +2775,13 @@
 
     Json::Value result = Json::arrayValue;
 
+    const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human);
+
     for (std::list<std::string>::const_iterator
            it = a.begin(); it != a.end(); ++it)
     {
       Json::Value resource;
-      if (OrthancRestApi::GetIndex(call).ExpandResource(resource, *it, end))
+      if (OrthancRestApi::GetIndex(call).ExpandResource(resource, *it, end, format))
       {
         result.append(resource);
       }
@@ -2810,6 +2795,8 @@
   {
     if (call.IsDocumentation())
     {
+      OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Full);
+
       ResourceType t = StringToResourceType(call.GetFullUri()[0].c_str());
       std::string r = GetResourceTypeText(t, false /* plural */, false /* upper case */);
       call.GetDocumentation()
@@ -2827,7 +2814,7 @@
 
     ServerContext& context = OrthancRestApi::GetContext(call);
     std::string publicId = call.GetUriComponent("id", "");
-    DicomToJsonFormat format = GetDicomFormat(call);
+    DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Full);
 
     std::set<DicomTag> ignoreTagLength;
     ParseSetOfTags(ignoreTagLength, call, "ignore-length");
@@ -2871,6 +2858,8 @@
 
     if (call.IsDocumentation())
     {
+      OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Human);
+
       const std::string parent = GetResourceTypeText(end, false /* plural */, false /* lower case */);
       const std::string resource = GetResourceTypeText(start, false /* plural */, false /* lower case */);
       call.GetDocumentation()
@@ -2904,8 +2893,10 @@
 
     assert(currentType == end);
 
+    const DicomToJsonFormat format = OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Human);
+
     Json::Value resource;
-    if (OrthancRestApi::GetIndex(call).ExpandResource(resource, current, end))
+    if (OrthancRestApi::GetIndex(call).ExpandResource(resource, current, end, format))
     {
       call.GetOutput().AnswerJson(resource);
     }
@@ -2978,16 +2969,13 @@
   {
     if (call.IsDocumentation())
     {
+      OrthancRestApi::DocumentDicomFormat(call, DicomToJsonFormat_Full);
       call.GetDocumentation()
         .SetTag("Instances")
         .SetSummary("Get DICOM meta-header")
         .SetDescription("Get the DICOM tags in the meta-header of the DICOM instance. By default, the `full` format is used, which "
                         "combines hexadecimal tags with human-readable description.")
         .SetUriArgument("id", "Orthanc identifier of the DICOM instance of interest")
-        .SetHttpGetArgument("simplify", RestApiCallDocumentation::Type_String,
-                            "If present, report the DICOM tags in human-readable format", false)
-        .SetHttpGetArgument("short", RestApiCallDocumentation::Type_String,
-                            "If present, report the DICOM tags indexed in hexadecimal format", false)
         .AddAnswerType(MimeType_Json, "JSON object containing the DICOM tags and their associated value")
         .SetHttpGetSample("https://demo.orthanc-server.com/instances/7c92ce8e-bbf67ed2-ffa3b8c1-a3b35d94-7ff3ae26/header", true);
       return;
@@ -3008,7 +2996,7 @@
     Json::Value header;
     OrthancConfiguration::DefaultDicomHeaderToJson(header, dicom);
 
-    AnswerDicomAsJson(call, header);
+    AnswerDicomAsJson(call, header, OrthancRestApi::GetDicomFormat(call, DicomToJsonFormat_Full));
   }
 
 
@@ -3183,8 +3171,8 @@
 
     Register("/instances/{id}/file", GetInstanceFile);
     Register("/instances/{id}/export", ExportInstanceFile);
-    Register("/instances/{id}/tags", GetInstanceTagsBis);
-    Register("/instances/{id}/simplified-tags", GetInstanceTags<DicomToJsonFormat_Human>);
+    Register("/instances/{id}/tags", GetInstanceTags);
+    Register("/instances/{id}/simplified-tags", GetInstanceSimplifiedTags);
     Register("/instances/{id}/frames", ListFrames);
 
     Register("/instances/{id}/frames/{frame}", RestApi::AutoListChildren);
--- a/OrthancServer/Sources/OrthancWebDav.cpp	Thu Jun 17 15:47:21 2021 +0200
+++ b/OrthancServer/Sources/OrthancWebDav.cpp	Fri Jun 18 16:08:35 2021 +0200
@@ -270,7 +270,7 @@
                        const Json::Value* dicomAsJson  /* unused (*) */)  ORTHANC_OVERRIDE
     {
       Json::Value resource;
-      if (context_.GetIndex().ExpandResource(resource, publicId, level_))
+      if (context_.GetIndex().ExpandResource(resource, publicId, level_, DicomToJsonFormat_Human))
       {
         if (success_)
         {