astro-rustimg-service
v0.1.1
Published
Drop-in Astro image service powered by Rust (image + webp crates) via napi-rs
Maintainers
Readme
astro-rustimg-service
A drop-in replacement for astro/assets/services/sharp that processes images
using native Rust — the image crate for
JPEG/PNG/GIF decoding & encoding and the
webp crate for quality-controlled lossy
WebP output.
Built with napi-rs — prebuilt binaries ship for every supported platform so your users never need Rust or a C compiler.
Features
| Capability | Detail |
|---|---|
| Input formats | JPEG, PNG, GIF, BMP, ICO, WebP |
| Output formats | JPEG, PNG, WebP (lossy), GIF |
| Resize modes | cover, contain, fill, inside, outside |
| Quality control | Numeric (1–100) or preset (low/mid/high/max) |
| Default output | WebP lossy (quality 80) |
| AVIF | Inputs decoded via WebP fallback; output redirected to WebP |
Prebuilt platform support
| Platform | Target |
|---|---|
| Linux x64 glibc | x86_64-unknown-linux-gnu |
| Linux x64 musl | x86_64-unknown-linux-musl |
| Linux arm64 glibc | aarch64-unknown-linux-gnu |
| Linux arm64 musl | aarch64-unknown-linux-musl |
| macOS arm64 (Apple Silicon) | aarch64-apple-darwin |
| Windows x64 | x86_64-pc-windows-msvc |
| Windows arm64 | aarch64-pc-windows-msvc |
Installation
bun add astro-rustimg-service
# — or —
npm install astro-rustimg-serviceThe correct prebuilt .node binary is installed automatically as an optional
dependency for your platform.
Usage
// astro.config.mjs
import { defineConfig } from 'astro/config';
export default defineConfig({
image: {
service: {
entrypoint: 'astro-rustimg-service',
// All config fields are optional
config: {
defaultQuality: 80, // 1-100, or 'low'|'mid'|'high'|'max'
defaultFit: 'cover', // 'cover'|'contain'|'fill'|'inside'|'outside'
},
},
},
});Then use Astro's <Image /> and <Picture /> components as usual — they work
identically to the sharp-backed service:
---
import { Image } from 'astro:assets';
import hero from '../assets/hero.jpg';
---
<!-- WebP, quality 80, cover-cropped to 800×400 -->
<Image src={hero} width={800} height={400} alt="Hero" />
<!-- Explicit format + quality -->
<Image src={hero} width={600} format="jpeg" quality="high" alt="Hero" />Per-image quality presets
| Preset | Value |
|---|---|
| low | 25 |
| mid | 50 |
| high | 80 |
| max | 100 |
Differences from the Sharp service
| Feature | Sharp | astro-rustimg-service |
|---|---|---|
| Default output format | original / WebP | WebP |
| AVIF output | ✅ | ❌ → redirected to WebP |
| GIF animation | ✅ | ✅ (supported via gif crate) |
| macOS x64 | ✅ | ❌ arm64 only |
| Zero native deps at install time | ❌ | ✅ (prebuilt binaries) |
Development — building from source
You need Rust (stable) and Bun installed.
# Install JS dependencies (includes @napi-rs/cli)
bun install
# Debug build for the current platform
bun run build:debug
# Release build for the current platform
bun run buildThe compiled rustimg.<platform>.node file is placed in the project root and
loaded automatically by index.cjs.
Cross-compilation
Cross-compilation is handled by GitHub Actions (.github/workflows/CI.yml).
Push a v* tag to trigger a full cross-platform release build and npm publish.
git tag v0.1.0
git push origin v0.1.0Make sure NPM_TOKEN is set as a GitHub Actions secret.
Architecture
astro-rustimg-service/
├── src/lib.rs # Rust image processing (decode → fit → encode)
├── Cargo.toml # napi-rs + image + webp dependencies
├── build.rs # napi-rs build script
├── index.cjs # Platform-aware .node loader (CommonJS)
├── index.d.cts # TypeScript types for the native binding
├── astro-service.js # Astro LocalImageService (ESM, extends baseService)
├── astro-service.d.ts # TypeScript types for the Astro service
├── npm/ # Per-platform package manifests
│ ├── linux-x64-gnu/
│ ├── linux-x64-musl/
│ ├── linux-arm64-gnu/
│ ├── linux-arm64-musl/
│ ├── darwin-arm64/
│ ├── win32-x64-msvc/
│ └── win32-arm64-msvc/
└── .github/workflows/
└── CI.yml # Cross-compile matrix + npm publishResize fit modes
| Mode | Behaviour |
|---|---|
| cover | Scale to fill the canvas, crop overflowing edges (default) |
| contain | Scale to fit entirely within the canvas, letterboxed |
| fill | Stretch to exact dimensions, ignoring aspect ratio |
| inside | Scale down only; original is returned if already smaller |
| outside | Scale so image covers at least width × height |
License
MIT
