plutofilter_rs/
lib.rs

1//! PlutoFilter implementation
2
3// TODO: input output issue ?
4// TODO: inplace functions are incorrect. Maybe push inplace code to surface level??
5
6mod error;
7mod surface;
8mod utils;
9#[cfg(feature = "image")]
10pub use arena::ImageEditor;
11pub use error::SurfaceError;
12pub use surface::{BlendMode, ColorChannel, CompositeOperator, Surface};
13pub use utils::get_resource_path;
14
15/// `arena` provides API using image crate to expose easy to use methods for surface API
16#[cfg(feature = "image")]
17pub mod arena {
18    use std::{
19        panic,
20        path::{Path, PathBuf},
21    };
22
23    use image::{DynamicImage, ImageBuffer, ImageReader, ImageResult};
24
25    use crate::{BlendMode, CompositeOperator, Surface};
26
27    /// Provide a unified interface for storing input and output and implementing operations on an
28    /// image
29    /// Example usage:
30    /// ```rust
31    /// use image::ImageResult;
32    /// #[cfg(feature = "image")]
33    /// fn main() -> ImageResult<()> {
34    ///     use plutofilter_rs::{ImageEditor, get_resource_path};
35    ///
36    ///     let base_file = get_resource_path(&["original_images"], "test-image.jpg");
37    ///     let editor = ImageEditor::open(&base_file);
38    ///     let output_path = get_resource_path(&["test_output_images", "example"], "test-image.jpg");
39    ///     editor
40    ///         .color_transform_contrast_inplace(0.97)
41    ///         .color_transform_hue_rotate_inplace(330.0)
42    ///         .color_transform_saturate_inplace(1.11)
43    ///         .save_to(&output_path)
44    /// }
45    /// ```
46    #[derive(Debug)]
47    pub struct ImageEditor {
48        input_image_path: PathBuf,
49        input_image: DynamicImage,
50        output_image: DynamicImage,
51    }
52
53    // TODO: Split this impl using typesafe builder pattern
54    impl ImageEditor {
55        // TODO: change to result type
56        /// Open an image and generate input and output buffers
57        pub fn open(input_image_path: impl AsRef<Path>) -> Self {
58            let input_image_path = input_image_path.as_ref().to_owned();
59            let input_image = Self::open_image(&input_image_path);
60            let output_image = Self::temp_output_image(input_image.width(), input_image.height());
61            Self {
62                input_image_path,
63                input_image,
64                output_image,
65            }
66        }
67
68        fn temp_output_image(width: u32, height: u32) -> DynamicImage {
69            let output_pixels =
70                ImageBuffer::from_vec(width, height, vec![0u8; (4 * width * height) as usize])
71                    .unwrap();
72            DynamicImage::ImageRgba8(output_pixels)
73        }
74
75        // TODO: remove panics
76        fn open_image(image_path: &Path) -> DynamicImage {
77            if !image_path.exists() {
78                panic!("Unable to find image path.");
79            }
80            let image_buffer = match ImageReader::open(image_path) {
81                Ok(image) => match image.decode() {
82                    Ok(image) => image,
83                    Err(err) => panic!("Unable to decode image: {err}"),
84                },
85                Err(err) => panic!("Unable to open Image: {err}"),
86            };
87            let rgba8_image_buffer = image_buffer.into_rgba8();
88            DynamicImage::ImageRgba8(rgba8_image_buffer)
89        }
90
91        /// Saves output image to provided path
92        pub fn save_to(self, output_path: impl AsRef<Path>) -> ImageResult<()> {
93            let output_path = output_path.as_ref();
94            self.output_image.save(output_path)
95        }
96
97        /// saves the output in the input image path
98        pub fn save(self) -> ImageResult<()> {
99            self.output_image.save(&self.input_image_path)
100        }
101
102        pub fn color_transform_inplace(mut self, matrix: [f32; 20]) -> Self {
103            let mut input_surface = Surface::from_image(&mut self.input_image);
104            let mut output_surface = Surface::from_image(&mut self.output_image);
105            Surface::color_transform(&mut input_surface, &mut output_surface, matrix);
106            Surface::copy_output_into_input(&mut input_surface, &output_surface);
107            self
108        }
109
110        pub fn color_transform(mut self, matrix: [f32; 20]) -> Self {
111            let mut input_surface = Surface::from_image(&mut self.input_image);
112            let mut output_surface = Surface::from_image(&mut self.output_image);
113            Surface::color_transform(&mut input_surface, &mut output_surface, matrix);
114            self
115        }
116
117        pub fn color_transform_opacity_inplace(mut self, amount: f32) -> Self {
118            let mut input_surface = Surface::from_image(&mut self.input_image);
119            let mut output_surface = Surface::from_image(&mut self.output_image);
120            Surface::color_transform_opacity(&mut input_surface, &mut output_surface, amount);
121            Surface::copy_output_into_input(&mut input_surface, &output_surface);
122            self
123        }
124
125        pub fn color_transform_opacity(mut self, amount: f32) -> Self {
126            let mut input_surface = Surface::from_image(&mut self.input_image);
127            let mut output_surface = Surface::from_image(&mut self.output_image);
128            Surface::color_transform_opacity(&mut input_surface, &mut output_surface, amount);
129            self
130        }
131
132        pub fn color_transform_brightness_inplace(mut self, amount: f32) -> Self {
133            let mut input_surface = Surface::from_image(&mut self.input_image);
134            let mut output_surface = Surface::from_image(&mut self.output_image);
135            Surface::color_transform_brightness(&mut input_surface, &mut output_surface, amount);
136            Surface::copy_output_into_input(&mut input_surface, &output_surface);
137            self
138        }
139
140        pub fn color_transform_brightness(mut self, amount: f32) -> Self {
141            let mut input_surface = Surface::from_image(&mut self.input_image);
142            let mut output_surface = Surface::from_image(&mut self.output_image);
143            Surface::color_transform_brightness(&mut input_surface, &mut output_surface, amount);
144            self
145        }
146
147        pub fn color_transform_invert_inplace(mut self, amount: f32) -> Self {
148            let mut input_surface = Surface::from_image(&mut self.input_image);
149            let mut output_surface = Surface::from_image(&mut self.output_image);
150            Surface::color_transform_invert(&mut input_surface, &mut output_surface, amount);
151            Surface::copy_output_into_input(&mut input_surface, &output_surface);
152            self
153        }
154
155        pub fn color_transform_invert(mut self, amount: f32) -> Self {
156            let mut input_surface = Surface::from_image(&mut self.input_image);
157            let mut output_surface = Surface::from_image(&mut self.output_image);
158            Surface::color_transform_invert(&mut input_surface, &mut output_surface, amount);
159            self
160        }
161
162        pub fn color_transform_contrast_inplace(mut self, amount: f32) -> Self {
163            let mut input_surface = Surface::from_image(&mut self.input_image);
164            let mut output_surface = Surface::from_image(&mut self.output_image);
165            Surface::color_transform_contrast(&mut input_surface, &mut output_surface, amount);
166            Surface::copy_output_into_input(&mut input_surface, &output_surface);
167            self
168        }
169
170        pub fn color_transform_contrast(mut self, amount: f32) -> Self {
171            let mut input_surface = Surface::from_image(&mut self.input_image);
172            let mut output_surface = Surface::from_image(&mut self.output_image);
173            Surface::color_transform_contrast(&mut input_surface, &mut output_surface, amount);
174            self
175        }
176
177        pub fn color_transform_saturate_inplace(mut self, amount: f32) -> Self {
178            let mut input_surface = Surface::from_image(&mut self.input_image);
179            let mut output_surface = Surface::from_image(&mut self.output_image);
180            Surface::color_transform_saturate(&mut input_surface, &mut output_surface, amount);
181            Surface::copy_output_into_input(&mut input_surface, &output_surface);
182            self
183        }
184
185        pub fn color_transform_saturate(mut self, amount: f32) -> Self {
186            let mut input_surface = Surface::from_image(&mut self.input_image);
187            let mut output_surface = Surface::from_image(&mut self.output_image);
188            Surface::color_transform_saturate(&mut input_surface, &mut output_surface, amount);
189            self
190        }
191
192        pub fn color_transform_grayscale_inplace(mut self, amount: f32) -> Self {
193            let mut input_surface = Surface::from_image(&mut self.input_image);
194            let mut output_surface = Surface::from_image(&mut self.output_image);
195            Surface::color_transform_grayscale(&mut input_surface, &mut output_surface, amount);
196            Surface::copy_output_into_input(&mut input_surface, &output_surface);
197            self
198        }
199
200        pub fn color_transform_grayscale(mut self, amount: f32) -> Self {
201            let mut input_surface = Surface::from_image(&mut self.input_image);
202            let mut output_surface = Surface::from_image(&mut self.output_image);
203            Surface::color_transform_grayscale(&mut input_surface, &mut output_surface, amount);
204            self
205        }
206
207        pub fn color_transform_sepia_inplace(mut self, amount: f32) -> Self {
208            let mut input_surface = Surface::from_image(&mut self.input_image);
209            let mut output_surface = Surface::from_image(&mut self.output_image);
210            Surface::color_transform_sepia(&mut input_surface, &mut output_surface, amount);
211            Surface::copy_output_into_input(&mut input_surface, &output_surface);
212            self
213        }
214
215        pub fn color_transform_sepia(mut self, amount: f32) -> Self {
216            let mut input_surface = Surface::from_image(&mut self.input_image);
217            let mut output_surface = Surface::from_image(&mut self.output_image);
218            Surface::color_transform_sepia(&mut input_surface, &mut output_surface, amount);
219            self
220        }
221
222        pub fn color_transform_hue_rotate_inplace(mut self, angle: f32) -> Self {
223            let mut input_surface = Surface::from_image(&mut self.input_image);
224            let mut output_surface = Surface::from_image(&mut self.output_image);
225            Surface::color_transform_hue_rotate(&mut input_surface, &mut output_surface, angle);
226            Surface::copy_output_into_input(&mut input_surface, &output_surface);
227            self
228        }
229
230        pub fn color_transform_hue_rotate(mut self, angle: f32) -> Self {
231            let mut input_surface = Surface::from_image(&mut self.input_image);
232            let mut output_surface = Surface::from_image(&mut self.output_image);
233            Surface::color_transform_hue_rotate(&mut input_surface, &mut output_surface, angle);
234            self
235        }
236
237        pub fn color_transform_luminance_to_alpha_inplace(mut self) -> Self {
238            let mut input_surface = Surface::from_image(&mut self.input_image);
239            let mut output_surface = Surface::from_image(&mut self.output_image);
240            Surface::color_transform_luminance_to_alpha(&mut input_surface, &mut output_surface);
241            Surface::copy_output_into_input(&mut input_surface, &output_surface);
242            self
243        }
244
245        pub fn color_transform_luminance_to_alpha(mut self) -> Self {
246            let mut input_surface = Surface::from_image(&mut self.input_image);
247            let mut output_surface = Surface::from_image(&mut self.output_image);
248            Surface::color_transform_luminance_to_alpha(&mut input_surface, &mut output_surface);
249            self
250        }
251
252        pub fn color_transform_srgb_to_linear_rgb_inplace(mut self) -> Self {
253            let mut input_surface = Surface::from_image(&mut self.input_image);
254            let mut output_surface = Surface::from_image(&mut self.output_image);
255            Surface::color_transform_srgb_to_linear_rgb(&mut input_surface, &mut output_surface);
256            Surface::copy_output_into_input(&mut input_surface, &output_surface);
257            self
258        }
259
260        pub fn color_transform_srgb_to_linear_rgb(mut self) -> Self {
261            let mut input_surface = Surface::from_image(&mut self.input_image);
262            let mut output_surface = Surface::from_image(&mut self.output_image);
263            Surface::color_transform_srgb_to_linear_rgb(&mut input_surface, &mut output_surface);
264            self
265        }
266
267        pub fn color_transform_linear_rgb_to_srgb_inplace(mut self) -> Self {
268            let mut input_surface = Surface::from_image(&mut self.input_image);
269            let mut output_surface = Surface::from_image(&mut self.output_image);
270            Surface::color_transform_linear_rgb_to_srgb(&mut input_surface, &mut output_surface);
271            Surface::copy_output_into_input(&mut input_surface, &output_surface);
272            self
273        }
274
275        pub fn color_transform_linear_rgb_to_srgb(mut self) -> Self {
276            let mut input_surface = Surface::from_image(&mut self.input_image);
277            let mut output_surface = Surface::from_image(&mut self.output_image);
278            Surface::color_transform_linear_rgb_to_srgb(&mut input_surface, &mut output_surface);
279            self
280        }
281
282        pub fn gaussian_blur_inplace(mut self, std_deviation_x: f32, std_deviation_y: f32) -> Self {
283            let mut input_surface = Surface::from_image(&mut self.input_image);
284            let mut output_surface = Surface::from_image(&mut self.output_image);
285            Surface::gaussian_blur(
286                &mut input_surface,
287                &mut output_surface,
288                std_deviation_x,
289                std_deviation_y,
290            );
291            Surface::copy_output_into_input(&mut input_surface, &output_surface);
292            self
293        }
294        pub fn gaussian_blur(mut self, std_deviation_x: f32, std_deviation_y: f32) -> Self {
295            let mut input_surface = Surface::from_image(&mut self.input_image);
296            let mut output_surface = Surface::from_image(&mut self.output_image);
297            Surface::gaussian_blur(
298                &mut input_surface,
299                &mut output_surface,
300                std_deviation_x,
301                std_deviation_y,
302            );
303            self
304        }
305
306        pub fn blend_inplace(mut self, blend_image: impl AsRef<Path>, mode: BlendMode) -> Self {
307            let mut input_surface = Surface::from_image(&mut self.input_image);
308            let mut output_surface = Surface::from_image(&mut self.output_image);
309
310            let mut blend_input_image = Self::open_image(blend_image.as_ref());
311            let mut blend_surface = Surface::from_image(&mut blend_input_image);
312            Surface::blend(
313                &mut input_surface,
314                &mut blend_surface,
315                &mut output_surface,
316                mode,
317            );
318            Surface::copy_output_into_input(&mut input_surface, &output_surface);
319            self
320        }
321
322        pub fn blend(mut self, blend_image: impl AsRef<Path>, mode: BlendMode) -> Self {
323            let mut input_surface = Surface::from_image(&mut self.input_image);
324            let mut output_surface = Surface::from_image(&mut self.output_image);
325
326            let mut blend_input_image = Self::open_image(blend_image.as_ref());
327            let mut blend_surface = Surface::from_image(&mut blend_input_image);
328            Surface::blend(
329                &mut input_surface,
330                &mut blend_surface,
331                &mut output_surface,
332                mode,
333            );
334            self
335        }
336        pub fn composite_inplace(
337            mut self,
338            composite_image: impl AsRef<Path>,
339            op: CompositeOperator,
340        ) -> Self {
341            let mut input_surface = Surface::from_image(&mut self.input_image);
342            let mut output_surface = Surface::from_image(&mut self.output_image);
343
344            let mut composite_input_image = Self::open_image(composite_image.as_ref());
345            let mut composite_surface = Surface::from_image(&mut composite_input_image);
346            Surface::composite(
347                &mut input_surface,
348                &mut composite_surface,
349                &mut output_surface,
350                op,
351            );
352            Surface::copy_output_into_input(&mut input_surface, &output_surface);
353            self
354        }
355
356        pub fn composite(
357            mut self,
358            composite_image: impl AsRef<Path>,
359            op: CompositeOperator,
360        ) -> Self {
361            let mut input_surface = Surface::from_image(&mut self.input_image);
362            let mut output_surface = Surface::from_image(&mut self.output_image);
363
364            let mut composite_input_image = Self::open_image(composite_image.as_ref());
365            let mut composite_surface = Surface::from_image(&mut composite_input_image);
366            Surface::composite(
367                &mut input_surface,
368                &mut composite_surface,
369                &mut output_surface,
370                op,
371            );
372            self
373        }
374        pub fn composite_arithmetic_inplace(
375            mut self,
376            composite_image: impl AsRef<Path>,
377            k1: f32,
378            k2: f32,
379            k3: f32,
380            k4: f32,
381        ) -> Self {
382            let mut input_surface = Surface::from_image(&mut self.input_image);
383            let mut output_surface = Surface::from_image(&mut self.output_image);
384
385            let mut composite_input_image = Self::open_image(composite_image.as_ref());
386            let mut composite_surface = Surface::from_image(&mut composite_input_image);
387            Surface::composite_arithmetic(
388                &mut input_surface,
389                &mut composite_surface,
390                &mut output_surface,
391                k1,
392                k2,
393                k3,
394                k4,
395            );
396            Surface::copy_output_into_input(&mut input_surface, &output_surface);
397            self
398        }
399        pub fn composite_arithmetic(
400            mut self,
401            composite_image: impl AsRef<Path>,
402            k1: f32,
403            k2: f32,
404            k3: f32,
405            k4: f32,
406        ) -> Self {
407            let mut input_surface = Surface::from_image(&mut self.input_image);
408            let mut output_surface = Surface::from_image(&mut self.output_image);
409
410            let mut composite_input_image = Self::open_image(composite_image.as_ref());
411            let mut composite_surface = Surface::from_image(&mut composite_input_image);
412            Surface::composite_arithmetic(
413                &mut input_surface,
414                &mut composite_surface,
415                &mut output_surface,
416                k1,
417                k2,
418                k3,
419                k4,
420            );
421            self
422        }
423    }
424}