From e60203b57dc19105241d5ceae4730cc585d04841 Mon Sep 17 00:00:00 2001 From: m-aXimilian <56168660+m-aXimilian@users.noreply.github.com> Date: Thu, 25 Sep 2025 19:25:17 +0200 Subject: [PATCH] Misc enhancements (#9) * deploy docs only for main * Revert "deploy docs only for main" This reverts commit 53e37bd8a43e7e20d5a64bed1b3e00ced551dcae. * init czi specific view * fix build --- lib/imaging/CMakeLists.txt | 2 +- lib/imaging/impl/PixelariumCzi.cpp | 32 +++++----- lib/imaging/impl/PixelariumCzi.hpp | 13 ++++ lib/rendering/CMakeLists.txt | 4 ++ lib/rendering/ImageViewFactory.cpp | 4 +- lib/rendering/PixelariumImageViewCzi.cpp | 66 ++++++++++++++++++++ lib/rendering/PixelariumImageViewCzi.hpp | 31 +++++++++ lib/rendering/PixelariumImageViewDefault.cpp | 37 ++--------- lib/rendering/RenderHelpers.cpp | 31 +++++++++ lib/rendering/RenderHelpers.hpp | 10 +++ 10 files changed, 180 insertions(+), 50 deletions(-) create mode 100644 lib/rendering/PixelariumImageViewCzi.cpp create mode 100644 lib/rendering/PixelariumImageViewCzi.hpp create mode 100644 lib/rendering/RenderHelpers.cpp create mode 100644 lib/rendering/RenderHelpers.hpp diff --git a/lib/imaging/CMakeLists.txt b/lib/imaging/CMakeLists.txt index 620719f..0757d72 100644 --- a/lib/imaging/CMakeLists.txt +++ b/lib/imaging/CMakeLists.txt @@ -29,4 +29,4 @@ target_link_libraries(${IMAGELIBLIBNAME} target_include_directories(${IMAGELIBLIBNAME} PUBLIC ${OpenCV_INCLUDE_DIRS} - PRIVATE ${LIBCZI_INCLUDE_DIR}) + PUBLIC ${LIBCZI_INCLUDE_DIR}) diff --git a/lib/imaging/impl/PixelariumCzi.cpp b/lib/imaging/impl/PixelariumCzi.cpp index 9829f03..099ae22 100644 --- a/lib/imaging/impl/PixelariumCzi.cpp +++ b/lib/imaging/impl/PixelariumCzi.cpp @@ -5,6 +5,22 @@ #include "libCZI.h" +pixelarium::imaging::PixelariumCzi::PixelariumCzi(const std::string& uri) +{ + if (!std::filesystem::exists(uri)) + { + throw std::runtime_error("Render file not found."); + } + + this->is_empty_ = false; + this->uri_ = std::filesystem::path(uri); + + auto stream = libCZI::CreateStreamFromFile(this->uri_.wstring().c_str()); + this->czi_reader_ = libCZI::CreateCZIReader(); + this->czi_reader_->Open(stream); + this->image_statistics_ = this->czi_reader_->GetStatistics(); +} + std::unique_ptr CZISubBlockToCvMat(std::shared_ptr bitmap, libCZI::PixelType pixeltype) { size_t pixel_size{0}; @@ -81,23 +97,9 @@ std::unique_ptr CZISubBlockToCvMat(std::shared_ptr return fill_mat; } -pixelarium::imaging::PixelariumCzi::PixelariumCzi(const std::string& uri) -{ - if (!std::filesystem::exists(uri)) - { - throw std::runtime_error("Render file not found."); - } - - this->is_empty_ = false; - this->uri_ = std::filesystem::path(uri); -} - std::unique_ptr pixelarium::imaging::PixelariumCzi::TryGetImage() { - auto stream = libCZI::CreateStreamFromFile(this->uri_.wstring().c_str()); - auto cziReader = libCZI::CreateCZIReader(); - cziReader->Open(stream); - auto block = cziReader->ReadSubBlock(0); + auto block = this->czi_reader_->ReadSubBlock(0); auto bitmap = block->CreateBitmap(); auto res = CZISubBlockToCvMat(bitmap, block->GetSubBlockInfo().pixelType); diff --git a/lib/imaging/impl/PixelariumCzi.hpp b/lib/imaging/impl/PixelariumCzi.hpp index 828c679..99e3b89 100644 --- a/lib/imaging/impl/PixelariumCzi.hpp +++ b/lib/imaging/impl/PixelariumCzi.hpp @@ -1,8 +1,10 @@ #pragma once +#include #include #include "../IPixelariumImage.hpp" +#include "libCZI.h" namespace pixelarium::imaging { @@ -15,6 +17,11 @@ class PixelariumCzi : public IPixelariumImage { public: explicit PixelariumCzi(const std::string& uri); + ~PixelariumCzi() + { + if (this->czi_reader_) + this->czi_reader_->Close(); + } // IPixelariumImage member implementations public: @@ -34,6 +41,8 @@ class PixelariumCzi : public IPixelariumImage bool Empty() const noexcept override { return this->is_empty_; } + const libCZI::SubBlockStatistics& GetStatistics() const { return this->image_statistics_; } + public: const static ImageFileType type_{ImageFileType::CZI}; @@ -41,5 +50,9 @@ class PixelariumCzi : public IPixelariumImage // this should be set by each image getter // after a new cv::Mat could be instantiated bool is_empty_{true}; + + libCZI::SubBlockStatistics image_statistics_; + + std::shared_ptr czi_reader_; }; } // namespace pixelarium::imaging diff --git a/lib/rendering/CMakeLists.txt b/lib/rendering/CMakeLists.txt index 8ca53c5..eb9a6b6 100644 --- a/lib/rendering/CMakeLists.txt +++ b/lib/rendering/CMakeLists.txt @@ -1,6 +1,8 @@ set(RENDERLIBNAME pixelariumrenderlib) set(RENDERLIBSRC + RenderHelpers.hpp + RenderHelpers.cpp CvMatRender.hpp CvMatRender.cpp RenderImageManager.hpp @@ -8,6 +10,8 @@ set(RENDERLIBSRC IPixelariumImageView.hpp PixelariumImageViewDefault.hpp PixelariumImageViewDefault.cpp + PixelariumImageViewCzi.hpp + PixelariumImageViewCzi.cpp ImageViewFactory.hpp ImageViewFactory.cpp) diff --git a/lib/rendering/ImageViewFactory.cpp b/lib/rendering/ImageViewFactory.cpp index acdac00..2ac5e70 100644 --- a/lib/rendering/ImageViewFactory.cpp +++ b/lib/rendering/ImageViewFactory.cpp @@ -3,6 +3,7 @@ #include #include "imaging/PixelariumImageFactory.hpp" #include "rendering/IPixelariumImageView.hpp" +#include "rendering/PixelariumImageViewCzi.hpp" #include "rendering/PixelariumImageViewDefault.hpp" /// @brief Creates a PixelariumImageView from a resource image. @@ -40,8 +41,7 @@ std::unique_ptr pixelarium::render::Im case imaging::ImageFileType::CZI: log_.Info("{}: Creating a CZI View"); // beware: here we copy the actual image resource over to the new image - return std::make_unique(img); - // return std::make_unique(img); + return std::make_unique(img); default: return {}; } diff --git a/lib/rendering/PixelariumImageViewCzi.cpp b/lib/rendering/PixelariumImageViewCzi.cpp new file mode 100644 index 0000000..815b213 --- /dev/null +++ b/lib/rendering/PixelariumImageViewCzi.cpp @@ -0,0 +1,66 @@ +#include "PixelariumImageViewCzi.hpp" + +#include + +#include "RenderHelpers.hpp" +#include "imaging/IPixelariumImage.hpp" +#include "imaging/impl/PixelariumCzi.hpp" +#include "imgui.h" + +/// @brief Displays the image in an ImGui window. +/// +/// If the image is null, empty, or has an empty name, the function returns immediately. Otherwise, it creates an ImGui +/// window with a horizontal scrollbar and menu bar. The image is rendered using the CvMatRender object, resizing it to +/// fit the available window space. The raw and rendered dimensions are displayed below the image. +void pixelarium::render::PixelariumImageViewCzi::ShowImage() +{ + auto czi_img = std::static_pointer_cast(this->img_); + + if (!czi_img) return; + + if (!this->cached_image_ || this->is_dirty_) + { + this->cached_image_ = this->img_->TryGetImage(); + this->is_dirty_ = false; + } + + if (czi_img->Empty() || this->img_->type_ == imaging::ImageFileType::UNKNOWN || !cached_image_ || + czi_img->Name().empty()) + { + // do nothing + return; + } + + ImGui::Begin(this->img_->Name().c_str(), &this->open_p, + ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_MenuBar); + + this->curr_dim_ = ImGui::GetContentRegionAvail(); + auto new_dim = ImGui::GetContentRegionAvail(); + auto texture = + dim_changed_p(this->curr_dim_, new_dim) + ? this->render_.Render(static_cast(this->curr_dim_.x), static_cast(this->curr_dim_.y)) + : this->render_.Render(); + + this->curr_dim_ = new_dim; + + ImVec2 dim(cached_image_->cols, cached_image_->rows); + + ImGui::Image(reinterpret_cast(reinterpret_cast(texture)), + aspect_const_dimensions(dim, new_dim)); + + ImGui::Separator(); + ImGui::Text("%s", std::format(" Raw Dimensions W : {}, H: {}", dim.x, dim.y).c_str()); + ImGui::Text("%s", std::format("Render Dimensions W : {}, H: {}", curr_dim_.x, curr_dim_.y).c_str()); + ImGui::Text("Dimensions"); + ImGui::Separator(); + + auto stats = czi_img->GetStatistics(); + stats.dimBounds.EnumValidDimensions( + [&](libCZI::DimensionIndex dim, int start, int size) -> bool + { + ImGui::Text("%c\t Start: %d\t End: %d", libCZI::Utils::DimensionToChar(dim), start, size); + return true; + }); + + ImGui::End(); +} diff --git a/lib/rendering/PixelariumImageViewCzi.hpp b/lib/rendering/PixelariumImageViewCzi.hpp new file mode 100644 index 0000000..2f3feca --- /dev/null +++ b/lib/rendering/PixelariumImageViewCzi.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "imgui.h" +#include "rendering/IPixelariumImageView.hpp" + +namespace pixelarium::render +{ +class PixelariumImageViewCzi : public IPixelariumImageView +{ + using Image = imaging::IPixelariumImage; + using Render = render::CvMatRender; + + public: + explicit PixelariumImageViewCzi(std::shared_ptr img) + { + img_ = img; + render_ = Render(img_); + } + PixelariumImageViewCzi() = delete; + PixelariumImageViewCzi(PixelariumImageViewCzi&) = delete; + PixelariumImageViewCzi(const PixelariumImageViewCzi&) = delete; + PixelariumImageViewCzi(PixelariumImageViewCzi&&) = delete; + PixelariumImageViewCzi& operator=(PixelariumImageViewCzi&) = delete; + PixelariumImageViewCzi& operator=(PixelariumImageViewCzi&&) = delete; + + void ShowImage() override; + + private: + ImVec2 curr_dim_{}; +}; +} // namespace pixelarium::render diff --git a/lib/rendering/PixelariumImageViewDefault.cpp b/lib/rendering/PixelariumImageViewDefault.cpp index 4f6f515..03f24dc 100644 --- a/lib/rendering/PixelariumImageViewDefault.cpp +++ b/lib/rendering/PixelariumImageViewDefault.cpp @@ -2,38 +2,9 @@ #include +#include "RenderHelpers.hpp" #include "imaging/IPixelariumImage.hpp" #include "imgui.h" - -/// @brief Checks if the dimensions of two ImVec2 vectors have changed significantly. -/// @param ref_rect The reference ImVec2 vector. -/// @param new_rect The new ImVec2 vector to compare against. -/// @return True if the absolute difference between the y-coordinates is greater than 5 or the x-coordinates are -/// different; otherwise, false. -static bool dim_changed_p(const ImVec2& ref_rect, const ImVec2& new_rect) -{ - if (std::abs(ref_rect.y - new_rect.y) > 5 || std::abs(ref_rect.x - new_rect.x)) - { - return true; - } - - return false; -} - -/// @brief Calculates dimensions to maintain aspect ratio. -/// @param img The input image. -/// @param curr_dim The current dimensions. -/// @return The calculated dimensions maintaining aspect ratio. -ImVec2 aspect_const_dimensions(const ImVec2& raw_dim, const ImVec2& curr_dim) -{ - const auto w_fact = (curr_dim.x / raw_dim.x); - const auto h_fact = (curr_dim.y / raw_dim.y); - - const auto fact = w_fact < h_fact ? w_fact : h_fact; - - return ImVec2(raw_dim.x * fact, raw_dim.y * fact); -} - /// @brief Displays the image in an ImGui window. /// /// If the image is null, empty, or has an empty name, the function returns immediately. Otherwise, it creates an ImGui @@ -47,13 +18,15 @@ void pixelarium::render::PixelariumImageViewDefault::ShowImage() this->is_dirty_ = false; } - if (this->img_->Empty() || this->img_->type_ == imaging::ImageFileType::UNKNOWN || !cached_image_ || this->img_->Name().empty()) + if (this->img_->Empty() || this->img_->type_ == imaging::ImageFileType::UNKNOWN || !cached_image_ || + this->img_->Name().empty()) { // do nothing return; } - ImGui::Begin(this->img_->Name().c_str(), &this->open_p, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_MenuBar); + ImGui::Begin(this->img_->Name().c_str(), &this->open_p, + ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_MenuBar); this->curr_dim_ = ImGui::GetContentRegionAvail(); auto new_dim = ImGui::GetContentRegionAvail(); diff --git a/lib/rendering/RenderHelpers.cpp b/lib/rendering/RenderHelpers.cpp new file mode 100644 index 0000000..a1ad36b --- /dev/null +++ b/lib/rendering/RenderHelpers.cpp @@ -0,0 +1,31 @@ +#include "RenderHelpers.hpp" + +#include +/// @brief Checks if the dimensions of two ImVec2 vectors have changed significantly. +/// @param ref_rect The reference ImVec2 vector. +/// @param new_rect The new ImVec2 vector to compare against. +/// @return True if the absolute difference between the y-coordinates is greater than 5 or the x-coordinates are +/// different; otherwise, false. +bool pixelarium::render::dim_changed_p(const ImVec2& ref_rect, const ImVec2& new_rect) +{ + if (std::abs(ref_rect.y - new_rect.y) > 5 || std::abs(ref_rect.x - new_rect.x)) + { + return true; + } + + return false; +} + +/// @brief Calculates dimensions to maintain aspect ratio. +/// @param img The input image. +/// @param curr_dim The current dimensions. +/// @return The calculated dimensions maintaining aspect ratio. +ImVec2 pixelarium::render::aspect_const_dimensions(const ImVec2& raw_dim, const ImVec2& curr_dim) +{ + const auto w_fact = (curr_dim.x / raw_dim.x); + const auto h_fact = (curr_dim.y / raw_dim.y); + + const auto fact = w_fact < h_fact ? w_fact : h_fact; + + return ImVec2(raw_dim.x * fact, raw_dim.y * fact); +} diff --git a/lib/rendering/RenderHelpers.hpp b/lib/rendering/RenderHelpers.hpp new file mode 100644 index 0000000..0633025 --- /dev/null +++ b/lib/rendering/RenderHelpers.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "imgui.h" + +namespace pixelarium::render +{ +bool dim_changed_p(const ImVec2& ref_rect, const ImVec2& new_rect); + +ImVec2 aspect_const_dimensions(const ImVec2& raw_dim, const ImVec2& curr_dim); +}; // namespace pixelarium::render