Arsitektur Dithering untuk Optimasi Egress
Dithering mengonversi gambar gradien kontinu menjadi representasi palet warna terbatas (misalnya 1-bit monokrom atau 4-warna) tanpa menghilangkan ilusi kedalaman visual. Teknik ini memangkas ukuran aset secara drastis—sering kali mereduksi payload hingga 80-90% dibandingkan JPEG/WebP standar—sehingga menekan biaya transfer data (egress) dan mempercepat render pada koneksi rendah atau layar e-ink.
Implementasi pipeline dithering berfokus pada trade-off lokasi pemrosesan: memproses seluruh aset di muka saat build pipeline (batch build-time) atau merendernya secara dinamis via Edge Worker berbasis WebAssembly (WASM). Pilihan ini dipengaruhi oleh karakteristik dua algoritma utama:
- Ordered Dithering (Bayer Matrix): Algoritma berbasis matriks threshold deterministik. Komputasi bersifat point-wise tanpa ketergantungan antar-piksel, menjadikannya operasi O(1) per piksel yang sangat kompatibel dengan paralelisasi SIMD dan ramah beban CPU rendah.
- Floyd-Steinberg Dithering: Algoritma error diffusion yang menyebarkan residu kuantisasi ke piksel tetangga (kanan, bawah-kiri, bawah, bawah-kanan). Proses bersifat sekuensial baris demi baris, membutuhkan ketergantungan memori lokal, dan memakan siklus CPU lebih tinggi.
Pendekatan 1: Build-Time Batch Processing (Sharp/libvips)
Pada pendekatan ini, pemrosesan dithering didelegasikan ke pipeline CI/CD atau script build berkala. Gambar sumber diproses menggunakan sharp (pembungkus C++ libvips) dan hasilnya disimpan langsung ke object storage (seperti AWS S3 atau Cloudflare R2), lalu didistribusikan melalui CDN statis.
Contoh Implementasi: Batch Script dengan Sharp
import sharp from "sharp";
import { promises as fs } from "fs";
import path from "path";
async function ditherImage(inputPath, outputPath) {
// Floyd-Steinberg via libvips color quantization (1-bit output)
await sharp(inputPath)
.resize({ width: 800, withoutEnlargement: true })
.grayscale()
.threshold(128, { grayscale: true }) // Alternatif: kuantisasi palet kustom
.png({ colours: 2, dither: 1.0 })
.toFile(outputPath);
}
// ponytail: single-threaded loop; add p-limit worker pool when catalog > 1000 items
async function run() {
const files = await fs.readdir("./raw-assets");
for (const file of files) {
if (file.endsWith(".png") || file.endsWith(".jpg")) {
await ditherImage(
path.join("./raw-assets", file),
path.join("./dist-assets", path.parse(file).name + ".png")
);
}
}
}
run().catch(console.error);Karakteristik Teknis Build-Time
- Biaya Komputasi Runtime Nol: Permintaan pengguna murni dilayani oleh CDN cache atau static bucket. Tidak ada risiko cold-start maupun batas waktu eksekusi runtime.
- Dampak CI/CD: Skalabilitas linier negatif terhadap volume aset. Katalog dengan 50.000 gambar akan meningkatkan durasi build pipeline secara ekstrem jika tidak menggunakan incremental build hashing yang ketat.
- Storage Footprint: Setiap kombinasi variasi (misal: 1-bit hitam-putih, 2-bit grayscale, thumbnail) membutuhkan objek terpisah di S3, melipatgandakan biaya penyimpanan statis.
Pendekatan 2: On-Demand Dynamic Processing (Edge Worker + WASM/Rust)
Pendekatan edge memindahkan transformasi ke CDN edge node (seperti Cloudflare Workers, Fastly Compute@Edge). Worker mengekstrak gambar asli dari origin, menjalankan algoritma dithering yang dikompilasi ke WebAssembly (WASM), mengembalikan output terkompresi, dan menyimpannya di Edge Cache API.
Contoh Implementasi: Ordered Dithering Core (Rust -> WASM)
// Rust: Bayer 4x4 Ordered Dithering
const BAYER_4X4: [f32; 16] = [
0.0/16.0, 8.0/16.0, 2.0/16.0, 10.0/16.0,
12.0/16.0, 4.0/16.0, 14.0/16.0, 6.0/16.0,
3.0/16.0, 11.0/16.0, 1.0/16.0, 9.0/16.0,
15.0/16.0, 7.0/16.0, 13.0/16.0, 5.0/16.0,
];
pub fn ordered_dither(pixels: &mut [u8], width: usize, height: usize) {
for y in 0..height {
for x in 0..width {
let idx = y * width + x;
let old_val = pixels[idx] as f32 / 255.0;
let threshold = BAYER_4X4[(y % 4) * 4 + (x % 4)];
pixels[idx] = if old_val > threshold { 255 } else { 0 };
}
}
}
// skipped: SIMD vectorization; add when targeting AVX2/Neon edge runtimesKarakteristik Teknis Edge Worker
- Batasan Eksekusi CPU: Worker serverless memiliki plafon CPU ketat (umumnya 10ms–50ms per request pada tier standar). Floyd-Steinberg pada gambar resolusi > 1080p dapat melampaui batas ini dan memicu kegagalan runtime (Worker CPU Time Exceeded). Bayer dithering jauh lebih aman di lingkungan ini.
- Cold Start dan Cache Hit Ratio: Request pertama (cache-miss) menanggung overhead: fetch origin, inisialisasi modul WASM, decode PNG/JPEG, kalkulasi dither, encode, dan write-back ke edge cache. Jika cache hit ratio rendah (< 85%), tail latency (p99) akan memburuk.
- Struktur Biaya: Menghilangkan storage varian S3, namun memunculkan biaya komputasi edge per request yang belum tercache (compute duration + worker invocation cost).
Perbandingan Parameter Arsitektur
| Metrik / Parameter | Build-Time (Sharp/CI) | On-Demand Edge (WASM) |
|---|---|---|
| Algoritma Optimal | Floyd-Steinberg & Ordered | Ordered (Bayer) |
| Biaya Storage Origin | Tinggi (N varian per gambar) | Rendah (Hanya gambar master) |
| Biaya Compute | CI/CD Runner minutes | Edge Invocations + CPU time |
| Cache Invalidation | Sederhana (Atomic deploy) | Kompleks (Purge edge cache) |
| Latency (p50 / p99) | Sangat Rendah (CDN static hit) | Bervariasi (Tergantung Cache Hit %) |
| Batas Ukuran Gambar | Hampir tak terbatas (RAM host) | Ketat (< 2-4MB input limit) |
Evaluasi Beban Kerja: Katalog Statis vs UGC
1. Katalog Statis (E-commerce, Dokumentasi, Portofolio)
Aset jarang berubah dan variasinya dapat diprediksi saat deploy. Pola akses mengikuti kurva Zipfian terdistribusi normal.
- Rekomendasi: Gunakan Build-Time Batch Processing.
- Alasan: Durasi eksekusi CI/CD dapat diisolasi dengan caching artefak (misal: hashing nama file source). Menghilangkan risiko eksekusi CPU edge terlampaui dan menjamin cache hit 100% pada layer CDN tanpa cold-start.
2. User-Generated Content (UGC & Media Dinamis)
Pengguna mengunggah gambar resolusi sembarang secara kontinu. Tidak memungkinkan melakukan rebuild CI/CD setiap kali ada upload baru.
- Rekomendasi: Gunakan On-Demand Edge Worker dengan Bayer Dithering, atau Asynchronous Event-Driven Pipeline.
- Alasan Teknis: Jika transformasi harus real-time on-the-fly, gunakan Rust/WASM dengan algoritma Ordered Dithering untuk menjamin durasi eksekusi tetap di bawah ambang batas batas CPU worker (misal < 20ms).
- Alternatif Pragmatis: Jika Floyd-Steinberg mutlak dibutuhkan untuk UGC resolusi tinggi, jangan jalankan di Edge Worker. Gunakan arsitektur asinkron: upload ke S3 -> trigger AWS Lambda/Cloud Run (libvips) -> simpan output dither ke S3 varian.
Peringatan Produksi: Hindari menjalankan Floyd-Steinberg dithering beresolusi di atas 1200x1200px di dalam edge worker standar tanpa isolated execution plan. Operasi error-diffusion sekuensial pada buffer memori besar akan memicu pemutusan thread worker oleh runtime watchdog.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!