Mercurial > hg > orthanc-dicomweb
changeset 697:a3801ea80734
basic thumbnail implementation
author | Alain Mazy <am@orthanc.team> |
---|---|
date | Thu, 17 Apr 2025 11:48:02 +0200 |
parents | 6e165e40b1df |
children | d55bf1f01495 |
files | CMakeLists.txt NEWS Plugin/Plugin.cpp Plugin/WadoRs.h Plugin/WadoRsRetrieveRendered.cpp Resources/Images/video-thumbnail.jpg TODO |
diffstat | 7 files changed, 90 insertions(+), 24 deletions(-) [+] |
line wrap: on
line diff
--- a/CMakeLists.txt Thu Apr 17 09:59:46 2025 +0200 +++ b/CMakeLists.txt Thu Apr 17 11:48:02 2025 +0200 @@ -157,6 +157,7 @@ --no-upcase-check ${ADDITIONAL_RESOURCES} JAVASCRIPT_LIBS ${JAVASCRIPT_LIBS_DIR} + VIDEO_THUMBNAIL ${CMAKE_SOURCE_DIR}/Resources/Images/video-thumbnail.jpg )
--- a/NEWS Thu Apr 17 09:59:46 2025 +0200 +++ b/NEWS Thu Apr 17 11:48:02 2025 +0200 @@ -6,6 +6,9 @@ * If calling /rendered route on a video, the plugin will now return the video file (MP4 or ...). This notably enables display of videos in OHIF 3.10.1. +* Added basic support for thumbnails (aka sup 203: https://www.dicomstandard.org/docs/librariesprovider2/dicomdocuments/news/progress/docs/sups/sup203.pdf). + Right now, /thumbnail is equivalent to /rendered except for videos for which the same default video is shown since we are not able to + extract a thumbnail from a video. This notably enables display of a video icon in the series list of OHIF 3.10.1. Version 1.18 (2024-12-18)
--- a/Plugin/Plugin.cpp Thu Apr 17 09:59:46 2025 +0200 +++ b/Plugin/Plugin.cpp Thu Apr 17 11:48:02 2025 +0200 @@ -528,6 +528,38 @@ return OrthancPluginErrorCode_Success; } +template <bool isThumbnail> +void RetrieveInstanceRenderedThumbnail(OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request) +{ + RetrieveInstanceRendered(output, url, request, isThumbnail); +} + +template <bool isThumbnail> +void RetrieveFrameRenderedThumbnail(OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request) +{ + RetrieveFrameRendered(output, url, request, isThumbnail); +} + +template <bool isThumbnail> +void RetrieveSeriesRenderedThumbnail(OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request) +{ + RetrieveSeriesRendered(output, url, request, isThumbnail); +} + +template <bool isThumbnail> +void RetrieveStudyRenderedThumbnail(OrthancPluginRestOutput* output, + const char* url, + const OrthancPluginHttpRequest* request) +{ + RetrieveStudyRendered(output, url, request, isThumbnail); +} + extern "C" @@ -662,10 +694,15 @@ OrthancPlugins::RegisterRestCallback<GetClientInformation>(root + "info", true); - OrthancPlugins::RegisterRestCallback<RetrieveStudyRendered>(root + "studies/([^/]*)/rendered", true); - OrthancPlugins::RegisterRestCallback<RetrieveSeriesRendered>(root + "studies/([^/]*)/series/([^/]*)/rendered", true); - OrthancPlugins::RegisterRestCallback<RetrieveInstanceRendered>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/rendered", true); - OrthancPlugins::RegisterRestCallback<RetrieveFrameRendered>(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/frames/([^/]*)/rendered", true); + OrthancPlugins::RegisterRestCallback<RetrieveStudyRenderedThumbnail<false> >(root + "studies/([^/]*)/rendered", true); + OrthancPlugins::RegisterRestCallback<RetrieveSeriesRenderedThumbnail<false> >(root + "studies/([^/]*)/series/([^/]*)/rendered", true); + OrthancPlugins::RegisterRestCallback<RetrieveInstanceRenderedThumbnail<false> >(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/rendered", true); + OrthancPlugins::RegisterRestCallback<RetrieveFrameRenderedThumbnail<false> >(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/frames/([^/]*)/rendered", true); + + OrthancPlugins::RegisterRestCallback<RetrieveStudyRenderedThumbnail<true> >(root + "studies/([^/]*)/thumbnail", true); + OrthancPlugins::RegisterRestCallback<RetrieveSeriesRenderedThumbnail<true> >(root + "studies/([^/]*)/series/([^/]*)/thumbnail", true); + OrthancPlugins::RegisterRestCallback<RetrieveInstanceRenderedThumbnail<true> >(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/thumbnail", true); + OrthancPlugins::RegisterRestCallback<RetrieveFrameRenderedThumbnail<true> >(root + "studies/([^/]*)/series/([^/]*)/instances/([^/]*)/frames/([^/]*)/thumbnail", true); if (!OrthancPlugins::Configuration::IsReadOnly()) {
--- a/Plugin/WadoRs.h Thu Apr 17 09:59:46 2025 +0200 +++ b/Plugin/WadoRs.h Thu Apr 17 11:48:02 2025 +0200 @@ -96,19 +96,23 @@ void RetrieveInstanceRendered(OrthancPluginRestOutput* output, const char* url, - const OrthancPluginHttpRequest* request); + const OrthancPluginHttpRequest* request, + bool isThumbnail); void RetrieveFrameRendered(OrthancPluginRestOutput* output, const char* url, - const OrthancPluginHttpRequest* request); + const OrthancPluginHttpRequest* request, + bool isThumbnail); void RetrieveSeriesRendered(OrthancPluginRestOutput* output, const char* url, - const OrthancPluginHttpRequest* request); + const OrthancPluginHttpRequest* request, + bool isThumbnail); void RetrieveStudyRendered(OrthancPluginRestOutput* output, const char* url, - const OrthancPluginHttpRequest* request); + const OrthancPluginHttpRequest* request, + bool isThumbnail); void SetPluginCanDownloadTranscodedFile(bool enable);
--- a/Plugin/WadoRsRetrieveRendered.cpp Thu Apr 17 09:59:46 2025 +0200 +++ b/Plugin/WadoRsRetrieveRendered.cpp Thu Apr 17 11:48:02 2025 +0200 @@ -29,6 +29,8 @@ #include <Images/ImageTraits.h> #include <Logging.h> #include <Toolbox.h> +#include <EmbeddedResources.h> + #if ORTHANC_FRAMEWORK_VERSION_IS_ABOVE(1, 9, 7) # include <SerializationToolbox.h> @@ -824,7 +826,8 @@ const std::string& instanceId, const std::string& transferSyntax, int frame, - const OrthancPluginHttpRequest* request) + const OrthancPluginHttpRequest* request, + bool isThumbnail) // for now, for every images except for videos, we consider that /rendered is equivalent to /thumbnail { // If the instance is a video, we shall provide the video file itself (MP4, ...) Orthanc::DicomTransferSyntax currentSyntax; @@ -832,13 +835,24 @@ { if (currentSyntax >= Orthanc::DicomTransferSyntax_MPEG2MainProfileAtMainLevel && currentSyntax <= Orthanc::DicomTransferSyntax_HEVCMain10ProfileLevel5_1) { - OrthancPlugins::RestApiClient apiClient; - apiClient.SetPath(std::string("/instances/") + instanceId + "/frames/0/raw"); - if (apiClient.Execute()) + if (isThumbnail) { - apiClient.Forward(OrthancPlugins::GetGlobalContext(), output); + // we are not able to extract a thumbnail from a video -> just return a camera icon + std::string videoThumbnail; + Orthanc::EmbeddedResources::GetFileResource(videoThumbnail, Orthanc::EmbeddedResources::VIDEO_THUMBNAIL); + OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, videoThumbnail.c_str(), videoThumbnail.size(), "image/jpeg"); return; } + else + { + OrthancPlugins::RestApiClient apiClient; + apiClient.SetPath(std::string("/instances/") + instanceId + "/frames/0/raw"); + if (apiClient.Execute()) + { + apiClient.Forward(OrthancPlugins::GetGlobalContext(), output); + return; + } + } } } @@ -986,7 +1000,8 @@ static void AnswerFrameRendered(OrthancPluginRestOutput* output, int frame, - const OrthancPluginHttpRequest* request) + const OrthancPluginHttpRequest* request, + bool isThumbnail) { if (request->method != OrthancPluginHttpMethod_Get) { @@ -999,7 +1014,7 @@ if (LocateInstance(output, instanceId, studyInstanceUid, seriesInstanceUid, sopInstanceUid, transferSyntax, request)) { - AnswerFrameRendered(output, instanceId, transferSyntax, frame, request); + AnswerFrameRendered(output, instanceId, transferSyntax, frame, request, isThumbnail); } else { @@ -1011,27 +1026,30 @@ void RetrieveInstanceRendered(OrthancPluginRestOutput* output, const char* url, - const OrthancPluginHttpRequest* request) + const OrthancPluginHttpRequest* request, + bool isThumbnail) { assert(request->groupsCount == 3); - AnswerFrameRendered(output, 1 /* first frame */, request); + AnswerFrameRendered(output, 1 /* first frame */, request, isThumbnail); } void RetrieveFrameRendered(OrthancPluginRestOutput* output, const char* url, - const OrthancPluginHttpRequest* request) + const OrthancPluginHttpRequest* request, + bool isThumbnail) { assert(request->groupsCount == 4); const char* frame = request->groups[3]; - AnswerFrameRendered(output, boost::lexical_cast<int>(frame), request); + AnswerFrameRendered(output, boost::lexical_cast<int>(frame), request, isThumbnail); } void RetrieveSeriesRendered(OrthancPluginRestOutput* output, const char* url, - const OrthancPluginHttpRequest* request) + const OrthancPluginHttpRequest* request, + bool isThumbnail) { assert(request->groupsCount == 2); @@ -1044,7 +1062,7 @@ std::string instanceOrthancId, studyInstanceUid, seriesInstanceUid, transferSyntax; if (LocateOneInstance(output, instanceOrthancId, studyInstanceUid, seriesInstanceUid, transferSyntax, request)) { - AnswerFrameRendered(output, instanceOrthancId, transferSyntax, 1 /* first frame */, request); + AnswerFrameRendered(output, instanceOrthancId, transferSyntax, 1 /* first frame */, request, isThumbnail); return; // Success } @@ -1055,7 +1073,8 @@ void RetrieveStudyRendered(OrthancPluginRestOutput* output, const char* url, - const OrthancPluginHttpRequest* request) + const OrthancPluginHttpRequest* request, + bool isThumbnail) { assert(request->groupsCount == 1); @@ -1068,7 +1087,7 @@ std::string instanceOrthancId, studyInstanceUid, seriesInstanceUid, transferSyntax; if (LocateOneInstance(output, instanceOrthancId, studyInstanceUid, seriesInstanceUid, transferSyntax, request)) { - AnswerFrameRendered(output, instanceOrthancId, transferSyntax, 1 /* first frame */, request); + AnswerFrameRendered(output, instanceOrthancId, transferSyntax, 1 /* first frame */, request, isThumbnail); return; // Success }
--- a/TODO Thu Apr 17 09:59:46 2025 +0200 +++ b/TODO Thu Apr 17 11:48:02 2025 +0200 @@ -31,7 +31,9 @@ * Add support for application/zip in /dicom-web/studies/ (aka sup 211: https://www.dicomstandard.org/docs/librariesprovider2/dicomdocuments/news/ftsup/docs/sups/sup211.pdf?sfvrsn=9fe9edae_2) -* Add support for thumbnails (aka sup 203: https://www.dicomstandard.org/docs/librariesprovider2/dicomdocuments/news/progress/docs/sups/sup203.pdf) +* Add support for thumbnails (aka sup 203: https://www.dicomstandard.org/docs/librariesprovider2/dicomdocuments/news/progress/docs/sups/sup203.pdf). + Right now, thumbnail is equivalent to /rendered except for video thumbnails for which the same default video icon is shown since we are not able to + extract a thumbnail from a video. * Support private tags in search fields: https://discourse.orthanc-server.org/t/dicomweb-plugin-exception-of-unknown-dicom-tag-for-private-data-element-tags-while-using-query-parameters/3998