changeset 2260:e8c876f65c56

fix video detection by introducing SeriesThumbnailsLoader::DicomWebGetOneInstanceInSeriesHandler
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 03 Dec 2025 18:11:55 +0100
parents fa76698bb9e0
children d212eabd6440
files OrthancStone/Sources/Loaders/SeriesThumbnailsLoader.cpp OrthancStone/Sources/Loaders/SeriesThumbnailsLoader.h
diffstat 2 files changed, 132 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancStone/Sources/Loaders/SeriesThumbnailsLoader.cpp	Wed Dec 03 16:32:09 2025 +0100
+++ b/OrthancStone/Sources/Loaders/SeriesThumbnailsLoader.cpp	Wed Dec 03 18:11:55 2025 +0100
@@ -418,6 +418,121 @@
   };
 
     
+  class SeriesThumbnailsLoader::DicomWebGetOneInstanceInSeriesHandler : public SeriesThumbnailsLoader::Handler
+  {
+  private:
+    void LogError() const
+    {
+      LOG(ERROR) << "Cannot download one instance from series: " << GetSeriesInstanceUid();
+    }
+
+  public:
+    DicomWebGetOneInstanceInSeriesHandler(boost::shared_ptr<SeriesThumbnailsLoader> loader,
+                                          const DicomSource& source,
+                                          const std::string& studyInstanceUid,
+                                          const std::string& seriesInstanceUid) :
+      Handler(loader, source, studyInstanceUid, seriesInstanceUid)
+    {
+    }
+
+    virtual void HandleSuccess(const std::string& body,
+                               const std::map<std::string, std::string>& headers) ORTHANC_OVERRIDE
+    {
+      Json::Value instances;
+
+      if (!Orthanc::Toolbox::ReadJson(instances, body) ||
+          instances.type() != Json::arrayValue)
+      {
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
+      }
+      else if (instances.empty())
+      {
+        LogError();
+      }
+      else
+      {
+        Orthanc::DicomMap instance;
+        instance.FromDicomWeb(instances[0]);
+
+        std::unique_ptr<IOracleCommand> command;
+
+        std::string sopInstanceUid;
+        std::string sopClassUid;
+        if (instance.LookupStringValue(sopInstanceUid, Orthanc::DICOM_TAG_SOP_INSTANCE_UID, false) &&
+            instance.LookupStringValue(sopClassUid, Orthanc::DICOM_TAG_SOP_CLASS_UID, false))
+        {
+          switch (StringToSopClassUid(sopClassUid))
+          {
+          case SopClassUid_VideoEndoscopicImageStorage:
+          case SopClassUid_VideoMicroscopicImageStorage:
+          case SopClassUid_VideoPhotographicImageStorage:
+            GetLoader()->AcquireThumbnail(GetSource(), GetStudyInstanceUid(),
+                                          GetSeriesInstanceUid(), new Thumbnail(SeriesThumbnailType_Video));
+            break;
+
+          case SopClassUid_EncapsulatedPdf:
+            GetLoader()->AcquireThumbnail(GetSource(), GetStudyInstanceUid(),
+                                          GetSeriesInstanceUid(), new Thumbnail(SeriesThumbnailType_Pdf));
+            break;
+
+          default:
+            if (GetSource().HasDicomWebRendered())
+            {
+              LOG(ERROR) << "OOOOO";
+              // By default, rely on server-side rendering
+
+              const std::string uri = ("/studies/" + GetStudyInstanceUid() +
+                                       "/series/" + GetSeriesInstanceUid() + "/rendered");
+
+              std::map<std::string, std::string> arguments, headers;
+              arguments["viewport"] = (boost::lexical_cast<std::string>(GetLoader()->width_) + "," +
+                                       boost::lexical_cast<std::string>(GetLoader()->height_));
+
+              // Needed to set this header explicitly, as long as emscripten
+              // does not include macro "EMSCRIPTEN_FETCH_RESPONSE_HEADERS"
+              // https://github.com/emscripten-core/emscripten/pull/8486
+              headers["Accept"] = Orthanc::MIME_JPEG;
+
+              command.reset(GetSource().CreateDicomWebCommand(
+                              uri, arguments, headers, new DicomWebThumbnailHandler(
+                                GetLoader()->GetSharedObserver(), GetSource(), GetStudyInstanceUid(), GetSeriesInstanceUid())));
+            }
+            else
+            {
+#if ORTHANC_ENABLE_DCMTK == 1
+              command.reset(ParseDicomFromWadoCommand::Create(
+                              GetSource(), GetStudyInstanceUid(), GetSeriesInstanceUid(), sopInstanceUid, false,
+                              Orthanc::DicomTransferSyntax_LittleEndianExplicit /* useless, as no transcoding */,
+                              new ThumbnailInformation(
+                                GetSource(), GetStudyInstanceUid(), GetSeriesInstanceUid())));
+#else
+              throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented,
+                                              "Stone of Orthanc was built without support to decode DICOM images");
+#endif
+            }
+
+            break;
+          }
+
+          if (command.get() != NULL)
+          {
+            GetLoader()->Schedule(command.release());
+          }
+        }
+        else
+        {
+          LogError();
+        }
+      }
+    }
+
+    virtual void HandleError() ORTHANC_OVERRIDE
+    {
+      LogError();
+    }
+  };
+
+
 #if ORTHANC_ENABLE_DCMTK == 1
   class SeriesThumbnailsLoader::SelectDicomWebInstanceHandler : public SeriesThumbnailsLoader::Handler
   {
@@ -682,6 +797,21 @@
 
     if (source.IsDicomWeb())
     {
+      {
+        std::map<std::string, std::string> arguments, headers;
+        arguments["0020000D"] = studyInstanceUid;
+        arguments["0020000E"] = seriesInstanceUid;
+        arguments["includefield"] = "00080016";  // SOP Class UID
+        arguments["limit"] = "1";
+
+        std::unique_ptr<IOracleCommand> command(
+          source.CreateDicomWebCommand(
+            "/instances", arguments, headers, new DicomWebGetOneInstanceInSeriesHandler(
+              GetSharedObserver(), source, studyInstanceUid, seriesInstanceUid)));
+        Schedule(command.release());
+      }
+
+#if 0
       if (!source.HasDicomWebRendered())
       {
 #if ORTHANC_ENABLE_DCMTK == 1
@@ -721,6 +851,7 @@
               GetSharedObserver(), source, studyInstanceUid, seriesInstanceUid)));
         Schedule(command.release());
       }
+#endif
 
       scheduledSeries_.insert(seriesInstanceUid);
     }
--- a/OrthancStone/Sources/Loaders/SeriesThumbnailsLoader.h	Wed Dec 03 16:32:09 2025 +0100
+++ b/OrthancStone/Sources/Loaders/SeriesThumbnailsLoader.h	Wed Dec 03 18:11:55 2025 +0100
@@ -140,6 +140,7 @@
     class ThumbnailInformation;
     class OrthancSopClassHandler;
     class SelectOrthancInstanceHandler;
+    class DicomWebGetOneInstanceInSeriesHandler;
 
 #if ORTHANC_ENABLE_DCMTK == 1
     class SelectDicomWebInstanceHandler;