use image::RgbaImage;
use nohash::IntMap;
use std::iter::once;
use crate::ColorPalette;
pub fn extrude_border(image: RgbaImage) -> RgbaImage {
let (w, h) = image.dimensions();
let w = w as usize;
let h = h as usize;
let src = image.as_raw();
let bpp = 4; let mut data: Vec<u8> = Vec::with_capacity(4 * (w + 2) * (h + 2));
let bpp_w = bpp * w;
for src_row in once(0).chain(0..h).chain(once(h - 1)) {
let ofs = src_row * bpp * w;
data.extend_from_slice(&src[ofs..ofs + bpp]); data.extend_from_slice(&src[ofs..ofs + bpp_w]); data.extend_from_slice(&src[ofs + bpp_w - bpp..ofs + bpp_w]);
}
RgbaImage::from_raw((w + 2) as u32, (h + 2) as u32, data).unwrap()
}
pub struct PaletteMapper {
map: IntMap<u32, u8>,
transparent: u8,
failure: u8,
}
pub struct MappingOptions {
pub failure: u8,
pub transparent: Option<u8>,
}
impl PaletteMapper {
pub fn new(palette: &ColorPalette, options: MappingOptions) -> PaletteMapper {
let mut map = IntMap::default();
for (idx, entry) in palette.entries.iter() {
let m =
entry.red() as u32 + ((entry.green() as u32) << 8) + ((entry.blue() as u32) << 16);
let col = if *idx < 256 {
*idx as u8
} else {
options.failure
};
let _ = map.insert(m, col);
}
PaletteMapper {
map,
transparent: options.transparent.unwrap_or(options.failure),
failure: options.failure,
}
}
pub fn lookup(&self, r: u8, g: u8, b: u8, alpha: u8) -> u8 {
if alpha != 255 {
return self.transparent;
}
let m = r as u32 + ((g as u32) << 8) + ((b as u32) << 16);
*self.map.get(&m).unwrap_or(&self.failure)
}
}
pub fn to_indexed_image(image: RgbaImage, mapper: &PaletteMapper) -> ((u32, u32), Vec<u8>) {
let data = image
.pixels()
.map(|c| mapper.lookup(c.0[0], c.0[1], c.0[2], c.0[3]))
.collect();
(image.dimensions(), data)
}