Image Processing di Browser — WebAssembly

Image Processing dengan Wasm Image processing adalah salah satu use case paling cocok untuk WebAssembly — manipulasi pixel-by-pixel yang compute-intensive…

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

Tips

Yang akan kamu pelajari