Mercurial > hg > orthanc-dicomweb
changeset 391:27001924c456
Fix issue #162 ("DICOMweb metadata resource reads all instances")
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 17 Feb 2020 16:33:32 +0100 |
parents | 5aa7b5a1bb38 |
children | c467391b3585 |
files | NEWS Plugin/Configuration.cpp Plugin/Configuration.h Plugin/WadoRs.cpp |
diffstat | 4 files changed, 130 insertions(+), 38 deletions(-) [+] |
line wrap: on
line diff
--- a/NEWS Mon Feb 10 10:29:59 2020 +0100 +++ b/NEWS Mon Feb 17 16:33:32 2020 +0100 @@ -7,6 +7,9 @@ * Support of "window", "viewport" and "quality" parameters in "Retrieve Rendered Transaction" * Support of "/studies/.../series/.../rendered" * QIDO-RS: Allow to query against a list of multiple values separated by commas +* WADO-RS "Retrieve Metadata": Configuration options "StudiesMetadata" and "SeriesMetadata", + whose value can be "Full" (read all DICOM instances from the storage area) or + "MainDicomTags" (only report the main DICOM tags from the Orthanc database) Maintenance ----------- @@ -18,6 +21,7 @@ * Accept multiple MIME types in Accept header for WADO-RS "Retrieve Metadata" * Added explicit "Accept" header to avoid uncompressing DICOM files by Google cloud https://groups.google.com/d/msg/orthanc-users/w1Ekrsc6-U8/T2a_DoQ5CwAJ +* Fix issue #162 ("DICOMweb metadata resource reads all instances") * Fix issue #164 ("JPEG YBR_422 generates a 500 in the DicomWeb plugin") * Upgrade to GDCM 3.0.4 in static builds
--- a/Plugin/Configuration.cpp Mon Feb 10 10:29:59 2020 +0100 +++ b/Plugin/Configuration.cpp Mon Feb 17 16:33:32 2020 +0100 @@ -307,6 +307,10 @@ OrthancPlugins::OrthancConfiguration servers; configuration_->GetSection(servers, "Servers"); OrthancPlugins::DicomWebServers::GetInstance().Load(servers.GetJson()); + + // Check configuration during initialization + GetMetadataMode(Orthanc::ResourceType_Study); + GetMetadataMode(Orthanc::ResourceType_Series); } @@ -605,5 +609,45 @@ return false; // By default, return DICOM+JSON } } + + + MetadataMode GetMetadataMode(Orthanc::ResourceType level) + { + static const std::string FULL = "Full"; + static const std::string MAIN_DICOM_TAGS = "MainDicomTags"; + + std::string key; + switch (level) + { + case Orthanc::ResourceType_Study: + key = "StudiesMetadata"; + break; + + case Orthanc::ResourceType_Series: + key = "SeriesMetadata"; + break; + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + + std::string value = GetStringValue(key, FULL); + + if (value == FULL) + { + return MetadataMode_Full; + } + else if (value == MAIN_DICOM_TAGS) + { + return MetadataMode_MainDicomTags; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange, + "Bad value for option \"" + key + + "\": Should be either \"" + FULL + "\" or \"" + + MAIN_DICOM_TAGS + "\""); + } + } } }
--- a/Plugin/Configuration.h Mon Feb 10 10:29:59 2020 +0100 +++ b/Plugin/Configuration.h Mon Feb 17 16:33:32 2020 +0100 @@ -45,6 +45,14 @@ static const Orthanc::DicomTag DICOM_TAG_REFERENCED_SOP_CLASS_UID(0x0008, 0x1150); static const Orthanc::DicomTag DICOM_TAG_REFERENCED_SOP_INSTANCE_UID(0x0008, 0x1155); + enum MetadataMode + { + MetadataMode_Full, // Read all the DICOM instances from the storage area + MetadataMode_MainDicomTags, // Only use the Orthanc database (main DICOM tags only) + MetadataMode_Interpolate // Unused so far + }; + + bool LookupHttpHeader(std::string& value, const OrthancPluginHttpRequest* request, const std::string& header); @@ -115,5 +123,7 @@ // TODO => REMOVE bool IsXmlExpected(const OrthancPluginHttpRequest* request); + + MetadataMode GetMetadataMode(Orthanc::ResourceType level); } }
--- a/Plugin/WadoRs.cpp Mon Feb 10 10:29:59 2020 +0100 +++ b/Plugin/WadoRs.cpp Mon Feb 17 16:33:32 2020 +0100 @@ -292,6 +292,7 @@ static bool ReadResource(Orthanc::DicomMap& dicom, std::string& parent, + OrthancPlugins::MetadataMode mode, const std::string& orthancId, Orthanc::ResourceType level) { @@ -362,17 +363,22 @@ } - /** - * Complete the series-level tags, with instance-level tags that - * are not considered as "main DICOM tags" in Orthanc, but that - * are necessary for Web viewers, and that should be constant - * throughout all the instances of the series. To this end, we - * read 1 DICOM instance of this series from disk, and extract - * the subset of tags of interest. Obviously, this is an - * approximation to improve performance. - **/ - if (level == Orthanc::ResourceType_Series) + if (mode == OrthancPlugins::MetadataMode_Interpolate && + level == Orthanc::ResourceType_Series) { + /** + * Complete the series-level tags, with instance-level tags + * that are not considered as "main DICOM tags" in Orthanc, + * but that are necessary for Web viewers, and that should be + * constant throughout all the instances of the series. To + * this end, we read 1 DICOM instance of this series from + * disk, and extract the subset of tags of + * interest. Obviously, this is an approximation to improve + * performance. + * + * TODO - Decide which tags are safe (i.e. what is supposed to + * be constant?) + **/ if (!value.isMember(INSTANCES) || value[INSTANCES].type() != Json::arrayValue || value[INSTANCES].size() == 0 || @@ -407,14 +413,14 @@ CopyTagIfMissing(dicom, instance, Orthanc::DICOM_TAG_SOP_CLASS_UID); CopyTagIfMissing(dicom, instance, Orthanc::DICOM_TAG_WINDOW_CENTER); CopyTagIfMissing(dicom, instance, Orthanc::DICOM_TAG_WINDOW_WIDTH); - CopyTagIfMissing(dicom, instance, Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR); - CopyTagIfMissing(dicom, instance, Orthanc::DICOM_TAG_FRAME_INCREMENT_POINTER); + CopyTagIfMissing(dicom, instance, Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR); // TODO => probably unsafe! + CopyTagIfMissing(dicom, instance, Orthanc::DICOM_TAG_FRAME_INCREMENT_POINTER); // TODO => probably unsafe! CopyTagIfMissing(dicom, instance, Orthanc::DICOM_TAG_SLICE_THICKNESS); //CopyTagIfMissing(dicom, instance, Orthanc::DICOM_TAG_IMAGE_POSITION_PATIENT); // => Already in main DICOM tags CopyTagIfMissing(dicom, instance, Orthanc::DICOM_TAG_IMAGE_ORIENTATION_PATIENT); CopyTagIfMissing(dicom, instance, Orthanc::DICOM_TAG_RESCALE_INTERCEPT); CopyTagIfMissing(dicom, instance, Orthanc::DICOM_TAG_RESCALE_SLOPE); - CopyTagIfMissing(dicom, instance, Orthanc::DICOM_TAG_DOSE_GRID_SCALING); + CopyTagIfMissing(dicom, instance, Orthanc::DICOM_TAG_DOSE_GRID_SCALING); // TODO => probably unsafe! // SeriesMetadataLoader //CopyTagIfMissing(dicom, instance, Orthanc::DICOM_TAG_SOP_INSTANCE_UID); // => Already in main DICOM tags @@ -444,6 +450,7 @@ bool Lookup(Orthanc::DicomMap& dicom, std::string& parent, + OrthancPlugins::MetadataMode mode, const std::string& orthancId, Orthanc::ResourceType level) { @@ -452,7 +459,7 @@ if (found == content_.end()) { std::auto_ptr<Info> info(new Info); - if (!ReadResource(info->dicom_, info->parent_, orthancId, level)) + if (!ReadResource(info->dicom_, info->parent_, mode, orthancId, level)) { return false; } @@ -481,13 +488,14 @@ bool GetInstance(Orthanc::DicomMap& dicom, + OrthancPlugins::MetadataMode mode, const std::string& orthancId) { std::string seriesId, studyId, nope; - return (ReadResource(dicom, seriesId, orthancId, Orthanc::ResourceType_Instance) && - Lookup(dicom, studyId, seriesId, Orthanc::ResourceType_Series) && - Lookup(dicom, nope, studyId, Orthanc::ResourceType_Study)); + return (ReadResource(dicom, seriesId, mode, orthancId, Orthanc::ResourceType_Instance) && + Lookup(dicom, studyId, mode, seriesId, Orthanc::ResourceType_Series) && + Lookup(dicom, nope /* patient id is unused */, mode, studyId, Orthanc::ResourceType_Study)); } }; } @@ -495,6 +503,7 @@ static void WriteInstanceMetadata(OrthancPlugins::DicomWebFormatter::HttpWriter& writer, + OrthancPlugins::MetadataMode mode, MainDicomTagsCache& cache, const std::string& orthancId, const std::string& studyInstanceUid, @@ -513,23 +522,42 @@ "/series/" + seriesInstanceUid + "/instances/" + sopInstanceUid + "/bulk"); -#if 0 - Orthanc::DicomMap dicom; - if (cache.GetInstance(dicom, orthancId)) + switch (mode) { - writer.AddOrthancMap(dicom); - } + case OrthancPlugins::MetadataMode_MainDicomTags: + case OrthancPlugins::MetadataMode_Interpolate: + { + Orthanc::DicomMap dicom; + if (cache.GetInstance(dicom, mode, orthancId)) + { + writer.AddOrthancMap(dicom); + } + + break; + } + + case OrthancPlugins::MetadataMode_Full: + { + // On a SSD drive, this version is twice slower than if using + // cache (see below) + + OrthancPlugins::MemoryBuffer dicom; + if (dicom.RestApiGet("/instances/" + orthancId + "/file", false)) + { + writer.AddDicom(dicom.GetData(), dicom.GetSize(), bulkRoot); + } + + break; + } + + default: + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + -#elif 1 - // On a SSD drive, this version is twice slower than if using - // cache (see below) - - OrthancPlugins::MemoryBuffer dicom; - if (dicom.RestApiGet("/instances/" + orthancId + "/file", false)) - { - writer.AddDicom(dicom.GetData(), dicom.GetSize(), bulkRoot); - } -#else +#if 0 + /** + **/ // TODO - Have a global setting to enable/disable caching of DICOMweb @@ -896,6 +924,9 @@ } else { + const OrthancPlugins::MetadataMode mode = + OrthancPlugins::Configuration::GetMetadataMode(Orthanc::ResourceType_Study); + MainDicomTagsCache cache; std::string studyOrthancId, studyInstanceUid; @@ -913,8 +944,8 @@ for (std::list<Identifier>::const_iterator b = instances.begin(); b != instances.end(); ++b) { - WriteInstanceMetadata(writer, cache, b->GetOrthancId(), studyInstanceUid, a->GetDicomUid(), b->GetDicomUid(), - OrthancPlugins::Configuration::GetBaseUrl(request)); + WriteInstanceMetadata(writer, mode, cache, b->GetOrthancId(), studyInstanceUid, a->GetDicomUid(), + b->GetDicomUid(), OrthancPlugins::Configuration::GetBaseUrl(request)); } } @@ -937,6 +968,9 @@ } else { + const OrthancPlugins::MetadataMode mode = + OrthancPlugins::Configuration::GetMetadataMode(Orthanc::ResourceType_Series); + MainDicomTagsCache cache; std::string seriesOrthancId, studyInstanceUid, seriesInstanceUid; @@ -949,8 +983,8 @@ for (std::list<Identifier>::const_iterator a = instances.begin(); a != instances.end(); ++a) { - WriteInstanceMetadata(writer, cache, a->GetOrthancId(), studyInstanceUid, seriesInstanceUid, a->GetDicomUid(), - OrthancPlugins::Configuration::GetBaseUrl(request)); + WriteInstanceMetadata(writer, mode, cache, a->GetOrthancId(), studyInstanceUid, seriesInstanceUid, + a->GetDicomUid(), OrthancPlugins::Configuration::GetBaseUrl(request)); } writer.Send(); @@ -976,8 +1010,8 @@ if (LocateInstance(output, orthancId, studyInstanceUid, seriesInstanceUid, sopInstanceUid, request)) { OrthancPlugins::DicomWebFormatter::HttpWriter writer(output, isXml); - WriteInstanceMetadata(writer, cache, orthancId, studyInstanceUid, seriesInstanceUid, sopInstanceUid, - OrthancPlugins::Configuration::GetBaseUrl(request)); + WriteInstanceMetadata(writer, OrthancPlugins::MetadataMode_Full, cache, orthancId, studyInstanceUid, + seriesInstanceUid, sopInstanceUid, OrthancPlugins::Configuration::GetBaseUrl(request)); writer.Send(); } }