image_go_nord/
lib.rs

1pub mod palette;
2pub mod utils;
3
4use color_quant::NeuQuant;
5use image::{
6    imageops::{blur, dither, resize, ColorMap, FilterType::Triangle},
7    Rgba, RgbaImage,
8};
9
10pub use palette::palettes::*;
11
12#[cfg(feature = "wee_alloc")]
13#[global_allocator]
14static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
15
16/// These options modify the algorithm(s) used by `convert`. You can specify
17/// built-in pre-processing operations like resizing and quantization,
18/// processing parameters like transparency tolerance and average kernel, and
19/// post-processing operations like Gaussian blur.
20///
21/// `Options` implements [`std::default::Default`], so you can use struct
22/// builder syntax to easily make an `Options` struct that "overrides" the
23/// default struct.
24///
25/// ```ignore
26/// let options = Options {
27///     resize: [1920, 1080],
28///     blur: 0.4,
29///     ..Default::default()
30/// };
31/// assert_eq!(options, Options {
32///     resize: [1920, 1080],
33///     quantize: 0,
34///     avg: [0, 0],
35///     transparency_tolerance: 0,
36///     blur: 0.4,
37/// })
38/// ```
39#[cfg_attr(feature = "ffi", repr(C))]
40#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
41#[derive(Clone, Debug, PartialEq)]
42pub struct Options {
43    /// Resize image by a certain factor before performing other processing. The
44    /// image will be resized using linear filtering back to the original
45    /// dimensions before it is output. This will cause the algorithm to
46    /// consider bigger "pixels" in the image, which will result in a
47    /// lower quality conversion.
48    #[deprecated]
49    pub resize: u32,
50    /// Quantize the image by the given balance. The value must be between 1 and
51    /// 30. A value closer to 1 will be slower, but provide better
52    /// quantization. The default value of 10 is a good balance between
53    /// speed and quality.
54    ///
55    /// Passing any invalid value (like 0) disables quantization, which is the
56    /// default behavior
57    pub quantize: i32,
58    /// Perform a Gaussian blur on the output image. This can help smooth
59    /// gradients and remove unwanted artifacts.
60    ///
61    /// `0.0` means don't blur.
62    pub blur: f32,
63}
64
65impl Default for Options {
66    #[allow(deprecated)]
67    fn default() -> Self {
68        Options {
69            blur: 0.,
70            resize: 0,
71            quantize: 0,
72        }
73    }
74}
75
76// TODO: make generic over different image types
77#[allow(deprecated)]
78pub fn convert(
79    img: &RgbaImage,
80    opt: Options,
81    palette: &impl ColorMap<Color = Rgba<u8>>,
82) -> RgbaImage {
83    // resize the image to simulate averaging of pixels
84    let (w, h) = img.dimensions(); // save width and height for later
85    let mut img = if opt.resize > 1 {
86        // sample using linear filtering
87        resize(img, w - w / opt.resize, h - h / opt.resize, Triangle)
88    } else {
89        img.clone()
90    };
91
92    // dither image using neu-quant quantization
93    if (1..=30).contains(&opt.quantize) {
94        let ref q = NeuQuant::new(opt.quantize, 256, img.as_raw()); // train neural network
95        dither(&mut img, q);
96    }
97
98    // re-color the image using the provided palette
99    dither(&mut img, palette);
100
101    // blur image
102    let img = if opt.blur > 0. {
103        blur(&img, opt.blur)
104    } else {
105        img
106    };
107
108    // if we resized earlier, restore original size
109    if opt.resize > 1 {
110        resize(&img, w, h, Triangle)
111    } else {
112        img
113    }
114}