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,
types::{
graph::edge::Edge,
nodes::{primitives::color_matrix::ColorMatrixType, standard_input::StandardInput},
nodes::{
primitives::{blend::BlendMode, color_matrix::ColorMatrixType},
standard_input::StandardInput,
},
},
Node,
};
@ -12,6 +15,12 @@ use svg_filters::{
fn main() {
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());
println!("{}", doc.generate_svg());
}

View file

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

View file

@ -4,6 +4,23 @@ use quick_xml::{events::attributes::Attribute, ElementWriter, Writer};
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 color_matrix;
pub mod component_transfer;

View file

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

View file

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

View file

@ -1,3 +1,5 @@
use super::WriteElement;
/// [feComponentTransfer](https://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement)
#[derive(Debug)]
pub struct ComponentTransfer {
@ -7,6 +9,16 @@ pub struct ComponentTransfer {
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)
#[derive(Debug)]
pub enum TransferFn {

View file

@ -51,23 +51,29 @@ impl WriteElement for Composite {
}];
if let Some([k1, k2, k3, k4]) = vals {
r.append(&mut vec![
Attribute {
key: QName(b"k1"),
value: Cow::from(k1.to_string().into_bytes()),
},
Attribute {
key: QName(b"k2"),
value: Cow::from(k2.to_string().into_bytes()),
},
Attribute {
key: QName(b"k3"),
value: Cow::from(k3.to_string().into_bytes()),
},
Attribute {
key: QName(b"k4"),
value: Cow::from(k4.to_string().into_bytes()),
},
// r.append(&mut vec![
// Attribute {
// key: QName(b"k1"),
// value: Cow::from(k1.to_string().into_bytes()),
// },
// Attribute {
// key: QName(b"k2"),
// value: Cow::from(k2.to_string().into_bytes()),
// },
// Attribute {
// key: QName(b"k3"),
// value: Cow::from(k3.to_string().into_bytes()),
// },
// Attribute {
// key: QName(b"k4"),
// 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 {
fn attrs(&self) -> Vec<quick_xml::events::attributes::Attribute> {
vec![
Attribute {
key: QName(b"flood-color"),
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()),
},
gen_attrs![
b"flood-color" = self.flood_color.to_hex_string(),
b"flood-opacity" = self.flood_opacity
]
}

View file

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

View file

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

View file

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