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}