1 | // Copyright © SixtyFPS GmbH <info@slint.dev> |
2 | // SPDX-License-Identifier: MIT |
3 | |
4 | use slint::SharedString; |
5 | use std::rc::Rc; |
6 | |
7 | slint::include_modules!(); |
8 | |
9 | #[cfg (target_arch = "wasm32" )] |
10 | use wasm_bindgen::prelude::*; |
11 | |
12 | struct Filter { |
13 | name: SharedString, |
14 | apply_function: fn(&image::RgbaImage) -> image::RgbaImage, |
15 | } |
16 | |
17 | struct Filters(Vec<Filter>); |
18 | |
19 | impl slint::Model for Filters { |
20 | type Data = SharedString; |
21 | |
22 | fn row_count(&self) -> usize { |
23 | self.0.len() |
24 | } |
25 | |
26 | fn row_data(&self, row: usize) -> Option<Self::Data> { |
27 | self.0.get(index:row).map(|x: &Filter| x.name.clone()) |
28 | } |
29 | |
30 | fn model_tracker(&self) -> &dyn slint::ModelTracker { |
31 | &() |
32 | } |
33 | } |
34 | |
35 | #[cfg_attr (target_arch = "wasm32" , wasm_bindgen(start))] |
36 | pub fn main() { |
37 | // This provides better error messages in debug mode. |
38 | // It's disabled in release mode so it doesn't bloat up the file size. |
39 | #[cfg (all(debug_assertions, target_arch = "wasm32" ))] |
40 | console_error_panic_hook::set_once(); |
41 | |
42 | let main_window = MainWindow::new().unwrap(); |
43 | |
44 | #[cfg (target_arch = "wasm32" )] |
45 | let source_image = |
46 | image::load_from_memory(include_bytes!("../assets/cat.jpg" )).unwrap().into_rgba8(); |
47 | #[cfg (not(target_arch = "wasm32" ))] |
48 | let source_image = { |
49 | let mut cat_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR" )); |
50 | cat_path.push("../assets/cat.jpg" ); |
51 | image::open(&cat_path).expect("Error loading cat image" ).into_rgba8() |
52 | }; |
53 | |
54 | main_window.set_original_image(slint::Image::from_rgba8( |
55 | slint::SharedPixelBuffer::clone_from_slice( |
56 | source_image.as_raw(), |
57 | source_image.width(), |
58 | source_image.height(), |
59 | ), |
60 | )); |
61 | |
62 | let filters = Filters(vec![ |
63 | Filter { |
64 | name: "Blur" .into(), |
65 | apply_function: |image: &image::RgbaImage| image::imageops::blur(image, 4.), |
66 | }, |
67 | Filter { |
68 | name: "Brighten" .into(), |
69 | apply_function: |image: &image::RgbaImage| { |
70 | image::imageops::colorops::brighten(image, 30) |
71 | }, |
72 | }, |
73 | Filter { |
74 | name: "Darken" .into(), |
75 | apply_function: |image: &image::RgbaImage| { |
76 | image::imageops::colorops::brighten(image, -30) |
77 | }, |
78 | }, |
79 | Filter { |
80 | name: "Increase Contrast" .into(), |
81 | apply_function: |image: &image::RgbaImage| { |
82 | image::imageops::colorops::contrast(image, 30.) |
83 | }, |
84 | }, |
85 | Filter { |
86 | name: "Decrease Contrast" .into(), |
87 | apply_function: |image: &image::RgbaImage| { |
88 | image::imageops::colorops::contrast(image, -30.) |
89 | }, |
90 | }, |
91 | Filter { |
92 | name: "Invert" .into(), |
93 | apply_function: |image: &image::RgbaImage| { |
94 | let mut inverted = image.clone(); |
95 | image::imageops::colorops::invert(&mut inverted); |
96 | inverted |
97 | }, |
98 | }, |
99 | ]); |
100 | let filters = Rc::new(filters); |
101 | |
102 | main_window.set_filters(slint::ModelRc::from(filters.clone())); |
103 | |
104 | main_window.on_filter_image(move |filter_index| { |
105 | let filter_fn = filters.0[filter_index as usize].apply_function; |
106 | let filtered_image = filter_fn(&source_image); |
107 | slint::Image::from_rgba8(slint::SharedPixelBuffer::clone_from_slice( |
108 | filtered_image.as_raw(), |
109 | filtered_image.width(), |
110 | filtered_image.height(), |
111 | )) |
112 | }); |
113 | |
114 | main_window.run().unwrap(); |
115 | } |
116 | |