1use std::ptr;
2
3use skia_bindings::{self as sb, SkImageFilter, SkRect};
4
5use crate::{
6 prelude::*, scalar, Blender, Color, Color4f, ColorChannel, ColorFilter, ColorSpace,
7 CubicResampler, IPoint, IRect, ISize, Image, ImageFilter, Matrix, Picture, Point3, Rect,
8 SamplingOptions, Shader, TileMode, Vector,
9};
10
11#[repr(C)]
15#[derive(Copy, Clone, PartialEq, Debug)]
16pub struct CropRect(Option<Rect>);
17
18impl CropRect {
19 pub const NO_CROP_RECT: CropRect = CropRect(None);
20
21 pub fn rect(&self) -> Option<Rect> {
22 self.0
23 }
24
25 fn native(&self) -> *const SkRect {
26 match &self.0 {
27 None => ptr::null(),
28 Some(r) => r.native(),
29 }
30 }
31}
32
33impl Default for CropRect {
34 fn default() -> Self {
35 CropRect::NO_CROP_RECT
36 }
37}
38
39impl From<Option<CropRect>> for CropRect {
40 fn from(opt: Option<CropRect>) -> Self {
41 opt.unwrap_or(Self::NO_CROP_RECT)
42 }
43}
44
45impl From<&CropRect> for CropRect {
46 fn from(cr: &CropRect) -> Self {
47 *cr
48 }
49}
50
51impl From<IRect> for CropRect {
52 fn from(r: IRect) -> Self {
53 Self(Some(Rect::from(r)))
54 }
55}
56
57impl From<&IRect> for CropRect {
58 fn from(r: &IRect) -> Self {
59 Self::from(*r)
60 }
61}
62
63impl From<Rect> for CropRect {
64 fn from(r: Rect) -> Self {
65 Self(Some(r))
66 }
67}
68
69impl From<&Rect> for CropRect {
70 fn from(r: &Rect) -> Self {
71 Self(Some(*r))
72 }
73}
74
75#[allow(clippy::too_many_arguments)]
84pub fn arithmetic(
85 k1: scalar,
86 k2: scalar,
87 k3: scalar,
88 k4: scalar,
89 enforce_pm_color: bool,
90 background: impl Into<Option<ImageFilter>>,
91 foreground: impl Into<Option<ImageFilter>>,
92 crop_rect: impl Into<CropRect>,
93) -> Option<ImageFilter> {
94 ImageFilter::from_ptr(unsafe {
95 sb::C_SkImageFilters_Arithmetic(
96 k1,
97 k2,
98 k3,
99 k4,
100 enforce_pm_color,
101 background.into().into_ptr_or_null(),
102 foreground.into().into_ptr_or_null(),
103 crop_rect.into().native(),
104 )
105 })
106}
107
108pub fn blend(
114 mode: impl Into<Blender>,
115 background: impl Into<Option<ImageFilter>>,
116 foreground: impl Into<Option<ImageFilter>>,
117 crop_rect: impl Into<CropRect>,
118) -> Option<ImageFilter> {
119 ImageFilter::from_ptr(unsafe {
120 sb::C_SkImageFilters_Blend(
121 mode.into().into_ptr(),
122 background.into().into_ptr_or_null(),
123 foreground.into().into_ptr_or_null(),
124 crop_rect.into().native(),
125 )
126 })
127}
128
129pub fn blur(
137 (sigma_x, sigma_y): (scalar, scalar),
138 tile_mode: impl Into<Option<TileMode>>,
139 input: impl Into<Option<ImageFilter>>,
140 crop_rect: impl Into<CropRect>,
141) -> Option<ImageFilter> {
142 ImageFilter::from_ptr(unsafe {
143 sb::C_SkImageFilters_Blur(
144 sigma_x,
145 sigma_y,
146 tile_mode.into().unwrap_or(TileMode::Decal),
147 input.into().into_ptr_or_null(),
148 crop_rect.into().native(),
149 )
150 })
151}
152
153pub fn color_filter(
154 cf: impl Into<ColorFilter>,
155 input: impl Into<Option<ImageFilter>>,
156 crop_rect: impl Into<CropRect>,
157) -> Option<ImageFilter> {
158 ImageFilter::from_ptr(unsafe {
159 sb::C_SkImageFilters_ColorFilter(
160 cf.into().into_ptr(),
161 input.into().into_ptr_or_null(),
162 crop_rect.into().native(),
163 )
164 })
165}
166
167pub fn compose(
172 outer: impl Into<ImageFilter>,
173 inner: impl Into<ImageFilter>,
174) -> Option<ImageFilter> {
175 ImageFilter::from_ptr(unsafe {
176 sb::C_SkImageFilters_Compose(outer.into().into_ptr(), inner.into().into_ptr())
177 })
178}
179
180pub fn crop(
188 rect: impl AsRef<Rect>,
189 tile_mode: impl Into<Option<TileMode>>,
190 input: impl Into<Option<ImageFilter>>,
191) -> Option<ImageFilter> {
192 ImageFilter::from_ptr(unsafe {
193 sb::C_SkImageFilters_Crop(
194 rect.as_ref().native(),
195 tile_mode.into().unwrap_or(TileMode::Decal),
196 input.into().into_ptr_or_null(),
197 )
198 })
199}
200
201pub fn displacement_map(
213 (x_channel_selector, y_channel_selector): (ColorChannel, ColorChannel),
214 scale: scalar,
215 displacement: impl Into<Option<ImageFilter>>,
216 color: impl Into<Option<ImageFilter>>,
217 crop_rect: impl Into<CropRect>,
218) -> Option<ImageFilter> {
219 ImageFilter::from_ptr(unsafe {
220 sb::C_SkImageFilters_DisplacementMap(
221 x_channel_selector,
222 y_channel_selector,
223 scale,
224 displacement.into().into_ptr_or_null(),
225 color.into().into_ptr_or_null(),
226 crop_rect.into().native(),
227 )
228 })
229}
230
231pub fn drop_shadow(
241 offset: impl Into<Vector>,
242 (sigma_x, sigma_y): (scalar, scalar),
243 color: impl Into<Color4f>,
244 color_space: impl Into<Option<ColorSpace>>,
245 input: impl Into<Option<ImageFilter>>,
246 crop_rect: impl Into<CropRect>,
247) -> Option<ImageFilter> {
248 let delta = offset.into();
249 ImageFilter::from_ptr(unsafe {
250 sb::C_SkImageFilters_DropShadow(
251 delta.x,
252 delta.y,
253 sigma_x,
254 sigma_y,
255 color.into().native(),
256 color_space.into().into_ptr_or_null(),
257 input.into().into_ptr_or_null(),
258 crop_rect.into().native(),
259 )
260 })
261}
262
263pub fn drop_shadow_only(
274 offset: impl Into<Vector>,
275 (sigma_x, sigma_y): (scalar, scalar),
276 color: impl Into<Color4f>,
277 color_space: impl Into<Option<ColorSpace>>,
278 input: impl Into<Option<ImageFilter>>,
279 crop_rect: impl Into<CropRect>,
280) -> Option<ImageFilter> {
281 let delta = offset.into();
282
283 ImageFilter::from_ptr(unsafe {
284 sb::C_SkImageFilters_DropShadowOnly(
285 delta.x,
286 delta.y,
287 sigma_x,
288 sigma_y,
289 color.into().native(),
290 color_space.into().into_ptr_or_null(),
291 input.into().into_ptr_or_null(),
292 crop_rect.into().native(),
293 )
294 })
295}
296
297pub fn empty() -> ImageFilter {
299 ImageFilter::from_ptr(unsafe { sb::C_SkImageFilters_Empty() }).unwrap()
300}
301pub fn image<'a>(
309 image: impl Into<Image>,
310 src_rect: impl Into<Option<&'a Rect>>,
311 dst_rect: impl Into<Option<&'a Rect>>,
312 sampling: impl Into<Option<SamplingOptions>>,
313) -> Option<ImageFilter> {
314 let image = image.into();
315 let image_rect = Rect::from_iwh(image.width(), image.height());
316 let src_rect = src_rect.into().unwrap_or(&image_rect);
317 let dst_rect = dst_rect.into().unwrap_or(&image_rect);
318 let sampling_options: SamplingOptions = sampling.into().unwrap_or_else(|| {
319 CubicResampler {
320 b: 1.0 / 3.0,
321 c: 1.0 / 3.0,
322 }
323 .into()
324 });
325
326 ImageFilter::from_ptr(unsafe {
327 sb::C_SkImageFilters_Image(
328 image.into_ptr(),
329 src_rect.as_ref().native(),
330 dst_rect.as_ref().native(),
331 sampling_options.native(),
332 )
333 })
334}
335
336pub fn magnifier(
345 lens_bounds: impl AsRef<Rect>,
346 zoom_amount: scalar,
347 inset: scalar,
348 sampling: SamplingOptions,
349 input: impl Into<Option<ImageFilter>>,
350 crop_rect: impl Into<CropRect>,
351) -> Option<ImageFilter> {
352 ImageFilter::from_ptr(unsafe {
353 sb::C_SkImageFilters_Magnifier(
354 lens_bounds.as_ref().native(),
355 zoom_amount,
356 inset,
357 sampling.native(),
358 input.into().into_ptr_or_null(),
359 crop_rect.into().native(),
360 )
361 })
362}
363
364#[allow(clippy::too_many_arguments)]
380pub fn matrix_convolution(
381 kernel_size: impl Into<ISize>,
382 kernel: &[scalar],
383 gain: scalar,
384 bias: scalar,
385 kernel_offset: impl Into<IPoint>,
386 tile_mode: TileMode,
387 convolve_alpha: bool,
388 input: impl Into<Option<ImageFilter>>,
389 crop_rect: impl Into<CropRect>,
390) -> Option<ImageFilter> {
391 let kernel_size = kernel_size.into();
392 assert_eq!(
393 (kernel_size.width * kernel_size.height) as usize,
394 kernel.len()
395 );
396 ImageFilter::from_ptr(unsafe {
397 sb::C_SkImageFilters_MatrixConvolution(
398 kernel_size.native(),
399 kernel.as_ptr(),
400 gain,
401 bias,
402 kernel_offset.into().native(),
403 tile_mode,
404 convolve_alpha,
405 input.into().into_ptr_or_null(),
406 crop_rect.into().native(),
407 )
408 })
409}
410
411pub fn matrix_transform(
418 matrix: &Matrix,
419 sampling: impl Into<SamplingOptions>,
420 input: impl Into<Option<ImageFilter>>,
421) -> Option<ImageFilter> {
422 ImageFilter::from_ptr(unsafe {
423 sb::C_SkImageFilters_MatrixTransform(
424 matrix.native(),
425 sampling.into().native(),
426 input.into().into_ptr_or_null(),
427 )
428 })
429}
430
431pub fn merge(
437 filters: impl IntoIterator<Item = Option<ImageFilter>>,
438 crop_rect: impl Into<CropRect>,
439) -> Option<ImageFilter> {
440 let filter_ptrs: Vec<*mut SkImageFilter> =
441 filters.into_iter().map(|f| f.into_ptr_or_null()).collect();
442 ImageFilter::from_ptr(unsafe {
443 sb::C_SkImageFilters_Merge(
444 filter_ptrs.as_ptr(),
445 filter_ptrs.len().try_into().unwrap(),
446 crop_rect.into().native(),
447 )
448 })
449}
450
451pub fn offset(
456 offset: impl Into<Vector>,
457 input: impl Into<Option<ImageFilter>>,
458 crop_rect: impl Into<CropRect>,
459) -> Option<ImageFilter> {
460 let delta = offset.into();
461 ImageFilter::from_ptr(unsafe {
462 sb::C_SkImageFilters_Offset(
463 delta.x,
464 delta.y,
465 input.into().into_ptr_or_null(),
466 crop_rect.into().native(),
467 )
468 })
469}
470
471pub fn picture<'a>(
477 pic: impl Into<Picture>,
478 target_rect: impl Into<Option<&'a Rect>>,
479) -> Option<ImageFilter> {
480 let picture = pic.into();
481 let picture_rect = picture.cull_rect();
482 let target_rect = target_rect.into().unwrap_or(&picture_rect);
483
484 ImageFilter::from_ptr(unsafe {
485 sb::C_SkImageFilters_Picture(picture.into_ptr(), target_rect.native())
486 })
487}
488
489pub fn runtime_shader(
490 builder: &RuntimeShaderBuilder,
491 child_shader_name: impl AsRef<str>,
492 input: impl Into<Option<ImageFilter>>,
493) -> Option<ImageFilter> {
494 let child_shader_name = child_shader_name.as_ref();
495 unsafe {
496 ImageFilter::from_ptr(sb::C_SkImageFilters_RuntimeShader(
497 builder.native() as *const _,
498 child_shader_name.as_ptr() as *const _,
499 child_shader_name.len(),
500 input.into().into_ptr_or_null(),
501 ))
502 }
503}
504
505pub use skia_bindings::SkImageFilters_Dither as Dither;
506
507use super::runtime_effect::RuntimeShaderBuilder;
508variant_name!(Dither::Yes);
509
510pub fn shader(shader: impl Into<Shader>, crop_rect: impl Into<CropRect>) -> Option<ImageFilter> {
520 shader_with_dither(shader, Dither::No, crop_rect)
521}
522
523pub fn shader_with_dither(
524 shader: impl Into<Shader>,
525 dither: Dither,
526 crop_rect: impl Into<CropRect>,
527) -> Option<ImageFilter> {
528 ImageFilter::from_ptr(unsafe {
529 sb::C_SkImageFilters_Shader(shader.into().into_ptr(), dither, crop_rect.into().native())
530 })
531}
532
533pub fn tile(
538 src: impl AsRef<Rect>,
539 dst: impl AsRef<Rect>,
540 input: impl Into<Option<ImageFilter>>,
541) -> Option<ImageFilter> {
542 ImageFilter::from_ptr(unsafe {
543 sb::C_SkImageFilters_Tile(
544 src.as_ref().native(),
545 dst.as_ref().native(),
546 input.into().into_ptr_or_null(),
547 )
548 })
549}
550
551pub fn dilate(
558 (radius_x, radius_y): (scalar, scalar),
559 input: impl Into<Option<ImageFilter>>,
560 crop_rect: impl Into<CropRect>,
561) -> Option<ImageFilter> {
562 ImageFilter::from_ptr(unsafe {
563 sb::C_SkImageFilters_Dilate(
564 radius_x,
565 radius_y,
566 input.into().into_ptr_or_null(),
567 crop_rect.into().native(),
568 )
569 })
570}
571
572pub fn erode(
579 (radius_x, radius_y): (scalar, scalar),
580 input: impl Into<Option<ImageFilter>>,
581 crop_rect: impl Into<CropRect>,
582) -> Option<ImageFilter> {
583 ImageFilter::from_ptr(unsafe {
584 sb::C_SkImageFilters_Erode(
585 radius_x,
586 radius_y,
587 input.into().into_ptr_or_null(),
588 crop_rect.into().native(),
589 )
590 })
591}
592
593pub fn distant_lit_diffuse(
604 direction: impl Into<Point3>,
605 light_color: impl Into<Color>,
606 surface_scale: scalar,
607 kd: scalar,
608 input: impl Into<Option<ImageFilter>>,
609 crop_rect: impl Into<CropRect>,
610) -> Option<ImageFilter> {
611 ImageFilter::from_ptr(unsafe {
612 sb::C_SkImageFilters_DistantLitDiffuse(
613 direction.into().native(),
614 light_color.into().into_native(),
615 surface_scale,
616 kd,
617 input.into().into_ptr_or_null(),
618 crop_rect.into().native(),
619 )
620 })
621}
622
623pub fn point_lit_diffuse(
634 location: impl Into<Point3>,
635 light_color: impl Into<Color>,
636 surface_scale: scalar,
637 kd: scalar,
638 input: impl Into<Option<ImageFilter>>,
639 crop_rect: impl Into<CropRect>,
640) -> Option<ImageFilter> {
641 ImageFilter::from_ptr(unsafe {
642 sb::C_SkImageFilters_PointLitDiffuse(
643 location.into().native(),
644 light_color.into().into_native(),
645 surface_scale,
646 kd,
647 input.into().into_ptr_or_null(),
648 crop_rect.into().native(),
649 )
650 })
651}
652
653#[allow(clippy::too_many_arguments)]
668pub fn spot_lit_diffuse(
669 location: impl Into<Point3>,
670 target: impl Into<Point3>,
671 falloff_exponent: scalar,
672 cutoff_angle: scalar,
673 light_color: impl Into<Color>,
674 surface_scale: scalar,
675 kd: scalar,
676 input: impl Into<Option<ImageFilter>>,
677 crop_rect: impl Into<CropRect>,
678) -> Option<ImageFilter> {
679 ImageFilter::from_ptr(unsafe {
680 sb::C_SkImageFilters_SpotLitDiffuse(
681 location.into().native(),
682 target.into().native(),
683 falloff_exponent,
684 cutoff_angle,
685 light_color.into().into_native(),
686 surface_scale,
687 kd,
688 input.into().into_ptr_or_null(),
689 crop_rect.into().native(),
690 )
691 })
692}
693
694pub fn distant_lit_specular(
706 direction: impl Into<Point3>,
707 light_color: impl Into<Color>,
708 surface_scale: scalar,
709 ks: scalar,
710 shininess: scalar,
711 input: impl Into<Option<ImageFilter>>,
712 crop_rect: impl Into<CropRect>,
713) -> Option<ImageFilter> {
714 ImageFilter::from_ptr(unsafe {
715 sb::C_ImageFilters_DistantLitSpecular(
716 direction.into().native(),
717 light_color.into().into_native(),
718 surface_scale,
719 ks,
720 shininess,
721 input.into().into_ptr_or_null(),
722 crop_rect.into().native(),
723 )
724 })
725}
726
727pub fn point_lit_specular(
739 location: impl Into<Point3>,
740 light_color: impl Into<Color>,
741 surface_scale: scalar,
742 ks: scalar,
743 shininess: scalar,
744 input: impl Into<Option<ImageFilter>>,
745 crop_rect: impl Into<CropRect>,
746) -> Option<ImageFilter> {
747 ImageFilter::from_ptr(unsafe {
748 sb::C_SkImageFilters_PointLitSpecular(
749 location.into().native(),
750 light_color.into().into_native(),
751 surface_scale,
752 ks,
753 shininess,
754 input.into().into_ptr_or_null(),
755 crop_rect.into().native(),
756 )
757 })
758}
759
760#[allow(clippy::too_many_arguments)]
776pub fn spot_lit_specular(
777 location: impl Into<Point3>,
778 target: impl Into<Point3>,
779 falloff_exponent: scalar,
780 cutoff_angle: scalar,
781 light_color: impl Into<Color>,
782 surface_scale: scalar,
783 ks: scalar,
784 shininess: scalar,
785 input: impl Into<Option<ImageFilter>>,
786 crop_rect: impl Into<CropRect>,
787) -> Option<ImageFilter> {
788 ImageFilter::from_ptr(unsafe {
789 sb::C_SkImageFilters_SpotLitSpecular(
790 location.into().native(),
791 target.into().native(),
792 falloff_exponent,
793 cutoff_angle,
794 light_color.into().into_native(),
795 surface_scale,
796 ks,
797 shininess,
798 input.into().into_ptr_or_null(),
799 crop_rect.into().native(),
800 )
801 })
802}
803
804impl ImageFilter {
805 pub fn arithmetic<'a>(
807 inputs: impl Into<ArithmeticFPInputs>,
808 background: impl Into<Option<Self>>,
809 foreground: impl Into<Option<Self>>,
810 crop_rect: impl Into<Option<&'a IRect>>,
811 ) -> Option<Self> {
812 let inputs = inputs.into();
813 arithmetic(
814 inputs.k[0],
815 inputs.k[1],
816 inputs.k[2],
817 inputs.k[3],
818 inputs.enforce_pm_color,
819 background,
820 foreground,
821 crop_rect.into().map(|r| r.into()),
822 )
823 }
824
825 pub fn blur<'a>(
827 self,
828 crop_rect: impl Into<Option<&'a IRect>>,
829 sigma: (scalar, scalar),
830 tile_mode: impl Into<Option<crate::TileMode>>,
831 ) -> Option<Self> {
832 blur(sigma, tile_mode, self, crop_rect.into().map(|r| r.into()))
833 }
834
835 pub fn color_filter<'a>(
837 self,
838 crop_rect: impl Into<Option<&'a IRect>>,
839 cf: impl Into<ColorFilter>,
840 ) -> Option<Self> {
841 color_filter(cf, self, crop_rect.into().map(|r| r.into()))
842 }
843
844 pub fn compose(outer: impl Into<ImageFilter>, inner: impl Into<ImageFilter>) -> Option<Self> {
846 compose(outer, inner)
847 }
848
849 pub fn crop(
851 rect: impl AsRef<Rect>,
852 tile_mode: impl Into<Option<TileMode>>,
853 input: impl Into<Option<ImageFilter>>,
854 ) -> Option<ImageFilter> {
855 crop(rect, tile_mode, input)
856 }
857
858 pub fn displacement_map_effect<'a>(
860 channel_selectors: (ColorChannel, ColorChannel),
861 scale: scalar,
862 displacement: impl Into<Option<ImageFilter>>,
863 color: impl Into<Option<ImageFilter>>,
864 crop_rect: impl Into<Option<&'a IRect>>,
865 ) -> Option<Self> {
866 displacement_map(
867 channel_selectors,
868 scale,
869 displacement,
870 color,
871 crop_rect.into().map(|r| r.into()),
872 )
873 }
874
875 pub fn distant_lit_diffuse_lighting<'a>(
877 self,
878 crop_rect: impl Into<Option<&'a IRect>>,
879 direction: impl Into<Point3>,
880 light_color: impl Into<Color>,
881 surface_scale: scalar,
882 kd: scalar,
883 ) -> Option<Self> {
884 distant_lit_diffuse(
885 direction,
886 light_color,
887 surface_scale,
888 kd,
889 self,
890 crop_rect.into().map(|r| r.into()),
891 )
892 }
893
894 pub fn point_lit_diffuse_lighting<'a>(
896 self,
897 crop_rect: impl Into<Option<&'a IRect>>,
898 location: impl Into<Point3>,
899 light_color: impl Into<Color>,
900 surface_scale: scalar,
901 kd: scalar,
902 ) -> Option<Self> {
903 point_lit_diffuse(
904 location,
905 light_color,
906 surface_scale,
907 kd,
908 self,
909 crop_rect.into().map(|r| r.into()),
910 )
911 }
912
913 #[allow(clippy::too_many_arguments)]
915 pub fn spot_lit_diffuse_lighting<'a>(
916 self,
917 crop_rect: impl Into<Option<&'a IRect>>,
918 location: impl Into<Point3>,
919 target: impl Into<Point3>,
920 specular_exponent: scalar,
921 cutoff_angle: scalar,
922 light_color: impl Into<Color>,
923 surface_scale: scalar,
924 kd: scalar,
925 ) -> Option<Self> {
926 spot_lit_diffuse(
927 location,
928 target,
929 specular_exponent,
930 cutoff_angle,
931 light_color,
932 surface_scale,
933 kd,
934 self,
935 crop_rect.into().map(|r| r.into()),
936 )
937 }
938
939 pub fn distant_lit_specular_lighting<'a>(
941 self,
942 crop_rect: impl Into<Option<&'a IRect>>,
943 direction: impl Into<Point3>,
944 light_color: impl Into<Color>,
945 surface_scale: scalar,
946 ks: scalar,
947 shininess: scalar,
948 ) -> Option<Self> {
949 distant_lit_specular(
950 direction,
951 light_color,
952 surface_scale,
953 ks,
954 shininess,
955 self,
956 crop_rect.into().map(|r| r.into()),
957 )
958 }
959
960 pub fn point_lit_specular_lighting<'a>(
962 self,
963 crop_rect: impl Into<Option<&'a IRect>>,
964 location: impl Into<Point3>,
965 light_color: impl Into<Color>,
966 surface_scale: scalar,
967 ks: scalar,
968 shininess: scalar,
969 ) -> Option<Self> {
970 point_lit_specular(
971 location,
972 light_color,
973 surface_scale,
974 ks,
975 shininess,
976 self,
977 crop_rect.into().map(|r| r.into()),
978 )
979 }
980
981 #[allow(clippy::too_many_arguments)]
983 pub fn spot_lit_specular_lighting<'a>(
984 self,
985 crop_rect: impl Into<Option<&'a IRect>>,
986 location: impl Into<Point3>,
987 target: impl Into<Point3>,
988 specular_exponent: scalar,
989 cutoff_angle: scalar,
990 light_color: impl Into<Color>,
991 surface_scale: scalar,
992 ks: scalar,
993 shininess: scalar,
994 ) -> Option<Self> {
995 spot_lit_specular(
996 location,
997 target,
998 specular_exponent,
999 cutoff_angle,
1000 light_color,
1001 surface_scale,
1002 ks,
1003 shininess,
1004 self,
1005 crop_rect.into().map(|r| r.into()),
1006 )
1007 }
1008
1009 pub fn magnifier<'a>(
1011 self,
1012 lens_bounds: impl AsRef<Rect>,
1013 zoom_amount: scalar,
1014 inset: scalar,
1015 sampling_options: SamplingOptions,
1016 crop_rect: impl Into<Option<&'a IRect>>,
1017 ) -> Option<Self> {
1018 magnifier(
1019 lens_bounds,
1020 zoom_amount,
1021 inset,
1022 sampling_options,
1023 self,
1024 crop_rect.into().map(|r| r.into()),
1025 )
1026 }
1027
1028 #[allow(clippy::too_many_arguments)]
1030 pub fn matrix_convolution<'a>(
1031 self,
1032 crop_rect: impl Into<Option<&'a IRect>>,
1033 kernel_size: impl Into<ISize>,
1034 kernel: &[scalar],
1035 gain: scalar,
1036 bias: scalar,
1037 kernel_offset: impl Into<IPoint>,
1038 tile_mode: crate::TileMode,
1039 convolve_alpha: bool,
1040 ) -> Option<Self> {
1041 matrix_convolution(
1042 kernel_size,
1043 kernel,
1044 gain,
1045 bias,
1046 kernel_offset,
1047 tile_mode,
1048 convolve_alpha,
1049 self,
1050 crop_rect.into().map(|r| r.into()),
1051 )
1052 }
1053
1054 pub fn merge<'a>(
1056 filters: impl IntoIterator<Item = Option<Self>>,
1057 crop_rect: impl Into<Option<&'a IRect>>,
1058 ) -> Option<Self> {
1059 merge(filters, crop_rect.into().map(|r| r.into()))
1060 }
1061
1062 pub fn dilate<'a>(
1064 self,
1065 crop_rect: impl Into<Option<&'a IRect>>,
1066 radii: (scalar, scalar),
1067 ) -> Option<Self> {
1068 dilate(radii, self, crop_rect.into().map(|r| r.into()))
1069 }
1070
1071 pub fn erode<'a>(
1073 self,
1074 crop_rect: impl Into<Option<&'a IRect>>,
1075 radii: (scalar, scalar),
1076 ) -> Option<Self> {
1077 erode(radii, self, crop_rect.into().map(|r| r.into()))
1078 }
1079
1080 pub fn offset<'a>(
1082 self,
1083 crop_rect: impl Into<Option<&'a IRect>>,
1084 delta: impl Into<Vector>,
1085 ) -> Option<Self> {
1086 offset(delta, self, crop_rect.into().map(|r| r.into()))
1087 }
1088
1089 pub fn from_picture<'a>(
1091 picture: impl Into<Picture>,
1092 crop_rect: impl Into<Option<&'a Rect>>,
1093 ) -> Option<Self> {
1094 self::picture(picture, crop_rect)
1095 }
1096
1097 pub fn tile(self, src: impl AsRef<Rect>, dst: impl AsRef<Rect>) -> Option<Self> {
1099 tile(src, dst, self)
1100 }
1101}
1102
1103#[derive(Copy, Clone, PartialEq, Debug)]
1104pub struct ArithmeticFPInputs {
1105 pub k: [f32; 4],
1106 pub enforce_pm_color: bool,
1107}
1108
1109impl From<([f32; 4], bool)> for ArithmeticFPInputs {
1110 fn from((k, enforce_pm_color): ([f32; 4], bool)) -> Self {
1111 ArithmeticFPInputs {
1112 k,
1113 enforce_pm_color,
1114 }
1115 }
1116}
1117
1118impl ArithmeticFPInputs {
1119 pub fn new(k0: f32, k1: f32, k2: f32, k3: f32, enforce_pm_color: bool) -> Self {
1120 Self {
1121 k: [k0, k1, k2, k3],
1122 enforce_pm_color,
1123 }
1124 }
1125}
1126
1127impl Picture {
1128 pub fn as_image_filter<'a>(
1129 &self,
1130 crop_rect: impl Into<Option<&'a Rect>>,
1131 ) -> Option<ImageFilter> {
1132 self.clone().into_image_filter(crop_rect)
1133 }
1134
1135 pub fn into_image_filter<'a>(
1136 self,
1137 crop_rect: impl Into<Option<&'a Rect>>,
1138 ) -> Option<ImageFilter> {
1139 picture(self, crop_rect)
1140 }
1141}
1142
1143#[cfg(test)]
1144mod tests {
1145 use super::CropRect;
1146 use crate::{IRect, Rect};
1147
1148 fn cr(crop_rect: impl Into<CropRect>) -> CropRect {
1149 crop_rect.into()
1150 }
1151
1152 #[test]
1153 fn test_crop_conversion_options() {
1154 assert_eq!(cr(None), CropRect::NO_CROP_RECT);
1155 assert_eq!(cr(CropRect::NO_CROP_RECT), CropRect::NO_CROP_RECT);
1156 #[allow(clippy::needless_borrow)]
1157 let cr_ref = cr(CropRect::NO_CROP_RECT);
1158 assert_eq!(cr_ref, CropRect::NO_CROP_RECT);
1159 let irect = IRect {
1160 left: 1,
1161 top: 2,
1162 right: 3,
1163 bottom: 4,
1164 };
1165 assert_eq!(cr(irect), CropRect(Some(Rect::from(irect))));
1166 #[allow(clippy::needless_borrow)]
1167 let cr_by_ref = cr(irect);
1168 assert_eq!(cr_by_ref, CropRect(Some(Rect::from(irect))));
1169 let rect = Rect {
1170 left: 1.0,
1171 top: 2.0,
1172 right: 3.0,
1173 bottom: 4.0,
1174 };
1175 assert_eq!(cr(rect), CropRect(Some(rect)));
1176 #[allow(clippy::needless_borrow)]
1177 let cr_by_ref = cr(rect);
1178 assert_eq!(cr_by_ref, CropRect(Some(rect)));
1179 }
1180
1181 #[test]
1182 fn test_drop_shadow_only() {
1183 let rect = Rect {
1184 left: 1.0,
1185 top: 2.0,
1186 right: 3.0,
1187 bottom: 4.0,
1188 };
1189
1190 let _ = super::drop_shadow_only((10., 10.), (1.0, 1.0), 0x404040, None, None, rect);
1191 }
1192}