Effector: C++/CMake image effects app
Port of the Python prototype to C++20 with a CMake build: - effector_core: GUI-free static library (effects, image IO via gdk-pixbuf, declarative param specs, registry, portable seeded RNG, thread helper) - scanlines effect: plans strips from the seeded RNG, then copies pixels in parallel with memcpy and doubling horizontal tiling - gtkmm 4 interface: native file dialogs, widgets generated from the param specs, coalesced background renders, preview as a GDK memory texture - CLI: flags generated from the effect registry, headless rendering with no display required - ctest suite covering the RNG, registry, effect geometry and image round trip The Python prototype is kept under python-reference/.
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace effector {
|
||||
|
||||
// Tightly packed 8-bit RGB. Row stride is always width * 3, which lets the
|
||||
// effects work with plain memcpy and hands GDK a buffer it can upload as is.
|
||||
class Image {
|
||||
public:
|
||||
Image() = default;
|
||||
Image(int width, int height);
|
||||
|
||||
int width() const noexcept { return width_; }
|
||||
int height() const noexcept { return height_; }
|
||||
std::size_t stride() const noexcept { return static_cast<std::size_t>(width_) * 3; }
|
||||
bool empty() const noexcept { return width_ <= 0 || height_ <= 0; }
|
||||
|
||||
std::uint8_t* row(int y) noexcept { return pixels_.data() + static_cast<std::size_t>(y) * stride(); }
|
||||
const std::uint8_t* row(int y) const noexcept {
|
||||
return pixels_.data() + static_cast<std::size_t>(y) * stride();
|
||||
}
|
||||
std::uint8_t* data() noexcept { return pixels_.data(); }
|
||||
const std::uint8_t* data() const noexcept { return pixels_.data(); }
|
||||
std::size_t byteSize() const noexcept { return pixels_.size(); }
|
||||
|
||||
const std::string& path() const noexcept { return path_; }
|
||||
void setPath(std::string path) { path_ = std::move(path); }
|
||||
|
||||
// Decodes via GdkPixbuf (PNG, JPEG, WebP, TIFF, BMP, ...), applying the
|
||||
// embedded EXIF orientation. Throws std::runtime_error on failure.
|
||||
static Image load(const std::string& path);
|
||||
|
||||
// Encodes by file extension; png is used when the extension is unknown.
|
||||
void save(const std::string& path) const;
|
||||
|
||||
private:
|
||||
int width_ = 0;
|
||||
int height_ = 0;
|
||||
std::vector<std::uint8_t> pixels_;
|
||||
std::string path_;
|
||||
};
|
||||
|
||||
struct LoadFailure {
|
||||
std::string path;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
// Loads every path, collecting rather than throwing on individual failures.
|
||||
std::vector<Image> loadImages(const std::vector<std::string>& paths,
|
||||
std::vector<LoadFailure>& failures);
|
||||
|
||||
} // namespace effector
|
||||
Reference in New Issue
Block a user