changeset 355:a307ec25a008

padding for on-the-fly pyramids
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 20 Dec 2024 13:48:34 +0100
parents 5d3672320879
children 03d33290cba1
files ViewerPlugin/OrthancPyramidFrameFetcher.cpp ViewerPlugin/OrthancPyramidFrameFetcher.h ViewerPlugin/Plugin.cpp
diffstat 3 files changed, 137 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/ViewerPlugin/OrthancPyramidFrameFetcher.cpp	Fri Dec 20 12:40:54 2024 +0100
+++ b/ViewerPlugin/OrthancPyramidFrameFetcher.cpp	Fri Dec 20 13:48:34 2024 +0100
@@ -63,7 +63,14 @@
   OrthancPyramidFrameFetcher::OrthancPyramidFrameFetcher(OrthancStone::IOrthancConnection* orthanc,
                                                          bool smooth) :
     orthanc_(orthanc),
-    smooth_(smooth)
+    smooth_(smooth),
+    tileWidth_(512),
+    tileHeight_(512),
+    paddingX_(0),
+    paddingY_(0),
+    backgroundRed_(0),
+    backgroundGreen_(0),
+    backgroundBlue_(0)
   {
     if (orthanc == NULL)
     {
@@ -72,6 +79,42 @@
   }
 
 
+  void OrthancPyramidFrameFetcher::SetTileWidth(unsigned int tileWidth)
+  {
+    if (tileWidth <= 2)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+    else
+    {
+      tileWidth_ = tileWidth;
+    }
+  }
+
+
+  void OrthancPyramidFrameFetcher::SetTileHeight(unsigned int tileHeight)
+  {
+    if (tileHeight <= 2)
+    {
+      throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
+    }
+    else
+    {
+      tileHeight_ = tileHeight;
+    }
+  }
+
+
+  void OrthancPyramidFrameFetcher::SetBackgroundColor(uint8_t red,
+                                                      uint8_t green,
+                                                      uint8_t blue)
+  {
+    backgroundRed_ = red;
+    backgroundGreen_ = green;
+    backgroundBlue_ = blue;
+  }
+
+
   DecodedTiledPyramid* OrthancPyramidFrameFetcher::Fetch(const std::string &instanceId,
                                                          unsigned frameNumber)
   {
@@ -104,26 +147,55 @@
     Orthanc::ImageAccessor source;
     source.AssignReadOnly(format, frame->GetWidth(), frame->GetHeight(), frame->GetPitch(), frame->GetBuffer());
 
-    std::unique_ptr<Orthanc::ImageAccessor> rendered(new Orthanc::Image(Orthanc::PixelFormat_RGB24, source.GetWidth(), source.GetHeight(), false));
+    unsigned int paddedWidth, paddedHeight;
+
+    if (paddingX_ >= 2)
+    {
+      paddedWidth = OrthancWSI::CeilingDivision(source.GetWidth(), paddingX_) * paddingX_;
+    }
+    else
+    {
+      paddedWidth = source.GetWidth();
+    }
+
+    if (paddingY_ >= 2)
+    {
+      paddedHeight = OrthancWSI::CeilingDivision(source.GetHeight(), paddingY_) * paddingY_;
+    }
+    else
+    {
+      paddedHeight = source.GetHeight();
+    }
+
+    std::unique_ptr<Orthanc::ImageAccessor> rendered(new Orthanc::Image(Orthanc::PixelFormat_RGB24, paddedWidth, paddedHeight, false));
+
+    if (paddedWidth != source.GetWidth() ||
+        paddedHeight != source.GetHeight())
+    {
+      Orthanc::ImageProcessing::Set(*rendered, backgroundRed_, backgroundGreen_, backgroundBlue_, 255 /* alpha */);
+    }
+
+    Orthanc::ImageAccessor region;
+    rendered->GetRegion(region, 0, 0, source.GetWidth(), source.GetHeight());
 
     switch (format)
     {
     case Orthanc::PixelFormat_RGB24:
-      Orthanc::ImageProcessing::Copy(*rendered, source);
+      Orthanc::ImageProcessing::Copy(region, source);
       break;
 
     case Orthanc::PixelFormat_Grayscale8:
-      Orthanc::ImageProcessing::Convert(*rendered, source);
+      Orthanc::ImageProcessing::Convert(region, source);
       break;
 
     case Orthanc::PixelFormat_Grayscale16:
-      RenderGrayscale(*rendered, source);
+      RenderGrayscale(region, source);
       break;
 
     default:
       throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
     }
 
-    return new OnTheFlyPyramid(rendered.release(), 512, 512, smooth_);
+    return new OnTheFlyPyramid(rendered.release(), tileWidth_, tileHeight_, smooth_);
   }
 }
--- a/ViewerPlugin/OrthancPyramidFrameFetcher.h	Fri Dec 20 12:40:54 2024 +0100
+++ b/ViewerPlugin/OrthancPyramidFrameFetcher.h	Fri Dec 20 13:48:34 2024 +0100
@@ -34,6 +34,13 @@
   private:
     std::unique_ptr<OrthancStone::IOrthancConnection>  orthanc_;
     bool                                               smooth_;
+    unsigned int                                       tileWidth_;
+    unsigned int                                       tileHeight_;
+    unsigned int                                       paddingX_;
+    unsigned int                                       paddingY_;
+    uint8_t                                            backgroundRed_;
+    uint8_t                                            backgroundGreen_;
+    uint8_t                                            backgroundBlue_;
 
     static void RenderGrayscale(Orthanc::ImageAccessor& target,
                                 const Orthanc::ImageAccessor& source);
@@ -42,6 +49,46 @@
     OrthancPyramidFrameFetcher(OrthancStone::IOrthancConnection* orthanc,
                                bool smooth);
 
+    unsigned int GetTileWidth() const
+    {
+      return tileWidth_;
+    }
+
+    void SetTileWidth(unsigned int tileWidth);
+
+    unsigned int GetTileHeight() const
+    {
+      return tileHeight_;
+    }
+
+    void SetTileHeight(unsigned int tileHeight);
+
+    unsigned int GetPaddingX() const
+    {
+      return paddingX_;
+    }
+
+    // "0" or "1" implies no padding
+    void SetPaddingX(unsigned int paddingX)
+    {
+      paddingX_ = paddingX;
+    }
+
+    unsigned int GetPaddingY() const
+    {
+      return paddingY_;
+    }
+
+    // "0" or "1" implies no padding
+    void SetPaddingY(unsigned int paddingY)
+    {
+      paddingY_ = paddingY;
+    }
+
+    void SetBackgroundColor(uint8_t red,
+                            uint8_t green,
+                            uint8_t blue);
+
     DecodedTiledPyramid* Fetch(const std::string &instanceId,
                                unsigned frameNumber) ORTHANC_OVERRIDE;
   };
--- a/ViewerPlugin/Plugin.cpp	Fri Dec 20 12:40:54 2024 +0100
+++ b/ViewerPlugin/Plugin.cpp	Fri Dec 20 13:48:34 2024 +0100
@@ -450,10 +450,18 @@
     OrthancPlugins::SetDescription(ORTHANC_PLUGIN_NAME, "Provides a Web viewer of whole-slide microscopic images within Orthanc.");
 
     OrthancWSI::DicomPyramidCache::InitializeInstance(10 /* Number of pyramids to be cached - TODO parameter */);
-    OrthancWSI::DecodedPyramidCache::InitializeInstance(
-      new OrthancWSI::OrthancPyramidFrameFetcher(new OrthancWSI::OrthancPluginConnection(), false /* TODO PARAMETER */),
-      10 /* TODO - PARAMETER */,
-      256 * 1024 * 1024 /* TODO - PARAMETER */);
+
+    {
+      std::unique_ptr<OrthancWSI::OrthancPyramidFrameFetcher> fetcher(
+        new OrthancWSI::OrthancPyramidFrameFetcher(new OrthancWSI::OrthancPluginConnection(), false /* TODO PARAMETER */));
+      fetcher->SetPaddingX(64);  // TODO PARAMETER
+      fetcher->SetPaddingY(64);  // TODO PARAMETER
+      fetcher->SetBackgroundColor(255, 255, 255);  // TODO PARAMETER
+
+      OrthancWSI::DecodedPyramidCache::InitializeInstance(fetcher.release(),
+                                                          10 /* TODO - PARAMETER */,
+                                                          256 * 1024 * 1024 /* TODO - PARAMETER */);
+    }
 
     OrthancPluginRegisterOnChangeCallback(OrthancPlugins::GetGlobalContext(), OnChangeCallback);