gardesk/garbg / 4fe782c

Browse files

add scale_image_fast using Triangle filter for animation frames

Authored by espadonne
SHA
4fe782c8ca2c6344ac7843cd87e1e38feda760f1
Parents
8d66b98
Tree
edffbe3

2 changed files

StatusFile+-
M garbg/src/media/mod.rs 1 1
M garbg/src/media/scaler.rs 33 13
garbg/src/media/mod.rsmodified
@@ -13,7 +13,7 @@ mod frame_buffer;
13
 mod video;
13
 mod video;
14
 
14
 
15
 pub use loader::ImageLoader;
15
 pub use loader::ImageLoader;
16
-pub use scaler::scale_image;
16
+pub use scaler::{scale_image, scale_image_fast};
17
 pub use gif::{AnimatedGif, AnimationFrame, is_animated_gif};
17
 pub use gif::{AnimatedGif, AnimationFrame, is_animated_gif};
18
 pub use webp::{AnimatedWebP, is_animated_webp, is_animated_webp_bytes};
18
 pub use webp::{AnimatedWebP, is_animated_webp, is_animated_webp_bytes};
19
 pub use apng::{AnimatedPng, is_animated_png, is_animated_png_bytes};
19
 pub use apng::{AnimatedPng, is_animated_png, is_animated_png_bytes};
garbg/src/media/scaler.rsmodified
@@ -4,24 +4,44 @@ use image::{imageops::FilterType, RgbaImage};
4
 
4
 
5
 use crate::config::ScaleMode;
5
 use crate::config::ScaleMode;
6
 
6
 
7
-/// Scale an image according to the specified mode
7
+/// Scale an image according to the specified mode (high quality, Lanczos3)
8
 pub fn scale_image(
8
 pub fn scale_image(
9
     image: &RgbaImage,
9
     image: &RgbaImage,
10
     target_width: u32,
10
     target_width: u32,
11
     target_height: u32,
11
     target_height: u32,
12
     mode: ScaleMode,
12
     mode: ScaleMode,
13
+) -> RgbaImage {
14
+    scale_image_inner(image, target_width, target_height, mode, FilterType::Lanczos3)
15
+}
16
+
17
+/// Scale an image using a fast filter (Triangle) — suited for animation frames
18
+pub fn scale_image_fast(
19
+    image: &RgbaImage,
20
+    target_width: u32,
21
+    target_height: u32,
22
+    mode: ScaleMode,
23
+) -> RgbaImage {
24
+    scale_image_inner(image, target_width, target_height, mode, FilterType::Triangle)
25
+}
26
+
27
+fn scale_image_inner(
28
+    image: &RgbaImage,
29
+    target_width: u32,
30
+    target_height: u32,
31
+    mode: ScaleMode,
32
+    filter: FilterType,
13
 ) -> RgbaImage {
33
 ) -> RgbaImage {
14
     match mode {
34
     match mode {
15
-        ScaleMode::Fill => scale_fill(image, target_width, target_height),
35
+        ScaleMode::Fill => scale_fill(image, target_width, target_height, filter),
16
-        ScaleMode::Fit => scale_fit(image, target_width, target_height),
36
+        ScaleMode::Fit => scale_fit(image, target_width, target_height, filter),
17
-        ScaleMode::Stretch => scale_stretch(image, target_width, target_height),
37
+        ScaleMode::Stretch => scale_stretch(image, target_width, target_height, filter),
18
         ScaleMode::Center => scale_center(image, target_width, target_height),
38
         ScaleMode::Center => scale_center(image, target_width, target_height),
19
         ScaleMode::Tile => scale_tile(image, target_width, target_height),
39
         ScaleMode::Tile => scale_tile(image, target_width, target_height),
20
     }
40
     }
21
 }
41
 }
22
 
42
 
23
 /// Fill: Scale to cover entire area, crop excess
43
 /// Fill: Scale to cover entire area, crop excess
24
-fn scale_fill(image: &RgbaImage, target_width: u32, target_height: u32) -> RgbaImage {
44
+fn scale_fill(image: &RgbaImage, target_width: u32, target_height: u32, filter: FilterType) -> RgbaImage {
25
     let (src_width, src_height) = image.dimensions();
45
     let (src_width, src_height) = image.dimensions();
26
 
46
 
27
     // Calculate scale factor to cover the entire target
47
     // Calculate scale factor to cover the entire target
@@ -33,7 +53,7 @@ fn scale_fill(image: &RgbaImage, target_width: u32, target_height: u32) -> RgbaI
33
     let scaled_height = (src_height as f64 * scale).round() as u32;
53
     let scaled_height = (src_height as f64 * scale).round() as u32;
34
 
54
 
35
     // Scale image
55
     // Scale image
36
-    let scaled = image::imageops::resize(image, scaled_width, scaled_height, FilterType::Lanczos3);
56
+    let scaled = image::imageops::resize(image, scaled_width, scaled_height, filter);
37
 
57
 
38
     // Crop to target size (center crop)
58
     // Crop to target size (center crop)
39
     let crop_x = (scaled_width.saturating_sub(target_width)) / 2;
59
     let crop_x = (scaled_width.saturating_sub(target_width)) / 2;
@@ -43,7 +63,7 @@ fn scale_fill(image: &RgbaImage, target_width: u32, target_height: u32) -> RgbaI
43
 }
63
 }
44
 
64
 
45
 /// Fit: Scale to fit within area, letterbox if needed
65
 /// Fit: Scale to fit within area, letterbox if needed
46
-fn scale_fit(image: &RgbaImage, target_width: u32, target_height: u32) -> RgbaImage {
66
+fn scale_fit(image: &RgbaImage, target_width: u32, target_height: u32, filter: FilterType) -> RgbaImage {
47
     let (src_width, src_height) = image.dimensions();
67
     let (src_width, src_height) = image.dimensions();
48
 
68
 
49
     // Calculate scale factor to fit within target
69
     // Calculate scale factor to fit within target
@@ -55,7 +75,7 @@ fn scale_fit(image: &RgbaImage, target_width: u32, target_height: u32) -> RgbaIm
55
     let scaled_height = (src_height as f64 * scale).round() as u32;
75
     let scaled_height = (src_height as f64 * scale).round() as u32;
56
 
76
 
57
     // Scale image
77
     // Scale image
58
-    let scaled = image::imageops::resize(image, scaled_width, scaled_height, FilterType::Lanczos3);
78
+    let scaled = image::imageops::resize(image, scaled_width, scaled_height, filter);
59
 
79
 
60
     // Create output with black background
80
     // Create output with black background
61
     let mut output = RgbaImage::from_pixel(target_width, target_height, image::Rgba([0, 0, 0, 255]));
81
     let mut output = RgbaImage::from_pixel(target_width, target_height, image::Rgba([0, 0, 0, 255]));
@@ -70,8 +90,8 @@ fn scale_fit(image: &RgbaImage, target_width: u32, target_height: u32) -> RgbaIm
70
 }
90
 }
71
 
91
 
72
 /// Stretch: Scale to exact target size, ignoring aspect ratio
92
 /// Stretch: Scale to exact target size, ignoring aspect ratio
73
-fn scale_stretch(image: &RgbaImage, target_width: u32, target_height: u32) -> RgbaImage {
93
+fn scale_stretch(image: &RgbaImage, target_width: u32, target_height: u32, filter: FilterType) -> RgbaImage {
74
-    image::imageops::resize(image, target_width, target_height, FilterType::Lanczos3)
94
+    image::imageops::resize(image, target_width, target_height, filter)
75
 }
95
 }
76
 
96
 
77
 /// Center: Display at original size, centered
97
 /// Center: Display at original size, centered
@@ -136,21 +156,21 @@ mod tests {
136
     #[test]
156
     #[test]
137
     fn test_scale_stretch() {
157
     fn test_scale_stretch() {
138
         let img = test_image(100, 100);
158
         let img = test_image(100, 100);
139
-        let scaled = scale_stretch(&img, 200, 150);
159
+        let scaled = scale_stretch(&img, 200, 150, FilterType::Lanczos3);
140
         assert_eq!(scaled.dimensions(), (200, 150));
160
         assert_eq!(scaled.dimensions(), (200, 150));
141
     }
161
     }
142
 
162
 
143
     #[test]
163
     #[test]
144
     fn test_scale_fill() {
164
     fn test_scale_fill() {
145
         let img = test_image(100, 100);
165
         let img = test_image(100, 100);
146
-        let scaled = scale_fill(&img, 200, 150);
166
+        let scaled = scale_fill(&img, 200, 150, FilterType::Lanczos3);
147
         assert_eq!(scaled.dimensions(), (200, 150));
167
         assert_eq!(scaled.dimensions(), (200, 150));
148
     }
168
     }
149
 
169
 
150
     #[test]
170
     #[test]
151
     fn test_scale_fit() {
171
     fn test_scale_fit() {
152
         let img = test_image(100, 100);
172
         let img = test_image(100, 100);
153
-        let scaled = scale_fit(&img, 200, 150);
173
+        let scaled = scale_fit(&img, 200, 150, FilterType::Lanczos3);
154
         assert_eq!(scaled.dimensions(), (200, 150));
174
         assert_eq!(scaled.dimensions(), (200, 150));
155
     }
175
     }
156
 
176