diff --git a/crates/svg-filters/src/codegen.rs b/crates/svg-filters/src/codegen.rs index a8e7b23..cd93d25 100644 --- a/crates/svg-filters/src/codegen.rs +++ b/crates/svg-filters/src/codegen.rs @@ -43,10 +43,25 @@ impl SvgDocument { self.filters.get_mut(&id.to_string()).unwrap() } + pub fn generate_svg_pretty(&self) -> String { + let mut result = Vec::new(); + let doc_writer = quick_xml::Writer::new_with_indent(&mut result, b' ', 2); + + self.generate(doc_writer); + + String::from_utf8_lossy(&result).to_string() + } + pub fn generate_svg(&self) -> String { let mut result = Vec::new(); - let mut doc_writer = quick_xml::Writer::new_with_indent(&mut result, b' ', 2); + let doc_writer = quick_xml::Writer::new(&mut result); + self.generate(doc_writer); + + String::from_utf8_lossy(&result).to_string() + } + + fn generate(&self, mut doc_writer: quick_xml::Writer<&mut Vec>) { doc_writer .create_element("svg") .write_inner_content(|writer| { @@ -55,8 +70,6 @@ impl SvgDocument { .try_fold(writer, Self::gen_filter) .map(|_| {}) }); - - String::from_utf8_lossy(&result).to_string() } fn gen_filter<'w, 'r>( diff --git a/crates/svg-filters/src/lib.rs b/crates/svg-filters/src/lib.rs index cc443d8..c3ddedc 100644 --- a/crates/svg-filters/src/lib.rs +++ b/crates/svg-filters/src/lib.rs @@ -5,4 +5,4 @@ pub mod types; pub use types::nodes::Node; #[cfg(test)] -mod tests {} +mod tests; diff --git a/crates/svg-filters/src/main.rs b/crates/svg-filters/src/main.rs index c5684de..aff0c94 100644 --- a/crates/svg-filters/src/main.rs +++ b/crates/svg-filters/src/main.rs @@ -10,51 +10,8 @@ use svg_filters::{ }; fn main() { - // - // - // - // - - // - - // - // - // - - // - // - // - let mut doc = SvgDocument::new(); - let chromabb = doc.create_filter("chromabb_gen"); - - let chan_r = chromabb.color_matrix( - StandardInput::SourceGraphic, - ColorMatrixType::Matrix(Box::new([ - 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., - ])), - ); - let offset_r = chromabb.offset(chan_r, 25., 0.); - let blur_r = chromabb.gaussian_blur_xy(offset_r, 5, 0); - - let chan_b = chromabb.color_matrix( - StandardInput::SourceGraphic, - ColorMatrixType::Matrix(Box::new([ - 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 1., 0., - ])), - ); - let offset_b = chromabb.offset(chan_b, -25., 0.); - let blur_b = chromabb.gaussian_blur_xy(offset_b, 5, 0); - - let composite_rb = chromabb.composite_arithmetic(blur_r, blur_b, 0., 1., 1., 0.); - - let chan_g = chromabb.color_matrix( - StandardInput::SourceGraphic, - ColorMatrixType::Matrix(Box::new([ - 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., - ])), - ); - chromabb.composite_arithmetic(composite_rb, chan_g, 0., 1., 1., 0.); + eprintln!("{}", doc.generate_svg_pretty()); println!("{}", doc.generate_svg()); } diff --git a/crates/svg-filters/src/tests.rs b/crates/svg-filters/src/tests.rs new file mode 100644 index 0000000..c09a957 --- /dev/null +++ b/crates/svg-filters/src/tests.rs @@ -0,0 +1,19 @@ +mod color_matrix; + +mod complex; +mod gaussian_blur; +mod offset; + +mod blend {} +mod component_transfer {} +mod composite {} +mod convolve_matrix {} +mod diffuse_lighting {} +mod displacement_map {} +mod flood {} +mod image {} +mod merge {} +mod morphology {} +mod specular_lighting {} +mod tile {} +mod turbulence {} diff --git a/crates/svg-filters/src/tests/color_matrix.rs b/crates/svg-filters/src/tests/color_matrix.rs new file mode 100644 index 0000000..e32d507 --- /dev/null +++ b/crates/svg-filters/src/tests/color_matrix.rs @@ -0,0 +1,25 @@ +use crate::{ + codegen::SvgDocument, + types::nodes::{primitives::color_matrix::ColorMatrixType, standard_input::StandardInput}, +}; + +#[test] +fn test_greyscale_channel_extraction() { + let mut doc = SvgDocument::new(); + let greyscale = doc.create_filter("greyscale"); + + greyscale.color_matrix( + StandardInput::SourceGraphic, + ColorMatrixType::Matrix(Box::new([ + 1., 0., 0., 0., 0., // + 1., 0., 0., 0., 0., // + 1., 0., 0., 0., 0., // + 0., 0., 0., 1., 0., + ])), + ); + + assert_eq!( + doc.generate_svg(), + r#""# + ); +} diff --git a/crates/svg-filters/src/tests/complex.rs b/crates/svg-filters/src/tests/complex.rs new file mode 100644 index 0000000..9b28304 --- /dev/null +++ b/crates/svg-filters/src/tests/complex.rs @@ -0,0 +1,42 @@ +use crate::{ + codegen::SvgDocument, + types::nodes::{primitives::color_matrix::ColorMatrixType, standard_input::StandardInput}, +}; + +#[test] +fn test_chrom_abb() { + let mut doc = SvgDocument::new(); + let chromabb = doc.create_filter("chromabb_gen"); + + let chan_r = chromabb.color_matrix( + StandardInput::SourceGraphic, + ColorMatrixType::Matrix(Box::new([ + 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., + ])), + ); + let offset_r = chromabb.offset(chan_r, 25., 0.); + let blur_r = chromabb.gaussian_blur_xy(offset_r, 5, 0); + + let chan_b = chromabb.color_matrix( + StandardInput::SourceGraphic, + ColorMatrixType::Matrix(Box::new([ + 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 1., 0., + ])), + ); + let offset_b = chromabb.offset(chan_b, -25., 0.); + let blur_b = chromabb.gaussian_blur_xy(offset_b, 5, 0); + + let composite_rb = chromabb.composite_arithmetic(blur_r, blur_b, 0., 1., 1., 0.); + + let chan_g = chromabb.color_matrix( + StandardInput::SourceGraphic, + ColorMatrixType::Matrix(Box::new([ + 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., + ])), + ); + chromabb.composite_arithmetic(composite_rb, chan_g, 0., 1., 1., 0.); + assert_eq!( + doc.generate_svg(), + r#""# + ); +} diff --git a/crates/svg-filters/src/tests/gaussian_blur.rs b/crates/svg-filters/src/tests/gaussian_blur.rs new file mode 100644 index 0000000..5739794 --- /dev/null +++ b/crates/svg-filters/src/tests/gaussian_blur.rs @@ -0,0 +1,13 @@ +use crate::{codegen::SvgDocument, types::nodes::standard_input::StandardInput}; + +#[test] +fn test_simple_blur() { + let mut doc = SvgDocument::new(); + let blur = doc.create_filter("blur"); + + blur.gaussian_blur_xy(StandardInput::SourceGraphic, 30, 30); + assert_eq!( + doc.generate_svg(), + r#""# + ) +} diff --git a/crates/svg-filters/src/tests/offset.rs b/crates/svg-filters/src/tests/offset.rs new file mode 100644 index 0000000..4d7319e --- /dev/null +++ b/crates/svg-filters/src/tests/offset.rs @@ -0,0 +1,14 @@ +use crate::{codegen::SvgDocument, types::nodes::standard_input::StandardInput}; + +#[test] +fn test_offset_simple() { + let mut doc = SvgDocument::new(); + let mut offset = doc.create_filter("offset"); + + offset.offset(StandardInput::SourceGraphic, 25., -25.); + + assert_eq!( + doc.generate_svg(), + r#""# + ) +} diff --git a/crates/svg-filters/src/types/nodes.rs b/crates/svg-filters/src/types/nodes.rs index b24251f..a1ca752 100644 --- a/crates/svg-filters/src/types/nodes.rs +++ b/crates/svg-filters/src/types/nodes.rs @@ -6,6 +6,7 @@ use self::{ primitives::{ blend::{Blend, BlendMode}, color_matrix::{ColorMatrix, ColorMatrixType}, + component_transfer::{ComponentTransfer, TransferFn}, composite::{Composite, CompositeOperator}, gaussian_blur::GaussianBlur, offset::Offset, @@ -145,9 +146,7 @@ impl Node { } pub fn composite_arithmetic(k1: f32, k2: f32, k3: f32, k4: f32) -> Self { - Self::simple(FePrimitive::Composite(Composite::arithmetic( - k1, k2, k3, k4, - ))) + Self::composite(CompositeOperator::Arithmetic { k1, k2, k3, k4 }) } pub fn gaussian_blur(v: u16) -> Self { @@ -161,4 +160,18 @@ impl Node { pub fn offset(dx: f32, dy: f32) -> Self { Self::simple(FePrimitive::Offset(Offset::new(dx, dy))) } + + pub fn component_transfer_rgba( + r: TransferFn, + g: TransferFn, + b: TransferFn, + a: TransferFn, + ) -> Self { + Self::simple(FePrimitive::ComponentTransfer(ComponentTransfer { + func_r: r, + func_g: g, + func_b: b, + func_a: a, + })) + } } diff --git a/crates/svg-filters/src/types/nodes/primitives.rs b/crates/svg-filters/src/types/nodes/primitives.rs index f43c820..c7526fd 100644 --- a/crates/svg-filters/src/types/nodes/primitives.rs +++ b/crates/svg-filters/src/types/nodes/primitives.rs @@ -61,7 +61,6 @@ pub trait WriteElement { /// svg filter effects primitives #[derive(Debug)] pub enum FePrimitive { - // 2 inputs Blend(blend::Blend), ColorMatrix(color_matrix::ColorMatrix), ComponentTransfer(component_transfer::ComponentTransfer), diff --git a/crates/svg-filters/src/types/nodes/primitives/component_transfer.rs b/crates/svg-filters/src/types/nodes/primitives/component_transfer.rs index 3ccc039..abfd5a0 100644 --- a/crates/svg-filters/src/types/nodes/primitives/component_transfer.rs +++ b/crates/svg-filters/src/types/nodes/primitives/component_transfer.rs @@ -1,15 +1,15 @@ /// [feComponentTransfer](https://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement) #[derive(Debug)] pub struct ComponentTransfer { - func_r: TransferFunction, - func_g: TransferFunction, - func_b: TransferFunction, - func_a: TransferFunction, + pub func_r: TransferFn, + pub func_g: TransferFn, + pub func_b: TransferFn, + pub func_a: TransferFn, } /// [transfer functions](https://www.w3.org/TR/SVG11/filters.html#transferFuncElements) #[derive(Debug)] -enum TransferFunction { +pub enum TransferFn { Identity, Table { table_values: Vec,