changeset 280:34b507959e32 iiif

integration mainline->iiif
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 12 Jul 2023 18:08:27 +0200
parents ac1508b438b1 (current diff) 77afef2cf64b (diff)
children ea08ace91b81
files Applications/Dicomizer.cpp NEWS
diffstat 8 files changed, 161 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Dicomizer.cpp	Wed Jul 12 16:14:19 2023 +0200
+++ b/Applications/Dicomizer.cpp	Wed Jul 12 18:08:27 2023 +0200
@@ -643,10 +643,10 @@
 
   boost::program_options::options_description volumeOptions("Description of the imaged volume");
   volumeOptions.add_options()
-    (OPTION_IMAGED_WIDTH, boost::program_options::value<float>()->default_value(15),
-     "Width of the specimen (in mm)")
-    (OPTION_IMAGED_HEIGHT, boost::program_options::value<float>()->default_value(15),
-     "Height of the specimen (in mm)")
+    (OPTION_IMAGED_WIDTH, boost::program_options::value<float>(),
+     "Width of the specimen (in mm), defaults to 15mm if missing")
+    (OPTION_IMAGED_HEIGHT, boost::program_options::value<float>(),
+     "Height of the specimen (in mm), defaults to 15mm if missing")
     (OPTION_IMAGED_DEPTH, boost::program_options::value<float>()->default_value(1),
      "Depth of the specimen (in mm)")
     (OPTION_OFFSET_X, boost::program_options::value<float>()->default_value(20), 
@@ -1010,6 +1010,7 @@
 
 
 OrthancWSI::ITiledPyramid* OpenInputPyramid(OrthancWSI::ImageCompression& sourceCompression,
+                                            OrthancWSI::ImagedVolumeParameters& volume,
                                             const std::string& path,
                                             const OrthancWSI::DicomizerParameters& parameters)
 {
@@ -1072,9 +1073,26 @@
   {
     LOG(WARNING) << "Trying to open the input pyramid with OpenSlide";
     sourceCompression = OrthancWSI::ImageCompression_Unknown;
-    return new OrthancWSI::OpenSlidePyramid(path, 
-                                            parameters.GetTargetTileWidth(512), 
-                                            parameters.GetTargetTileHeight(512));
+
+    std::unique_ptr<OrthancWSI::OpenSlidePyramid> openslide(
+      new OrthancWSI::OpenSlidePyramid(path, parameters.GetTargetTileWidth(512),
+                                       parameters.GetTargetTileHeight(512)));
+
+    float volumeWidth, volumeHeight;
+    if (openslide->LookupImagedVolumeSize(volumeWidth, volumeHeight))
+    {
+      if (!volume.HasWidth())
+      {
+        volume.SetWidth(volumeWidth);
+      }
+
+      if (!volume.HasHeight())
+      {
+        volume.SetHeight(volumeHeight);
+      }
+    }
+
+    return openslide.release();
   }
   catch (Orthanc::OrthancException&)
   {
@@ -1101,7 +1119,7 @@
       OrthancWSI::ImageCompression sourceCompression;
       std::unique_ptr<OrthancWSI::ITiledPyramid> source;
 
-      source.reset(OpenInputPyramid(sourceCompression, parameters.GetInputFile(), parameters));
+      source.reset(OpenInputPyramid(sourceCompression, volume, parameters.GetInputFile(), parameters));
       if (source.get() == NULL)
       {
         throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
--- a/Framework/ImagedVolumeParameters.cpp	Wed Jul 12 16:14:19 2023 +0200
+++ b/Framework/ImagedVolumeParameters.cpp	Wed Jul 12 18:08:27 2023 +0200
@@ -27,25 +27,54 @@
 
 namespace OrthancWSI
 {
-  ImagedVolumeParameters::ImagedVolumeParameters()
+  ImagedVolumeParameters::ImagedVolumeParameters() :
+    hasWidth_(false),
+    hasHeight_(false)
   {
-    // Typical parameters of a specimen millimeters
-    width_ = 15;
-    height_ = 15;
+    // Typical parameters for a specimen, in millimeters
     depth_ = 1;
     offsetX_ = 20;
     offsetY_ = 40;
   }
 
 
+  float ImagedVolumeParameters::GetWidth() const
+  {
+    if (hasWidth_)
+    {
+      return width_;
+    }
+    else
+    {
+      return 15;  // Typical width of a specimen
+    }
+  }
+
+
+  float ImagedVolumeParameters::GetHeight() const
+  {
+    if (hasHeight_)
+    {
+      return height_;
+    }
+    else
+    {
+      return 15;  // Typical height of a specimen
+    }
+  }
+
+
   void ImagedVolumeParameters::SetWidth(float width)
   {
     if (width <= 0)
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
-
-    width_ = width;
+    else
+    {
+      width_ = width;
+      hasWidth_ = true;
+    }
   }
     
 
@@ -55,8 +84,11 @@
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
-
-    height_ = height;
+    else
+    {
+      height_ = height;
+      hasHeight_ = true;
+    }
   }
 
     
--- a/Framework/ImagedVolumeParameters.h	Wed Jul 12 16:14:19 2023 +0200
+++ b/Framework/ImagedVolumeParameters.h	Wed Jul 12 18:08:27 2023 +0200
@@ -27,6 +27,8 @@
   class ImagedVolumeParameters
   {
   private:
+    bool   hasWidth_;
+    bool   hasHeight_;
     float  width_;
     float  height_;
     float  depth_;
@@ -36,15 +38,19 @@
   public:
     ImagedVolumeParameters();
 
-    float GetWidth() const
+    bool HasWidth() const
     {
-      return width_;
+      return hasWidth_;
+    }
+
+    bool HasHeight() const
+    {
+      return hasHeight_;
     }
     
-    float GetHeight() const
-    {
-      return height_;
-    }
+    float GetWidth() const;
+
+    float GetHeight() const;
     
     float GetDepth() const
     {
--- a/Framework/Inputs/OpenSlideLibrary.cpp	Wed Jul 12 16:14:19 2023 +0200
+++ b/Framework/Inputs/OpenSlideLibrary.cpp	Wed Jul 12 18:08:27 2023 +0200
@@ -44,6 +44,8 @@
     getLevelDownsample_ = (FunctionGetLevelDownsample) library_.GetFunction("openslide_get_level_downsample");
     open_ = (FunctionOpen) library_.GetFunction("openslide_open");
     readRegion_ = (FunctionReadRegion) library_.GetFunction("openslide_read_region");
+    getPropertyNames_ = (FunctionGetPropertyNames) library_.GetFunction("openslide_get_property_names");
+    getPropertyValue_ = (FunctionGetPropertyValue) library_.GetFunction("openslide_get_property_value");
   }
 
 
@@ -144,6 +146,27 @@
     handle_(NULL)
   {
     Initialize(path);
+
+    const char* const* properties = that_.getPropertyNames_(handle_);
+    if (properties == NULL)
+    {
+      that_.close_(handle_);
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+    }
+
+    for (size_t i = 0; properties[i] != NULL; i++)
+    {
+      const char* value = that_.getPropertyValue_(handle_, properties[i]);
+      if (value == NULL)
+      {
+        that_.close_(handle_);
+        throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
+      }
+      else
+      {
+        properties_[properties[i]] = value;
+      }
+    }
   }
 
 
@@ -237,4 +260,21 @@
   {
     globalLibrary_.reset(NULL);
   }
+
+
+  bool OpenSlideLibrary::Image::LookupProperty(std::string& value,
+                                               const std::string& property) const
+  {
+    std::map<std::string, std::string>::const_iterator found = properties_.find(property);
+
+    if (found == properties_.end())
+    {
+      return false;
+    }
+    else
+    {
+      value = found->second;
+      return true;
+    }
+  }
 }
--- a/Framework/Inputs/OpenSlideLibrary.h	Wed Jul 12 16:14:19 2023 +0200
+++ b/Framework/Inputs/OpenSlideLibrary.h	Wed Jul 12 18:08:27 2023 +0200
@@ -25,6 +25,7 @@
 #include <Images/ImageAccessor.h>
 #include <SharedLibrary.h>
 
+#include <map>
 #include <vector>
 
 namespace OrthancWSI
@@ -39,6 +40,10 @@
     typedef void*   (*FunctionOpen) (const char*);
     typedef void    (*FunctionReadRegion) (void*, uint32_t*, int64_t, int64_t, int32_t, int64_t, int64_t);
 
+    // New in WSI 2.0
+    typedef const char* const* (*FunctionGetPropertyNames) (void*);
+    typedef const char*        (*FunctionGetPropertyValue) (void*, const char*);
+
     Orthanc::SharedLibrary      library_;
     FunctionClose               close_;
     FunctionGetLevelCount       getLevelCount_;
@@ -46,6 +51,8 @@
     FunctionGetLevelDownsample  getLevelDownsample_;
     FunctionOpen                open_;
     FunctionReadRegion          readRegion_;
+    FunctionGetPropertyNames    getPropertyNames_;
+    FunctionGetPropertyValue    getPropertyValue_;
 
   public:
     explicit OpenSlideLibrary(const std::string& path);
@@ -72,9 +79,10 @@
               double downsample);
       };
 
-      OpenSlideLibrary&   that_;
-      void*               handle_;
-      std::vector<Level>  levels_;
+      OpenSlideLibrary&                   that_;
+      void*                               handle_;
+      std::vector<Level>                  levels_;
+      std::map<std::string, std::string>  properties_;
 
       void Initialize(const std::string& path);
 
@@ -109,6 +117,9 @@
                                          uint64_t y,
                                          unsigned int width,
                                          unsigned int height);
+
+      bool LookupProperty(std::string& value,
+                          const std::string& property) const;
     };
   };
 }
--- a/Framework/Inputs/OpenSlidePyramid.cpp	Wed Jul 12 16:14:19 2023 +0200
+++ b/Framework/Inputs/OpenSlidePyramid.cpp	Wed Jul 12 18:08:27 2023 +0200
@@ -26,6 +26,7 @@
 #include <Compatibility.h>  // For std::unique_ptr
 #include <Images/ImageProcessing.h>
 #include <OrthancException.h>
+#include <SerializationToolbox.h>
 #include <Logging.h>
 
 #include <memory>
@@ -50,4 +51,28 @@
     tileHeight_(tileHeight)
   {
   }
+
+
+  bool OpenSlidePyramid::LookupImagedVolumeSize(float& width,
+                                                float& height) const
+  {
+    std::string s;
+    double mppx;
+    double mppy;
+
+    if (image_.LookupProperty(s, "openslide.mpp-x") &&
+        Orthanc::SerializationToolbox::ParseDouble(mppx, s) &&
+        image_.LookupProperty(s, "openslide.mpp-y") &&
+        Orthanc::SerializationToolbox::ParseDouble(mppy, s))
+    {
+      // In the 2 lines below, remember to switch X/Y when going from physical to pixel coordinates!
+      width = mppy / 1000.0 * static_cast<double>(image_.GetLevelHeight(0));
+      height = mppx / 1000.0 * static_cast<double>(image_.GetLevelWidth(0));
+      return true;
+    }
+    else
+    {
+      return false;
+    }
+  }
 }
--- a/Framework/Inputs/OpenSlidePyramid.h	Wed Jul 12 16:14:19 2023 +0200
+++ b/Framework/Inputs/OpenSlidePyramid.h	Wed Jul 12 18:08:27 2023 +0200
@@ -79,5 +79,8 @@
     {
       return Orthanc::PhotometricInterpretation_RGB;
     }
+
+    bool LookupImagedVolumeSize(float& width,
+                                float& height) const;
   };
 }
--- a/NEWS	Wed Jul 12 16:14:19 2023 +0200
+++ b/NEWS	Wed Jul 12 18:08:27 2023 +0200
@@ -2,6 +2,7 @@
 ===============================
 
 * Support of IIIF
+* Automated extraction of the imaged volume if using OpenSlide
 * URI "/wsi/tiles/{id}/{z}/{x}/{y}" supports the "Accept" HTTP header
   to force JPEG, JPEG2k or PNG in the decoded tiles