# HG changeset patch # User Sebastien Jodogne <s.jodogne@gmail.com> # Date 1734362464 -3600 # Node ID 9e43494cb0543185880164d075331c7078e0cd25 # Parent bef0d7030f2d1a501703fcf630581575c7456223# Parent a5241defb36f800c7dc362985b61ed773f1881a5 integration mainline->find-refactoring diff -r bef0d7030f2d -r 9e43494cb054 NEWS --- a/NEWS Fri Sep 27 18:49:59 2024 +0200 +++ b/NEWS Mon Dec 16 16:21:04 2024 +0100 @@ -1,11 +1,13 @@ Pending changes in the mainline =============================== -* Added a "Server" entry in the DICOMWeb job content. -* Fixed parsing of numerical values in QIDO-RS response that prevented, amongst other, - the retrieval of NumberOfStudyRelatedInstances, NumberOfStudyRelatedSeries, ... -* Fixed non latin PatientName values that were empty in some QIDO-RS responses. -* Optimization when running with an Orthanc that supports the ExtendedFind. +* Added a "Server" entry in the DICOMweb job content. +* Fixed parsing of numerical values in QIDO-RS response that prevented, among other, + the retrieval of "NumberOfStudyRelatedInstances", "NumberOfStudyRelatedSeries",... +* Fixed non-Latin "PatientName" values that were empty in some QIDO-RS responses. +* Optimized the retrieval of single frame in WADO-RS when no transcoding is required. + This greatly improves the download time of multi-frame images in OHIF. +* Optimization when running with an Orthanc that supports the "ExtendedFind" primitive. * Added support for Orthanc running in "ReadOnly" mode. diff -r bef0d7030f2d -r 9e43494cb054 Plugin/WadoRsRetrieveFrames.cpp --- a/Plugin/WadoRsRetrieveFrames.cpp Fri Sep 27 18:49:59 2024 +0200 +++ b/Plugin/WadoRsRetrieveFrames.cpp Mon Dec 16 16:21:04 2024 +0100 @@ -433,6 +433,43 @@ } +static void AnswerFrame(OrthancPluginRestOutput* output, + const OrthancPluginHttpRequest* request, + const OrthancPlugins::MemoryBuffer& instanceContent, + const std::string& studyInstanceUid, + const std::string& seriesInstanceUid, + const std::string& sopInstanceUid, + unsigned int frame, + Orthanc::DicomTransferSyntax outputSyntax) +{ + if (OrthancPluginStartMultipartAnswer( + OrthancPlugins::GetGlobalContext(), + output, "related", GetMimeType(outputSyntax)) != OrthancPluginErrorCode_Success) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_Plugin, + "Cannot start a multipart answer"); + } + + OrthancPluginErrorCode error; + +#if HAS_SEND_MULTIPART_ITEM_2 == 1 + const std::string base = OrthancPlugins::Configuration::GetBasePublicUrl(request); + std::string location = ( + OrthancPlugins::Configuration::GetWadoUrl(base, studyInstanceUid, seriesInstanceUid, sopInstanceUid) + + "frames/" + boost::lexical_cast<std::string>(frame + 1)); + const char *keys[] = { "Content-Location" }; + const char *values[] = { location.c_str() }; + error = OrthancPluginSendMultipartItem2(OrthancPlugins::GetGlobalContext(), output, instanceContent.GetData(), instanceContent.GetSize(), 1, keys, values); +#else + error = OrthancPluginSendMultipartItem(OrthancPlugins::GetGlobalContext(), instanceContent.GetData(), instanceContent.GetSize(), size); +#endif + + if (error != OrthancPluginErrorCode_Success) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); + } +} + static void RetrieveFrames(OrthancPluginRestOutput* output, const OrthancPluginHttpRequest* request, bool allFrames, @@ -499,9 +536,23 @@ { throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "DICOMWeb: Unable to get transcoded file for instance " + orthancId); } + + // TODO-OPTI: this takes a huge amount of time; e.g: 1.5s for a 600MB file while the DicomInstance usually already exists in the Orthanc core + // call /instances/../frames/../transcoded (to be implemented in future Orthanc release) instance.reset(new OrthancPlugins::DicomInstance(content.GetData(), content.GetSize())); } - else // pre 1.12.2 code (or no transcoding needed) + else if (!allFrames && frames.size() == 1 && !transcodeThisInstance) // no transcoding needed, let's retrieve the raw frame directly from the core to avoid Orthanc to recreate a DicomInstance for every frame + { + if (!content.RestApiGet("/instances/" + orthancId + "/frames/" + boost::lexical_cast<std::string>(frames.front()) + "/raw", false)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "DICOMWeb: Unable to get file for instance " + orthancId); + } + + AnswerFrame(output, request, content, studyInstanceUid, seriesInstanceUid, + sopInstanceUid, frames.front(), targetSyntax); + return; + } + else { if (!content.RestApiGet("/instances/" + orthancId + "/file", false)) { diff -r bef0d7030f2d -r 9e43494cb054 TODO --- a/TODO Fri Sep 27 18:49:59 2024 +0200 +++ b/TODO Mon Dec 16 16:21:04 2024 +0100 @@ -10,6 +10,8 @@ curl -H "Accept: multipart/related; type=application/octet-stream" http://localhost:8043/dicom-web/studies/1.2.156.112536.1.2143.25015081191207.14610300430.5/series/1.2.156.112536.1.2143.25015081191207.14610300430.6/instances/1.2.156.112536.1.2143.25015081191207.14610309990.44/frames/3 --output /tmp/out.bin check for these logs: DICOMweb RetrieveFrames: Transcoding instance a7aec17a-e296e51f-2abe8ad8-bc95d57b-4de269d0 to transfer syntax 1.2.840.10008.1.2.1 + Note: This has been partially handled in 1.18: Tf no transcoding is needed, we avoid downloading the full instance from Orthanc + We should very likely implement a cache in the DicomWEB plugin and make sure that, if 3 clients are requesting the same instance at the same time, we only request one transcoding. @@ -18,6 +20,7 @@ https://discourse.orthanc-server.org/t/possible-memory-leak-with-multiframe-dicom-orthanc-ohif/3988/12 + * Implement capabilities: https://www.dicomstandard.org/using/dicomweb/capabilities/ from https://groups.google.com/d/msgid/orthanc-users/c60227f2-c6da-4fd9-9b03-3ce9bf7d1af5n%40googlegroups.com?utm_medium=email&utm_source=footer