Skip to content

An open source "Rust ↦ WASM, k-Means Color Quantization" crate for Image-to-Pixel-Art conversions in the browser

License

Notifications You must be signed in to change notification settings

gametorch/image_to_pixel_art_wasm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Live UI

Try the pixel-art converter instantly at https://gametorch.app/image-to-pixel-art
Free forever · no sign-up required · runs 100 % in your browser

Spirit Moose


image_to_pixel_art_wasm

A tiny Rust → WebAssembly library that turns any raster image into low-color pixel-art.

Features

  • K-means palette extraction with user-selectable color count or supply your own palette.
  • Keeps transparency intact – only opaque pixels are processed.
  • Down-samples to a fixed tile grid (e.g. 64 × 64) using nearest-neighbour then scales back up – aspect-ratio preserved.
  • Pure client-side: the heavy lifting happens completely inside your browser thanks to WASM.

The public API exported via wasm-bindgen:

// palette is optional: string[ ] of 6-char HEX, e.g. ["FFAA00", "112233"]
// returns { image: Uint8Array, palette: string[ ] }
function pixelate(
  input: Uint8Array,
  n_colors: number,
  scale: number,
  output_size?: number,
  palette?: string[]
): { image: Uint8Array; palette: string[] };

It returns PNG-encoded bytes plus the palette actually used (either supplied or discovered).


Building the WebAssembly bundle

Prerequisites

  1. Rust nightly or stable (≥ 1.70).
  2. wasm-pack (cargo install wasm-pack).

Compile:

wasm-pack build --release --target web

Under pkg/ you will get:

  • image_to_pixel_art_wasm_bg.wasm – the WebAssembly binary.
  • image_to_pixel_art_wasm.js – a tiny ES module wrapper generated by wasm-bindgen.

Building with plain cargo

If you prefer not to use wasm-pack, compile directly via Cargo after setting the getrandom backend flag:

# Unix
RUSTFLAGS='--cfg getrandom_backend="wasm_js"' \
    cargo build --release --target wasm32-unknown-unknown

# Windows (PowerShell)
$Env:RUSTFLAGS='--cfg getrandom_backend="wasm_js"'
cargo build --release --target wasm32-unknown-unknown

This produces the raw WebAssembly binary at

target/wasm32-unknown-unknown/release/image_to_pixel_art_wasm.wasm

You will then need to run the wasm-bindgen CLI to create the JavaScript glue files (equivalent to what wasm-pack did automatically):

wasm-bindgen --target web --out-dir ./pkg \
    target/wasm32-unknown-unknown/release/image_to_pixel_art_wasm.wasm

After this step the pkg/ directory will contain the same two files described earlier (*.wasm and the corresponding ES-module wrapper).


Using from vanilla JavaScript / TypeScript

<script type="module">
import init, { pixelate } from './pkg/image_to_pixel_art_wasm.js';

// Wait for WASM to finish loading
await init();

const file = await fetch('my_photo.jpg').then(r => r.arrayBuffer());
const pngBytes = pixelate(new Uint8Array(file), /* n_colors */ 8, /* scale */ 64);

const blob = new Blob([pngBytes], { type: 'image/png' });
document.getElementById('out').src = URL.createObjectURL(blob);
</script>
<img id="out" />

No bundler required — modern browsers understand ES modules & WASM directly.


crate-type = ["cdylib", "rlib"] — what & why?

Rust's crate type controls which artifacts Cargo builds:

  • rlib – Rust static library. Other Rust crates can link to it, enabling unit tests, benches or workspace integration. This is the default for library crates.
  • cdylibC dynamic library. It strips out Rust-specific metadata, producing a clean binary that can be loaded by foreign tool-chains. In the WASM world wasm-bindgen requires cdylib so it can massage the output into a .wasm file plus the JS glue code.

By declaring both we keep the crate usable as a normal Rust dependency and ready for WebAssembly packaging.


License

This project is released under the MIT license.


CLI Tool and Bulk Conversions

If you prefer a native command-line workflow (and want to batch-process many files) you can build the optional pixelate-cli binary.

Build it (native only – no WASM):

cargo build --release --features native-bin --bin pixelate-cli
# binary at target/release/pixelate-cli

Or install it for system-wide use, assuming ~/.cargo/bin is in your PATH environment variable):

cargo install --path . --features native-bin --bin pixelate-cli

Usage overview:

Pixel-artify images using the Rust WASM library (native wrapper)

Usage: pixelate-cli [OPTIONS] <INPUTS>...

Arguments:
  <INPUTS>...  One or more input image paths

Options:
  -k, --n-colors <N_COLORS>        Number of colors for k-means when no custom palette is provided [default: 8]
  -s, --scale <SCALE>              Target down-sample size (longest side) [default: 64]
  -o, --output-size <OUTPUT_SIZE>  Optional upscale size. If omitted, original dimensions are used
  -c, --palette <PALETTE>          Comma-separated list of hex colors to use as palette (skip k-means)
      --fix-palette <FILE>         Extract k-means palette from this reference image, then apply to inputs
      --no-downscale               Skip downscale before palette extraction
  -d, --out-dir <OUT_DIR>          Output directory
  -p, --prefix <PREFIX>            Output filename prefix (ignored when --out-dir supplied) [default: pixelated_]
      --porcelain                  Machine-readable output (JSON)
  -h, --help                       Print help
  -V, --version                    Print version

Examples

# Basic conversion
pixelate-cli moose.jpg --n-colors 64

# Make the resulting "pixels" smaller (there will be more "pixels")
pixelate-cli moose.jpg --n-colors 64 --relative-scale 0.25

# Basic bulk conversion
pixelate-cli photos/*.jpg

# Basic bulk conversion with ONE color palette used for all images
pixelate-cli photos/*.jpg --fix-palette photos/my_reference_image.jpg

# Custom palette & write into `out/` directory
pixelate-cli sprites/*.png \
  --palette "FF0000,00FF00,0000FF" \
  --scale 32 \
  --out-dir out

Original WASM crate authored entirely with o3 in 30 minutes — see the git commit timestamps for proof.

About

An open source "Rust ↦ WASM, k-Means Color Quantization" crate for Image-to-Pixel-Art conversions in the browser

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages