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}