changeset 384:63936f094eaa

merge
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 07 Apr 2025 18:41:34 +0200
parents 30959cb91e89 (current diff) 50cb2a69655f (diff)
children 87701a7be3f4
files Framework/Inputs/DicomPyramidInstance.cpp Framework/Inputs/DicomPyramidLevel.cpp
diffstat 11 files changed, 127 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/CMakeLists.txt	Mon Apr 07 18:40:34 2025 +0200
+++ b/Applications/CMakeLists.txt	Mon Apr 07 18:41:34 2025 +0200
@@ -19,7 +19,7 @@
 # along with this program. If not, see <http://www.gnu.org/licenses/>.
 
 
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8...4.0)
 project(OrthancWSIApplications)
 
 include(${CMAKE_SOURCE_DIR}/../Resources/CMake/Version.cmake)
--- a/Framework/Enumerations.h	Mon Apr 07 18:40:34 2025 +0200
+++ b/Framework/Enumerations.h	Mon Apr 07 18:41:34 2025 +0200
@@ -42,7 +42,8 @@
     ImageCompression_Png = 4,
     ImageCompression_Jpeg = 5,
     ImageCompression_Jpeg2000 = 6,
-    ImageCompression_Tiff = 7
+    ImageCompression_Tiff = 7,
+    ImageCompression_UseOrthancPreview = 8
   };
 
   enum OpticalPath
--- a/Framework/ImageToolbox.cpp	Mon Apr 07 18:40:34 2025 +0200
+++ b/Framework/ImageToolbox.cpp	Mon Apr 07 18:41:34 2025 +0200
@@ -356,5 +356,54 @@
           throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
       }
     }
+
+
+    bool HasPngSignature(const std::string& buffer)
+    {
+      if (buffer.size() < 8)
+      {
+        return false;
+      }
+      else
+      {
+        // https://en.wikipedia.org/wiki/PNG#File_header
+        // https://en.wikipedia.org/wiki/List_of_file_signatures
+        const uint8_t* p = reinterpret_cast<const uint8_t*>(buffer.data());
+        return (p[0] == 0x89 &&
+                p[1] == 0x50 &&
+                p[2] == 0x4e &&
+                p[3] == 0x47 &&
+                p[4] == 0x0d &&
+                p[5] == 0x0a &&
+                p[6] == 0x1a &&
+                p[7] == 0x0a);
+      }
+    }
+
+
+    bool HasJpegSignature(const std::string& buffer)
+    {
+      if (buffer.size() < 18)
+      {
+        return false;
+      }
+      else
+      {
+        // https://en.wikipedia.org/wiki/List_of_file_signatures
+        const uint8_t* p = reinterpret_cast<const uint8_t*>(buffer.data());
+        if (p[0] != 0xff ||
+            p[1] != 0xd8 ||
+            p[2] != 0xff)
+        {
+          return false;
+        }
+
+        // This is only a rough guess!
+        return (p[3] == 0xdb ||
+                p[3] == 0xe0 ||
+                p[3] == 0xee ||
+                p[3] == 0xe1);
+      }
+    }
   }
 }
--- a/Framework/ImageToolbox.h	Mon Apr 07 18:40:34 2025 +0200
+++ b/Framework/ImageToolbox.h	Mon Apr 07 18:41:34 2025 +0200
@@ -77,5 +77,9 @@
     void ConvertJpegYCbCrToRgb(Orthanc::ImageAccessor& image /* inplace */);
 
     ImageCompression Convert(Orthanc::MimeType type);
+
+    bool HasPngSignature(const std::string& buffer);
+
+    bool HasJpegSignature(const std::string& buffer);
   }
 }
--- a/Framework/Inputs/DicomPyramidInstance.cpp	Mon Apr 07 18:40:34 2025 +0200
+++ b/Framework/Inputs/DicomPyramidInstance.cpp	Mon Apr 07 18:41:34 2025 +0200
@@ -82,6 +82,10 @@
     {
       return ImageCompression_Jpeg2000;
     }
+    else if (s == "1.2.840.10008.1.2.4.80")
+    {
+      return ImageCompression_UseOrthancPreview;
+    }
     else
     {
       LOG(ERROR) << "Unsupported transfer syntax: " << s;
--- a/Framework/Inputs/DicomPyramidLevel.cpp	Mon Apr 07 18:40:34 2025 +0200
+++ b/Framework/Inputs/DicomPyramidLevel.cpp	Mon Apr 07 18:41:34 2025 +0200
@@ -132,15 +132,39 @@
       assert(tile.instance_ != NULL);
       DicomPyramidInstance& instance = *tile.instance_;
 
-      std::string uri = ("/instances/" + instance.GetInstanceId() + 
-                         "/frames/" + boost::lexical_cast<std::string>(tile.frame_) + "/raw");
-
-      orthanc.RestApiGet(raw, uri);
-
       compression = instance.GetImageCompression(orthanc);
       format = instance.GetPixelFormat();
 
-      return true;
+      if (compression == ImageCompression_UseOrthancPreview)
+      {
+        // If the WSI viewer plugin has no built-in support for this transfer syntax,
+        // use the decoding primitives offered by the Orthanc core
+        std::string uri = ("/instances/" + instance.GetInstanceId() +
+                           "/frames/" + boost::lexical_cast<std::string>(tile.frame_) + "/preview");
+        orthanc.RestApiGet(raw, uri);
+
+        if (ImageToolbox::HasPngSignature(raw))  // In theory, Orthanc should always generate PNG by default
+        {
+          compression = ImageCompression_Png;
+          return true;
+        }
+        else if (ImageToolbox::HasJpegSignature(raw))
+        {
+          compression = ImageCompression_Jpeg;
+          return true;
+        }
+        else
+        {
+          throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Cannot decode a preview image generated by the Orthanc core");
+        }
+      }
+      else
+      {
+        std::string uri = ("/instances/" + instance.GetInstanceId() +
+                           "/frames/" + boost::lexical_cast<std::string>(tile.frame_) + "/raw");
+        orthanc.RestApiGet(raw, uri);
+        return true;
+      }
     }
     else
     {
--- a/NEWS	Mon Apr 07 18:40:34 2025 +0200
+++ b/NEWS	Mon Apr 07 18:41:34 2025 +0200
@@ -3,6 +3,7 @@
 
 * Support windowing when rendering grayscale images using on-the-fly deep zoom
 * Added tolerance to imaged volume width/height by looking only at the finest level
+* Added support for JPEG-LS transfer syntax in the Web viewer plugin
 
 
 Version 3.1 (2025-03-17)
--- a/Resources/Orthanc/CMake/Compiler.cmake	Mon Apr 07 18:40:34 2025 +0200
+++ b/Resources/Orthanc/CMake/Compiler.cmake	Mon Apr 07 18:41:34 2025 +0200
@@ -22,6 +22,16 @@
 
 # This file sets all the compiler-related flags
 
+if (${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
+  # Since Orthanc 1.12.7 that allows CMake 4.0, builds for macOS
+  # require the C++ standard to be explicitly set to C++11. Do *not*
+  # do this on GNU/Linux, as third-party system libraries could have
+  # been compiled with higher versions of the C++ standard.
+  set(CMAKE_CXX_STANDARD 11)
+  set(CMAKE_CXX_STANDARD_REQUIRED ON)
+  set(CMAKE_CXX_EXTENSIONS OFF)
+endif()
+
 
 # Save the current compiler flags to the cache every time cmake configures the project
 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "compiler flags" FORCE)
--- a/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake	Mon Apr 07 18:40:34 2025 +0200
+++ b/Resources/Orthanc/CMake/DownloadOrthancFramework.cmake	Mon Apr 07 18:41:34 2025 +0200
@@ -169,6 +169,8 @@
         set(ORTHANC_FRAMEWORK_MD5 "5bb69f092981fdcfc11dec0a0f9a7db3")
       elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.6")
         set(ORTHANC_FRAMEWORK_MD5 "0e971f32f4f3e4951e0f3b5de49a3da6")
+      elseif (ORTHANC_FRAMEWORK_VERSION STREQUAL "1.12.7")
+        set(ORTHANC_FRAMEWORK_MD5 "f27c27d7a7a694dab1fd7f0a99d9715a")
 
       # Below this point are development snapshots that were used to
       # release some plugin, before an official release of the Orthanc
@@ -501,7 +503,15 @@
   
   include(CheckIncludeFile)
   include(CheckIncludeFileCXX)
-  include(FindPythonInterp)
+  
+  if(CMAKE_VERSION VERSION_GREATER "3.11")
+    find_package(Python REQUIRED COMPONENTS Interpreter)
+    set(PYTHON_EXECUTABLE ${Python_EXECUTABLE})
+  else()
+    include(FindPythonInterp)
+    find_package(PythonInterp REQUIRED)
+  endif()
+  
   include(${CMAKE_CURRENT_LIST_DIR}/Compiler.cmake)
   include(${CMAKE_CURRENT_LIST_DIR}/DownloadPackage.cmake)
   include(${CMAKE_CURRENT_LIST_DIR}/AutoGeneratedCode.cmake)
--- a/ViewerPlugin/CMakeLists.txt	Mon Apr 07 18:40:34 2025 +0200
+++ b/ViewerPlugin/CMakeLists.txt	Mon Apr 07 18:41:34 2025 +0200
@@ -19,7 +19,7 @@
 # along with this program. If not, see <http://www.gnu.org/licenses/>.
 
 
-cmake_minimum_required(VERSION 2.8)
+cmake_minimum_required(VERSION 2.8...4.0)
 project(OrthancWSIPlugin)
 
 include(${CMAKE_SOURCE_DIR}/../Resources/CMake/Version.cmake)
--- a/ViewerPlugin/RawTile.cpp	Mon Apr 07 18:40:34 2025 +0200
+++ b/ViewerPlugin/RawTile.cpp	Mon Apr 07 18:41:34 2025 +0200
@@ -31,6 +31,7 @@
 #include <Compatibility.h>  // For std::unique_ptr
 #include <Images/ImageProcessing.h>
 #include <Images/JpegReader.h>
+#include <Images/PngReader.h>
 #include <Images/PngWriter.h>
 #include <MultiThreading/Semaphore.h>
 #include <OrthancException.h>
@@ -78,6 +79,19 @@
         return decoded.release();
       }
 
+      case ImageCompression_Png:
+      {
+        /**
+         * This is used if the DICOM instance has a transfer syntax
+         * that is not natively supported by the WSI viewer plugin, in
+         * which case the tile comes from the "/preview" route of the
+         * REST API of Orthanc.
+         **/
+        std::unique_ptr<Orthanc::PngReader> decoded(new Orthanc::PngReader);
+        decoded->ReadFromMemory(tile_);
+        return decoded.release();
+      }
+
       default:
         throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
     }