1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//! A library and command line tool for spatial color quantization.
//!
//! # Overview
//!
//! Rust port of Derrick Coetzee's [`scolorq`][scolorq], based on the 1998 paper
//! "On spatial quantization of color images" by Jan Puzicha, Markus Held, Jens
//! Ketterer, Joachim M. Buhmann, & Dieter Fellner. *Spatial quantization* is
//! defined as simultaneously performing halftoning (dithering) and color
//! quantization (limiting the colors in an image). For more information, visit
//! [the original implementation's website][scolorq].
//!
//! The algorithm is excellent for retaining image detail and minimizing visual
//! distortions for color palettes in the neighborhood of 4, 8, or 16 colors,
//! especially as the image size is reduced. It combines limiting the color palette
//! and dithering the image into a simultaneous process as opposed to sequentially
//! limiting the colors then dithering. Colors are chosen based on their context in
//! the image, hence the "spatial" aspect of spatial color quantization. The
//! colors are selected based on their neighbors to mix as an average illusory
//! color in the human eye.
//!
//! To use as a library, add the following to your `Cargo.toml`; add the
//! `palette_color` feature to enable Lab color quantization. See the
//! [README.md][readme] for image examples, output, and usage.
//!
//! ```toml
//! [dependencies.rscolorq]
//! version = "0.1"
//! default-features = false
//! ```
//!
//! [readme]: https://github.com/okaneco/rscolorq/blob/master/README.md
//! [scolorq]: http://people.eecs.berkeley.edu/~dcoetzee/downloads/scolorq/
//!
//! ## Usage
//!
//! The following example shows the mapping of an image buffer in Rgb from
//! `[u8; 3]` to `[f64; 3]`, performing the color quantization, then filling
//! a buffer with `u8` to be saved as an image.
//!
//! [Matrix2d]: struct.Matrix2d.html
//! ```
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # let width = 2;
//! # let height = 1;
//! # let palette_size = 4;
//! # let img = vec![[0, 0, 0], [255, 255, 255]];
//! use rscolorq::{color::Rgb, spatial_color_quant, Matrix2d, Params};
//!
//! // Create the output buffer and quantized palette index buffer
//! let mut imgbuf = Vec::with_capacity(width * height * 3);
//! let mut quantized_image = Matrix2d::new(width, height);
//!
//! // Build the quantization parameters, verify if accepting user input
//! let mut conditions = Params::new();
//! conditions.palette_size(palette_size);
//! conditions.verify_parameters()?;
//!
//! // Convert the input image buffer from Rgb<u8> to Rgb<f64>
//! let image = Matrix2d::from_vec(
//! img.iter()
//! .map(|&c| Rgb {
//! red: c[0] as f64 / 255.0,
//! green: c[1] as f64 / 255.0,
//! blue: c[2] as f64 / 255.0,
//! })
//! .collect(),
//! width,
//! height,
//! );
//!
//! let mut palette = Vec::with_capacity(palette_size as usize);
//!
//! spatial_color_quant(&image, &mut quantized_image, &mut palette, &conditions)?;
//!
//! // Convert the Rgb<f64> palette to Rgb<u8>
//! let palette = palette
//! .iter()
//! .map(|&c| {
//! let color = 255.0 * c;
//! [
//! color.red.round() as u8,
//! color.green.round() as u8,
//! color.blue.round() as u8,
//! ]
//! })
//! .collect::<Vec<[u8; 3]>>();
//!
//! // Create the final image by color lookup from the palette
//! for &c in quantized_image.iter() {
//! let color = palette
//! .get(c as usize)
//! .ok_or("Could not retrieve color from palette")?;
//! imgbuf.extend_from_slice(color);
//! }
//!
//! # Ok(())
//! # }
//! ```
//!
//! ## Features
//! - use RGB or Lab color space for calculations
//! - can dither based on fixed color palette
//! - seedable RNG for reproducible results
//!
//! ## Limitations
//!
//! ### It's "slow"
//! - Larger images or images with smooth transitions/gradients will take longer.
//! Higher palette sizes will take longer.
//! - The algorithm is suited towards retaining detail with smaller color palettes.
//! You can still use it on larger images but be aware it's not close to real-time
//! unless the image is small.
//!
//! ### Filter size 1x1
//! - Doesn't produce an image resembling the input, nor does the original.
//!
//! ### Filter size 5x5
//! - Doesn't always converge.
//! - I'm unsure if this is an error in this implementation or a problem with the
//! random number generator being used. The original implementation may take a while
//! but eventually completes with filter size 5.
//! - Any help on this would be appreciated.
pub use QuantError;
pub use ;
pub use ;
/// A trait required to calculate the spatial quantization on a color type.
/// A trait for calculating the inverse of a matrix.