spiegel-web/webclient/src/samples.rs

99 lines
2.9 KiB
Rust

use image::{load_from_memory_with_format, RgbaImage};
use std::sync::OnceLock;
use wasm_bindgen::prelude::*;
use include_dir::{include_dir, Dir, DirEntry};
static mut SAMPLES: OnceLock<Vec<ColorSample>> = OnceLock::new();
static SAMPLES_DIR: Dir = include_dir!("src/samples");
pub fn init() {
unsafe {
SAMPLES.get_or_init(|| {
log("reading image samples");
read_color_samples().unwrap()
});
}
}
pub fn get_closest_color<'a>(r: u8, g: u8, b: u8) -> &'static ColorSample {
unsafe {
let color_samples = SAMPLES.get_mut().unwrap();
let mut closest = None;
let mut min_diff: f32 = 4294967295.0; //0xFFFFFFFF
for sample in color_samples {
let diff = get_distance(sample.r, sample.g, sample.b, r, g, b);
if diff < min_diff {
closest = Some(sample);
min_diff = diff;
}
}
let closest = closest.unwrap();
if closest.image.is_none() {
let sample_image =
load_from_memory_with_format(closest.raw_bytes, image::ImageFormat::Jpeg)
.unwrap()
.to_rgba8();
closest.image = Some(sample_image);
}
closest
}
}
/// returns squared euclidian color distance
/// as if colors were points in 3d space
fn get_distance(r1: u8, g1: u8, b1: u8, r2: u8, g2: u8, b2: u8) -> f32 {
let red_dif = r1 as f32 - r2 as f32;
let green_dif = g1 as f32 - g2 as f32;
let blue_dif = b1 as f32 - b2 as f32;
return red_dif * red_dif + green_dif * green_dif + blue_dif * blue_dif;
}
/// read all sample jpegs into memory
pub fn read_color_samples() -> anyhow::Result<Vec<ColorSample>> {
let mut color_samples: Vec<ColorSample> = Vec::new();
for entry in SAMPLES_DIR.entries() {
if let DirEntry::File(f) = entry {
let filename = entry.path().file_name().unwrap().to_str().unwrap();
let hex_r = &filename[0..2];
let hex_g = &filename[2..4];
let hex_b = &filename[4..6];
color_samples.push(ColorSample {
filename: filename.into(),
r: u8::from_str_radix(&hex_r, 16)?,
g: u8::from_str_radix(&hex_g, 16)?,
b: u8::from_str_radix(&hex_b, 16)?,
raw_bytes: f.contents(),
image: None,
});
}
}
log("Done reading image samples");
Ok(color_samples)
}
#[derive(Debug)]
pub struct ColorSample {
pub filename: String,
pub r: u8,
pub g: u8,
pub b: u8,
pub raw_bytes: &'static [u8],
pub image: Option<RgbaImage>,
}
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
pub fn log(s: &str);
#[wasm_bindgen(js_namespace = console, js_name = log)]
fn log_u32(a: u32);
#[wasm_bindgen(js_namespace = console, js_name = log)]
fn log_many(a: &str, b: &str);
}