* get image returns optional<Mat> instead of unique_ptr<Mat>

* introduce complexity

* rename image load function

* add example for a basic reader for binary image files

* fix windows build?

* add a status bar underneath the menu bar

* use status bar in custom_0 example app

* clang formats

* packing w/ pragma push

* add "Save As" functions to image views

* resize over reserve

* rm local override uri

* add simple thread pool

* rename to simple_thread_pool

* get rid of useless renderlib

* document version inc

* extract hardcoded values to in-header

* clang format patch

* clone registered image in custom_0

* document binary-file header

* minor fixes

* clang format

* rm unused render cmake
This commit is contained in:
m-aXimilian
2026-01-23 23:00:35 +00:00
committed by Maximilian Kueffner
parent e3e161ce52
commit b37814204f
52 changed files with 712 additions and 207 deletions
-1
View File
@@ -7,7 +7,6 @@ add_executable(${CUSTOM_0_NAME} ${SRC})
target_link_libraries(${CUSTOM_0_NAME}
PRIVATE pixelariumimagelib
PRIVATE pixelariumrenderlib
PRIVATE pixelariumutilslib
PRIVATE pixelariumresourcelib
PRIVATE pixelariumapplicationlib)
+169 -3
View File
@@ -1,7 +1,16 @@
#include <opencv2/core/hal/interface.h>
#include <cstdint>
#include <filesystem>
#include <format>
#include <fstream>
#include <memory>
#include <string>
#include "DefaultApp.hpp"
#include "imgui.h"
#include "impl/PixelariumMem.hpp"
#include "portable-file-dialogs.h"
#include "resources/resource.hpp"
#include "utilities/ILog.hpp"
#include "utilities/SpdLogger.hpp"
@@ -20,9 +29,165 @@ unique_ptr<Log> logger{
make_unique<utils::log::SpdLogger>(string(getenv("HOME")) + "/.cache/pixelarium/simple_app.log", "default")};
#endif
// instantiate an image pool for the application
resources::ImageResourcePool image_pool;
constexpr auto ToCVPixelType(size_t depth, size_t chans) -> int
{
int tp{};
switch (depth)
{
case 8:
tp = CV_8U;
break;
case 16:
tp = CV_16U;
break;
default:
return -1;
}
if (chans > 1)
{
return CV_MAKETYPE(tp, chans);
}
return tp;
}
struct StatusReport
{
const std::function<void(const std::string&)> report_status;
const std::function<void()> reset_status;
};
class BinaryReader
{
private:
filesystem::path bin_file{};
vector<std::byte> buffer{};
uintmax_t file_size;
// struct __attribute__((packed)) ParsedImage // gcc and clang only
#pragma pack(push, 1)
struct ParsedImage
{
uint8_t depth;
uint8_t channels;
uint16_t width;
uint16_t height;
void* data;
};
#pragma pack(pop)
auto RegisterImage(const ParsedImage& img, string& name, const StatusReport& report) -> void
{
if (img.width == 0 || img.height == 0 || img.channels == 0 || img.depth == 0 || !img.data)
{
report.reset_status();
report.report_status(
format("Parsing {} failed: Dimensions (w: {}, h: {}, d: {}, c: {}) cannot be parsed! The provided "
"bin-file is probably corrupted.",
name, img.width, img.height, img.depth, img.channels));
return;
}
auto tmp_mat =
cv::Mat(img.height, img.width, ToCVPixelType(img.depth, img.channels), const_cast<void*>(img.data));
// not cloning is a dangling reference once the externally managed data pointer is freed
auto mat{tmp_mat.clone()};
image_pool.SetResource(make_unique<imaging::PixelariumMem>(mat, name.c_str(), *logger));
}
auto ReadFile(const filesystem::path& file, const StatusReport& report) -> ParsedImage
{
uint8_t depth{};
uint8_t channels{};
uint16_t width{};
uint16_t height{};
uint64_t pixel_count{};
if (!filesystem::exists(file)) return {};
auto sz = filesystem::file_size(file);
// header layout of binary file
// | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
// | ^ | ^ | ^ | ^ | pixel count in byte |
// | |______ |__ |
// pixel depth | | height in px
// | width in px
// channel count
constexpr auto header_size{14};
bool can_read = sz >= header_size;
if (!can_read) return {};
if (!buffer.empty())
{
buffer.clear();
}
// buffer = static_cast<char*>(malloc(sz));
ifstream inp_stream(file, ios::binary);
if (inp_stream)
{
inp_stream.read(reinterpret_cast<char*>(&width), sizeof(width));
inp_stream.read(reinterpret_cast<char*>(&height), sizeof(height));
inp_stream.read(reinterpret_cast<char*>(&depth), sizeof(depth));
inp_stream.read(reinterpret_cast<char*>(&channels), sizeof(channels));
inp_stream.read(reinterpret_cast<char*>(&pixel_count), sizeof(pixel_count));
logger->Info(format("{}(): Pixel count {}", __FUNCTION__, pixel_count));
if (pixel_count <= sz - header_size)
{
buffer.resize(pixel_count);
inp_stream.read(reinterpret_cast<char*>(buffer.data()), pixel_count);
}
}
logger->Info(format("{}: Parsed image with width: {}, height: {}, depth: {}, channels: {}", __PRETTY_FUNCTION__,
width, height, depth, channels));
report.report_status(
format("Parsed image with width: {}, height: {}, depth: {}, channels: {}", width, height, depth, channels));
return {.depth = depth, .channels = channels, .width = width, .height = height, .data = buffer.data()};
}
public:
auto Present(const StatusReport& report) -> void
{
using namespace ImGui;
SetNextWindowSize({256, 124});
Begin("Load Binary File");
if (Button("Load File"))
{
auto res{pfd::open_file("Load Inputs", pfd::path::home(), {"Bin Files", "*.bin"}).result()};
if (!res.empty()) bin_file = filesystem::path(res.at(0));
}
if (filesystem::exists(bin_file))
{
file_size = filesystem::file_size(bin_file);
Text("File: %s (%lu)", bin_file.filename().c_str(), file_size);
if (Button("Parse File"))
{
auto buff = ReadFile(bin_file, report);
auto name = bin_file.filename().string();
RegisterImage(buff, name, report);
}
}
End();
}
};
// create a custom app inheriting from the library's default app
class MyApp : public application::DefaultApp
{
private:
BinaryReader bin_read;
public:
MyApp(const Log& log, Pool& pool) : application::DefaultApp(log, pool) {}
@@ -37,9 +202,6 @@ int main()
// some initial log message
logger->Info(std::format("{}: Starting Application {}", __FUNCTION__, "Pixelarium"));
// instantiate an image pool for the application
resources::ImageResourcePool image_pool;
// create a custom application, inject its dependencies and start it
auto app{MyApp(*logger, image_pool)};
@@ -50,4 +212,8 @@ void MyApp::Run()
{
this->gallery_.RenderGallery();
this->gallery_.RenderImages();
const auto reporter =
StatusReport{.report_status = [this](const std::string& msg) { this->SetStatusTimed(msg, 5); },
.reset_status = [this]() { this->ResetStatus(); }};
bin_read.Present(reporter);
}
-1
View File
@@ -7,7 +7,6 @@ add_executable(${CUSTOM_1_NAME} ${SRC})
target_link_libraries(${CUSTOM_1_NAME}
PRIVATE pixelariumimagelib
PRIVATE pixelariumrenderlib
PRIVATE pixelariumutilslib
PRIVATE pixelariumresourcelib
PRIVATE pixelariumapplicationlib)
+5 -4
View File
@@ -52,7 +52,7 @@ class Selector
if (ImGui::BeginCombo("Select first image", preview_0_.c_str()))
{
pool_.Enumerate(
[&](resources::ResourceKey key, size_t idx, const imaging::IPixelariumImage& img) -> void
[&](resources::ResourceKey key, size_t idx, const imaging::IPixelariumImage<cv::Mat>& img) -> void
{
const bool is_selected = static_cast<int>(idx) == selected_idx_0;
if (ImGui::Selectable(img.Name().c_str(), is_selected))
@@ -74,7 +74,7 @@ class Selector
if (ImGui::BeginCombo("Select second image", preview_1_.c_str()))
{
pool_.Enumerate(
[&](resources::ResourceKey key, size_t idx, const imaging::IPixelariumImage& img) -> void
[&](resources::ResourceKey key, size_t idx, const imaging::IPixelariumImage<cv::Mat>& img) -> void
{
const bool is_selected = static_cast<int>(idx) == selected_idx_1;
if (ImGui::Selectable(img.Name().c_str(), is_selected))
@@ -100,11 +100,12 @@ class Selector
auto img1 = pool_.GetResource(selected_key_1);
auto img_mat1 = img1.lock()->TryGetImage();
if (img_mat0 == nullptr || img_mat1 == nullptr || img_mat0->empty() || img_mat1->empty()) return;
if (!img_mat0.has_value() || !img_mat1.has_value() || img_mat0.value().empty() || img_mat1.value().empty())
return;
if (img_mat0->size != img_mat1->size) return;
cv::multiply(*img_mat0, *img_mat1, *img_mat0);
cv::multiply(img_mat0.value(), img_mat1.value(), img_mat0.value());
std::string name{std::format("Multiply_{}", idx_)};
pool_.SetResource(std::make_unique<imaging::PixelariumMem>(*img_mat0, name, *logger));
-1
View File
@@ -7,7 +7,6 @@ add_executable(${SIMPLE_NAME} ${SRC})
target_link_libraries(${SIMPLE_NAME}
PRIVATE pixelariumimagelib
PRIVATE pixelariumrenderlib
PRIVATE pixelariumutilslib
PRIVATE pixelariumresourcelib
PRIVATE pixelariumapplicationlib)