svg-filters & basic parser #15

Merged
schrottkatze merged 67 commits from schrottkatze/iowo:svg-filters into main 2024-07-08 18:29:05 +00:00
12 changed files with 94 additions and 108 deletions
Showing only changes of commit dc7d76dc26 - Show all commits

View file

@ -4,7 +4,10 @@ use svg_filters::{
codegen::SvgDocument, codegen::SvgDocument,
types::{ types::{
graph::edge::Edge, graph::edge::Edge,
nodes::{primitives::color_matrix::ColorMatrixType, standard_input::StandardInput}, nodes::{
primitives::{blend::BlendMode, color_matrix::ColorMatrixType},
standard_input::StandardInput,
},
}, },
Node, Node,
}; };
@ -12,6 +15,12 @@ use svg_filters::{
fn main() { fn main() {
let mut doc = SvgDocument::new(); let mut doc = SvgDocument::new();
let blend = doc.create_filter("blend");
let offset0 = blend.offset(StandardInput::SourceGraphic, 100., 0.);
let offset1 = blend.offset(StandardInput::SourceGraphic, -100., 0.);
blend.blend(offset0, offset1, BlendMode::Multiply);
eprintln!("{}", doc.generate_svg_pretty()); eprintln!("{}", doc.generate_svg_pretty());
println!("{}", doc.generate_svg()); println!("{}", doc.generate_svg());
} }

View file

@ -36,7 +36,7 @@ impl Default for Node {
} }
#[derive(Default, Debug, Clone, Copy)] #[derive(Default, Debug, Clone, Copy)]
pub(crate) struct CommonAttrs { pub struct CommonAttrs {
pub x: Coordinate, pub x: Coordinate,
pub y: Coordinate, pub y: Coordinate,
pub width: Length, pub width: Length,

View file

@ -4,6 +4,23 @@ use quick_xml::{events::attributes::Attribute, ElementWriter, Writer};
use super::CommonAttrs; use super::CommonAttrs;
macro_rules! gen_attr {
($name:literal = $out:expr) => {
quick_xml::events::attributes::Attribute {
key: quick_xml::name::QName($name),
value: std::borrow::Cow::from(($out).to_string().into_bytes()),
}
};
}
macro_rules! gen_attrs {
($($name:literal = $out:expr),+) => {
vec![
$(gen_attr!($name = $out)),+
]
};
}
pub mod blend; pub mod blend;
pub mod color_matrix; pub mod color_matrix;
pub mod component_transfer; pub mod component_transfer;

View file

@ -29,10 +29,7 @@ impl WriteElement for Blend {
if let BlendMode::Normal = self.mode { if let BlendMode::Normal = self.mode {
Vec::new() Vec::new()
} else { } else {
vec![Attribute { gen_attrs![b"mode" = self.mode]
key: QName(b"mode"),
value: Cow::from(self.mode.to_string().into_bytes()),
}]
} }
} }

View file

@ -1,7 +1,3 @@
use std::borrow::Cow;
use quick_xml::{events::attributes::Attribute, name::QName};
use super::WriteElement; use super::WriteElement;
/// [feColorMatrix](https://www.w3.org/TR/SVG11/filters.html#feColorMatrixElement) /// [feColorMatrix](https://www.w3.org/TR/SVG11/filters.html#feColorMatrixElement)
@ -19,24 +15,20 @@ impl ColorMatrix {
impl WriteElement for ColorMatrix { impl WriteElement for ColorMatrix {
fn attrs(&self) -> Vec<quick_xml::events::attributes::Attribute> { fn attrs(&self) -> Vec<quick_xml::events::attributes::Attribute> {
match &self.cm_type { match &self.cm_type {
ColorMatrixType::Matrix(v) => vec![Attribute { ColorMatrixType::Matrix(v) => gen_attrs![
key: QName(b"values"), b"values" = v
value: Cow::from( .iter()
v.iter()
.map(std::string::ToString::to_string) .map(std::string::ToString::to_string)
.reduce(|mut acc, e| { .reduce(|mut acc, e| {
acc.push(' '); acc.push(' ');
acc.push_str(&e); acc.push_str(&e);
acc acc
}) })
.expect("Should be able to concatenate the thingies") .expect("fixed length arr should always work")
.into_bytes(), ],
), ColorMatrixType::Saturate(v) | ColorMatrixType::HueRotate(v) => {
}], gen_attrs![b"values" = v]
ColorMatrixType::Saturate(v) | ColorMatrixType::HueRotate(v) => vec![Attribute { }
key: QName(b"values"),
value: Cow::from(v.to_string().into_bytes()),
}],
ColorMatrixType::LuminanceToAlpha => Vec::new(), ColorMatrixType::LuminanceToAlpha => Vec::new(),
} }
} }

View file

@ -1,3 +1,5 @@
use super::WriteElement;
/// [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 {
@ -7,6 +9,16 @@ pub struct ComponentTransfer {
pub func_a: TransferFn, pub func_a: TransferFn,
} }
impl WriteElement for ComponentTransfer {
fn attrs(&self) -> Vec<quick_xml::events::attributes::Attribute> {
Vec::new()
}
fn tag_name(&self) -> &'static str {
"feComponentTransfer"
}
}
/// [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)]
pub enum TransferFn { pub enum TransferFn {

View file

@ -51,23 +51,29 @@ impl WriteElement for Composite {
}]; }];
if let Some([k1, k2, k3, k4]) = vals { if let Some([k1, k2, k3, k4]) = vals {
r.append(&mut vec![ // r.append(&mut vec![
Attribute { // Attribute {
key: QName(b"k1"), // key: QName(b"k1"),
value: Cow::from(k1.to_string().into_bytes()), // value: Cow::from(k1.to_string().into_bytes()),
}, // },
Attribute { // Attribute {
key: QName(b"k2"), // key: QName(b"k2"),
value: Cow::from(k2.to_string().into_bytes()), // value: Cow::from(k2.to_string().into_bytes()),
}, // },
Attribute { // Attribute {
key: QName(b"k3"), // key: QName(b"k3"),
value: Cow::from(k3.to_string().into_bytes()), // value: Cow::from(k3.to_string().into_bytes()),
}, // },
Attribute { // Attribute {
key: QName(b"k4"), // key: QName(b"k4"),
value: Cow::from(k4.to_string().into_bytes()), // value: Cow::from(k4.to_string().into_bytes()),
}, // },
// ]);
r.append(&mut gen_attrs![
b"k1" = k1,
b"k2" = k2,
b"k3" = k3,
b"k4" = k4
]); ]);
} }

View file

@ -14,15 +14,9 @@ pub struct Flood {
impl WriteElement for Flood { impl WriteElement for Flood {
fn attrs(&self) -> Vec<quick_xml::events::attributes::Attribute> { fn attrs(&self) -> Vec<quick_xml::events::attributes::Attribute> {
vec![ gen_attrs![
Attribute { b"flood-color" = self.flood_color.to_hex_string(),
key: QName(b"flood-color"), b"flood-opacity" = self.flood_opacity
value: Cow::from(self.flood_color.to_hex_string().into_bytes()),
},
Attribute {
key: QName(b"flood-opacity"),
value: Cow::from(self.flood_opacity.to_string().into_bytes()),
},
] ]
} }

View file

@ -26,12 +26,7 @@ impl GaussianBlur {
impl WriteElement for GaussianBlur { impl WriteElement for GaussianBlur {
fn attrs(&self) -> Vec<quick_xml::events::attributes::Attribute> { fn attrs(&self) -> Vec<quick_xml::events::attributes::Attribute> {
vec![Attribute { gen_attrs![b"stdDeviation" = format!("{} {}", self.std_deviation.0, self.std_deviation.1)]
key: QName(b"stdDeviation"),
value: Cow::from(
format!("{} {}", self.std_deviation.0, self.std_deviation.1).into_bytes(),
),
}]
} }
fn tag_name(&self) -> &'static str { fn tag_name(&self) -> &'static str {

View file

@ -13,15 +13,9 @@ pub struct Morphology {
impl WriteElement for Morphology { impl WriteElement for Morphology {
fn attrs(&self) -> Vec<quick_xml::events::attributes::Attribute> { fn attrs(&self) -> Vec<quick_xml::events::attributes::Attribute> {
vec![ gen_attrs![
Attribute { b"operator" = self.operator,
key: QName(b"operator"), b"radius" = format!("{} {}", self.radius.0, self.radius.1)
value: Cow::from(self.operator.to_string().into_bytes()),
},
Attribute {
key: QName(b"radius"),
value: Cow::from(format!("{} {}", self.radius.0, self.radius.1).into_bytes()),
},
] ]
} }

View file

@ -19,16 +19,7 @@ impl Offset {
impl WriteElement for Offset { impl WriteElement for Offset {
fn attrs(&self) -> Vec<quick_xml::events::attributes::Attribute> { fn attrs(&self) -> Vec<quick_xml::events::attributes::Attribute> {
vec![ gen_attrs![b"dx" = self.dx, b"dy" = self.dy]
Attribute {
key: QName(b"dx"),
value: Cow::from(self.dx.to_string().into_bytes()),
},
Attribute {
key: QName(b"dy"),
value: Cow::from(self.dy.to_string().into_bytes()),
},
]
} }
fn tag_name(&self) -> &'static str { fn tag_name(&self) -> &'static str {

View file

@ -1,10 +1,3 @@
use std::borrow::Cow;
use quick_xml::{
events::attributes::{Attr, Attribute},
name::QName,
};
use super::WriteElement; use super::WriteElement;
/// [feTurbulence](https://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement) /// [feTurbulence](https://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement)
@ -19,40 +12,26 @@ pub struct Turbulence {
} }
impl WriteElement for Turbulence { impl WriteElement for Turbulence {
#[allow(clippy::str_to_string, reason = "in macro invocation")]
fn attrs(&self) -> Vec<quick_xml::events::attributes::Attribute> { fn attrs(&self) -> Vec<quick_xml::events::attributes::Attribute> {
let mut r = Vec::from([Attribute { let mut r = gen_attrs!(
key: QName(b"baseFrequency"), b"baseFrequency" = format!("{} {}", self.base_frequency.0, self.base_frequency.1)
value: Cow::from( );
format!("{} {}", self.base_frequency.0, self.base_frequency.1).into_bytes(),
),
}]);
if self.num_octaves != 1 { if self.num_octaves != 1 {
r.push(Attribute { r.push(gen_attr!(b"numOctaves" = self.num_octaves));
key: QName(b"numOctaves"),
value: Cow::from(format!("{}", self.num_octaves).into_bytes()),
});
} }
if self.seed != 0 { if self.seed != 0 {
r.push(Attribute { r.push(gen_attr!(b"seed" = self.seed));
key: QName(b"seed"),
value: Cow::from(self.seed.to_string().into_bytes()),
});
} }
if self.stitch_tiles != StitchTiles::NoStitch { if self.stitch_tiles != StitchTiles::NoStitch {
r.push(Attribute { r.push(gen_attr!(b"stitchTiles" = "stitch"));
key: QName(b"stitchTiles"),
value: Cow::from(b"stitch".to_vec()),
});
} }
if self.noise_type != NoiseType::Turbulence { if self.noise_type != NoiseType::Turbulence {
r.push(Attribute { r.push(gen_attr!(b"type" = "fractalNoise"));
key: QName(b"type"),
value: Cow::from(b"fractalNoise".to_vec()),
});
} }
r r