use crate::color::NHPaletteItem;
use exoquant::optimizer::Optimizer;
use exoquant::ditherer::Ditherer;
use exoquant::{Color, Histogram, Quantizer, SimpleColorSpace, Remapper};
use std::iter::{Extend, IntoIterator, repeat_with, once};
pub struct Design {
image: Vec<Color>,
dimensions: (usize, usize),
histogram: Histogram,
palette: Vec<NHPaletteItem>,
}
impl Default for Design {
fn default() -> Self {
let mut palette: Vec<NHPaletteItem> = once(NHPaletteItem::default()).chain(repeat_with(|| NHPaletteItem::Transparent)).take(16).collect();
palette.push(NHPaletteItem::Transparent);
Design {
palette,
histogram: Histogram::new(),
image: vec![Color::new(0, 0, 0, 255)],
dimensions: (1, 1),
}
}
}
impl Design {
pub fn palette(&self) -> &[NHPaletteItem] {
&self.palette
}
pub fn load_image(&mut self, image: Vec<(u8, u8, u8, u8)>, dimensions: (usize, usize)) -> Result<(), String> {
if image.len() != dimensions.0 * dimensions.1 {
return Err(format!("There was an error with the image dimensions. The dimensions say the image should be {}x{} for {} pixels, but the image was actually {} pixels", dimensions.0, dimensions.1, dimensions.0 * dimensions.1, image.len()));
}
if dimensions.0 > 64 || dimensions.1 > 64 {
return Err(format!("The max image size is 64x64, but you tried to load an image with {}x{} pixels", dimensions.0, dimensions.1));
}
self.image = image.into_iter().map(|p| {
if p.3 == 0 {
Color {
r: 0,
g: 0,
b: 0,
a: 0,
}
} else {
Color {
r: p.0,
g: p.1,
b: p.2,
a: 255,
}
}
}).collect();
self.dimensions = dimensions;
Ok(())
}
pub fn load_histogram(&mut self, images: Vec<Vec<(u8, u8, u8, u8)>>) -> Result<(), String> {
self.histogram = Histogram::new();
for image in images {
if image.len() > 4096 {
return Err(format!("The max allowed image size is 4096 pixels (64x64). You tried to load an image with {} pixels", image.len()));
}
self.histogram.extend(image.iter()
.filter(|p| p.3 > 0)
.map(|p| {
let input_color = Color {
r: p.0,
g: p.1,
b: p.2,
a: 255,
};
let nh_color: NHPaletteItem = input_color.into();
nh_color.into()
}));
}
Ok(())
}
pub fn optimize_palette<O>(&mut self, optimizer: O)
where
O: Optimizer,
{
let colorspace = SimpleColorSpace::default();
let mut quantizer = Quantizer::new(&self.histogram, &colorspace);
while quantizer.num_colors() < 15 {
quantizer.step();
quantizer = quantizer.optimize(&optimizer, 4);
}
let palette = quantizer.colors(&colorspace);
let palette = optimizer.optimize_palette(&colorspace, &palette, &self.histogram, 16);
self.palette = palette.into_iter().map(Into::into).collect();
self.palette.sort();
self.palette.dedup();
self.palette.resize(16, NHPaletteItem::Transparent);
}
pub fn dimensions(&self) -> (usize, usize) {
self.dimensions
}
pub fn generate<D>(&self, ditherer: D) -> Vec<u8>
where D: Ditherer
{
let colorspace = SimpleColorSpace::default();
let palette: Vec<Color> = self.palette.iter().map(Into::into).collect();
let remapper = Remapper::new(&palette, &colorspace, &ditherer);
remapper.remap(&self.image, self.dimensions.0)
}
}