1use strict_num::PositiveF32;
7
8use crate::{BlendMode, Color, Group, NonEmptyString, NonZeroF32, NonZeroRect, Opacity};
9
10#[derive(Debug)]
14pub struct Filter {
15 pub(crate) id: NonEmptyString,
16 pub(crate) rect: NonZeroRect,
17 pub(crate) primitives: Vec<Primitive>,
18}
19
20impl Filter {
21 pub fn id(&self) -> &str {
26 self.id.get()
27 }
28
29 pub fn rect(&self) -> NonZeroRect {
33 self.rect
34 }
35
36 pub fn primitives(&self) -> &[Primitive] {
38 &self.primitives
39 }
40}
41
42#[derive(Clone, Debug)]
44pub struct Primitive {
45 pub(crate) rect: NonZeroRect,
46 pub(crate) color_interpolation: ColorInterpolation,
47 pub(crate) result: String,
48 pub(crate) kind: Kind,
49}
50
51impl Primitive {
52 pub fn rect(&self) -> NonZeroRect {
56 self.rect
57 }
58
59 pub fn color_interpolation(&self) -> ColorInterpolation {
63 self.color_interpolation
64 }
65
66 pub fn result(&self) -> &str {
70 &self.result
71 }
72
73 pub fn kind(&self) -> &Kind {
75 &self.kind
76 }
77}
78
79#[allow(missing_docs)]
81#[derive(Clone, Debug)]
82pub enum Kind {
83 Blend(Blend),
84 ColorMatrix(ColorMatrix),
85 ComponentTransfer(ComponentTransfer),
86 Composite(Composite),
87 ConvolveMatrix(ConvolveMatrix),
88 DiffuseLighting(DiffuseLighting),
89 DisplacementMap(DisplacementMap),
90 DropShadow(DropShadow),
91 Flood(Flood),
92 GaussianBlur(GaussianBlur),
93 Image(Image),
94 Merge(Merge),
95 Morphology(Morphology),
96 Offset(Offset),
97 SpecularLighting(SpecularLighting),
98 Tile(Tile),
99 Turbulence(Turbulence),
100}
101
102impl Kind {
103 pub fn has_input(&self, input: &Input) -> bool {
105 match self {
106 Kind::Blend(fe) => fe.input1 == *input || fe.input2 == *input,
107 Kind::ColorMatrix(fe) => fe.input == *input,
108 Kind::ComponentTransfer(fe) => fe.input == *input,
109 Kind::Composite(fe) => fe.input1 == *input || fe.input2 == *input,
110 Kind::ConvolveMatrix(fe) => fe.input == *input,
111 Kind::DiffuseLighting(fe) => fe.input == *input,
112 Kind::DisplacementMap(fe) => fe.input1 == *input || fe.input2 == *input,
113 Kind::DropShadow(fe) => fe.input == *input,
114 Kind::Flood(_) => false,
115 Kind::GaussianBlur(fe) => fe.input == *input,
116 Kind::Image(_) => false,
117 Kind::Merge(fe) => fe.inputs.iter().any(|i| i == input),
118 Kind::Morphology(fe) => fe.input == *input,
119 Kind::Offset(fe) => fe.input == *input,
120 Kind::SpecularLighting(fe) => fe.input == *input,
121 Kind::Tile(fe) => fe.input == *input,
122 Kind::Turbulence(_) => false,
123 }
124 }
125}
126
127#[allow(missing_docs)]
129#[derive(Clone, PartialEq, Debug)]
130pub enum Input {
131 SourceGraphic,
132 SourceAlpha,
133 Reference(String),
134}
135
136#[allow(missing_docs)]
140#[derive(Clone, Copy, PartialEq, Debug, Default)]
141pub enum ColorInterpolation {
142 SRGB,
143 #[default]
144 LinearRGB,
145}
146
147#[derive(Clone, Debug)]
151pub struct Blend {
152 pub(crate) input1: Input,
153 pub(crate) input2: Input,
154 pub(crate) mode: BlendMode,
155}
156
157impl Blend {
158 pub fn input1(&self) -> &Input {
162 &self.input1
163 }
164
165 pub fn input2(&self) -> &Input {
169 &self.input2
170 }
171
172 pub fn mode(&self) -> BlendMode {
176 self.mode
177 }
178}
179
180#[derive(Clone, Debug)]
184pub struct ColorMatrix {
185 pub(crate) input: Input,
186 pub(crate) kind: ColorMatrixKind,
187}
188
189impl ColorMatrix {
190 pub fn input(&self) -> &Input {
194 &self.input
195 }
196
197 pub fn kind(&self) -> &ColorMatrixKind {
201 &self.kind
202 }
203}
204
205#[derive(Clone, Debug)]
207#[allow(missing_docs)]
208pub enum ColorMatrixKind {
209 Matrix(Vec<f32>), Saturate(PositiveF32),
211 HueRotate(f32),
212 LuminanceToAlpha,
213}
214
215impl Default for ColorMatrixKind {
216 fn default() -> Self {
217 ColorMatrixKind::Matrix(vec![
218 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,
219 0.0, 1.0, 0.0,
220 ])
221 }
222}
223
224#[derive(Clone, Debug)]
228pub struct ComponentTransfer {
229 pub(crate) input: Input,
230 pub(crate) func_r: TransferFunction,
231 pub(crate) func_g: TransferFunction,
232 pub(crate) func_b: TransferFunction,
233 pub(crate) func_a: TransferFunction,
234}
235
236impl ComponentTransfer {
237 pub fn input(&self) -> &Input {
241 &self.input
242 }
243
244 pub fn func_r(&self) -> &TransferFunction {
246 &self.func_r
247 }
248
249 pub fn func_g(&self) -> &TransferFunction {
251 &self.func_g
252 }
253
254 pub fn func_b(&self) -> &TransferFunction {
256 &self.func_b
257 }
258
259 pub fn func_a(&self) -> &TransferFunction {
261 &self.func_a
262 }
263}
264
265#[derive(Clone, Debug)]
269pub enum TransferFunction {
270 Identity,
272
273 Table(Vec<f32>),
277
278 Discrete(Vec<f32>),
282
283 #[allow(missing_docs)]
285 Linear { slope: f32, intercept: f32 },
286
287 #[allow(missing_docs)]
289 Gamma {
290 amplitude: f32,
291 exponent: f32,
292 offset: f32,
293 },
294}
295
296#[derive(Clone, Debug)]
300pub struct Composite {
301 pub(crate) input1: Input,
302 pub(crate) input2: Input,
303 pub(crate) operator: CompositeOperator,
304}
305
306impl Composite {
307 pub fn input1(&self) -> &Input {
311 &self.input1
312 }
313
314 pub fn input2(&self) -> &Input {
318 &self.input2
319 }
320
321 pub fn operator(&self) -> CompositeOperator {
325 self.operator
326 }
327}
328
329#[allow(missing_docs)]
331#[derive(Clone, Copy, PartialEq, Debug)]
332pub enum CompositeOperator {
333 Over,
334 In,
335 Out,
336 Atop,
337 Xor,
338 Lighter,
339 Arithmetic { k1: f32, k2: f32, k3: f32, k4: f32 },
340}
341
342#[derive(Clone, Debug)]
346pub struct ConvolveMatrix {
347 pub(crate) input: Input,
348 pub(crate) matrix: ConvolveMatrixData,
349 pub(crate) divisor: NonZeroF32,
350 pub(crate) bias: f32,
351 pub(crate) edge_mode: EdgeMode,
352 pub(crate) preserve_alpha: bool,
353}
354
355impl ConvolveMatrix {
356 pub fn input(&self) -> &Input {
360 &self.input
361 }
362
363 pub fn matrix(&self) -> &ConvolveMatrixData {
365 &self.matrix
366 }
367
368 pub fn divisor(&self) -> NonZeroF32 {
372 self.divisor
373 }
374
375 pub fn bias(&self) -> f32 {
379 self.bias
380 }
381
382 pub fn edge_mode(&self) -> EdgeMode {
386 self.edge_mode
387 }
388
389 pub fn preserve_alpha(&self) -> bool {
393 self.preserve_alpha
394 }
395}
396
397#[derive(Clone, Debug)]
401pub struct ConvolveMatrixData {
402 pub(crate) target_x: u32,
403 pub(crate) target_y: u32,
404 pub(crate) columns: u32,
405 pub(crate) rows: u32,
406 pub(crate) data: Vec<f32>,
407}
408
409impl ConvolveMatrixData {
410 pub fn target_x(&self) -> u32 {
414 self.target_x
415 }
416
417 pub fn target_y(&self) -> u32 {
421 self.target_y
422 }
423
424 pub fn columns(&self) -> u32 {
428 self.columns
429 }
430
431 pub fn rows(&self) -> u32 {
435 self.rows
436 }
437
438 pub fn data(&self) -> &[f32] {
440 &self.data
441 }
442}
443
444impl ConvolveMatrixData {
445 pub(crate) fn new(
453 target_x: u32,
454 target_y: u32,
455 columns: u32,
456 rows: u32,
457 data: Vec<f32>,
458 ) -> Option<Self> {
459 if (columns * rows) as usize != data.len() || target_x >= columns || target_y >= rows {
460 return None;
461 }
462
463 Some(ConvolveMatrixData {
464 target_x,
465 target_y,
466 columns,
467 rows,
468 data,
469 })
470 }
471
472 pub fn get(&self, x: u32, y: u32) -> f32 {
478 self.data[(y * self.columns + x) as usize]
479 }
480}
481
482#[allow(missing_docs)]
484#[derive(Clone, Copy, PartialEq, Debug)]
485pub enum EdgeMode {
486 None,
487 Duplicate,
488 Wrap,
489}
490
491#[derive(Clone, Debug)]
495pub struct DisplacementMap {
496 pub(crate) input1: Input,
497 pub(crate) input2: Input,
498 pub(crate) scale: f32,
499 pub(crate) x_channel_selector: ColorChannel,
500 pub(crate) y_channel_selector: ColorChannel,
501}
502
503impl DisplacementMap {
504 pub fn input1(&self) -> &Input {
508 &self.input1
509 }
510
511 pub fn input2(&self) -> &Input {
515 &self.input2
516 }
517
518 pub fn scale(&self) -> f32 {
522 self.scale
523 }
524
525 pub fn x_channel_selector(&self) -> ColorChannel {
529 self.x_channel_selector
530 }
531
532 pub fn y_channel_selector(&self) -> ColorChannel {
536 self.y_channel_selector
537 }
538}
539
540#[allow(missing_docs)]
542#[derive(Clone, Copy, PartialEq, Debug)]
543pub enum ColorChannel {
544 R,
545 G,
546 B,
547 A,
548}
549
550#[derive(Clone, Debug)]
556pub struct DropShadow {
557 pub(crate) input: Input,
558 pub(crate) dx: f32,
559 pub(crate) dy: f32,
560 pub(crate) std_dev_x: PositiveF32,
561 pub(crate) std_dev_y: PositiveF32,
562 pub(crate) color: Color,
563 pub(crate) opacity: Opacity,
564}
565
566impl DropShadow {
567 pub fn input(&self) -> &Input {
571 &self.input
572 }
573
574 pub fn dx(&self) -> f32 {
576 self.dx
577 }
578
579 pub fn dy(&self) -> f32 {
581 self.dy
582 }
583
584 pub fn std_dev_x(&self) -> PositiveF32 {
588 self.std_dev_x
589 }
590
591 pub fn std_dev_y(&self) -> PositiveF32 {
595 self.std_dev_y
596 }
597
598 pub fn color(&self) -> Color {
602 self.color
603 }
604
605 pub fn opacity(&self) -> Opacity {
609 self.opacity
610 }
611}
612
613#[derive(Clone, Copy, Debug)]
617pub struct Flood {
618 pub(crate) color: Color,
619 pub(crate) opacity: Opacity,
620}
621
622impl Flood {
623 pub fn color(&self) -> Color {
627 self.color
628 }
629
630 pub fn opacity(&self) -> Opacity {
634 self.opacity
635 }
636}
637
638#[derive(Clone, Debug)]
642pub struct GaussianBlur {
643 pub(crate) input: Input,
644 pub(crate) std_dev_x: PositiveF32,
645 pub(crate) std_dev_y: PositiveF32,
646}
647
648impl GaussianBlur {
649 pub fn input(&self) -> &Input {
653 &self.input
654 }
655
656 pub fn std_dev_x(&self) -> PositiveF32 {
660 self.std_dev_x
661 }
662
663 pub fn std_dev_y(&self) -> PositiveF32 {
667 self.std_dev_y
668 }
669}
670
671#[derive(Clone, Debug)]
675pub struct Image {
676 pub(crate) root: Group,
677}
678
679impl Image {
680 pub fn root(&self) -> &Group {
682 &self.root
683 }
684}
685
686#[derive(Clone, Debug)]
690pub struct DiffuseLighting {
691 pub(crate) input: Input,
692 pub(crate) surface_scale: f32,
693 pub(crate) diffuse_constant: f32,
694 pub(crate) lighting_color: Color,
695 pub(crate) light_source: LightSource,
696}
697
698impl DiffuseLighting {
699 pub fn input(&self) -> &Input {
703 &self.input
704 }
705
706 pub fn surface_scale(&self) -> f32 {
710 self.surface_scale
711 }
712
713 pub fn diffuse_constant(&self) -> f32 {
717 self.diffuse_constant
718 }
719
720 pub fn lighting_color(&self) -> Color {
724 self.lighting_color
725 }
726
727 pub fn light_source(&self) -> LightSource {
729 self.light_source
730 }
731}
732
733#[derive(Clone, Debug)]
737pub struct SpecularLighting {
738 pub(crate) input: Input,
739 pub(crate) surface_scale: f32,
740 pub(crate) specular_constant: f32,
741 pub(crate) specular_exponent: f32,
742 pub(crate) lighting_color: Color,
743 pub(crate) light_source: LightSource,
744}
745
746impl SpecularLighting {
747 pub fn input(&self) -> &Input {
751 &self.input
752 }
753
754 pub fn surface_scale(&self) -> f32 {
758 self.surface_scale
759 }
760
761 pub fn specular_constant(&self) -> f32 {
765 self.specular_constant
766 }
767
768 pub fn specular_exponent(&self) -> f32 {
774 self.specular_exponent
775 }
776
777 pub fn lighting_color(&self) -> Color {
781 self.lighting_color
782 }
783
784 pub fn light_source(&self) -> LightSource {
786 self.light_source
787 }
788}
789
790#[allow(missing_docs)]
792#[derive(Clone, Copy, Debug)]
793pub enum LightSource {
794 DistantLight(DistantLight),
795 PointLight(PointLight),
796 SpotLight(SpotLight),
797}
798
799#[derive(Clone, Copy, Debug)]
803pub struct DistantLight {
804 pub azimuth: f32,
809
810 pub elevation: f32,
814}
815
816#[derive(Clone, Copy, Debug)]
820pub struct PointLight {
821 pub x: f32,
825
826 pub y: f32,
830
831 pub z: f32,
835}
836
837#[derive(Clone, Copy, Debug)]
841pub struct SpotLight {
842 pub x: f32,
846
847 pub y: f32,
851
852 pub z: f32,
856
857 pub points_at_x: f32,
861
862 pub points_at_y: f32,
866
867 pub points_at_z: f32,
871
872 pub specular_exponent: PositiveF32,
876
877 pub limiting_cone_angle: Option<f32>,
881}
882
883#[derive(Clone, Debug)]
887pub struct Merge {
888 pub(crate) inputs: Vec<Input>,
889}
890
891impl Merge {
892 pub fn inputs(&self) -> &[Input] {
896 &self.inputs
897 }
898}
899
900#[derive(Clone, Debug)]
904pub struct Morphology {
905 pub(crate) input: Input,
906 pub(crate) operator: MorphologyOperator,
907 pub(crate) radius_x: PositiveF32,
908 pub(crate) radius_y: PositiveF32,
909}
910
911impl Morphology {
912 pub fn input(&self) -> &Input {
916 &self.input
917 }
918
919 pub fn operator(&self) -> MorphologyOperator {
923 self.operator
924 }
925
926 pub fn radius_x(&self) -> PositiveF32 {
932 self.radius_x
933 }
934
935 pub fn radius_y(&self) -> PositiveF32 {
941 self.radius_y
942 }
943}
944
945#[allow(missing_docs)]
947#[derive(Clone, Copy, PartialEq, Debug)]
948pub enum MorphologyOperator {
949 Erode,
950 Dilate,
951}
952
953#[derive(Clone, Debug)]
957pub struct Offset {
958 pub(crate) input: Input,
959 pub(crate) dx: f32,
960 pub(crate) dy: f32,
961}
962
963impl Offset {
964 pub fn input(&self) -> &Input {
968 &self.input
969 }
970
971 pub fn dx(&self) -> f32 {
973 self.dx
974 }
975
976 pub fn dy(&self) -> f32 {
978 self.dy
979 }
980}
981
982#[derive(Clone, Debug)]
986pub struct Tile {
987 pub(crate) input: Input,
988}
989
990impl Tile {
991 pub fn input(&self) -> &Input {
995 &self.input
996 }
997}
998
999#[derive(Clone, Copy, Debug)]
1003pub struct Turbulence {
1004 pub(crate) base_frequency_x: PositiveF32,
1005 pub(crate) base_frequency_y: PositiveF32,
1006 pub(crate) num_octaves: u32,
1007 pub(crate) seed: i32,
1008 pub(crate) stitch_tiles: bool,
1009 pub(crate) kind: TurbulenceKind,
1010}
1011
1012impl Turbulence {
1013 pub fn base_frequency_x(&self) -> PositiveF32 {
1017 self.base_frequency_x
1018 }
1019
1020 pub fn base_frequency_y(&self) -> PositiveF32 {
1024 self.base_frequency_y
1025 }
1026
1027 pub fn num_octaves(&self) -> u32 {
1031 self.num_octaves
1032 }
1033
1034 pub fn seed(&self) -> i32 {
1038 self.seed
1039 }
1040
1041 pub fn stitch_tiles(&self) -> bool {
1045 self.stitch_tiles
1046 }
1047
1048 pub fn kind(&self) -> TurbulenceKind {
1052 self.kind
1053 }
1054}
1055
1056#[allow(missing_docs)]
1058#[derive(Clone, Copy, PartialEq, Debug)]
1059pub enum TurbulenceKind {
1060 FractalNoise,
1061 Turbulence,
1062}