展示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构建,并为批处理提供了一个命令行界面。

Hacker News的一篇帖子强调了一个基于Rust的WASM板条箱,用于K-Means颜色量化,旨在将图像转换为像素艺术(github.com/gametorch)。海报gametorch收到的反馈是,演示对至少一个用户不起作用。Simlevesque报道称,在图像上传后,演示什么也没做。Gametorch怀疑这个问题可能与大图像尺寸有关,并指出处理可能需要时间,尤其是在移动设备上。Gametorch要求simlevesque检查devtools中的错误消息,以协助调试。另一位用户sdovan1在延迟20秒后报告成功,这表明加载指示器会有所帮助。Gametorch做出了积极回应,承认了这一建议,并提到了添加预定义调色板和利用LLM生成调色板的计划。
相关文章

原文

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