Skip to content

Repository files navigation

artefact

Rust WASM Vue Vite Bun TailwindCSS TypeScript License Platform

Reconstructs lost JPEG detail for smoother, more pleasing images — Rust rewrite of jpeg2png, ~3× faster, runs natively via CLI or directly in the browser via WASM.

JPEG compression discards data and regular decoders "fill in" the gaps with noisy guesses that create visible artifacts. Instead of patching holes, artefact re-optimizes the DCT coefficients with a regularized solver to produce smoother gradients with less staircasing.

Maintenance mode. Feature work is complete. The project receives automated dependency and security updates only — Dependabot runs daily with a 14-day cooldown, batched into weekly releases. Bug reports are welcome; new features and large changes are unlikely to be accepted.

Demos

Photo by Aleksandar Pasaric

Photo by Toa Heftiba Şinca

Features

  • Rust core — port of jpeg2png from C++ to Rust (backend/artefact-core)
  • ~3× faster — rayon parallelism + optional SIMD (std::simd, adaptive x8/x16/x32/x64 dispatch via the simd feature; wasm uses uniform x8)
  • GPU acceleration — optional wgpu backend for native and browser solves, with tolerance-checked equivalence and explicit CPU fallback
  • WASM-ready — backend/artefact-wasm via wasm-pack, runs 100% client-side at artefact.delnegend.com (no upload)
  • CLI + Web — same solver for native binary (artefact-cli) and browser (frontend Vue 3 + Vite)
  • Flexible I/O — input .jpg/.jpeg, output png/webp/tiff/bmp (auto by extension)
  • Tunable solver — per-channel weight / pweight / iterations, separate_components for YCbCr

Quick start

Installation

Pre-built CLI (recommended):

# download from Releases (output: artefact-cli, .exe on Windows)
# https://github.com/Delnegend/artefact/releases/latest

Build from source:

git clone https://github.com/Delnegend/artefact.git
cd artefact

# native CLI (release, uses mold + clang if in devcontainer)
cargo build --bin artefact-cli --release
# or: just build

# cross-compiled (linux x64, windows x64, macOS arm64)
# built on GitHub Actions via .github/workflows/release.yml — see Development

Web (no install):

Open artefact.delnegend.com — everything runs in your browser.

Usage

1. The performance way — CLI:

# basic: input.jpg -> input.png (same dir)
artefact-cli input.jpg

# choose output and format
artefact-cli input.jpg -o output.webp --format webp -y

# tune solver (single value for all channels, or Y,Cb,Cr)
artefact-cli input.jpg --weight 0.3 --pweight 0.001 --iterations 50
artefact-cli input.jpg --weight 0.3,0.2,0.3 --iterations 50,30,50

# benchmark without writing file
artefact-cli input.jpg --benchmark

# use the GPU when available, otherwise fall back to the CPU
artefact-cli input.jpg --gpu

# help
artefact-cli --help

Solver backends: process() always uses the CPU pipeline. The CLI’s --gpu uses process_auto(): it logs the selected wgpu adapter and solving on GPU when usable, otherwise warns and returns to solving on CPU pipeline. Set RUST_LOG=debug for lower-level selection diagnostics.

To compare production solves without asserting benchmark timings:

RUSTFLAGS="-C target-cpu=native" RAYON_NUM_THREADS=8 \
  cargo bench -p artefact-core --features bench,simd,gpu --bench gpu

2. The convenience way — browser:

  1. Go to artefact.delnegend.com
  2. Drop a JPEG
  3. Compare input/output with the slider and download PNG

WASM is slower than native but stays fully client-side. The browser worker probes for a usable WebGPU adapter (including GPUAdapter.info) and passes that decision to the async compute API: GPU when available, CPU otherwise.

Development

Prerequisites

Recommended: devcontainer — no host toolchain needed:

# VS Code: Command Palette → Reopen in Container
# CLI:
devcontainer up --workspace-folder .

Toolchain is baked into the image (Rust nightly + rust-analyzer, mold 2.42.1, cargo-binstall/flamegraph/wasm-pack, just, fzf, bun, node) for cache and for editors that skip postCreateCommand (e.g. Zed). postinstall.sh only runs bun i in frontend.

Without devcontainer:

  • Rust via rustup (nightly, minimal profile)
  • just, bun, wasm-pack
  • zip/tar only if manually archiving — releases (linux x64, windows x64, macOS arm64) are built on GitHub Actions via .github/workflows/release.yml. ffmpeg only for sample image generation (not in devcontainer by default).

See docs/development.md for full prerequisites and sample-image helpers.

Repository overview

.
├── backend/
│   ├── artefact-core/    # core solver — pipeline/{scalar,simd,gpu} + shared utils
│   ├── artefact-cli/     # native binary (clap)
│   ├── artefact-wasm/    # wasm-pack cdylib for frontend
│   └── zune-jpeg/        # fork of zune-jpeg — exposes DCT coeffs + fixes
├── frontend/             # Vue 3 + Vite + Tailwind — src/utils/artefact-wasm is generated
├── assets/               # demo images (01.png-04.png)
└── docs/development.md   # directory structure, SIMD flags, cross-compile, WASM/web builds

Workspace versions are centralized in [workspace.dependencies] at the root Cargo.toml:5 — bump once, inherited via workspace = true in each crate.

Build

# frontend dev (hot reload)
just dev
# or: cd frontend && bun x vite

# WASM lib (generates frontend/src/utils/artefact-wasm)
just build wasm
# or: wasm-pack build backend/artefact-wasm --target web --out-dir frontend/src/utils/artefact-wasm

# web (static build for GitHub Pages -> frontend/dist)
just build web
# or: cd frontend && bun x vite build

# native CLI (release, LTO)
just build            # -> target/release/artefact-cli
# or: cargo build --bin artefact-cli --release

# cross-compiled releases (linux x64, windows x64, macOS arm64)
# built on GitHub Actions via .github/workflows/release.yml
# trigger: weekly cron (Sunday 00:00 UTC) or workflow_dispatch

SIMD / solver flags are toggled in backend/artefact-core/Cargo.toml features (simd) and enabled in dependent crates — see docs/development.md#solver-pipelines. Pipelines live in pipeline/{scalar,simd,gpu} with shared logic in utils/ (scalar is the frozen reference, simd is the default for the CLI and wasm).

Checks

just check          # fmt + clippy + tests + oxlint + oxfmt (all)
just check rust     # Rust only
just check js       # frontend only (oxlint + oxfmt)

just check rust sets ARTEFACT_REQUIRE_GPU=1, so GPU tests cannot pass by skipping missing adapters or required fixtures. Plain cargo test keeps the lenient skips for machines without a GPU.

Sample images with chroma subsampling:

just encode              # assets/sample.png -> assets/sample.{j444,j422,j420,444,422,420}.input.jpg (needs ffmpeg)
just decode 420          # -> assets/sample.420.decoded.png via artefact-cli
just flame 420           # flamegraph for profiling

Architecture

graph TD
    Z[zune-jpeg<br/>fork - DCT coeffs] --> L[artefact-core<br/>solver<br/>pipeline/{scalar,simd,gpu}<br/>rayon]
    L --> C[artefact-cli<br/>clap - png/webp/tiff/bmp<br/>--gpu optional]
    L --> W[artefact-wasm<br/>wasm-bindgen<br/>cdylib<br/>process_auto/process]
    W --> F[frontend<br/>Vue 3 / Vite<br/>Tailwind + PWA<br/>artefact.delnegend.com]
    F -. upload .-> W
Loading

artefact-core is feature-gated: without simd, pipeline::scalar is used; simd selects the SIMD pipeline. Native uses adaptive x8/x16/x32/x64 dispatch over std::simd; wasm uses uniform x8. gpu adds the pipeline::gpu backend with process_gpu, process_gpu_with, and process_auto. Decoding always goes through the vendored zune-jpeg fork.

CLI reference

Flag Short Default Description
<input> — — Input JPEG file
--output <path> -o <input>.png Output file (extension infers format when --format auto)
--format <fmt> -f auto auto or png/webp/tiff/bmp
--weight <f32> -w 0.3 2nd-order weight — higher = smoother, less staircasing. Single or Y,Cb,Cr
--pweight <f32> -p 0.001 Fidelity weight — higher = closer to source JPEG
--iterations <n> -i 50 Solver iterations — higher = better but slower. Single or Y,Cb,Cr
--separate-components -s false Optimize Y/Cb/Cr separately instead of jointly
--gpu -g false Use the GPU when available (process_auto), otherwise fall back to CPU
--benchmark -b false Run solver but don't write output
--overwrite -y false Overwrite existing output

Defined in backend/artefact-cli/main.rs:18 and backend/artefact-core/lib.rs:63.

Contributing

The project is in maintenance mode: bug fixes and dependency/security updates are welcome, but feature work is paused. Please open an issue before starting anything substantial.

git clone https://github.com/Delnegend/artefact.git
# devcontainer recommended, else install prerequisites above
just check   # must pass before PR

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion shall be dual-licensed as below without additional terms (per Apache-2.0 §5).

License

Licensed under either of

at your option.

Acknowledgements

Based on jpeg2png by Victor van der Elst. Thanks to zune-jpeg / zune-image and the Rust / WASM / Vue / Vite communities.

About

Remove JPEG compression artefacts — Rust rewrite of jpeg2png (native CLI + WebGPU/WASM in the browser)

Topics

Resources

Stars

2 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages