forked from katzen-cafe/iowo
svg-filters: simplify and refactor a bit
This commit is contained in:
parent
5368951254
commit
bf60bdd814
15 changed files with 532 additions and 227 deletions
|
@ -1,10 +1,8 @@
|
|||
use std::convert::Into;
|
||||
|
||||
use quick_xml::{events::attributes::Attribute, ElementWriter, Writer};
|
||||
|
||||
use crate::types::length::{Coordinate, Length};
|
||||
|
||||
use self::blend::BlendMode;
|
||||
|
||||
use super::Node;
|
||||
use super::CommonAttrs;
|
||||
|
||||
pub mod blend;
|
||||
pub mod color_matrix;
|
||||
|
@ -29,10 +27,34 @@ pub trait WriteElement {
|
|||
fn element_writer<'writer, 'result>(
|
||||
&self,
|
||||
writer: &'writer mut Writer<&'result mut Vec<u8>>,
|
||||
) -> ElementWriter<'writer, &'result mut Vec<u8>> {
|
||||
writer
|
||||
common: CommonAttrs,
|
||||
inputs: Vec<String>,
|
||||
output: Option<String>,
|
||||
) -> quick_xml::Result<&'writer mut quick_xml::Writer<&'result mut Vec<u8>>> {
|
||||
let attrs: Vec<_> = inputs
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(i, edge)| {
|
||||
(
|
||||
match i {
|
||||
0 => "in".to_owned(),
|
||||
n => format!("in{}", n + 1),
|
||||
}
|
||||
.into_bytes(),
|
||||
edge.into_bytes(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
let mut el_writer = writer
|
||||
.create_element(self.tag_name())
|
||||
.with_attributes(Into::<Vec<Attribute<'_>>>::into(common))
|
||||
.with_attributes(self.attrs())
|
||||
.with_attributes(attrs.iter().map(|(k, v)| (&k[..], &v[..])));
|
||||
if let Some(output) = output {
|
||||
el_writer = el_writer.with_attribute(("result", output.as_str()));
|
||||
}
|
||||
|
||||
el_writer.write_empty()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
use std::{borrow::Cow, fmt::Display};
|
||||
|
||||
use quick_xml::{events::attributes::Attribute, name::QName};
|
||||
|
||||
use super::WriteElement;
|
||||
|
||||
/// [feBlend](https://www.w3.org/TR/SVG11/filters.html#feBlendElement)
|
||||
#[derive(Debug)]
|
||||
pub struct Blend {
|
||||
|
@ -18,6 +24,23 @@ impl Default for Blend {
|
|||
}
|
||||
}
|
||||
|
||||
impl WriteElement for Blend {
|
||||
fn attrs(&self) -> Vec<quick_xml::events::attributes::Attribute> {
|
||||
if let BlendMode::Normal = self.mode {
|
||||
Vec::new()
|
||||
} else {
|
||||
vec![Attribute {
|
||||
key: QName(b"mode"),
|
||||
value: Cow::from(self.mode.to_string().into_bytes()),
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
fn tag_name(&self) -> &'static str {
|
||||
"feBlend"
|
||||
}
|
||||
}
|
||||
|
||||
/// as according to https://drafts.fxtf.org/compositing-1/#blending
|
||||
#[derive(Debug)]
|
||||
pub enum BlendMode {
|
||||
|
@ -39,3 +62,26 @@ pub enum BlendMode {
|
|||
Color,
|
||||
Luminosity,
|
||||
}
|
||||
|
||||
impl Display for BlendMode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
BlendMode::Normal => "normal",
|
||||
BlendMode::Multiply => "multiply",
|
||||
BlendMode::Screen => "screen",
|
||||
BlendMode::Overlay => "overlay",
|
||||
BlendMode::Darken => "darken",
|
||||
BlendMode::Lighten => "lighten",
|
||||
BlendMode::ColorDodge => "color-dodge",
|
||||
BlendMode::ColorBurn => "color-burn",
|
||||
BlendMode::HardLight => "hard-light",
|
||||
BlendMode::SoftLight => "soft-light",
|
||||
BlendMode::Difference => "difference",
|
||||
BlendMode::Exclusion => "exclusion",
|
||||
BlendMode::Hue => "hue",
|
||||
BlendMode::Saturation => "saturation",
|
||||
BlendMode::Color => "color",
|
||||
BlendMode::Luminosity => "luminosity",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use quick_xml::{events::attributes::Attribute, name::QName, se::to_string};
|
||||
use quick_xml::{events::attributes::Attribute, name::QName};
|
||||
|
||||
use super::WriteElement;
|
||||
|
||||
|
@ -23,7 +23,7 @@ impl WriteElement for ColorMatrix {
|
|||
key: QName(b"values"),
|
||||
value: Cow::from(
|
||||
v.iter()
|
||||
.map(|v| v.to_string())
|
||||
.map(std::string::ToString::to_string)
|
||||
.reduce(|mut acc, e| {
|
||||
acc.push(' ');
|
||||
acc.push_str(&e);
|
||||
|
@ -33,9 +33,11 @@ impl WriteElement for ColorMatrix {
|
|||
.into_bytes(),
|
||||
),
|
||||
}],
|
||||
ColorMatrixType::Saturate(v) => todo!(),
|
||||
ColorMatrixType::HueRotate(v) => todo!(),
|
||||
ColorMatrixType::LuminanceToAlpha => todo!(),
|
||||
ColorMatrixType::Saturate(v) | ColorMatrixType::HueRotate(v) => vec![Attribute {
|
||||
key: QName(b"values"),
|
||||
value: Cow::from(v.to_string().into_bytes()),
|
||||
}],
|
||||
ColorMatrixType::LuminanceToAlpha => Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use csscolorparser::Color;
|
||||
use quick_xml::{events::attributes::Attribute, name::QName};
|
||||
|
||||
use super::WriteElement;
|
||||
|
||||
/// [feFlood](https://www.w3.org/TR/SVG11/filters.html#feFloodElement)
|
||||
#[derive(Debug)]
|
||||
|
@ -6,3 +11,22 @@ pub struct Flood {
|
|||
flood_color: Color,
|
||||
flood_opacity: f32,
|
||||
}
|
||||
|
||||
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()),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn tag_name(&self) -> &'static str {
|
||||
"feFlood"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
use std::{borrow::Cow, fmt::Display};
|
||||
|
||||
use quick_xml::{events::attributes::Attribute, name::QName};
|
||||
|
||||
use super::WriteElement;
|
||||
|
||||
/// [feMorphology](https://www.w3.org/TR/SVG11/filters.html#feMorphologyElement)
|
||||
#[derive(Debug)]
|
||||
pub struct Morphology {
|
||||
|
@ -5,8 +11,36 @@ pub struct Morphology {
|
|||
radius: (f32, f32),
|
||||
}
|
||||
|
||||
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()),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn tag_name(&self) -> &'static str {
|
||||
"feMorphology"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Operator {
|
||||
Erode,
|
||||
Dilate,
|
||||
}
|
||||
|
||||
impl Display for Operator {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(match self {
|
||||
Operator::Erode => "erode",
|
||||
Operator::Dilate => "dilate",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,15 @@
|
|||
use super::WriteElement;
|
||||
|
||||
/// [feTile](https://www.w3.org/TR/SVG11/filters.html#feTileElement)
|
||||
#[derive(Debug)]
|
||||
pub struct Tile;
|
||||
|
||||
impl WriteElement for Tile {
|
||||
fn attrs(&self) -> Vec<quick_xml::events::attributes::Attribute> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn tag_name(&self) -> &'static str {
|
||||
"feTile"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,75 @@
|
|||
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)
|
||||
#[derive(Debug)]
|
||||
pub struct Turbulence {
|
||||
base_frequency: (f32, f32),
|
||||
num_octaves: (u16),
|
||||
num_octaves: u16,
|
||||
seed: u32,
|
||||
stich_tiles: StitchTiles,
|
||||
stitch_tiles: StitchTiles,
|
||||
// attr name: type
|
||||
noise_type: NoiseType,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum StitchTiles {
|
||||
impl WriteElement for Turbulence {
|
||||
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(),
|
||||
),
|
||||
}]);
|
||||
|
||||
if self.num_octaves != 1 {
|
||||
r.push(Attribute {
|
||||
key: QName(b"numOctaves"),
|
||||
value: Cow::from(format!("{}", self.num_octaves).into_bytes()),
|
||||
});
|
||||
}
|
||||
|
||||
if self.seed != 0 {
|
||||
r.push(Attribute {
|
||||
key: QName(b"seed"),
|
||||
value: Cow::from(self.seed.to_string().into_bytes()),
|
||||
});
|
||||
}
|
||||
|
||||
if self.stitch_tiles != StitchTiles::NoStitch {
|
||||
r.push(Attribute {
|
||||
key: QName(b"stitchTiles"),
|
||||
value: Cow::from(b"stitch".to_vec()),
|
||||
});
|
||||
}
|
||||
|
||||
if self.noise_type != NoiseType::Turbulence {
|
||||
r.push(Attribute {
|
||||
key: QName(b"type"),
|
||||
value: Cow::from(b"fractalNoise".to_vec()),
|
||||
});
|
||||
}
|
||||
|
||||
r
|
||||
}
|
||||
|
||||
fn tag_name(&self) -> &'static str {
|
||||
"feTurbulence"
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum StitchTiles {
|
||||
Stitch,
|
||||
NoStitch,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
enum NoiseType {
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum NoiseType {
|
||||
Turbulence,
|
||||
FractalNoise,
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/// [svg filter effect standard input](https://www.w3.org/TR/SVG11/filters.html#FilterPrimitiveInAttribute)
|
||||
/// technically not a node, but for implementation simplicity... yeah
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum StandardInput {
|
||||
SourceGraphic,
|
||||
SourceAlpha,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue