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
pub mod color;
pub mod design;
use color::HSVRGBA;
use design::Design;
use exoquant::optimizer;
use exoquant::ditherer;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
#[wasm_bindgen(start)]
pub fn main() -> Result<(), JsValue> {
let window = web_sys::window().expect("no global `window` exists");
let document = window.document().expect("should have a document on window");
document.body().expect("document should have a body");
Ok(())
}
#[wasm_bindgen]
pub fn design_new() -> *mut Design {
Box::into_raw(Box::new(Design::default()))
}
#[wasm_bindgen]
pub fn design_palette(design: *const Design) -> Result<JsValue, JsValue> {
if let Some(design) = unsafe { design.as_ref() } {
let items: Vec<HSVRGBA> = design.palette().iter().map(Into::into).collect();
JsValue::from_serde(&items).map_err(|e| e.to_string().into())
} else {
Err("Got a null pointer for design".into())
}
}
#[wasm_bindgen]
pub fn design_dimensions(design: *const Design) -> Result<JsValue, JsValue> {
if let Some(design) = unsafe { design.as_ref() } {
JsValue::from_serde(&design.dimensions()).map_err(|e| e.to_string().into())
} else {
Err("Got a null pointer for design".into())
}
}
#[wasm_bindgen]
pub fn design_generate(design: *const Design, ditherer: String) -> Result<JsValue, JsValue> {
if let Some(design) = unsafe { design.as_ref() } {
let data = match ditherer.as_str() {
"none" => design.generate(ditherer::None),
"floydsteinberg" => design.generate(ditherer::FloydSteinberg::new()),
"floydsteinbergvanilla" => design.generate(ditherer::FloydSteinberg::vanilla()),
"floydsteinbergcheckered" => design.generate(ditherer::FloydSteinberg::checkered()),
"ordered" => design.generate(ditherer::Ordered),
e => return Err(format!("ditherer {} not recognized", e).into()),
};
JsValue::from_serde(&data).map_err(|e| e.to_string().into())
} else {
Err("Got a null pointer for design".into())
}
}
#[wasm_bindgen]
pub fn design_load_palette(design: *mut Design, buffers: JsValue) -> Result<(), JsValue> {
if let Some(design) = unsafe { design.as_mut() } {
let array: js_sys::Array = buffers.into();
let buffers: Vec<js_sys::Uint8ClampedArray> = array.to_vec().into_iter().map(Into::into).collect();
let data: Vec<Vec<(u8, u8, u8, u8)>> = buffers.into_iter().map(|b| b.to_vec().chunks_exact(4).map(|slice| (slice[0], slice[1], slice[2], slice[3])).collect()).collect();
design.load_histogram(data).map_err(Into::into)
} else {
Err("Got a null pointer for design".into())
}
}
#[wasm_bindgen]
pub fn design_optimize_palette(design: *mut Design, optimizer: String) -> Result<(), JsValue> {
if let Some(design) = unsafe { design.as_mut() } {
match optimizer.as_str() {
"kmeans" => design.optimize_palette(optimizer::KMeans),
"weightedkmeans" => design.optimize_palette(optimizer::WeightedKMeans),
e => return Err(format!("optimizer {} not recognized", e).into()),
}
Ok(())
} else {
Err("Got a null pointer for design".into())
}
}
#[wasm_bindgen]
pub fn design_load_image(design: *mut Design, buffer: JsValue, width: u32, height: u32) -> Result<(), JsValue> {
if let Some(design) = unsafe { design.as_mut() } {
let buffer: js_sys::Uint8ClampedArray = buffer.into();
let data: Vec<(u8, u8, u8, u8)> = buffer.to_vec().chunks_exact(4).map(|slice| (slice[0], slice[1], slice[2], slice[3])).collect();
design.load_image(data, (width as usize, height as usize)).map_err(Into::into)
} else {
Err("Got a null pointer for design".into())
}
}