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
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).
Prerequisites
- Rust nightly or stable (≥ 1.70).
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 bywasm-bindgen
.
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).
<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.
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.cdylib
– C dynamic library. It strips out Rust-specific metadata, producing a clean binary that can be loaded by foreign tool-chains. In the WASM worldwasm-bindgen
requirescdylib
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.
This project is released under the MIT license.
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.