Created
December 18, 2024 10:01
-
-
Save udzura/6409550d7200f52b32b057e02ba2f8e9 to your computer and use it in GitHub Desktop.
grayscale.wasm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[package] | |
name = "advent-ruby-grayscale" | |
version = "0.1.0" | |
edition = "2021" | |
[dependencies] | |
base64 = "0.22.1" | |
image = { version = "0.25.2", default-features = false, features = ["png"] } | |
[lib] | |
crate-type = ["cdylib", "rlib"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern crate image; | |
use core::str; | |
use core::slice::from_raw_parts; | |
use base64::{engine::general_purpose, Engine}; | |
#[no_mangle] | |
pub unsafe fn grayscale( | |
width: u32, | |
height: u32, | |
src: *const u8, // メモリにセットしたdataURLのoffset | |
slen: i32, // メモリにセットしたdataURLの長さ | |
) -> *const u8 { | |
let src = from_raw_parts(src, slen as usize); | |
// メモリを内部でも確保してコピーする(元の領域が万一破壊されるのを防ぐ) | |
let mut tmp_buf: Vec<u8> = Vec::<u8>::new(); | |
tmp_buf.resize(slen as usize, 0); | |
tmp_buf.copy_from_slice(src); | |
// 返却用のバッファを、大きく確保する | |
let mut result_buf: Vec<u8> = Vec::<u8>::new(); | |
result_buf.resize(1<<22, 0); | |
// URLをstrに変換し、base64部分だけ取り出す | |
let url = str::from_utf8(&tmp_buf).unwrap(); | |
let collected = url.split(",").collect::<Vec<&str>>(); | |
let src = collected[1].as_bytes(); | |
// decode base64 | |
let blob: Vec<u8> = general_purpose::STANDARD.decode(src).unwrap(); | |
// 渡されたデータをPNGとして解釈する | |
let img = image::load_from_memory_with_format( | |
&blob, image::ImageFormat::Png).unwrap(); | |
let img: image::ImageBuffer<image::Rgb<u8>, _> = img.to_rgb8(); | |
// あとは元のgrayscaleと同様のコード | |
let mut dest = image::GrayImage::new(width, height); | |
for y in 0..height { | |
for x in 0..width { | |
let pixel: &image::Rgb<u8> = img.get_pixel(x, y); | |
let val = | |
(pixel[0] as f32 + pixel[1] as f32 + pixel[2] as f32) / 3.0; | |
let val = [val as u8; 1]; | |
dest.put_pixel(x, y, image::Luma(val)); | |
} | |
} | |
// デバッグのため、wasmでないときにファイルを生成する | |
#[cfg(not(target_arch="wasm32"))] | |
{ | |
dest.save("/tmp/debug.png").unwrap(); | |
} | |
// オンメモリで変換後のPNGを生成する | |
let mut inter_buf = Vec::<u8>::new(); | |
let enc = image::codecs::png::PngEncoder::new(&mut inter_buf); | |
dest.write_with_encoder(enc).unwrap_or_else(|_| panic!("encode failed") ); | |
// オンメモリのデータをbase64にエンコードする | |
general_purpose::STANDARD.encode_slice(&inter_buf, &mut result_buf).unwrap(); | |
// データの先頭ポインタ = offset を返却 | |
result_buf.as_ptr() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment