changeset 277:ac1508b438b1 iiif

support of "Accept" header in /wsi/tiles/{id}/{z}/{x}/{y}
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 12 Jul 2023 16:14:19 +0200
parents ef8a673b5fb9
children 34b507959e32
files NEWS ViewerPlugin/Plugin.cpp ViewerPlugin/RawTile.cpp
diffstat 3 files changed, 81 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/NEWS	Wed Jul 12 14:51:46 2023 +0200
+++ b/NEWS	Wed Jul 12 16:14:19 2023 +0200
@@ -2,6 +2,8 @@
 ===============================
 
 * Support of IIIF
+* URI "/wsi/tiles/{id}/{z}/{x}/{y}" supports the "Accept" HTTP header
+  to force JPEG, JPEG2k or PNG in the decoded tiles
 
 
 Version 1.1 (2021-12-11)
--- a/ViewerPlugin/Plugin.cpp	Wed Jul 12 14:51:46 2023 +0200
+++ b/ViewerPlugin/Plugin.cpp	Wed Jul 12 16:14:19 2023 +0200
@@ -27,9 +27,9 @@
 #include "RawTile.h"
 
 #include <Compatibility.h>  // For std::unique_ptr
-#include <Logging.h>
 #include <Images/Image.h>
 #include <Images/ImageProcessing.h>
+#include <Logging.h>
 #include <OrthancException.h>
 #include <SystemToolbox.h>
 
@@ -161,20 +161,72 @@
                                           static_cast<unsigned int>(tileY)));
   }
 
+  Orthanc::MimeType mime;
+
   if (rawTile->GetCompression() == OrthancWSI::ImageCompression_Jpeg)
   {
     // The tile is already a JPEG image. In such a case, we can
     // serve it as such, because any Web browser can handle JPEG.
-    rawTile->Answer(output, Orthanc::MimeType_Jpeg);
+    mime = Orthanc::MimeType_Jpeg;
   }
   else
   {
-    // This is a lossless frame (coming from a JPEG2000 or an
-    // uncompressed DICOM instance), which is not a DICOM-JPEG
-    // instance. We need to decompress the raw tile, then transcode it
-    // to the PNG/JPEG, depending on the "encoding".
-    rawTile->Answer(output, Orthanc::MimeType_Png);
+    // This is a lossless frame (coming from JPEG2000 or uncompressed
+    // DICOM instance), not a DICOM-JPEG instance. Decompress the raw
+    // tile, then transcode it to PNG to prevent lossy compression and
+    // to avoid JPEG2000 that is not supported by all the browsers.
+    mime = Orthanc::MimeType_Png;
   }
+
+  // Lookup whether a "Accept" HTTP header is present, to overwrite
+  // the default MIME type
+  for (uint32_t i = 0; i < request->headersCount; i++)
+  {
+    std::string key(request->headersKeys[i]);
+    Orthanc::Toolbox::ToLowerCase(key);
+
+    if (key == "accept")
+    {
+      std::vector<std::string> tokens;
+      Orthanc::Toolbox::TokenizeString(tokens, request->headersValues[i], ',');
+
+      bool found = false;
+
+      for (size_t j = 0; j < tokens.size(); j++)
+      {
+        std::string s = Orthanc::Toolbox::StripSpaces(tokens[j]);
+
+        if (s == Orthanc::EnumerationToString(Orthanc::MimeType_Png))
+        {
+          mime = Orthanc::MimeType_Png;
+          found = true;
+        }
+        else if (s == Orthanc::EnumerationToString(Orthanc::MimeType_Jpeg))
+        {
+          mime = Orthanc::MimeType_Jpeg;
+          found = true;
+        }
+        else if (s == Orthanc::EnumerationToString(Orthanc::MimeType_Jpeg2000))
+        {
+          mime = Orthanc::MimeType_Jpeg2000;
+          found = true;
+        }
+        else if (s == "*/*" ||
+                 s == "image/*")
+        {
+          found = true;
+        }
+      }
+
+      if (!found)
+      {
+        OrthancPluginSendHttpStatusCode(OrthancPlugins::GetGlobalContext(), output, 406 /* Not acceptable */);
+        return;
+      }
+    }
+  }
+
+  rawTile->Answer(output, mime);
 }
 
 
--- a/ViewerPlugin/RawTile.cpp	Wed Jul 12 14:51:46 2023 +0200
+++ b/ViewerPlugin/RawTile.cpp	Wed Jul 12 16:14:19 2023 +0200
@@ -39,6 +39,25 @@
 
 namespace OrthancWSI
 {
+  static ImageCompression Convert(Orthanc::MimeType type)
+  {
+    switch (type)
+    {
+      case Orthanc::MimeType_Png:
+        return ImageCompression_Png;
+
+      case Orthanc::MimeType_Jpeg:
+        return ImageCompression_Jpeg;
+
+      case Orthanc::MimeType_Jpeg2000:
+        return ImageCompression_Jpeg2000;
+
+      default:
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
   Orthanc::ImageAccessor* RawTile::DecodeInternal()
   {
     switch (compression_)
@@ -82,30 +101,11 @@
     }
   }
 
-
   void RawTile::EncodeInternal(std::string& encoded,
                                const Orthanc::ImageAccessor& decoded,
                                Orthanc::MimeType encoding)
   {
-    switch (encoding)
-    {
-      case Orthanc::MimeType_Png:
-      {
-        Orthanc::PngWriter writer;
-        Orthanc::IImageWriter::WriteToMemory(writer, encoded, decoded);
-        break;
-      }
-
-      case Orthanc::MimeType_Jpeg:
-      {
-        Orthanc::JpegWriter writer;
-        Orthanc::IImageWriter::WriteToMemory(writer, encoded, decoded);
-        break;
-      }
-
-      default:
-        throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
-    }
+    ImageToolbox::EncodeTile(encoded, decoded, Convert(encoding), 90 /* only used for JPEG */);
   }