展示HN:Rust->WASM,K-Means用于图像到像素艺术的颜色量化板条箱
Show HN: Rust -> WASM, K-Means Color Quantization Crate for Image-to-Pixel-Art

原始链接: https://github.com/gametorch/image_to_pixel_art_wasm

本文档描述了一个编译为WebAssembly(WASM)的Rust库,该库可以直接在浏览器中将光栅图像转换为像素艺术。它利用K-means聚类进行调色板提取,允许用户指定颜色数量或提供自定义调色板。透明度得以保留。使用最近邻插值将图像缩小到固定的平铺网格,然后缩小,保持纵横比。 该库提供了一个“像素化”函数,接受图像数据、颜色计数、比例和可选调色板,并返回PNG编码的字节和使用的调色板。不涉及服务器端处理。 提供了使用“WASM-pack”或直接使用“cargo”构建WASM包的说明。JavaScript/TypeScript中的示例用法演示了如何导入WASM模块、加载图像、将其像素化并显示结果。 可选的本地CLI工具“pixelate-CLI”支持批量图像转换,具有颜色计数、比例、输出目录、自定义调色板和文件名前缀等选项。它可以用Rust构建,并为批处理提供了一个命令行界面。

A Hacker News post showcases a Rust-based crate that performs K-Means color quantization to convert images into pixel art using WASM. The demo is available on Github. One user, simlevesque, reported the demo didn't work, with the image uploading but nothing happening afterward. The creator, gametorch, responded, suggesting the image size could be a factor and offered troubleshooting assistance. Another user, sdovan1, confirmed the demo worked but suggested adding a loading indicator due to the processing time. Gametorch took note of the suggestion and mentioned plans to add predefined color palettes and explore LLMs for generating color palettes. vintermann suggested a masking tool to prioritize certain image regions in the clustering algorithm and the ability to lock the color palette, potentially requiring dithering. Finally, chaz6 inquired about exporting the output as terminal code.
相关文章

原文

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


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.


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

Usage overview:

pixelate-cli <INPUTS>... [options]

OPTIONS
  -k, --n-colors <N>    Number of colors for k-means (ignored when you supply a palette) [default: 8]
  -s, --scale <S>       Down-sample size for the longest side            [default: 64]
      --output-size <S> Final upscale size (longest side). Defaults to the original dimensions.
  -c, --palette <HEX,…> Comma-separated list of 6-char hex colors to use instead of running k-means.
  -d, --out-dir <DIR>   Directory to write results into (keeps original stems).
  -p, --prefix <STR>    Prefix for output filenames when not using --out-dir  [default: pixelated_]

Examples

# Basic bulk conversion with default options
target/release/pixelate-cli photos/*.jpg

# Custom palette & write into `out/` directory
target/release/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.

联系我们 contact @ memedata.com