From deba03b83fd49210af3a2ad043bf25836ef74837 Mon Sep 17 00:00:00 2001 From: Bauke Date: Tue, 23 Jan 2024 13:53:15 +0100 Subject: [PATCH] Add the GeglOperation code with Bloom and Cartoon to begin with. --- gegl/source/lib.rs | 45 +++++++++++++++++++++++++++++ gegl/source/operations/generator.rs | 45 +++++++++++++++++++++++++++++ gegl/source/operations/mod.rs | 28 ++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 gegl/source/lib.rs create mode 100644 gegl/source/operations/generator.rs create mode 100644 gegl/source/operations/mod.rs diff --git a/gegl/source/lib.rs b/gegl/source/lib.rs new file mode 100644 index 0000000..672eba0 --- /dev/null +++ b/gegl/source/lib.rs @@ -0,0 +1,45 @@ +//! # GEGL +//! +//! > **Ad-hoc GEGL data structure library for Rust.** + +mod operations; + +pub use operations::*; + +pub use indexmap::indexmap; + +/// Type alias for a [`indexmap::IndexMap`] with static [`str`] keys and +/// [`String`] values. The reason for [`indexmap`] is to preserve insertion +/// order for simpler testing. +pub type GeglData = indexmap::IndexMap<&'static str, String>; + +/// The [`GeglOperation`] trait defines a set of common functions for the +/// individual operations to implement so they can be used with the GEGL CLI. +pub trait GeglOperation: Default + std::fmt::Debug { + /// Some GEGL operations will run infinitely unless you limit the buffer in + /// some way, so all operations must indicate whether or not they should be + /// followed by a crop operation. + fn append_crop_operation(&self) -> bool; + + /// Creates the parameters for the graph to be used with the GEGL CLI. + fn graph(&self, include_default_values: bool) -> Vec { + let mut graph = vec![self.name().to_string()]; + let defaults = Self::default().values(); + + for (key, value) in self.values() { + if !include_default_values && defaults.get(key) == Some(&value) { + continue; + } + + graph.push(format!("{key}={value}")); + } + + graph + } + + /// Returns the name of the operation, starting with `gegl:`. + fn name(&self) -> &'static str; + + /// Returns the set of configured values for this operation. + fn values(&self) -> GeglData; +} diff --git a/gegl/source/operations/generator.rs b/gegl/source/operations/generator.rs new file mode 100644 index 0000000..0e49766 --- /dev/null +++ b/gegl/source/operations/generator.rs @@ -0,0 +1,45 @@ +//! Macro-based [`crate::GeglOperation`] struct generator. + +/// A macro to generate a struct that implements [`crate::GeglOperation`]. +#[macro_export] +macro_rules! gegl_operation { + ( + struct_name: $struct_name:ident, + gegl_name: $gegl_name:expr, + append_crop: $append_crop:expr, + values: ($($key:ident: $key_type:ty, $key_default:expr, $key_doc:expr),*,), + ) => { + #[doc = concat!(" The `gegl:", $gegl_name, "` operation.")] + #[derive(Debug)] + pub struct $struct_name { + $( + #[doc = concat!(" ", $key_doc)] + pub $key: $key_type, + )* + } + + impl Default for $struct_name { + fn default() -> $struct_name { + $struct_name { + $($key: $key_default,)* + } + } + } + + impl $crate::GeglOperation for $struct_name { + fn append_crop_operation(&self) -> bool { + $append_crop + } + + fn name(&self) -> &'static str { + concat!("gegl:", $gegl_name) + } + + fn values(&self) -> $crate::GeglData { + $crate::indexmap! { + $(stringify!($key) => self.$key.to_string(),)* + } + } + } + }; +} diff --git a/gegl/source/operations/mod.rs b/gegl/source/operations/mod.rs new file mode 100644 index 0000000..6fdfb43 --- /dev/null +++ b/gegl/source/operations/mod.rs @@ -0,0 +1,28 @@ +//! All supported GEGL operations. + +mod generator; + +pub use crate::gegl_operation; + +gegl_operation!( + struct_name: Bloom, + gegl_name: "bloom", + append_crop: false, + values: ( + limit_exposure: bool, false, "Don't over-expose highlights.", + radius: f64, 10.0, "Glow radius.", + softness: f64, 25.0, "Glow-area edge softness.", + strength: f64, 50.0, "Glow strength.", + threshold: f64, 50.0, "Glow-area brightness threshold.", + ), +); + +gegl_operation!( + struct_name: Cartoon, + gegl_name: "cartoon", + append_crop: true, + values: ( + mask_radius: f64, 7.0, "The mask radius.", + pct_black: f64, 0.2, "The percentage of black.", + ), +);