diff --git a/crates/svg-filters/src/tests.rs b/crates/svg-filters/src/tests.rs
index 72b970f..771ab3a 100644
--- a/crates/svg-filters/src/tests.rs
+++ b/crates/svg-filters/src/tests.rs
@@ -5,7 +5,44 @@ mod complex;
mod gaussian_blur;
mod offset;
-mod component_transfer {}
+mod component_transfer {
+ use crate::{
+ codegen::SvgDocument,
+ types::nodes::primitives::{
+ component_transfer::{ComponentTransfer, TransferFn},
+ FePrimitive,
+ },
+ Node,
+ };
+
+ #[test]
+ fn test_comp_trans_simple() {
+ let mut doc = SvgDocument::new();
+
+ let comptrans = doc.create_filter("comp_trans");
+
+ comptrans.add_node(Node::simple(FePrimitive::ComponentTransfer(
+ ComponentTransfer {
+ func_r: TransferFn::Table {
+ table_values: vec![0., 0.1, 0.4, 0.9],
+ },
+ func_g: TransferFn::Discrete {
+ table_values: vec![0.1, 0.3, 0.5, 0.7, 0.9],
+ },
+ func_b: TransferFn::Linear {
+ slope: 1.0,
+ intercept: 0.75,
+ },
+ func_a: TransferFn::Identity,
+ },
+ )));
+
+ assert_eq!(
+ doc.generate_svg(),
+ r#""#
+ );
+ }
+}
mod composite {}
mod convolve_matrix {}
mod diffuse_lighting {}
diff --git a/crates/svg-filters/src/types/nodes/primitives.rs b/crates/svg-filters/src/types/nodes/primitives.rs
index f3c101a..0b6e758 100644
--- a/crates/svg-filters/src/types/nodes/primitives.rs
+++ b/crates/svg-filters/src/types/nodes/primitives.rs
@@ -84,7 +84,7 @@ impl WriteElement for FePrimitive {
match self {
FePrimitive::Blend(el) => el.attrs(),
FePrimitive::ColorMatrix(el) => el.attrs(),
- FePrimitive::ComponentTransfer(_) => todo!(),
+ FePrimitive::ComponentTransfer(el) => el.attrs(),
FePrimitive::Composite(el) => el.attrs(),
FePrimitive::ConvolveMatrix(_) => todo!(),
FePrimitive::DiffuseLighting(_) => todo!(),
@@ -105,7 +105,7 @@ impl WriteElement for FePrimitive {
match self {
FePrimitive::Blend(el) => el.tag_name(),
FePrimitive::ColorMatrix(el) => el.tag_name(),
- FePrimitive::ComponentTransfer(_) => todo!(),
+ FePrimitive::ComponentTransfer(el) => el.tag_name(),
FePrimitive::Composite(el) => el.tag_name(),
FePrimitive::ConvolveMatrix(_) => todo!(),
FePrimitive::DiffuseLighting(_) => todo!(),
@@ -121,4 +121,31 @@ impl WriteElement for FePrimitive {
FePrimitive::Turbulence(el) => el.tag_name(),
}
}
+
+ fn element_writer<'writer, 'result>(
+ &self,
+ writer: &'writer mut Writer<&'result mut Vec>,
+ common: CommonAttrs,
+ inputs: Vec,
+ output: Option,
+ ) -> quick_xml::Result<&'writer mut quick_xml::Writer<&'result mut Vec>> {
+ match self {
+ FePrimitive::Blend(el) => el.element_writer(writer, common, inputs, output),
+ FePrimitive::ColorMatrix(el) => el.element_writer(writer, common, inputs, output),
+ FePrimitive::ComponentTransfer(el) => el.element_writer(writer, common, inputs, output),
+ FePrimitive::Composite(el) => el.element_writer(writer, common, inputs, output),
+ FePrimitive::ConvolveMatrix(_) => todo!(),
+ FePrimitive::DiffuseLighting(_) => todo!(),
+ FePrimitive::DisplacementMap(_) => todo!(),
+ FePrimitive::Flood(_) => todo!(),
+ FePrimitive::GaussianBlur(el) => el.element_writer(writer, common, inputs, output),
+ FePrimitive::Image(_) => todo!(),
+ FePrimitive::Merge(_) => todo!(),
+ FePrimitive::Morphology(_) => todo!(),
+ FePrimitive::Offset(el) => el.element_writer(writer, common, inputs, output),
+ FePrimitive::SpecularLighting(_) => todo!(),
+ FePrimitive::Tile(_) => todo!(),
+ FePrimitive::Turbulence(el) => el.element_writer(writer, common, inputs, output),
+ }
+ }
}
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 d495ecc..1c37c50 100644
--- a/crates/svg-filters/src/types/nodes/primitives/component_transfer.rs
+++ b/crates/svg-filters/src/types/nodes/primitives/component_transfer.rs
@@ -1,3 +1,5 @@
+use quick_xml::{events::attributes::Attribute, Writer};
+
use super::WriteElement;
/// [feComponentTransfer](https://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement)
@@ -17,6 +19,44 @@ impl WriteElement for ComponentTransfer {
fn tag_name(&self) -> &'static str {
"feComponentTransfer"
}
+
+ fn element_writer<'writer, 'result>(
+ &self,
+ writer: &'writer mut quick_xml::Writer<&'result mut Vec>,
+ common: crate::types::nodes::CommonAttrs,
+ inputs: Vec,
+ output: Option,
+ ) -> quick_xml::Result<&'writer mut quick_xml::Writer<&'result mut Vec>> {
+ let inputs: 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(inputs.iter().map(|(k, v)| (&k[..], &v[..])))
+ .with_attributes(Into::>>::into(common));
+ if let Some(output) = output {
+ el_writer = el_writer.with_attribute(("result", output.as_str()));
+ }
+
+ el_writer.write_inner_content(|writer| {
+ self.func_r.write_self(writer, "feFuncR")?;
+ self.func_g.write_self(writer, "feFuncG")?;
+ self.func_b.write_self(writer, "feFuncB")?;
+ self.func_a.write_self(writer, "feFuncA")?;
+ Ok(())
+ })
+ }
}
/// [transfer functions](https://www.w3.org/TR/SVG11/filters.html#transferFuncElements)
@@ -39,3 +79,56 @@ pub enum TransferFn {
offset: f32,
},
}
+
+impl TransferFn {
+ #[allow(clippy::str_to_string, reason = "inside macro call")]
+ fn write_self<'writer, 'result>(
+ &self,
+ target: &'writer mut Writer<&'result mut Vec>,
+ name: &'static str,
+ ) -> quick_xml::Result<&'writer mut Writer<&'result mut Vec>> {
+ target
+ .create_element(name)
+ .with_attributes(match self {
+ TransferFn::Identity => gen_attrs![b"type": "identity"],
+ TransferFn::Table { table_values } => gen_attrs![
+ b"type": "table",
+ b"tableValues": table_values
+ .iter()
+ .map(std::string::ToString::to_string)
+ .reduce(|mut acc, e| {
+ acc.push(' ');
+ acc.push_str(&e);
+ acc
+ }).expect("empty tables disallowed")
+ ],
+ TransferFn::Discrete { table_values } => gen_attrs![
+ b"type": "discrete",
+ b"tableValues": table_values
+ .iter()
+ .map(std::string::ToString::to_string)
+ .reduce(|mut acc, e| {
+ acc.push(' ');
+ acc.push_str(&e);
+ acc
+ }).expect("empty tables disallowed")
+ ],
+ TransferFn::Linear { slope, intercept } => gen_attrs![
+ b"type": "linear",
+ b"slope": slope,
+ b"intercept": intercept
+ ],
+ TransferFn::Gamma {
+ amplitude,
+ exponent,
+ offset,
+ } => gen_attrs![
+ b"type": "gamma",
+ b"amplitude": amplitude,
+ b"exponent": exponent,
+ b"offset": offset
+ ],
+ })
+ .write_empty()
+ }
+}