Image Processing dengan Wasm
Image processing adalah salah satu use case paling cocok untuk WebAssembly — manipulasi pixel-by-pixel yang compute-intensive, jauh lebih cepat dibanding JavaScript murni.
Arsitektur
// Flow:
Canvas/Image → getImageData() → pixel array (JS)
→ copy ke Wasm memory
→ process pixels (Wasm - super cepat)
→ copy kembali ke JS
→ putImageData() → Canvas
Rust: Filter Grayscale
use wasm_bindgen::prelude::*;
use wasm_bindgen::Clamped;
#[wasm_bindgen]
pub fn grayscale(pixels: Clamped<&mut [u8]>, width: u32, height: u32) {
let data = &mut pixels.0;
let total = (width * height * 4) as usize;
let mut i = 0;
while i < total {
// Setiap pixel: [R, G, B, A]
let r = data[i] as f32;
let g = data[i + 1] as f32;
let b = data[i + 2] as f32;
// Luminance formula (persepsi mata manusia)
let gray = (0.299 * r + 0.587 * g + 0.114 * b) as u8;
data[i] = gray; // R
data[i + 1] = gray; // G
data[i + 2] = gray; // B
// data[i + 3] tetap (Alpha)
i += 4;
}
}
#[wasm_bindgen]
pub fn brightness(pixels: Clamped<&mut [u8]>, amount: i32) {
let data = &mut pixels.0;
for i in (0..data.len()).step_by(4) {
data[i] = clamp(data[i] as i32 + amount);
data[i + 1] = clamp(data[i + 1] as i32 + amount);
data[i + 2] = clamp(data[i + 2] as i32 + amount);
}
}
fn clamp(val: i32) -> u8 {
val.max(0).min(255) as u8
}
JavaScript Integration
import init, { grayscale, brightness } from "./pkg/image_wasm.js";
await init();
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
// Load image ke canvas
const img = new Image();
img.src = "photo.jpg";
await img.decode();
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
// Ambil pixel data
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
// Process dengan Wasm (sangat cepat!)
console.time("wasm-grayscale");
grayscale(imageData.data, canvas.width, canvas.height);
console.timeEnd("wasm-grayscale"); // ~2ms untuk 4K image
// Tampilkan hasil
ctx.putImageData(imageData, 0, 0);
Perbandingan Performa
- Grayscale 4K image (3840x2160) — JS: ~45ms, Wasm: ~3ms (15x lebih cepat)
- Gaussian blur 5x5 — JS: ~300ms, Wasm: ~20ms (15x lebih cepat)
- Edge detection (Sobel) — JS: ~200ms, Wasm: ~15ms (13x lebih cepat)
Tips
- Batch processing — Kirim seluruh pixel array sekaligus, bukan per-pixel
- OffscreenCanvas — Proses di Web Worker agar UI tetap responsif
- SIMD — Wasm SIMD (128-bit) bisa mempercepat 2-4x lagi untuk operasi pixel