1use alloc::string::String;
7use alloc::vec;
8use alloc::vec::Vec;
9use strict_num::PositiveF32;
10
11use crate::{BlendMode, Color, Group, NonEmptyString, NonZeroF32, NonZeroRect, Opacity};
12
13#[derive(Debug)]
17pub struct Filter {
18 pub(crate) id: NonEmptyString,
19 pub(crate) rect: NonZeroRect,
20 pub(crate) primitives: Vec<Primitive>,
21}
22
23impl Filter {
24 pub fn id(&self) -> &str {
29 self.id.get()
30 }
31
32 pub fn rect(&self) -> NonZeroRect {
36 self.rect
37 }
38
39 pub fn primitives(&self) -> &[Primitive] {
41 &self.primitives
42 }
43}
44
45#[derive(Clone, Debug)]
47pub struct Primitive {
48 pub(crate) rect: NonZeroRect,
49 pub(crate) color_interpolation: ColorInterpolation,
50 pub(crate) result: String,
51 pub(crate) kind: Kind,
52}
53
54impl Primitive {
55 pub fn rect(&self) -> NonZeroRect {
59 self.rect
60 }
61
62 pub fn color_interpolation(&self) -> ColorInterpolation {
66 self.color_interpolation
67 }
68
69 pub fn result(&self) -> &str {
73 &self.result
74 }
75
76 pub fn kind(&self) -> &Kind {
78 &self.kind
79 }
80}
81
82#[allow(missing_docs)]
84#[derive(Clone, Debug)]
85pub enum Kind {
86 Blend(Blend),
87 ColorMatrix(ColorMatrix),
88 ComponentTransfer(ComponentTransfer),
89 Composite(Composite),
90 ConvolveMatrix(ConvolveMatrix),
91 DiffuseLighting(DiffuseLighting),
92 DisplacementMap(DisplacementMap),
93 DropShadow(DropShadow),
94 Flood(Flood),
95 GaussianBlur(GaussianBlur),
96 Image(Image),
97 Merge(Merge),
98 Morphology(Morphology),
99 Offset(Offset),
100 SpecularLighting(SpecularLighting),
101 Tile(Tile),
102 Turbulence(Turbulence),
103}
104
105impl Kind {
106 pub fn has_input(&self, input: &Input) -> bool {
108 match self {
109 Kind::Blend(fe) => fe.input1 == *input || fe.input2 == *input,
110 Kind::ColorMatrix(fe) => fe.input == *input,
111 Kind::ComponentTransfer(fe) => fe.input == *input,
112 Kind::Composite(fe) => fe.input1 == *input || fe.input2 == *input,
113 Kind::ConvolveMatrix(fe) => fe.input == *input,
114 Kind::DiffuseLighting(fe) => fe.input == *input,
115 Kind::DisplacementMap(fe) => fe.input1 == *input || fe.input2 == *input,
116 Kind::DropShadow(fe) => fe.input == *input,
117 Kind::Flood(_) => false,
118 Kind::GaussianBlur(fe) => fe.input == *input,
119 Kind::Image(_) => false,
120 Kind::Merge(fe) => fe.inputs.iter().any(|i| i == input),
121 Kind::Morphology(fe) => fe.input == *input,
122 Kind::Offset(fe) => fe.input == *input,
123 Kind::SpecularLighting(fe) => fe.input == *input,
124 Kind::Tile(fe) => fe.input == *input,
125 Kind::Turbulence(_) => false,
126 }
127 }
128}
129
130#[allow(missing_docs)]
132#[derive(Clone, PartialEq, Debug)]
133pub enum Input {
134 SourceGraphic,
135 SourceAlpha,
136 Reference(String),
137}
138
139#[allow(missing_docs)]
143#[derive(Clone, Copy, PartialEq, Debug, Default)]
144pub enum ColorInterpolation {
145 SRGB,
146 #[default]
147 LinearRGB,
148}
149
150#[derive(Clone, Debug)]
154pub struct Blend {
155 pub(crate) input1: Input,
156 pub(crate) input2: Input,
157 pub(crate) mode: BlendMode,
158}
159
160impl Blend {
161 pub fn input1(&self) -> &Input {
165 &self.input1
166 }
167
168 pub fn input2(&self) -> &Input {
172 &self.input2
173 }
174
175 pub fn mode(&self) -> BlendMode {
179 self.mode
180 }
181}
182
183#[derive(Clone, Debug)]
187pub struct ColorMatrix {
188 pub(crate) input: Input,
189 pub(crate) kind: ColorMatrixKind,
190}
191
192impl ColorMatrix {
193 pub fn input(&self) -> &Input {
197 &self.input
198 }
199
200 pub fn kind(&self) -> &ColorMatrixKind {
204 &self.kind
205 }
206}
207
208#[derive(Clone, Debug)]
210#[allow(missing_docs)]
211pub enum ColorMatrixKind {
212 Matrix(Vec<f32>), Saturate(PositiveF32),
214 HueRotate(f32),
215 LuminanceToAlpha,
216}
217
218impl Default for ColorMatrixKind {
219 fn default() -> Self {
220 ColorMatrixKind::Matrix(vec![
221 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,
222 0.0, 1.0, 0.0,
223 ])
224 }
225}
226
227#[derive(Clone, Debug)]
231pub struct ComponentTransfer {
232 pub(crate) input: Input,
233 pub(crate) func_r: TransferFunction,
234 pub(crate) func_g: TransferFunction,
235 pub(crate) func_b: TransferFunction,
236 pub(crate) func_a: TransferFunction,
237}
238
239impl ComponentTransfer {
240 pub fn input(&self) -> &Input {
244 &self.input
245 }
246
247 pub fn func_r(&self) -> &TransferFunction {
249 &self.func_r
250 }
251
252 pub fn func_g(&self) -> &TransferFunction {
254 &self.func_g
255 }
256
257 pub fn func_b(&self) -> &TransferFunction {
259 &self.func_b
260 }
261
262 pub fn func_a(&self) -> &TransferFunction {
264 &self.func_a
265 }
266}
267
268#[derive(Clone, Debug)]
272pub enum TransferFunction {
273 Identity,
275
276 Table(Vec<f32>),
280
281 Discrete(Vec<f32>),
285
286 #[allow(missing_docs)]
288 Linear { slope: f32, intercept: f32 },
289
290 #[allow(missing_docs)]
292 Gamma {
293 amplitude: f32,
294 exponent: f32,
295 offset: f32,
296 },
297}
298
299#[derive(Clone, Debug)]
303pub struct Composite {
304 pub(crate) input1: Input,
305 pub(crate) input2: Input,
306 pub(crate) operator: CompositeOperator,
307}
308
309impl Composite {
310 pub fn input1(&self) -> &Input {
314 &self.input1
315 }
316
317 pub fn input2(&self) -> &Input {
321 &self.input2
322 }
323
324 pub fn operator(&self) -> CompositeOperator {
328 self.operator
329 }
330}
331
332#[allow(missing_docs)]
334#[derive(Clone, Copy, PartialEq, Debug)]
335pub enum CompositeOperator {
336 Over,
337 In,
338 Out,
339 Atop,
340 Xor,
341 Arithmetic { k1: f32, k2: f32, k3: f32, k4: f32 },
342}
343
344#[derive(Clone, Debug)]
348pub struct ConvolveMatrix {
349 pub(crate) input: Input,
350 pub(crate) matrix: ConvolveMatrixData,
351 pub(crate) divisor: NonZeroF32,
352 pub(crate) bias: f32,
353 pub(crate) edge_mode: EdgeMode,
354 pub(crate) preserve_alpha: bool,
355}
356
357impl ConvolveMatrix {
358 pub fn input(&self) -> &Input {
362 &self.input
363 }
364
365 pub fn matrix(&self) -> &ConvolveMatrixData {
367 &self.matrix
368 }
369
370 pub fn divisor(&self) -> NonZeroF32 {
374 self.divisor
375 }
376
377 pub fn bias(&self) -> f32 {
381 self.bias
382 }
383
384 pub fn edge_mode(&self) -> EdgeMode {
388 self.edge_mode
389 }
390
391 pub fn preserve_alpha(&self) -> bool {
395 self.preserve_alpha
396 }
397}
398
399#[derive(Clone, Debug)]
403pub struct ConvolveMatrixData {
404 pub(crate) target_x: u32,
405 pub(crate) target_y: u32,
406 pub(crate) columns: u32,
407 pub(crate) rows: u32,
408 pub(crate) data: Vec<f32>,
409}
410
411impl ConvolveMatrixData {
412 pub fn target_x(&self) -> u32 {
416 self.target_x
417 }
418
419 pub fn target_y(&self) -> u32 {
423 self.target_y
424 }
425
426 pub fn columns(&self) -> u32 {
430 self.columns
431 }
432
433 pub fn rows(&self) -> u32 {
437 self.rows
438 }
439
440 pub fn data(&self) -> &[f32] {
442 &self.data
443 }
444}
445
446impl ConvolveMatrixData {
447 pub(crate) fn new(
455 target_x: u32,
456 target_y: u32,
457 columns: u32,
458 rows: u32,
459 data: Vec<f32>,
460 ) -> Option<Self> {
461 if (columns * rows) as usize != data.len() || target_x >= columns || target_y >= rows {
462 return None;
463 }
464
465 Some(ConvolveMatrixData {
466 target_x,
467 target_y,
468 columns,
469 rows,
470 data,
471 })
472 }
473
474 pub fn get(&self, x: u32, y: u32) -> f32 {
480 self.data[(y * self.columns + x) as usize]
481 }
482}
483
484#[allow(missing_docs)]
486#[derive(Clone, Copy, PartialEq, Debug)]
487pub enum EdgeMode {
488 None,
489 Duplicate,
490 Wrap,
491}
492
493#[derive(Clone, Debug)]
497pub struct DisplacementMap {
498 pub(crate) input1: Input,
499 pub(crate) input2: Input,
500 pub(crate) scale: f32,
501 pub(crate) x_channel_selector: ColorChannel,
502 pub(crate) y_channel_selector: ColorChannel,
503}
504
505impl DisplacementMap {
506 pub fn input1(&self) -> &Input {
510 &self.input1
511 }
512
513 pub fn input2(&self) -> &Input {
517 &self.input2
518 }
519
520 pub fn scale(&self) -> f32 {
524 self.scale
525 }
526
527 pub fn x_channel_selector(&self) -> ColorChannel {
531 self.x_channel_selector
532 }
533
534 pub fn y_channel_selector(&self) -> ColorChannel {
538 self.y_channel_selector
539 }
540}
541
542#[allow(missing_docs)]
544#[derive(Clone, Copy, PartialEq, Debug)]
545pub enum ColorChannel {
546 R,
547 G,
548 B,
549 A,
550}
551
552#[derive(Clone, Debug)]
558pub struct DropShadow {
559 pub(crate) input: Input,
560 pub(crate) dx: f32,
561 pub(crate) dy: f32,
562 pub(crate) std_dev_x: PositiveF32,
563 pub(crate) std_dev_y: PositiveF32,
564 pub(crate) color: Color,
565 pub(crate) opacity: Opacity,
566}
567
568impl DropShadow {
569 pub fn input(&self) -> &Input {
573 &self.input
574 }
575
576 pub fn dx(&self) -> f32 {
578 self.dx
579 }
580
581 pub fn dy(&self) -> f32 {
583 self.dy
584 }
585
586 pub fn std_dev_x(&self) -> PositiveF32 {
590 self.std_dev_x
591 }
592
593 pub fn std_dev_y(&self) -> PositiveF32 {
597 self.std_dev_y
598 }
599
600 pub fn color(&self) -> Color {
604 self.color
605 }
606
607 pub fn opacity(&self) -> Opacity {
611 self.opacity
612 }
613}
614
615#[derive(Clone, Copy, Debug)]
619pub struct Flood {
620 pub(crate) color: Color,
621 pub(crate) opacity: Opacity,
622}
623
624impl Flood {
625 pub fn color(&self) -> Color {
629 self.color
630 }
631
632 pub fn opacity(&self) -> Opacity {
636 self.opacity
637 }
638}
639
640#[derive(Clone, Debug)]
644pub struct GaussianBlur {
645 pub(crate) input: Input,
646 pub(crate) std_dev_x: PositiveF32,
647 pub(crate) std_dev_y: PositiveF32,
648}
649
650impl GaussianBlur {
651 pub fn input(&self) -> &Input {
655 &self.input
656 }
657
658 pub fn std_dev_x(&self) -> PositiveF32 {
662 self.std_dev_x
663 }
664
665 pub fn std_dev_y(&self) -> PositiveF32 {
669 self.std_dev_y
670 }
671}
672
673#[derive(Clone, Debug)]
677pub struct Image {
678 pub(crate) root: Group,
679}
680
681impl Image {
682 pub fn root(&self) -> &Group {
684 &self.root
685 }
686}
687
688#[derive(Clone, Debug)]
692pub struct DiffuseLighting {
693 pub(crate) input: Input,
694 pub(crate) surface_scale: f32,
695 pub(crate) diffuse_constant: f32,
696 pub(crate) lighting_color: Color,
697 pub(crate) light_source: LightSource,
698}
699
700impl DiffuseLighting {
701 pub fn input(&self) -> &Input {
705 &self.input
706 }
707
708 pub fn surface_scale(&self) -> f32 {
712 self.surface_scale
713 }
714
715 pub fn diffuse_constant(&self) -> f32 {
719 self.diffuse_constant
720 }
721
722 pub fn lighting_color(&self) -> Color {
726 self.lighting_color
727 }
728
729 pub fn light_source(&self) -> LightSource {
731 self.light_source
732 }
733}
734
735#[derive(Clone, Debug)]
739pub struct SpecularLighting {
740 pub(crate) input: Input,
741 pub(crate) surface_scale: f32,
742 pub(crate) specular_constant: f32,
743 pub(crate) specular_exponent: f32,
744 pub(crate) lighting_color: Color,
745 pub(crate) light_source: LightSource,
746}
747
748impl SpecularLighting {
749 pub fn input(&self) -> &Input {
753 &self.input
754 }
755
756 pub fn surface_scale(&self) -> f32 {
760 self.surface_scale
761 }
762
763 pub fn specular_constant(&self) -> f32 {
767 self.specular_constant
768 }
769
770 pub fn specular_exponent(&self) -> f32 {
776 self.specular_exponent
777 }
778
779 pub fn lighting_color(&self) -> Color {
783 self.lighting_color
784 }
785
786 pub fn light_source(&self) -> LightSource {
788 self.light_source
789 }
790}
791
792#[allow(missing_docs)]
794#[derive(Clone, Copy, Debug)]
795pub enum LightSource {
796 DistantLight(DistantLight),
797 PointLight(PointLight),
798 SpotLight(SpotLight),
799}
800
801#[derive(Clone, Copy, Debug)]
805pub struct DistantLight {
806 pub azimuth: f32,
811
812 pub elevation: f32,
816}
817
818#[derive(Clone, Copy, Debug)]
822pub struct PointLight {
823 pub x: f32,
827
828 pub y: f32,
832
833 pub z: f32,
837}
838
839#[derive(Clone, Copy, Debug)]
843pub struct SpotLight {
844 pub x: f32,
848
849 pub y: f32,
853
854 pub z: f32,
858
859 pub points_at_x: f32,
863
864 pub points_at_y: f32,
868
869 pub points_at_z: f32,
873
874 pub specular_exponent: PositiveF32,
878
879 pub limiting_cone_angle: Option<f32>,
883}
884
885#[derive(Clone, Debug)]
889pub struct Merge {
890 pub(crate) inputs: Vec<Input>,
891}
892
893impl Merge {
894 pub fn inputs(&self) -> &[Input] {
898 &self.inputs
899 }
900}
901
902#[derive(Clone, Debug)]
906pub struct Morphology {
907 pub(crate) input: Input,
908 pub(crate) operator: MorphologyOperator,
909 pub(crate) radius_x: PositiveF32,
910 pub(crate) radius_y: PositiveF32,
911}
912
913impl Morphology {
914 pub fn input(&self) -> &Input {
918 &self.input
919 }
920
921 pub fn operator(&self) -> MorphologyOperator {
925 self.operator
926 }
927
928 pub fn radius_x(&self) -> PositiveF32 {
934 self.radius_x
935 }
936
937 pub fn radius_y(&self) -> PositiveF32 {
943 self.radius_y
944 }
945}
946
947#[allow(missing_docs)]
949#[derive(Clone, Copy, PartialEq, Debug)]
950pub enum MorphologyOperator {
951 Erode,
952 Dilate,
953}
954
955#[derive(Clone, Debug)]
959pub struct Offset {
960 pub(crate) input: Input,
961 pub(crate) dx: f32,
962 pub(crate) dy: f32,
963}
964
965impl Offset {
966 pub fn input(&self) -> &Input {
970 &self.input
971 }
972
973 pub fn dx(&self) -> f32 {
975 self.dx
976 }
977
978 pub fn dy(&self) -> f32 {
980 self.dy
981 }
982}
983
984#[derive(Clone, Debug)]
988pub struct Tile {
989 pub(crate) input: Input,
990}
991
992impl Tile {
993 pub fn input(&self) -> &Input {
997 &self.input
998 }
999}
1000
1001#[derive(Clone, Copy, Debug)]
1005pub struct Turbulence {
1006 pub(crate) base_frequency_x: PositiveF32,
1007 pub(crate) base_frequency_y: PositiveF32,
1008 pub(crate) num_octaves: u32,
1009 pub(crate) seed: i32,
1010 pub(crate) stitch_tiles: bool,
1011 pub(crate) kind: TurbulenceKind,
1012}
1013
1014impl Turbulence {
1015 pub fn base_frequency_x(&self) -> PositiveF32 {
1019 self.base_frequency_x
1020 }
1021
1022 pub fn base_frequency_y(&self) -> PositiveF32 {
1026 self.base_frequency_y
1027 }
1028
1029 pub fn num_octaves(&self) -> u32 {
1033 self.num_octaves
1034 }
1035
1036 pub fn seed(&self) -> i32 {
1040 self.seed
1041 }
1042
1043 pub fn stitch_tiles(&self) -> bool {
1047 self.stitch_tiles
1048 }
1049
1050 pub fn kind(&self) -> TurbulenceKind {
1054 self.kind
1055 }
1056}
1057
1058#[allow(missing_docs)]
1060#[derive(Clone, Copy, PartialEq, Debug)]
1061pub enum TurbulenceKind {
1062 FractalNoise,
1063 Turbulence,
1064}