dusrelimage — Offline image toolkit

Compress, resize, crop, convert, watermark, annotate, pick colours, extract palettes, build collages and pixelate — instantly, on-device, with no network call and no data leaving your machine. One Rust core, one package, bindings for JavaScript, Python and Rust, plus a CLI.

Install

npm install dusrelimage
import { compressImage } from 'dusrelimage';

const out = compressImage(input, { quality: 70 }); // Uint8Array out
console.log(out.length);
from dusrelimage import compress_image

out = compress_image(data, quality=70)  # bytes out

Why dusrelimage

🖼️ 10 tools, one package

Compress, resize, crop, convert, watermark, annotate, colour picker, palette, collage, pixelate. No per-feature subpackages.

🔌 Fully offline

No API keys, no network calls, no per-image fees. Works in a Lambda, a CLI, or a browser with no internet. Your photos never leave the machine.

🦀 One Rust core

One implementation, one test suite — the same rules in JavaScript, Python and Rust. No drift between ports, same answer everywhere.

🇮🇳 Hindi + English errors

Every failure carries a stable code plus message_en and message_hi, so your error messages make sense to every user.

🎛️ Pro control

Options everywhere: quality, fit modes, filters, positions, opacity, rotation, EXIF handling, size limits — a real control layer, not presets.

⌨️ CLI

dusrelimage compress, resize, watermark, palette, collage … with --json output for scripts.

🧪 Bytes in, bytes out

Every operation takes bytes and returns bytes. No temp files, no shared state — steps compose like a pipeline.

🖥️ In-browser playground

The real Rust core compiled to WASM. Your files never leave the browser — try it before installing anything.

The 10 tools

ToolWhat it doesExample
CompressShrink file size at a quality, or to an exact target sizecompressImage(img, { quality: 70 })
ResizeNew width / height / percent, fit modes, filtersresizeImage(img, { width: 800 })
CropCut a rectangle, or an anchor presetcropImage(img, { width: 500, height: 500, anchor: 'Center' })
ConvertChange format — JPEG, PNG, WebP, AVIF, GIF, BMPconvertImage(img, { format: 'WebP' })
WatermarkText or logo stamp, 9 anchors + tiledaddWatermark(img, { text: { text: '© dusrel' } })
AnnotateArrows, rectangles, ellipses, lines, textannotateImage(img, [{ type: 'Arrow', … }])
Colour pickerThe exact colour of one pixel — hex, RGB, HSLpickColour(img, 120, 80)
PaletteDominant colours, most frequent firstextractPalette(img, 5)
CollageSeveral images into one grid / row / columnmakeCollage([a, b, c, d], { layout: '2x2' })
PixelateMosaic-blur a rectangle (faces, plates)pixelateImage(img, { x: 100, y: 80, width: 120, height: 120, blockSize: 16 })

Error codes — machine-readable, stable across releases

CodeMeans
INVALID_IMAGEInput is not an image, is truncated, or cannot be decoded
UNSUPPORTED_FORMATFormat recognised but not supported for this operation
IMAGE_TOO_LARGEOver the max_pixels limit (default 120,000,000)
TARGET_SIZE_UNREACHABLEEven the lowest quality exceeds the target size
CROP_OUT_OF_BOUNDSCrop rectangle sticks out of the image
PIXEL_OUT_OF_BOUNDSPicked pixel is outside the image
INVALID_QUALITYQuality outside 1–100
INVALID_DIMENSIONSBad or missing dimensions, or a side over the limit
INVALID_ARGUMENTBad argument (opacity, block size, bad layout, …)
EMPTY_INPUTEmpty input list / byte buffer where one item is required
INVALID_TYPEWrong value type reached a bindings API

Branch on code, never on the message text. Every failure also carries a Hindi message (message_hi). Full error-code table →

⚠️ Honest limits — read this first

v0.1.0 has no HEIC support and doesnot stream — the whole image lives in memory.

Full changelog →