photon_rs/
noise.rs

1//! Add noise to images.
2
3use image::Pixel;
4use image::{GenericImage, GenericImageView};
5
6use crate::helpers;
7use crate::iter::ImageIterator;
8use crate::PhotonImage;
9
10#[cfg(feature = "enable_wasm")]
11use wasm_bindgen::prelude::*;
12
13#[cfg(all(target_family = "wasm", not(target_os = "wasi")))]
14use js_sys::Math::random;
15
16#[cfg(not(all(target_arch = "wasm64", not(target_os = "wasi"))))]
17use rand::Rng;
18
19/// Add randomized noise to an image.
20/// This function adds a Gaussian Noise Sample to each pixel through incrementing each channel by a randomized offset.
21/// This randomized offset is generated by creating a randomized thread pool.
22/// **[WASM SUPPORT IS AVAILABLE]**: Randomized thread pools cannot be created with WASM, but
23/// a workaround using js_sys::Math::random works now.
24/// # Arguments
25/// * `img` - A PhotonImage.
26///
27/// # Example
28///
29/// ```no_run
30/// // For example:
31/// use photon_rs::native::open_image;
32/// use photon_rs::noise::add_noise_rand;
33/// use photon_rs::PhotonImage;
34///
35/// let mut img = open_image("img.jpg").expect("File should open");
36/// add_noise_rand(&mut img);
37/// ```
38#[cfg_attr(feature = "enable_wasm", wasm_bindgen)]
39pub fn add_noise_rand(photon_image: &mut PhotonImage) {
40    let mut img = helpers::dyn_image_from_raw(photon_image);
41
42    #[cfg(not(all(target_arch = "wasm64", not(target_os = "wasi"))))]
43    let mut rng = rand::thread_rng();
44
45    for (x, y) in ImageIterator::with_dimension(&img.dimensions()) {
46        #[cfg(not(all(target_arch = "wasm64", not(target_os = "wasi"))))]
47        let offset = rng.gen_range(0, 150);
48
49        #[cfg(all(target_arch = "wasm64", not(target_os = "wasi")))]
50        let offset = (random() * 150.0) as u8;
51
52        let px =
53            img.get_pixel(x, y).map(
54                |ch| {
55                    if ch <= 255 - offset {
56                        ch + offset
57                    } else {
58                        255
59                    }
60                },
61            );
62        img.put_pixel(x, y, px);
63    }
64    photon_image.raw_pixels = img.into_bytes();
65}
66
67/// Add pink-tinted noise to an image.
68///
69/// **[WASM SUPPORT IS AVAILABLE]**: Randomized thread pools cannot be created with WASM, but
70/// a workaround using js_sys::Math::random works now.
71/// # Arguments
72/// * `name` - A PhotonImage that contains a view into the image.
73///
74/// # Example
75///
76/// ```no_run
77/// // For example, to add pink-tinted noise to an image:
78/// use photon_rs::native::open_image;
79/// use photon_rs::noise::pink_noise;
80///
81/// let mut img = open_image("img.jpg").expect("File should open");
82/// pink_noise(&mut img);
83/// ```
84#[cfg_attr(feature = "enable_wasm", wasm_bindgen)]
85pub fn pink_noise(photon_image: &mut PhotonImage) {
86    let mut img = helpers::dyn_image_from_raw(photon_image);
87    #[cfg(not(all(target_arch = "wasm64", not(target_os = "wasi"))))]
88    let mut rng = rand::thread_rng();
89
90    #[cfg(not(all(target_arch = "wasm64", not(target_os = "wasi"))))]
91    let mut rng_gen = move || rng.gen();
92
93    #[cfg(all(target_arch = "wasm64", not(target_os = "wasi")))]
94    let rng_gen = || random();
95
96    for (x, y) in ImageIterator::with_dimension(&img.dimensions()) {
97        let ran1: f64 = rng_gen(); // generates a float between 0 and 1
98        let ran2: f64 = rng_gen();
99        let ran3: f64 = rng_gen();
100
101        let ran_color1: f64 = 0.6 + ran1 * 0.6;
102        let ran_color2: f64 = 0.6 + ran2 * 0.1;
103        let ran_color3: f64 = 0.6 + ran3 * 0.4;
104
105        let mut px = img.get_pixel(x, y);
106        let channels = px.channels();
107
108        let new_r_val = (channels[0] as f64 * 0.99 * ran_color1) as u8;
109        let new_g_val = (channels[1] as f64 * 0.99 * ran_color2) as u8;
110        let new_b_val = (channels[2] as f64 * 0.99 * ran_color3) as u8;
111        px = image::Rgba([new_r_val, new_g_val, new_b_val, 255]);
112        img.put_pixel(x, y, px);
113    }
114    photon_image.raw_pixels = img.into_bytes();
115}