Dither images to correct width
This commit is contained in:
parent
5cafe3fe2b
commit
6112a8c02f
2 changed files with 69 additions and 7 deletions
|
|
@ -26,8 +26,18 @@
|
||||||
|
|
||||||
#import plugin("plugin.wasm") as p
|
#import plugin("plugin.wasm") as p
|
||||||
|
|
||||||
#let dither(path) = {
|
#let _length_to_bytes(len) = {
|
||||||
let bytes = read(path, encoding: none)
|
let len = len.pt()
|
||||||
let dithered = p.dither(bytes)
|
let n = if len > 10000 { -1 } else { int(len) }
|
||||||
image(dithered)
|
n.to-bytes(size: 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#let dither(path) = layout(size => {
|
||||||
|
let bytes = read(path, encoding: none)
|
||||||
|
let dithered = p.dither(
|
||||||
|
bytes,
|
||||||
|
_length_to_bytes(size.width),
|
||||||
|
_length_to_bytes(size.height),
|
||||||
|
)
|
||||||
|
image(dithered)
|
||||||
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,57 @@
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
use image::ImageFormat;
|
use image::{
|
||||||
|
ImageFormat,
|
||||||
|
imageops::{self, FilterType},
|
||||||
|
};
|
||||||
use mark::dither::{AlgoFloydSteinberg, Algorithm, DiffEuclid, Palette};
|
use mark::dither::{AlgoFloydSteinberg, Algorithm, DiffEuclid, Palette};
|
||||||
use palette::LinSrgb;
|
use palette::LinSrgb;
|
||||||
use wasm_minimal_protocol::{initiate_protocol, wasm_func};
|
use wasm_minimal_protocol::{initiate_protocol, wasm_func};
|
||||||
|
|
||||||
initiate_protocol!();
|
initiate_protocol!();
|
||||||
|
|
||||||
|
fn i64_from_bytes(bytes: &[u8]) -> Result<i64, String> {
|
||||||
|
let bytes: [u8; 8] = bytes.try_into().map_err(|it| format!("{it}"))?;
|
||||||
|
Ok(i64::from_le_bytes(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size_from_i64(size: i64) -> Result<Option<u32>, String> {
|
||||||
|
if size < 0 {
|
||||||
|
return Ok(None); // Unlimited width
|
||||||
|
}
|
||||||
|
|
||||||
|
let size: u32 = size.try_into().map_err(|_| "size too large")?;
|
||||||
|
Ok(Some(size))
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_func]
|
#[wasm_func]
|
||||||
pub fn dither(image: &[u8]) -> Result<Vec<u8>, String> {
|
pub fn dither(image: &[u8], max_width: &[u8], max_height: &[u8]) -> Result<Vec<u8>, String> {
|
||||||
let image = image::load_from_memory(image)
|
let max_width = size_from_i64(i64_from_bytes(max_width)?)?;
|
||||||
|
let max_height = size_from_i64(i64_from_bytes(max_height)?)?;
|
||||||
|
|
||||||
|
let mut image = image::load_from_memory(image)
|
||||||
.map_err(|it| format!("Failed to read image: {it:?}"))?
|
.map_err(|it| format!("Failed to read image: {it:?}"))?
|
||||||
.to_rgba8();
|
.to_rgba8();
|
||||||
|
|
||||||
|
let image_width = image.width();
|
||||||
|
let image_height = image.height();
|
||||||
|
|
||||||
|
let scale_factor = match (max_width, max_height) {
|
||||||
|
(None, None) => 1.0,
|
||||||
|
(None, Some(height)) => height as f32 / image_height as f32,
|
||||||
|
(Some(width), None) => width as f32 / image_width as f32,
|
||||||
|
(Some(width), Some(height)) => {
|
||||||
|
(width as f32 / image_width as f32).min(height as f32 / image_height as f32)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let target_width = (image_width as f32 * scale_factor) as u32;
|
||||||
|
let target_height = (image_height as f32 * scale_factor) as u32;
|
||||||
|
|
||||||
|
if image_width != target_width || image_height != target_height {
|
||||||
|
image = imageops::resize(&image, target_width, target_height, FilterType::CatmullRom);
|
||||||
|
}
|
||||||
|
|
||||||
let palette = Palette::new(vec![
|
let palette = Palette::new(vec![
|
||||||
LinSrgb::new(0.0, 0.0, 0.0),
|
LinSrgb::new(0.0, 0.0, 0.0),
|
||||||
LinSrgb::new(1.0, 1.0, 1.0),
|
LinSrgb::new(1.0, 1.0, 1.0),
|
||||||
|
|
@ -27,3 +66,16 @@ pub fn dither(image: &[u8]) -> Result<Vec<u8>, String> {
|
||||||
|
|
||||||
Ok(bytes)
|
Ok(bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_func]
|
||||||
|
pub fn debug(value: &[u8]) -> Result<Vec<u8>, String> {
|
||||||
|
// let value: [u8; 4] = value
|
||||||
|
// .try_into()
|
||||||
|
// .map_err(|it| format!("incorrect number of bytes: {it}"))?;
|
||||||
|
|
||||||
|
// let be = u32::from_be_bytes(value);
|
||||||
|
// let le = u32::from_le_bytes(value);
|
||||||
|
|
||||||
|
// Ok(format!("be: {be}, le: {le}").into_bytes())
|
||||||
|
Ok(format!("{value:?}").into_bytes())
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue