1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: MIT
3
4use slint::SharedString;
5use std::rc::Rc;
6
7slint::include_modules!();
8
9#[cfg(target_arch = "wasm32")]
10use wasm_bindgen::prelude::*;
11
12struct Filter {
13 name: SharedString,
14 apply_function: fn(&image::RgbaImage) -> image::RgbaImage,
15}
16
17struct Filters(Vec<Filter>);
18
19impl 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))]
36pub 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