blurhash_fast/
encode.rs

1use rayon::iter::IndexedParallelIterator;
2use rayon::iter::IntoParallelIterator;
3use rayon::iter::ParallelIterator;
4
5use super::{alternating_current, base83, direct_current};
6use super::Error;
7use super::util::multiply_basis_function;
8
9/// Calculates the blurhash for an image using the given x and y component counts.
10pub fn encode(
11    components_x: u32,
12    components_y: u32,
13    width: u32,
14    height: u32,
15    rgba_image: &[u8],
16) -> Result<String, Error> {
17    if !(1..=9).contains(&components_x)
18        || !(1..=9).contains(&components_y)
19    {
20        return Err(Error::ComponentsOutOfRange);
21    }
22
23    let factors: Vec<[f32; 3]> = (0..components_y)
24        .into_par_iter()
25        .map(
26            |y| {
27                (0..components_x)
28                    .into_par_iter()
29                    .map(
30                        |x| {
31                            multiply_basis_function(
32                                x,
33                                y,
34                                width,
35                                height,
36                                rgba_image,
37                            )
38                        }
39                    )
40                    .collect::<Vec<[f32; 3]>>()
41            }
42        )
43        .flatten()
44        .collect();
45
46    let dc = factors[0];
47    let ac = &factors[1..];
48
49    let mut blurhash = String::new();
50
51    let size_flag =
52        (components_x - 1)
53            + (components_y - 1)
54            * 9;
55
56    blurhash
57        .push_str(
58            &base83::encode(
59                size_flag,
60                1,
61            ),
62        );
63
64    let maximum_value: f32;
65
66    if !ac.is_empty() {
67        let mut actualmaximum_value = 0.0;
68
69        for i in 0..components_y * components_x - 1 {
70            actualmaximum_value = f32::max(f32::abs(ac[i as usize][0]), actualmaximum_value);
71            actualmaximum_value = f32::max(f32::abs(ac[i as usize][1]), actualmaximum_value);
72            actualmaximum_value = f32::max(f32::abs(ac[i as usize][2]), actualmaximum_value);
73        }
74
75        let quantised_maximum_value =
76            f32::max(
77                0.,
78                f32::min(
79                    82.,
80                    f32::floor(
81                        actualmaximum_value
82                            * 166.
83                            - 0.5,
84                    ),
85                ),
86            ) as u32;
87
88        maximum_value = (quantised_maximum_value + 1) as f32 / 166.;
89
90        blurhash.push_str(&base83::encode(quantised_maximum_value, 1));
91    } else {
92        maximum_value = 1.;
93
94        blurhash.push_str(&base83::encode(0, 1));
95    }
96
97    blurhash.push_str(&base83::encode(direct_current::encode(dc), 4));
98
99    for i in 0..components_y * components_x - 1 {
100        blurhash.push_str(&base83::encode(
101            alternating_current::encode(ac[i as usize], maximum_value),
102            2,
103        ));
104    }
105
106    Ok(blurhash)
107}