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(ref fe) => fe.input1 == *input || fe.input2 == *input,
107 Kind::ColorMatrix(ref fe) => fe.input == *input,
108 Kind::ComponentTransfer(ref fe) => fe.input == *input,
109 Kind::Composite(ref fe) => fe.input1 == *input || fe.input2 == *input,
110 Kind::ConvolveMatrix(ref fe) => fe.input == *input,
111 Kind::DiffuseLighting(ref fe) => fe.input == *input,
112 Kind::DisplacementMap(ref fe) => fe.input1 == *input || fe.input2 == *input,
113 Kind::DropShadow(ref fe) => fe.input == *input,
114 Kind::Flood(_) => false,
115 Kind::GaussianBlur(ref fe) => fe.input == *input,
116 Kind::Image(_) => false,
117 Kind::Merge(ref fe) => fe.inputs.iter().any(|i| i == input),
118 Kind::Morphology(ref fe) => fe.input == *input,
119 Kind::Offset(ref fe) => fe.input == *input,
120 Kind::SpecularLighting(ref fe) => fe.input == *input,
121 Kind::Tile(ref 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 Arithmetic { k1: f32, k2: f32, k3: f32, k4: f32 },
339}
340
341#[derive(Clone, Debug)]
345pub struct ConvolveMatrix {
346 pub(crate) input: Input,
347 pub(crate) matrix: ConvolveMatrixData,
348 pub(crate) divisor: NonZeroF32,
349 pub(crate) bias: f32,
350 pub(crate) edge_mode: EdgeMode,
351 pub(crate) preserve_alpha: bool,
352}
353
354impl ConvolveMatrix {
355 pub fn input(&self) -> &Input {
359 &self.input
360 }
361
362 pub fn matrix(&self) -> &ConvolveMatrixData {
364 &self.matrix
365 }
366
367 pub fn divisor(&self) -> NonZeroF32 {
371 self.divisor
372 }
373
374 pub fn bias(&self) -> f32 {
378 self.bias
379 }
380
381 pub fn edge_mode(&self) -> EdgeMode {
385 self.edge_mode
386 }
387
388 pub fn preserve_alpha(&self) -> bool {
392 self.preserve_alpha
393 }
394}
395
396#[derive(Clone, Debug)]
400pub struct ConvolveMatrixData {
401 pub(crate) target_x: u32,
402 pub(crate) target_y: u32,
403 pub(crate) columns: u32,
404 pub(crate) rows: u32,
405 pub(crate) data: Vec<f32>,
406}
407
408impl ConvolveMatrixData {
409 pub fn target_x(&self) -> u32 {
413 self.target_x
414 }
415
416 pub fn target_y(&self) -> u32 {
420 self.target_y
421 }
422
423 pub fn columns(&self) -> u32 {
427 self.columns
428 }
429
430 pub fn rows(&self) -> u32 {
434 self.rows
435 }
436
437 pub fn data(&self) -> &[f32] {
439 &self.data
440 }
441}
442
443impl ConvolveMatrixData {
444 pub(crate) fn new(
452 target_x: u32,
453 target_y: u32,
454 columns: u32,
455 rows: u32,
456 data: Vec<f32>,
457 ) -> Option<Self> {
458 if (columns * rows) as usize != data.len() || target_x >= columns || target_y >= rows {
459 return None;
460 }
461
462 Some(ConvolveMatrixData {
463 target_x,
464 target_y,
465 columns,
466 rows,
467 data,
468 })
469 }
470
471 pub fn get(&self, x: u32, y: u32) -> f32 {
477 self.data[(y * self.columns + x) as usize]
478 }
479}
480
481#[allow(missing_docs)]
483#[derive(Clone, Copy, PartialEq, Debug)]
484pub enum EdgeMode {
485 None,
486 Duplicate,
487 Wrap,
488}
489
490#[derive(Clone, Debug)]
494pub struct DisplacementMap {
495 pub(crate) input1: Input,
496 pub(crate) input2: Input,
497 pub(crate) scale: f32,
498 pub(crate) x_channel_selector: ColorChannel,
499 pub(crate) y_channel_selector: ColorChannel,
500}
501
502impl DisplacementMap {
503 pub fn input1(&self) -> &Input {
507 &self.input1
508 }
509
510 pub fn input2(&self) -> &Input {
514 &self.input2
515 }
516
517 pub fn scale(&self) -> f32 {
521 self.scale
522 }
523
524 pub fn x_channel_selector(&self) -> ColorChannel {
528 self.x_channel_selector
529 }
530
531 pub fn y_channel_selector(&self) -> ColorChannel {
535 self.y_channel_selector
536 }
537}
538
539#[allow(missing_docs)]
541#[derive(Clone, Copy, PartialEq, Debug)]
542pub enum ColorChannel {
543 R,
544 G,
545 B,
546 A,
547}
548
549#[derive(Clone, Debug)]
555pub struct DropShadow {
556 pub(crate) input: Input,
557 pub(crate) dx: f32,
558 pub(crate) dy: f32,
559 pub(crate) std_dev_x: PositiveF32,
560 pub(crate) std_dev_y: PositiveF32,
561 pub(crate) color: Color,
562 pub(crate) opacity: Opacity,
563}
564
565impl DropShadow {
566 pub fn input(&self) -> &Input {
570 &self.input
571 }
572
573 pub fn dx(&self) -> f32 {
575 self.dx
576 }
577
578 pub fn dy(&self) -> f32 {
580 self.dy
581 }
582
583 pub fn std_dev_x(&self) -> PositiveF32 {
587 self.std_dev_x
588 }
589
590 pub fn std_dev_y(&self) -> PositiveF32 {
594 self.std_dev_y
595 }
596
597 pub fn color(&self) -> Color {
601 self.color
602 }
603
604 pub fn opacity(&self) -> Opacity {
608 self.opacity
609 }
610}
611
612#[derive(Clone, Copy, Debug)]
616pub struct Flood {
617 pub(crate) color: Color,
618 pub(crate) opacity: Opacity,
619}
620
621impl Flood {
622 pub fn color(&self) -> Color {
626 self.color
627 }
628
629 pub fn opacity(&self) -> Opacity {
633 self.opacity
634 }
635}
636
637#[derive(Clone, Debug)]
641pub struct GaussianBlur {
642 pub(crate) input: Input,
643 pub(crate) std_dev_x: PositiveF32,
644 pub(crate) std_dev_y: PositiveF32,
645}
646
647impl GaussianBlur {
648 pub fn input(&self) -> &Input {
652 &self.input
653 }
654
655 pub fn std_dev_x(&self) -> PositiveF32 {
659 self.std_dev_x
660 }
661
662 pub fn std_dev_y(&self) -> PositiveF32 {
666 self.std_dev_y
667 }
668}
669
670#[derive(Clone, Debug)]
674pub struct Image {
675 pub(crate) root: Group,
676}
677
678impl Image {
679 pub fn root(&self) -> &Group {
681 &self.root
682 }
683}
684
685#[derive(Clone, Debug)]
689pub struct DiffuseLighting {
690 pub(crate) input: Input,
691 pub(crate) surface_scale: f32,
692 pub(crate) diffuse_constant: f32,
693 pub(crate) lighting_color: Color,
694 pub(crate) light_source: LightSource,
695}
696
697impl DiffuseLighting {
698 pub fn input(&self) -> &Input {
702 &self.input
703 }
704
705 pub fn surface_scale(&self) -> f32 {
709 self.surface_scale
710 }
711
712 pub fn diffuse_constant(&self) -> f32 {
716 self.diffuse_constant
717 }
718
719 pub fn lighting_color(&self) -> Color {
723 self.lighting_color
724 }
725
726 pub fn light_source(&self) -> LightSource {
728 self.light_source
729 }
730}
731
732#[derive(Clone, Debug)]
736pub struct SpecularLighting {
737 pub(crate) input: Input,
738 pub(crate) surface_scale: f32,
739 pub(crate) specular_constant: f32,
740 pub(crate) specular_exponent: f32,
741 pub(crate) lighting_color: Color,
742 pub(crate) light_source: LightSource,
743}
744
745impl SpecularLighting {
746 pub fn input(&self) -> &Input {
750 &self.input
751 }
752
753 pub fn surface_scale(&self) -> f32 {
757 self.surface_scale
758 }
759
760 pub fn specular_constant(&self) -> f32 {
764 self.specular_constant
765 }
766
767 pub fn specular_exponent(&self) -> f32 {
773 self.specular_exponent
774 }
775
776 pub fn lighting_color(&self) -> Color {
780 self.lighting_color
781 }
782
783 pub fn light_source(&self) -> LightSource {
785 self.light_source
786 }
787}
788
789#[allow(missing_docs)]
791#[derive(Clone, Copy, Debug)]
792pub enum LightSource {
793 DistantLight(DistantLight),
794 PointLight(PointLight),
795 SpotLight(SpotLight),
796}
797
798#[derive(Clone, Copy, Debug)]
802pub struct DistantLight {
803 pub azimuth: f32,
808
809 pub elevation: f32,
813}
814
815#[derive(Clone, Copy, Debug)]
819pub struct PointLight {
820 pub x: f32,
824
825 pub y: f32,
829
830 pub z: f32,
834}
835
836#[derive(Clone, Copy, Debug)]
840pub struct SpotLight {
841 pub x: f32,
845
846 pub y: f32,
850
851 pub z: f32,
855
856 pub points_at_x: f32,
860
861 pub points_at_y: f32,
865
866 pub points_at_z: f32,
870
871 pub specular_exponent: PositiveF32,
875
876 pub limiting_cone_angle: Option<f32>,
880}
881
882#[derive(Clone, Debug)]
886pub struct Merge {
887 pub(crate) inputs: Vec<Input>,
888}
889
890impl Merge {
891 pub fn inputs(&self) -> &[Input] {
895 &self.inputs
896 }
897}
898
899#[derive(Clone, Debug)]
903pub struct Morphology {
904 pub(crate) input: Input,
905 pub(crate) operator: MorphologyOperator,
906 pub(crate) radius_x: PositiveF32,
907 pub(crate) radius_y: PositiveF32,
908}
909
910impl Morphology {
911 pub fn input(&self) -> &Input {
915 &self.input
916 }
917
918 pub fn operator(&self) -> MorphologyOperator {
922 self.operator
923 }
924
925 pub fn radius_x(&self) -> PositiveF32 {
931 self.radius_x
932 }
933
934 pub fn radius_y(&self) -> PositiveF32 {
940 self.radius_y
941 }
942}
943
944#[allow(missing_docs)]
946#[derive(Clone, Copy, PartialEq, Debug)]
947pub enum MorphologyOperator {
948 Erode,
949 Dilate,
950}
951
952#[derive(Clone, Debug)]
956pub struct Offset {
957 pub(crate) input: Input,
958 pub(crate) dx: f32,
959 pub(crate) dy: f32,
960}
961
962impl Offset {
963 pub fn input(&self) -> &Input {
967 &self.input
968 }
969
970 pub fn dx(&self) -> f32 {
972 self.dx
973 }
974
975 pub fn dy(&self) -> f32 {
977 self.dy
978 }
979}
980
981#[derive(Clone, Debug)]
985pub struct Tile {
986 pub(crate) input: Input,
987}
988
989impl Tile {
990 pub fn input(&self) -> &Input {
994 &self.input
995 }
996}
997
998#[derive(Clone, Copy, Debug)]
1002pub struct Turbulence {
1003 pub(crate) base_frequency_x: PositiveF32,
1004 pub(crate) base_frequency_y: PositiveF32,
1005 pub(crate) num_octaves: u32,
1006 pub(crate) seed: i32,
1007 pub(crate) stitch_tiles: bool,
1008 pub(crate) kind: TurbulenceKind,
1009}
1010
1011impl Turbulence {
1012 pub fn base_frequency_x(&self) -> PositiveF32 {
1016 self.base_frequency_x
1017 }
1018
1019 pub fn base_frequency_y(&self) -> PositiveF32 {
1023 self.base_frequency_y
1024 }
1025
1026 pub fn num_octaves(&self) -> u32 {
1030 self.num_octaves
1031 }
1032
1033 pub fn seed(&self) -> i32 {
1037 self.seed
1038 }
1039
1040 pub fn stitch_tiles(&self) -> bool {
1044 self.stitch_tiles
1045 }
1046
1047 pub fn kind(&self) -> TurbulenceKind {
1051 self.kind
1052 }
1053}
1054
1055#[allow(missing_docs)]
1057#[derive(Clone, Copy, PartialEq, Debug)]
1058pub enum TurbulenceKind {
1059 FractalNoise,
1060 Turbulence,
1061}