# HG changeset patch # User Alain Mazy # Date 1650894709 -7200 # Node ID 87b0e7e4d8d50a24f8df154b209b6fbeb7b7776c # Parent fe0671a4c145dda735dd0822bedd4754083a5e08# Parent c76d81c6fee851c25a17bdd074b6e921a1b26230 merged more-tags -> default diff -r fe0671a4c145 -r 87b0e7e4d8d5 NEWS --- a/NEWS Mon Dec 06 12:59:24 2021 +0100 +++ b/NEWS Mon Apr 25 15:51:49 2022 +0200 @@ -1,7 +1,37 @@ Pending changes in the mainline =============================== +=> Minimum Orthanc version: 1.11.0 <= + * Show an error message when trying to send studies > 4GB via STOW-RS +* Optimized QIDO-RS to build its responses from DB if tags are saved in "ExtraMainDicomTags". + Recommended configuration to optmize dicom-web usage: + "ExtraMainDicomTags" : { + "Instance" : [ + "Rows", + "Columns", + "ImageType", + "SOPClassUID", + "ContentDate", + "ContentTime", + "FrameOfReferenceUID", + "PixelSpacing", + "SpecificCharacterSet", + "BitsAllocated", + "BitsStored" + ], + "Series" : [ + "TimezoneOffsetFromUTC", + "PerformedProcedureStepStartDate", + "PerformedProcedureStepStartTime" + ], + "Study": [ + "TimezoneOffsetFromUTC" + ], + "Patient": [] + } + + Version 1.7 (2021-08-31) ======================== diff -r fe0671a4c145 -r 87b0e7e4d8d5 Plugin/QidoRs.cpp --- a/Plugin/QidoRs.cpp Mon Dec 06 12:59:24 2021 +0100 +++ b/Plugin/QidoRs.cpp Mon Apr 25 15:51:49 2022 +0200 @@ -66,7 +66,7 @@ result.insert(Orthanc::DicomTag(0x0008, 0x0030)); // Study Time result.insert(Orthanc::DicomTag(0x0008, 0x0050)); // Accession Number result.insert(Orthanc::DicomTag(0x0008, 0x0056)); // Instance Availability - //result.insert(Orthanc::DicomTag(0x0008, 0x0061)); // Modalities in Study => SPECIAL CASE + result.insert(Orthanc::DicomTag(0x0008, 0x0061)); // Modalities in Study => SPECIAL CASE result.insert(Orthanc::DicomTag(0x0008, 0x0090)); // Referring Physician's Name result.insert(Orthanc::DicomTag(0x0008, 0x0201)); // Timezone Offset From UTC //result.insert(Orthanc::DicomTag(0x0008, 0x1190)); // Retrieve URL => SPECIAL CASE @@ -76,8 +76,8 @@ result.insert(Orthanc::DicomTag(0x0010, 0x0040)); // Patient's Sex result.insert(Orthanc::DicomTag(0x0020, 0x000D)); // Study Instance UID result.insert(Orthanc::DicomTag(0x0020, 0x0010)); // Study ID - //result.insert(Orthanc::DicomTag(0x0020, 0x1206)); // Number of Study Related Series => SPECIAL CASE - //result.insert(Orthanc::DicomTag(0x0020, 0x1208)); // Number of Study Related Instances => SPECIAL CASE + result.insert(Orthanc::DicomTag(0x0020, 0x1206)); // Number of Study Related Series => SPECIAL CASE + result.insert(Orthanc::DicomTag(0x0020, 0x1208)); // Number of Study Related Instances => SPECIAL CASE break; case Orthanc::ResourceType_Series: @@ -89,7 +89,7 @@ //result.insert(Orthanc::DicomTag(0x0008, 0x1190)); // Retrieve URL => SPECIAL CASE result.insert(Orthanc::DicomTag(0x0020, 0x000E)); // Series Instance UID result.insert(Orthanc::DicomTag(0x0020, 0x0011)); // Series Number - //result.insert(Orthanc::DicomTag(0x0020, 0x1209)); // Number of Series Related Instances => SPECIAL CASE + result.insert(Orthanc::DicomTag(0x0020, 0x1209)); // Number of Series Related Instances => SPECIAL CASE result.insert(Orthanc::DicomTag(0x0040, 0x0244)); // Performed Procedure Step Start Date result.insert(Orthanc::DicomTag(0x0040, 0x0245)); // Performed Procedure Step Start Time result.insert(Orthanc::DicomTag(0x0040, 0x0275)); // Request Attribute Sequence @@ -272,10 +272,12 @@ result["CaseSensitive"] = caseSensitive; } - result["Expand"] = false; + result["Expand"] = true; + result["Full"] = true; result["Query"] = Json::objectValue; result["Limit"] = limit_; result["Since"] = offset_; + result["RequestedTags"] = Json::arrayValue; if (offset_ != 0 && !OrthancPlugins::CheckMinimalOrthancVersion(1, 3, 0)) @@ -290,130 +292,22 @@ { result["Query"][it->first.Format()] = it->second; } + + std::set requestedTags; + ExtractResultFields(requestedTags, level); + + for (std::set::const_iterator it = requestedTags.begin(); + it != requestedTags.end(); it++) + { + result["RequestedTags"].append(it->Format()); + } } - void ComputeDerivedTags(Orthanc::DicomMap& target, - std::string& someInstance, - Orthanc::ResourceType level, - const std::string& resource) const + + void ExtractResultFields(std::set& fields, + Orthanc::ResourceType level) const { - static const char* const INSTANCES = "Instances"; - static const char* const MAIN_DICOM_TAGS = "MainDicomTags"; - static const char* const MODALITY = "Modality"; - - switch (level) - { - case Orthanc::ResourceType_Instance: - someInstance = resource; - break; - - case Orthanc::ResourceType_Study: - { - Json::Value series; - if (OrthancPlugins::RestApiGet(series, "/studies/" + resource + "/series?expand", false) && - series.type() == Json::arrayValue) - { - // Collect the Modality of all the child series, and - std::set modalities; - unsigned int countInstances = 0; - - for (Json::Value::ArrayIndex i = 0; i < series.size(); i++) - { - if (series[i].type() == Json::objectValue) - { - if (series[i].isMember(MAIN_DICOM_TAGS) && - series[i][MAIN_DICOM_TAGS].type() == Json::objectValue && - series[i][MAIN_DICOM_TAGS].isMember(MODALITY) && - series[i][MAIN_DICOM_TAGS][MODALITY].type() == Json::stringValue) - { - modalities.insert(series[i][MAIN_DICOM_TAGS][MODALITY].asString()); - } - - if (series[i].isMember(INSTANCES) && - series[i][INSTANCES].type() == Json::arrayValue) - { - if (series[i][INSTANCES].size() > 0 && - series[i][INSTANCES][0].type() == Json::stringValue) - { - someInstance = series[i][INSTANCES][0].asString(); - } - - countInstances += series[i][INSTANCES].size(); - } - } - } - - target.SetValue(Orthanc::DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES, - boost::lexical_cast(series.size()), false); - - target.SetValue(Orthanc::DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES, - boost::lexical_cast(countInstances), false); - - std::string s; - for (std::set::const_iterator - it = modalities.begin(); it != modalities.end(); ++it) - { - if (!s.empty()) - { - s += "\\"; - } - - s += *it; - } - - target.SetValue(Orthanc::DICOM_TAG_MODALITIES_IN_STUDY, s, false); - } - else - { - target.SetValue(Orthanc::DICOM_TAG_MODALITIES_IN_STUDY, "", false); - target.SetValue(Orthanc::DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES, "0", false); - target.SetValue(Orthanc::DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES, "0", false); - } - - break; - } - - case Orthanc::ResourceType_Series: - { - Json::Value series; - if (OrthancPlugins::RestApiGet(series, "/series/" + resource, false) && - series.type() == Json::objectValue && - series.isMember(INSTANCES) && - series[INSTANCES].type() == Json::arrayValue) - { - if (series[INSTANCES].size() > 0 && - series[INSTANCES][0].type() == Json::stringValue) - { - someInstance = series[INSTANCES][0].asString(); - } - - // Number of Series Related Instances - target.SetValue(Orthanc::DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES, - boost::lexical_cast(series[INSTANCES].size()), false); - } - else - { - // Should never happen - target.SetValue(Orthanc::DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES, "0", false); - } - - break; - } - - default: - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - } - - - void ExtractFields(Orthanc::DicomMap& result, - const Orthanc::DicomMap& source, - const std::string& wadoBase, - Orthanc::ResourceType level) const - { - std::set fields; - for (std::list::const_iterator it = includeFields_.begin(); it != includeFields_.end(); ++it) { @@ -447,6 +341,16 @@ AddResultAttributesForLevel(fields, Orthanc::ResourceType_Series); } + } + + void ExtractFields(Orthanc::DicomMap& result, + const Orthanc::DicomMap& source, + const std::string& wadoBase, + Orthanc::ResourceType level) const + { + std::set fields; + ExtractResultFields(fields, level); + // Copy all the required fields to the target for (std::set::const_iterator it = fields.begin(); it != fields.end(); ++it) @@ -506,30 +410,21 @@ OrthancPlugins::DicomWebFormatter::HttpWriter writer( output, OrthancPlugins::Configuration::IsXmlExpected(request)); - // Fix of issue #13 for (Json::Value::ArrayIndex i = 0; i < resources.size(); i++) { - const std::string resource = resources[i].asString(); + const Json::Value& resource = resources[i]; - Orthanc::DicomMap derivedTags; - std::string someInstance; - matcher.ComputeDerivedTags(derivedTags, someInstance, level, resource); - - Json::Value tags; - if (!someInstance.empty() && - OrthancPlugins::RestApiGet(tags, "/instances/" + someInstance + "/tags", false)) + Orthanc::DicomMap source; + if (resource["RequestedTags"].isObject()) { - Orthanc::DicomMap source; - source.FromDicomAsJson(tags); + source.FromDicomAsJson(resource["RequestedTags"]); + } - Orthanc::DicomMap target; - target.Assign(derivedTags); - matcher.ExtractFields(target, source, wadoBase, level); + Orthanc::DicomMap target; - writer.AddOrthancMap(target); - } + matcher.ExtractFields(target, source, wadoBase, level); + writer.AddOrthancMap(target); } - writer.Send(); }