usvg_tree/filter.rs
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
5//! SVG filter types.
6
7use std::cell::RefCell;
8use std::rc::Rc;
9
10use strict_num::PositiveF32;
11use svgtypes::AspectRatio;
12
13use crate::{BlendMode, Color, Group, ImageRendering, NonZeroF32, NonZeroRect, Opacity, Units};
14
15/// A filter element.
16///
17/// `filter` element in the SVG.
18#[derive(Clone, Debug)]
19pub struct Filter {
20 /// Element's ID.
21 ///
22 /// Taken from the SVG itself.
23 /// Used only during SVG writing. `resvg` doesn't rely on this property.
24 pub id: String,
25
26 /// Region coordinate system units.
27 ///
28 /// `filterUnits` in the SVG.
29 pub units: Units,
30
31 /// Content coordinate system units.
32 ///
33 /// `primitiveUnits` in the SVG.
34 pub primitive_units: Units,
35
36 /// Filter region.
37 ///
38 /// `x`, `y`, `width` and `height` in the SVG.
39 pub rect: NonZeroRect,
40
41 /// A list of filter primitives.
42 pub primitives: Vec<Primitive>,
43}
44
45/// An alias for a shared `Filter`.
46pub type SharedFilter = Rc<RefCell<Filter>>;
47
48/// A filter primitive element.
49#[derive(Clone, Debug)]
50pub struct Primitive {
51 /// `x` coordinate of the filter subregion.
52 pub x: Option<f32>,
53
54 /// `y` coordinate of the filter subregion.
55 pub y: Option<f32>,
56
57 /// The filter subregion width.
58 pub width: Option<f32>,
59
60 /// The filter subregion height.
61 pub height: Option<f32>,
62
63 /// Color interpolation mode.
64 ///
65 /// `color-interpolation-filters` in the SVG.
66 pub color_interpolation: ColorInterpolation,
67
68 /// Assigned name for this filter primitive.
69 ///
70 /// `result` in the SVG.
71 pub result: String,
72
73 /// Filter primitive kind.
74 pub kind: Kind,
75}
76
77/// A filter kind.
78#[allow(missing_docs)]
79#[derive(Clone, Debug)]
80pub enum Kind {
81 Blend(Blend),
82 ColorMatrix(ColorMatrix),
83 ComponentTransfer(ComponentTransfer),
84 Composite(Composite),
85 ConvolveMatrix(ConvolveMatrix),
86 DiffuseLighting(DiffuseLighting),
87 DisplacementMap(DisplacementMap),
88 DropShadow(DropShadow),
89 Flood(Flood),
90 GaussianBlur(GaussianBlur),
91 Image(Image),
92 Merge(Merge),
93 Morphology(Morphology),
94 Offset(Offset),
95 SpecularLighting(SpecularLighting),
96 Tile(Tile),
97 Turbulence(Turbulence),
98}
99
100impl Kind {
101 /// Checks that `FilterKind` has a specific input.
102 pub fn has_input(&self, input: &Input) -> bool {
103 match self {
104 Kind::Blend(ref fe) => fe.input1 == *input || fe.input2 == *input,
105 Kind::ColorMatrix(ref fe) => fe.input == *input,
106 Kind::ComponentTransfer(ref fe) => fe.input == *input,
107 Kind::Composite(ref fe) => fe.input1 == *input || fe.input2 == *input,
108 Kind::ConvolveMatrix(ref fe) => fe.input == *input,
109 Kind::DiffuseLighting(ref fe) => fe.input == *input,
110 Kind::DisplacementMap(ref fe) => fe.input1 == *input || fe.input2 == *input,
111 Kind::DropShadow(ref fe) => fe.input == *input,
112 Kind::Flood(_) => false,
113 Kind::GaussianBlur(ref fe) => fe.input == *input,
114 Kind::Image(_) => false,
115 Kind::Merge(ref fe) => fe.inputs.iter().any(|i| i == input),
116 Kind::Morphology(ref fe) => fe.input == *input,
117 Kind::Offset(ref fe) => fe.input == *input,
118 Kind::SpecularLighting(ref fe) => fe.input == *input,
119 Kind::Tile(ref fe) => fe.input == *input,
120 Kind::Turbulence(_) => false,
121 }
122 }
123}
124
125/// Identifies input for a filter primitive.
126#[allow(missing_docs)]
127#[derive(Clone, PartialEq, Debug)]
128pub enum Input {
129 SourceGraphic,
130 SourceAlpha,
131 Reference(String),
132}
133
134/// A color interpolation mode.
135#[allow(missing_docs)]
136#[derive(Clone, Copy, PartialEq, Debug)]
137pub enum ColorInterpolation {
138 SRGB,
139 LinearRGB,
140}
141
142impl Default for ColorInterpolation {
143 fn default() -> Self {
144 ColorInterpolation::LinearRGB
145 }
146}
147
148/// A blend filter primitive.
149///
150/// `feBlend` element in the SVG.
151#[derive(Clone, Debug)]
152pub struct Blend {
153 /// Identifies input for the given filter primitive.
154 ///
155 /// `in` in the SVG.
156 pub input1: Input,
157
158 /// Identifies input for the given filter primitive.
159 ///
160 /// `in2` in the SVG.
161 pub input2: Input,
162
163 /// A blending mode.
164 ///
165 /// `mode` in the SVG.
166 pub mode: BlendMode,
167}
168
169/// A color matrix filter primitive.
170///
171/// `feColorMatrix` element in the SVG.
172#[derive(Clone, Debug)]
173pub struct ColorMatrix {
174 /// Identifies input for the given filter primitive.
175 ///
176 /// `in` in the SVG.
177 pub input: Input,
178
179 /// A matrix kind.
180 ///
181 /// `type` in the SVG.
182 pub kind: ColorMatrixKind,
183}
184
185/// A color matrix filter primitive kind.
186#[derive(Clone, Debug)]
187#[allow(missing_docs)]
188pub enum ColorMatrixKind {
189 Matrix(Vec<f32>), // Guarantee to have 20 numbers.
190 Saturate(PositiveF32),
191 HueRotate(f32),
192 LuminanceToAlpha,
193}
194
195impl Default for ColorMatrixKind {
196 fn default() -> Self {
197 ColorMatrixKind::Matrix(vec![
198 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
199 0.0, 1.0, 0.0,
200 ])
201 }
202}
203
204/// A component-wise remapping filter primitive.
205///
206/// `feComponentTransfer` element in the SVG.
207#[derive(Clone, Debug)]
208pub struct ComponentTransfer {
209 /// Identifies input for the given filter primitive.
210 ///
211 /// `in` in the SVG.
212 pub input: Input,
213
214 /// `feFuncR` in the SVG.
215 pub func_r: TransferFunction,
216
217 /// `feFuncG` in the SVG.
218 pub func_g: TransferFunction,
219
220 /// `feFuncB` in the SVG.
221 pub func_b: TransferFunction,
222
223 /// `feFuncA` in the SVG.
224 pub func_a: TransferFunction,
225}
226
227/// A transfer function used by `FeComponentTransfer`.
228///
229/// <https://www.w3.org/TR/SVG11/filters.html#transferFuncElements>
230#[derive(Clone, Debug)]
231pub enum TransferFunction {
232 /// Keeps a component as is.
233 Identity,
234
235 /// Applies a linear interpolation to a component.
236 ///
237 /// The number list can be empty.
238 Table(Vec<f32>),
239
240 /// Applies a step function to a component.
241 ///
242 /// The number list can be empty.
243 Discrete(Vec<f32>),
244
245 /// Applies a linear shift to a component.
246 #[allow(missing_docs)]
247 Linear { slope: f32, intercept: f32 },
248
249 /// Applies an exponential shift to a component.
250 #[allow(missing_docs)]
251 Gamma {
252 amplitude: f32,
253 exponent: f32,
254 offset: f32,
255 },
256}
257
258/// A composite filter primitive.
259///
260/// `feComposite` element in the SVG.
261#[derive(Clone, Debug)]
262pub struct Composite {
263 /// Identifies input for the given filter primitive.
264 ///
265 /// `in` in the SVG.
266 pub input1: Input,
267
268 /// Identifies input for the given filter primitive.
269 ///
270 /// `in2` in the SVG.
271 pub input2: Input,
272
273 /// A compositing operation.
274 ///
275 /// `operator` in the SVG.
276 pub operator: CompositeOperator,
277}
278
279/// An images compositing operation.
280#[allow(missing_docs)]
281#[derive(Clone, Copy, PartialEq, Debug)]
282pub enum CompositeOperator {
283 Over,
284 In,
285 Out,
286 Atop,
287 Xor,
288 Arithmetic { k1: f32, k2: f32, k3: f32, k4: f32 },
289}
290
291/// A matrix convolution filter primitive.
292///
293/// `feConvolveMatrix` element in the SVG.
294#[derive(Clone, Debug)]
295pub struct ConvolveMatrix {
296 /// Identifies input for the given filter primitive.
297 ///
298 /// `in` in the SVG.
299 pub input: Input,
300
301 /// A convolve matrix.
302 pub matrix: ConvolveMatrixData,
303
304 /// A matrix divisor.
305 ///
306 /// `divisor` in the SVG.
307 pub divisor: NonZeroF32,
308
309 /// A kernel matrix bias.
310 ///
311 /// `bias` in the SVG.
312 pub bias: f32,
313
314 /// An edges processing mode.
315 ///
316 /// `edgeMode` in the SVG.
317 pub edge_mode: EdgeMode,
318
319 /// An alpha preserving flag.
320 ///
321 /// `preserveAlpha` in the SVG.
322 pub preserve_alpha: bool,
323}
324
325/// A convolve matrix representation.
326///
327/// Used primarily by [`ConvolveMatrix`].
328#[derive(Clone, Debug)]
329pub struct ConvolveMatrixData {
330 /// Returns a matrix's X target.
331 ///
332 /// `targetX` in the SVG.
333 pub target_x: u32,
334
335 /// Returns a matrix's Y target.
336 ///
337 /// `targetY` in the SVG.
338 pub target_y: u32,
339
340 /// Returns a number of columns in the matrix.
341 ///
342 /// Part of the `order` attribute in the SVG.
343 pub columns: u32,
344
345 /// Returns a number of rows in the matrix.
346 ///
347 /// Part of the `order` attribute in the SVG.
348 pub rows: u32,
349
350 /// The actual matrix.
351 pub data: Vec<f32>,
352}
353
354impl ConvolveMatrixData {
355 /// Creates a new `ConvolveMatrixData`.
356 ///
357 /// Returns `None` when:
358 ///
359 /// - `columns` * `rows` != `data.len()`
360 /// - `target_x` >= `columns`
361 /// - `target_y` >= `rows`
362 pub fn new(
363 target_x: u32,
364 target_y: u32,
365 columns: u32,
366 rows: u32,
367 data: Vec<f32>,
368 ) -> Option<Self> {
369 if (columns * rows) as usize != data.len() || target_x >= columns || target_y >= rows {
370 return None;
371 }
372
373 Some(ConvolveMatrixData {
374 target_x,
375 target_y,
376 columns,
377 rows,
378 data,
379 })
380 }
381
382 /// Returns a matrix value at the specified position.
383 ///
384 /// # Panics
385 ///
386 /// - When position is out of bounds.
387 pub fn get(&self, x: u32, y: u32) -> f32 {
388 self.data[(y * self.columns + x) as usize]
389 }
390}
391
392/// An edges processing mode.
393#[allow(missing_docs)]
394#[derive(Clone, Copy, PartialEq, Debug)]
395pub enum EdgeMode {
396 None,
397 Duplicate,
398 Wrap,
399}
400
401/// A displacement map filter primitive.
402///
403/// `feDisplacementMap` element in the SVG.
404#[derive(Clone, Debug)]
405pub struct DisplacementMap {
406 /// Identifies input for the given filter primitive.
407 ///
408 /// `in` in the SVG.
409 pub input1: Input,
410
411 /// Identifies input for the given filter primitive.
412 ///
413 /// `in2` in the SVG.
414 pub input2: Input,
415
416 /// Scale factor.
417 ///
418 /// `scale` in the SVG.
419 pub scale: f32,
420
421 /// Indicates a source color channel along the X-axis.
422 ///
423 /// `xChannelSelector` in the SVG.
424 pub x_channel_selector: ColorChannel,
425
426 /// Indicates a source color channel along the Y-axis.
427 ///
428 /// `yChannelSelector` in the SVG.
429 pub y_channel_selector: ColorChannel,
430}
431
432/// A color channel.
433#[allow(missing_docs)]
434#[derive(Clone, Copy, PartialEq, Debug)]
435pub enum ColorChannel {
436 R,
437 G,
438 B,
439 A,
440}
441
442/// A drop shadow filter primitive.
443///
444/// This is essentially `feGaussianBlur`, `feOffset` and `feFlood` joined together.
445///
446/// `feDropShadow` element in the SVG.
447#[derive(Clone, Debug)]
448pub struct DropShadow {
449 /// Identifies input for the given filter primitive.
450 ///
451 /// `in` in the SVG.
452 pub input: Input,
453
454 /// The amount to offset the input graphic along the X-axis.
455 pub dx: f32,
456
457 /// The amount to offset the input graphic along the Y-axis.
458 pub dy: f32,
459
460 /// A standard deviation along the X-axis.
461 ///
462 /// `stdDeviation` in the SVG.
463 pub std_dev_x: PositiveF32,
464
465 /// A standard deviation along the Y-axis.
466 ///
467 /// `stdDeviation` in the SVG.
468 pub std_dev_y: PositiveF32,
469
470 /// A flood color.
471 ///
472 /// `flood-color` in the SVG.
473 pub color: Color,
474
475 /// A flood opacity.
476 ///
477 /// `flood-opacity` in the SVG.
478 pub opacity: Opacity,
479}
480
481/// A flood filter primitive.
482///
483/// `feFlood` element in the SVG.
484#[derive(Clone, Copy, Debug)]
485pub struct Flood {
486 /// A flood color.
487 ///
488 /// `flood-color` in the SVG.
489 pub color: Color,
490
491 /// A flood opacity.
492 ///
493 /// `flood-opacity` in the SVG.
494 pub opacity: Opacity,
495}
496
497/// A Gaussian blur filter primitive.
498///
499/// `feGaussianBlur` element in the SVG.
500#[derive(Clone, Debug)]
501pub struct GaussianBlur {
502 /// Identifies input for the given filter primitive.
503 ///
504 /// `in` in the SVG.
505 pub input: Input,
506
507 /// A standard deviation along the X-axis.
508 ///
509 /// `stdDeviation` in the SVG.
510 pub std_dev_x: PositiveF32,
511
512 /// A standard deviation along the Y-axis.
513 ///
514 /// `stdDeviation` in the SVG.
515 pub std_dev_y: PositiveF32,
516}
517
518/// An image filter primitive.
519///
520/// `feImage` element in the SVG.
521#[derive(Clone, Debug)]
522pub struct Image {
523 /// Value of the `preserveAspectRatio` attribute.
524 pub aspect: AspectRatio,
525
526 /// Rendering method.
527 ///
528 /// `image-rendering` in SVG.
529 pub rendering_mode: ImageRendering,
530
531 /// Image data.
532 pub data: ImageKind,
533}
534
535/// Kind of the `feImage` data.
536#[derive(Clone, Debug)]
537pub enum ImageKind {
538 /// An image data.
539 Image(crate::ImageKind),
540
541 /// An SVG node.
542 Use(Box<Group>),
543}
544
545/// A diffuse lighting filter primitive.
546///
547/// `feDiffuseLighting` element in the SVG.
548#[derive(Clone, Debug)]
549pub struct DiffuseLighting {
550 /// Identifies input for the given filter primitive.
551 ///
552 /// `in` in the SVG.
553 pub input: Input,
554
555 /// A surface scale.
556 ///
557 /// `surfaceScale` in the SVG.
558 pub surface_scale: f32,
559
560 /// A diffuse constant.
561 ///
562 /// `diffuseConstant` in the SVG.
563 pub diffuse_constant: f32,
564
565 /// A lighting color.
566 ///
567 /// `lighting-color` in the SVG.
568 pub lighting_color: Color,
569
570 /// A light source.
571 pub light_source: LightSource,
572}
573
574/// A specular lighting filter primitive.
575///
576/// `feSpecularLighting` element in the SVG.
577#[derive(Clone, Debug)]
578pub struct SpecularLighting {
579 /// Identifies input for the given filter primitive.
580 ///
581 /// `in` in the SVG.
582 pub input: Input,
583
584 /// A surface scale.
585 ///
586 /// `surfaceScale` in the SVG.
587 pub surface_scale: f32,
588
589 /// A specular constant.
590 ///
591 /// `specularConstant` in the SVG.
592 pub specular_constant: f32,
593
594 /// A specular exponent.
595 ///
596 /// Should be in 1..128 range.
597 ///
598 /// `specularExponent` in the SVG.
599 pub specular_exponent: f32,
600
601 /// A lighting color.
602 ///
603 /// `lighting-color` in the SVG.
604 pub lighting_color: Color,
605
606 /// A light source.
607 pub light_source: LightSource,
608}
609
610/// A light source kind.
611#[allow(missing_docs)]
612#[derive(Clone, Copy, Debug)]
613pub enum LightSource {
614 DistantLight(DistantLight),
615 PointLight(PointLight),
616 SpotLight(SpotLight),
617}
618
619/// A distant light source.
620///
621/// `feDistantLight` element in the SVG.
622#[derive(Clone, Copy, Debug)]
623pub struct DistantLight {
624 /// Direction angle for the light source on the XY plane (clockwise),
625 /// in degrees from the x axis.
626 ///
627 /// `azimuth` in the SVG.
628 pub azimuth: f32,
629
630 /// Direction angle for the light source from the XY plane towards the z axis, in degrees.
631 ///
632 /// `elevation` in the SVG.
633 pub elevation: f32,
634}
635
636/// A point light source.
637///
638/// `fePointLight` element in the SVG.
639#[derive(Clone, Copy, Debug)]
640pub struct PointLight {
641 /// X location for the light source.
642 ///
643 /// `x` in the SVG.
644 pub x: f32,
645
646 /// Y location for the light source.
647 ///
648 /// `y` in the SVG.
649 pub y: f32,
650
651 /// Z location for the light source.
652 ///
653 /// `z` in the SVG.
654 pub z: f32,
655}
656
657/// A spot light source.
658///
659/// `feSpotLight` element in the SVG.
660#[derive(Clone, Copy, Debug)]
661pub struct SpotLight {
662 /// X location for the light source.
663 ///
664 /// `x` in the SVG.
665 pub x: f32,
666
667 /// Y location for the light source.
668 ///
669 /// `y` in the SVG.
670 pub y: f32,
671
672 /// Z location for the light source.
673 ///
674 /// `z` in the SVG.
675 pub z: f32,
676
677 /// X point at which the light source is pointing.
678 ///
679 /// `pointsAtX` in the SVG.
680 pub points_at_x: f32,
681
682 /// Y point at which the light source is pointing.
683 ///
684 /// `pointsAtY` in the SVG.
685 pub points_at_y: f32,
686
687 /// Z point at which the light source is pointing.
688 ///
689 /// `pointsAtZ` in the SVG.
690 pub points_at_z: f32,
691
692 /// Exponent value controlling the focus for the light source.
693 ///
694 /// `specularExponent` in the SVG.
695 pub specular_exponent: PositiveF32,
696
697 /// A limiting cone which restricts the region where the light is projected.
698 ///
699 /// `limitingConeAngle` in the SVG.
700 pub limiting_cone_angle: Option<f32>,
701}
702
703/// A merge filter primitive.
704///
705/// `feMerge` element in the SVG.
706#[derive(Clone, Debug)]
707pub struct Merge {
708 /// List of input layers that should be merged.
709 ///
710 /// List of `feMergeNode`'s in the SVG.
711 pub inputs: Vec<Input>,
712}
713
714/// A morphology filter primitive.
715///
716/// `feMorphology` element in the SVG.
717#[derive(Clone, Debug)]
718pub struct Morphology {
719 /// Identifies input for the given filter primitive.
720 ///
721 /// `in` in the SVG.
722 pub input: Input,
723
724 /// A filter operator.
725 ///
726 /// `operator` in the SVG.
727 pub operator: MorphologyOperator,
728
729 /// A filter radius along the X-axis.
730 ///
731 /// A value of zero disables the effect of the given filter primitive.
732 ///
733 /// `radius` in the SVG.
734 pub radius_x: PositiveF32,
735
736 /// A filter radius along the Y-axis.
737 ///
738 /// A value of zero disables the effect of the given filter primitive.
739 ///
740 /// `radius` in the SVG.
741 pub radius_y: PositiveF32,
742}
743
744/// A morphology operation.
745#[allow(missing_docs)]
746#[derive(Clone, Copy, PartialEq, Debug)]
747pub enum MorphologyOperator {
748 Erode,
749 Dilate,
750}
751
752/// An offset filter primitive.
753///
754/// `feOffset` element in the SVG.
755#[derive(Clone, Debug)]
756pub struct Offset {
757 /// Identifies input for the given filter primitive.
758 ///
759 /// `in` in the SVG.
760 pub input: Input,
761
762 /// The amount to offset the input graphic along the X-axis.
763 pub dx: f32,
764
765 /// The amount to offset the input graphic along the Y-axis.
766 pub dy: f32,
767}
768
769/// A tile filter primitive.
770///
771/// `feTile` element in the SVG.
772#[derive(Clone, Debug)]
773pub struct Tile {
774 /// Identifies input for the given filter primitive.
775 ///
776 /// `in` in the SVG.
777 pub input: Input,
778}
779
780/// A turbulence generation filter primitive.
781///
782/// `feTurbulence` element in the SVG.
783#[derive(Clone, Copy, Debug)]
784pub struct Turbulence {
785 /// Identifies the base frequency for the noise function.
786 ///
787 /// `baseFrequency` in the SVG.
788 pub base_frequency_x: PositiveF32,
789
790 /// Identifies the base frequency for the noise function.
791 ///
792 /// `baseFrequency` in the SVG.
793 pub base_frequency_y: PositiveF32,
794
795 /// Identifies the number of octaves for the noise function.
796 ///
797 /// `numOctaves` in the SVG.
798 pub num_octaves: u32,
799
800 /// The starting number for the pseudo random number generator.
801 ///
802 /// `seed` in the SVG.
803 pub seed: i32,
804
805 /// Smooth transitions at the border of tiles.
806 ///
807 /// `stitchTiles` in the SVG.
808 pub stitch_tiles: bool,
809
810 /// Indicates whether the filter primitive should perform a noise or turbulence function.
811 ///
812 /// `type` in the SVG.
813 pub kind: TurbulenceKind,
814}
815
816/// A turbulence kind for the `feTurbulence` filter.
817#[allow(missing_docs)]
818#[derive(Clone, Copy, PartialEq, Debug)]
819pub enum TurbulenceKind {
820 FractalNoise,
821 Turbulence,
822}