photeryx
v0.1.5
Published
Fast Rust + WebAssembly image processing for the browser.
Maintainers
Readme
Photeryx
High-performance Rust + WebAssembly image processing for modern web applications.
🚀 Overview
Photeryx is a fast, lightweight image processing pipeline powered by Rust + WebAssembly, designed for browsers and modern frontend apps. It supports loading multiple images, transforming them, and exporting them in various formats, all locally without backend services.
This makes it ideal for:
- Image editors
- Upload preprocessors
- Offline-first web apps
- High-performance React / Vue / Svelte applications
✨ Core Features
- Written in Rust, compiled to WebAssembly
- Manage multiple images in memory at once
- Load images from:
FileURLArrayBuffer
- Transformations:
- Rotate
- Crop
- Resize
- Filters (brightness, contrast, blur, sharpen, etc.)
- Export formats:
JPEGPNGWebP
- Export as:
Uint8ArrayBlob- Base64
data:URL
- Duplicate detection across loaded images (returns
Photo[][]) - Manual memory control: free images when you’re done
- Zero network dependency
📦 Installation
npm install photeryx🧱 TypeScript API Overview
export interface RotationConfig {
degrees: number;
}
export interface CropConfig {
x: number;
y: number;
width: number;
height: number;
}
export interface ResizeConfig {
max_width: number;
max_height: number;
mode: "fit" | "exact" | "fill";
}
export interface SharpenConfig {
radius: number;
threshold: number;
}
export interface FilterConfig {
grayscale?: boolean;
invert?: boolean;
sharpen?: SharpenConfig | null;
brightness?: number | null;
contrast?: number | null;
blur?: number | null;
}
export type ExportConfig =
| {
format: "jpeg";
quality: number;
}
| {
format: "png";
}
| {
format: "webp";
};
export interface ImageConfig {
rotation?: RotationConfig | null;
crop?: CropConfig | null;
resize?: ResizeConfig | null;
filters?: FilterConfig | null;
export: ExportConfig;
}
export declare class Photo {
#private;
constructor(manager: Photeryx, id: number);
get id(): number;
exportAsBytes(config: ImageConfig): Promise<Uint8Array>;
exportAsBlob(config: ImageConfig): Promise<Blob>;
exportAsDataUrl(config: ImageConfig): Promise<string>;
free(): void;
_unsafeFreeWithoutDetach(): void;
}
export declare class Photeryx {
#private;
get photos(): readonly Photo[];
addFromFile(file: File): Promise<Photo>;
addFromUrl(url: string): Promise<Photo>;
addFromArrayBuffer(buffer: ArrayBuffer): Promise<Photo>;
exportAllAsBytes(config: ImageConfig): Promise<Uint8Array[]>;
exportAllAsBlobs(config: ImageConfig): Promise<Blob[]>;
exportAllAsDataUrls(config: ImageConfig): Promise<string[]>;
findDuplicates(threshold?: number): Promise<Photo[][]>;
freeAll(): void;
_detach(photo: Photo): void;
}
export default Photeryx;🖼 Using Photeryx
1) Import & Initialize
import Photeryx, { type ImageConfig } from "photeryx";
const ph = new Photeryx();2) Load Images
const photo1 = await ph.addFromFile(fileInput.files[0]);
const photo2 = await ph.addFromUrl("https://example.com/image.jpg");
// Or from ArrayBuffer
const buffer = await someFetchOrFileApi();
const photo3 = await ph.addFromArrayBuffer(buffer);3) Configure Processing
const config: ImageConfig = {
rotation: { degrees: 90 },
crop: { x: 0, y: 0, width: 800, height: 600 },
resize: { max_width: 1200, max_height: 1200, mode: "fit" },
filters: {
grayscale: false,
sharpen: { radius: 2, threshold: 1 },
brightness: 10,
contrast: 20,
blur: 1,
},
export: { format: "jpeg", quality: 85 },
};4) Export Options (single image)
// Uint8Array
const bytes = await photo1.exportAsBytes(config);
// Blob
const blob = await photo1.exportAsBlob(config);
// Base64 string (data URL)
const base64 = await photo1.exportAsDataUrl(config);
// If you need a File instance:
const file = new File([blob], "output.jpeg", { type: "image/jpeg" });5) Export All Loaded Images
// As Uint8Array[]
const allBytes = await ph.exportAllAsBytes(config);
// As Blob[]
const allBlobs = await ph.exportAllAsBlobs(config);
// As data URLs
const allDataUrls = await ph.exportAllAsDataUrls(config);6) Duplicate Detection
findDuplicates compares all loaded photos and returns groups of Photo instances that are considered duplicates or very similar.
// Optionally pass a threshold (implementation-defined, e.g. 0–100)
const groups = await ph.findDuplicates(90);
// Example shape:
// [
// [Photo, Photo], // first duplicate group
// [Photo, Photo, Photo] // second duplicate group
// ]
for (const group of groups) {
console.log("Duplicate group:");
for (const photo of group) {
console.log(" Photo id:", photo.id);
}
}You can still access the flat list of currently loaded photos through ph.photos.
7) Memory Management
Photeryx gives you full control over WebAssembly memory:
photo1.free(); // Free one image
ph.freeAll(); // Free all images⚠️ After .free() or .freeAll(), freed objects can no longer be used.
🧪 Browser Requirements
| Feature | Support | | --------------------------- | -------- | | WebAssembly | Required | | ES6 Modules | Required | | Offscreen Canvas (optional) | Optional |
📚 Full API Reference
Class: Photeryx
| Member / Method | Description |
| ----------------------------- | ------------------------------------------------------------ |
| photos: readonly Photo[] | Readonly list of currently loaded photos |
| addFromFile(file) | Load an image from a File |
| addFromUrl(url) | Fetch and load image from a URL |
| addFromArrayBuffer(buffer) | Load image from raw ArrayBuffer |
| exportAllAsBytes(config) | Export all loaded images as Uint8Array[] |
| exportAllAsBlobs(config) | Export all loaded images as Blob[] |
| exportAllAsDataUrls(config) | Export all loaded images as Base64 data URLs (string[]) |
| findDuplicates(threshold?) | Find duplicate/similar images, returns groups of Photo[][] |
| freeAll() | Free all images from WebAssembly memory |
Class: Photo
| Member / Method | Description |
| ------------------------- | ---------------------------------- |
| id: number | Stable numeric ID for this photo |
| exportAsBytes(config) | Export as Uint8Array |
| exportAsBlob(config) | Export as Blob |
| exportAsDataUrl(config) | Export as Base64 data URL string |
| free() | Free memory of this image |
📄 License
Apache-2.0 © Mehran Taslimi
