Compare commits

..

4 commits

11 changed files with 152 additions and 57 deletions

View file

@ -43,10 +43,25 @@ impl SvgDocument {
self.filters.get_mut(&id.to_string()).unwrap() 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 { pub fn generate_svg(&self) -> String {
let mut result = Vec::new(); 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<u8>>) {
doc_writer doc_writer
.create_element("svg") .create_element("svg")
.write_inner_content(|writer| { .write_inner_content(|writer| {
@ -55,8 +70,6 @@ impl SvgDocument {
.try_fold(writer, Self::gen_filter) .try_fold(writer, Self::gen_filter)
.map(|_| {}) .map(|_| {})
}); });
String::from_utf8_lossy(&result).to_string()
} }
fn gen_filter<'w, 'r>( fn gen_filter<'w, 'r>(

View file

@ -5,4 +5,4 @@ pub mod types;
pub use types::nodes::Node; pub use types::nodes::Node;
#[cfg(test)] #[cfg(test)]
mod tests {} mod tests;

View file

@ -10,51 +10,8 @@ use svg_filters::{
}; };
fn main() { fn main() {
// <filter id="chromabb" >
// <feColorMatrix values="1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" in="SourceGraphic" />
// <feOffset dx="25" dy="0" />
// <feGaussianBlur stdDeviation="5 0" result="red" />
// <feColorMatrix values="0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0" result="grn" in="SourceGraphic" />
// <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0" in="SourceGraphic" />
// <feOffset dx="-25" dy="0" />
// <feGaussianBlur stdDeviation="5 0" result="blu"/>
// <feComposite in="red" in2="blu" operator="arithmetic" k2="1" k3="1" result="rb" />
// <feComposite in="rb" in2="grn" operator="arithmetic" k2="1" k3="1" />
// </filter>
let mut doc = SvgDocument::new(); 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()); println!("{}", doc.generate_svg());
} }

View file

@ -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 {}

View file

@ -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#"<svg><filter id="greyscale"><feColorMatrix values="1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0" in="SourceGraphic"/></filter></svg>"#
);
}

View file

@ -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#"<svg><filter id="chromabb_gen"><feColorMatrix values="0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0" in="SourceGraphic" result="r13"/><feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0" in="SourceGraphic" result="r9"/><feOffset dx="-25" dy="0" in="r9" result="r10"/><feGaussianBlur stdDeviation="5 0" in="r10" result="r11"/><feColorMatrix values="1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0" in="SourceGraphic" result="r6"/><feOffset dx="25" dy="0" in="r6" result="r7"/><feGaussianBlur stdDeviation="5 0" in="r7" result="r8"/><feComposite operator="arithmetic" k1="0" k2="1" k3="1" k4="0" in="r8" in2="r11" result="r12"/><feComposite operator="arithmetic" k1="0" k2="1" k3="1" k4="0" in="r12" in2="r13"/></filter></svg>"#
);
}

View file

@ -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#"<svg><filter id="blur"><feGaussianBlur stdDeviation="30 30" in="SourceGraphic"/></filter></svg>"#
)
}

View file

@ -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#"<svg><filter id="offset"><feOffset dx="25" dy="-25" in="SourceGraphic"/></filter></svg>"#
)
}

View file

@ -6,6 +6,7 @@ use self::{
primitives::{ primitives::{
blend::{Blend, BlendMode}, blend::{Blend, BlendMode},
color_matrix::{ColorMatrix, ColorMatrixType}, color_matrix::{ColorMatrix, ColorMatrixType},
component_transfer::{ComponentTransfer, TransferFn},
composite::{Composite, CompositeOperator}, composite::{Composite, CompositeOperator},
gaussian_blur::GaussianBlur, gaussian_blur::GaussianBlur,
offset::Offset, offset::Offset,
@ -145,9 +146,7 @@ impl Node {
} }
pub fn composite_arithmetic(k1: f32, k2: f32, k3: f32, k4: f32) -> Self { pub fn composite_arithmetic(k1: f32, k2: f32, k3: f32, k4: f32) -> Self {
Self::simple(FePrimitive::Composite(Composite::arithmetic( Self::composite(CompositeOperator::Arithmetic { k1, k2, k3, k4 })
k1, k2, k3, k4,
)))
} }
pub fn gaussian_blur(v: u16) -> Self { pub fn gaussian_blur(v: u16) -> Self {
@ -161,4 +160,18 @@ impl Node {
pub fn offset(dx: f32, dy: f32) -> Self { pub fn offset(dx: f32, dy: f32) -> Self {
Self::simple(FePrimitive::Offset(Offset::new(dx, dy))) 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,
}))
}
} }

View file

@ -61,7 +61,6 @@ pub trait WriteElement {
/// svg filter effects primitives /// svg filter effects primitives
#[derive(Debug)] #[derive(Debug)]
pub enum FePrimitive { pub enum FePrimitive {
// 2 inputs
Blend(blend::Blend), Blend(blend::Blend),
ColorMatrix(color_matrix::ColorMatrix), ColorMatrix(color_matrix::ColorMatrix),
ComponentTransfer(component_transfer::ComponentTransfer), ComponentTransfer(component_transfer::ComponentTransfer),

View file

@ -1,15 +1,15 @@
/// [feComponentTransfer](https://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement) /// [feComponentTransfer](https://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement)
#[derive(Debug)] #[derive(Debug)]
pub struct ComponentTransfer { pub struct ComponentTransfer {
func_r: TransferFunction, pub func_r: TransferFn,
func_g: TransferFunction, pub func_g: TransferFn,
func_b: TransferFunction, pub func_b: TransferFn,
func_a: TransferFunction, pub func_a: TransferFn,
} }
/// [transfer functions](https://www.w3.org/TR/SVG11/filters.html#transferFuncElements) /// [transfer functions](https://www.w3.org/TR/SVG11/filters.html#transferFuncElements)
#[derive(Debug)] #[derive(Debug)]
enum TransferFunction { pub enum TransferFn {
Identity, Identity,
Table { Table {
table_values: Vec<f32>, table_values: Vec<f32>,