Changelog
All notable changes to imgkit.
[2.4.0] - 2026-09-14
Added
WebAssembly build - imgkit now runs on platforms with no prebuilt native addon (Issue #12)
- Compiled from the same Rust source as the native addon for
wasm32-wasip1-threadsvia napi-rs/emnapi bun run build:wasmemits towasm/; the module and both loaders ship in the packagesrc/loader.tsfalls back to WebAssembly after every native strategy, so an unsupported platform degrades instead of throwing at import. Verified by installing the packed tarball into a clean project.- New
codecBackend()reports the loaded backend and its capabilities at runtime - Browser and edge support is not finished. The artifacts ship, but the browser entry point is still to be built, so
import 'imgkit'does not yet work in a bundle. napi's generatedbrowser.jsre-exports an unpublished package and would bypass the TypeScript layer, so nobrowserexport condition is advertised. - See the WebAssembly guide for the full trade-off table
- Compiled from the same Rust source as the native addon for
native-codecscargo feature - the C codecs (libjpeg-turbo, libwebp) are now optional--no-default-featuresbuilds with pure-Rust codecs and zero C dependencies, so the crate builds without nasm/cmake- This is what makes the WebAssembly target possible
Fixed
thumbhash()was broken in the ESM build on Node -src/api/thumbhash.tsusedrequire("zlib")inside a module bundled to ESM, which tsup rewrote into a "Dynamic require is not supported" throw. Bun tolerates require-in-ESM, so the bun-only test suite asserteddataUrland still passed. Now a static import.- WebP images without an alpha channel failed to decode via
decode_webp_fast. The code assumed thewebpcrate always returns RGBA, but it returns RGB (3 bytes/px) when there is no alpha, so the RGBA->RGB conversion built a buffer of the wrong length and every such decode failed with "Failed to create RGB image from WebP". The existing suite missed it because its WebP tests all pass target dimensions, which route through a different decoder.
Known limitations (WebAssembly only)
- WebP output is lossless only (
imagehas no lossy WebP encoder), soqualityhas no effect. JPEG quality is honoured. - No shrink-on-load, so thumbnailing decodes at full resolution first.
- Async functions run on the calling thread, and
timeoutMsis rejected rather than silently dropped. - Requires Node; Bun's
node:wasilacksinitialize(). Bun users get the faster native addon anyway. - Requires
emnapi@2.0.0-alpha.x; the 1.x line cannot link againstnapi-build2.4.2.
[2.3.0] - 2026-06-23
Added
- Composite / Overlay / Watermark — New
composite()/compositeSync()API for painting one or more layers onto a base image- Placement — gravity (
center,southEast, …) withoffsetX/offsetY, or absoluteleft/topcoordinates (off-canvas/negative positions are clipped) - Blend modes —
over(default),multiply,screen,overlay,darken,lighten,add - Per-layer
opacity(0.0–1.0) and per-layerresize(scale a logo before compositing) tile— repeat a layer across the whole base for watermark patterns- Multiple layers painted in order; output defaults to PNG (or set
outputfor JPEG/PNG/WebP) - Full async support with
timeoutMs/AbortSignal - See the Composite API and Composite & Watermark example
- Placement — gravity (
[2.2.1] - 2026-03-21
Fixed
- Native binding fails to load on macOS arm64 - Missing
libheif.1.dylib(Issue #10)- Switched from dynamic linking to static linking for libheif via
embedded-libheif - All HEIC/HEIF codec dependencies are now compiled from source and statically linked
- No system-installed libheif or Homebrew dependencies required
- Eliminates dylib version mismatches (e.g.
libheif.1.dylibvslibheif.19.dylib) - See Issue #10 for details
- Switched from dynamic linking to static linking for libheif via
[2.2.0] - 2026-02-17
Added
- Timeout & AbortSignal Support - All async functions now accept
AsyncOptions(Issue #9)timeoutMs— Rust-level timeout via tokio; rejects promise after specified durationsignal— JavaScript AbortSignal for programmatic cancellation- Works with
AbortController,AbortSignal.timeout(), and custom abort reasons - Both options can be combined for maximum protection
- Fully backward compatible
- See Timeout & Cancellation API for details
[2.1.0] - 2026-01-25
Added
Bun Single-File Executable Support - Native module now works with
bun build --compile(Issue #8)- New
imgkit-buildCLI tool automates compilation with native module handling - Usage:
bunx imgkit-build --compile --outfile dist/app src/index.ts - Automatic native module discovery from executable directory
- No manual configuration required
- See Bun Executables Guide for details
- New
Enhanced Loader - Improved native module loading for Bun executables
- Detects Bun single-file executables via
$bunfsfilesystem - Prioritizes executable directory for native module search
- Context-aware error messages with specific guidance
- Detects Bun single-file executables via
[2.0.2] - 2026-01-25
Fixed
- Bun Native Binding Loading - Fixed native module loading on Bun runtime (Issue #7)
- Added Bun runtime detection
- Use
globalThis.requirefor Bun's native module loading - Reordered loading strategies for better Bun compatibility
- Fixes "Failed to load native binding" error on Bun 1.3.6+ with Apple Silicon
[2.0.1] - 2026-01-24
Fixed
- Windows Package Names - Renamed Windows packages to avoid npm spam detection
imgkit-win32-x64-msvc→imgkit-windows-x64imgkit-win32-arm64-msvc→imgkit-windows-arm64- Windows users can now install imgkit without issues
[2.0.0] - 2026-01-19
BREAKING CHANGES
- Package Renamed -
bun-image-turbois nowimgkitbashnpm uninstall bun-image-turbo && npm install imgkit- All imports change from
'bun-image-turbo'to'imgkit' - API is 100% compatible - no code changes needed beyond import path
- All imports change from
Added
- Fast Thumbnail Generation - Optimized thumbnail pipeline with shrink-on-load
thumbnail()/thumbnailSync()- Generate thumbnails with full metadatathumbnailBuffer()/thumbnailBufferSync()- Generate thumbnails (buffer only)- Shrink-on-Load: JPEG decodes at 1/2, 1/4, 1/8 scale; WebP scales during decode
- Fast Mode: Maximum speed with 2-4x improvement over normal mode
- 4-10x faster than standard resize for large images
Performance
| Method | 1MB JPEG | 10MB JPEG | vs Sharp |
|---|---|---|---|
| thumbnail (shrinkOnLoad) | 9.1ms | 100ms | 1.2x faster |
| thumbnail (fastMode) | 9.1ms | 107ms | 1.2x faster |
| sharp | 10.9ms | 119ms | baseline |
Concurrent (100 images): 157ms total (1.6ms/img) - 1.9x faster than sharp
Test Results
- 176 tests pass
- All shrink-on-load optimizations verified
[1.9.1] - 2026-01-15
Added
- GitHub Community Standards - CONTRIBUTING.md, CODE_OF_CONDUCT.md, SECURITY.md, issue templates
[1.9.0] - 2026-01-15
Added
Native Smart Crop - Content-aware image cropping using saliency detection
smartCrop()/smartCropSync()- Automatically find and crop to the most interesting regionsmartCropAnalyze()/smartCropAnalyzeSync()- Get optimal crop coordinates without cropping- Aspect Ratio Support:
1:1- Square (Instagram, profile pictures)16:9- Landscape (YouTube, Twitter)9:16- Portrait (Stories, TikTok)4:3,3:2,21:9- And any custom ratio
- Algorithm Features:
- Saliency detection - Finds visually interesting areas
- Edge detection - Preserves important details
- Rule of thirds - Natural composition weighting
- Use cases: Social media thumbnails, profile pictures, e-commerce product images
Dominant Color Extraction - Extract the most prominent colors from any image
dominantColors()/dominantColorsSync()- Get a palette of dominant colors- Returns RGB values and hex strings for each color
- Configurable color count (default: 5 colors)
- Result includes:
colors[]- Array of dominant colors sorted by prominenceprimary- The most dominant color (convenience accessor)- Each color has:
r,g,b(0-255) andhex("#RRGGBB")
- Use cases: UI theming, image placeholders, color palettes, accessibility
Why These Features Matter
Smart Crop automatically finds the best region - no manual coordinates needed:
- Works with any aspect ratio
- Finds faces, objects, and interesting content
- Native Rust implementation using smartcrop2 crate
Dominant Colors enables dynamic UI theming:
- Auto-theme UI based on images (like Spotify album art)
- Generate color placeholders while images load
- Create color palettes from photos
- Native Rust implementation using dominant_color crate
Test Results
- 150 tests pass (22 smart crop + 17 dominant colors)
- All features verified with async and sync APIs
- Works with JPEG, PNG, and WebP images
[1.8.0] - 2026-01-15
Added
- Native Perceptual Hashing - First JavaScript package with native SIMD-accelerated perceptual hashing for image similarity detection
imageHash()/imageHashSync()- Generate perceptual hash from any imageimageHashDistance()/imageHashDistanceSync()- Calculate hamming distance between hashes- 4 Hash Algorithms:
PHash- Perceptual hash using DCT (best for most use cases)DHash- Difference hash using gradients (fast, good for similar images)AHash- Average hash (fastest, least robust)BlockHash- Block hash (good balance of speed and accuracy)
- 3 Hash Sizes:
Size8- 8x8 hash (64 bits) - fastest, good for most casesSize16- 16x16 hash (256 bits) - more accurateSize32- 32x32 hash (1024 bits) - highest accuracy
- Use cases: Duplicate detection, content moderation, reverse image search, copyright detection
Why Perceptual Hashing Matters
Unlike cryptographic hashes (MD5, SHA), perceptual hashes allow similar images to have similar hashes:
- Resized, compressed, or slightly modified images still match
- Distance threshold: <5 = very similar, <10 = similar, >10 = different
- Native Rust implementation is 10-50x faster than JavaScript alternatives
Test Results
- 111 tests pass (24 new perceptual hash tests)
- All algorithms (PHash, DHash, AHash, BlockHash) verified
- Hash consistency and distance calculation tested
[1.7.9] - 2026-01-15
Changed
- Upgraded to napi-rs v3 - Major upgrade to the latest napi-rs framework
napiupgraded from v2 to v3.8.2napi-deriveupgraded from v2 to v3.5.1@napi-rs/cliupgraded from v2.18.4 to v3.5.1- Enables future streaming features (ReadableStream, AsyncGenerator)
- Better async/await patterns with improved lifetime management
Fixed
- Added explicit
#[derive(Clone)]to all string enums for napi-rs v3 compatibility - Removed deprecated
napi.namefield from package.json
Test Results
- 87 tests pass - All existing functionality verified with napi-rs v3
[1.7.1] - 2026-01-13
Added
- ML Tensor Conversion - First JavaScript package with native SIMD-accelerated image-to-tensor conversion
toTensor()/toTensorSync()- Convert images to tensor format for ML frameworks- Built-in normalization presets:
Imagenet- ResNet, VGG, EfficientNet (mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])Clip- CLIP, OpenCLIP, BLIP models (mean=[0.481, 0.458, 0.408], std=[0.269, 0.261, 0.276])ZeroOne- Values in [0, 1] rangeNegOneOne- Values in [-1, 1] range
- Layout support:
Chw- Channel-first for PyTorch, ONNX RuntimeHwc- Channel-last for TensorFlow.js
- Data types:
Float32(default) andUint8 - Optional batch dimension for inference-ready tensors
- Helper methods:
toFloat32Array(),toUint8Array()
Performance
Benchmarks on Apple M3 Pro (800x600 JPEG input):
| Operation | Time | Throughput |
|---|---|---|
| 224x224 ImageNet | 12.5ms | 80 img/s |
| 224x224 Uint8 | 5.2ms | 192 img/s |
| 384x384 ImageNet | 33.0ms | 30 img/s |
| 1920x1080 → 224x224 | 25.8ms | 39 img/s |
10-16x faster than JavaScript-based alternatives!
Why This Matters
- No manual normalization - Built-in presets for popular models
- SIMD optimization - Native Rust with parallel channel processing via Rayon
- Shrink-on-load - Large images downscaled during decode
- Zero-copy - Minimal memory allocations
- Type-safe - Full TypeScript support with proper types
Test Results
- 87 tests pass (10 new toTensor tests)
- All normalization presets verified
- Both layouts (CHW/HWC) and dtypes (Float32/Uint8) tested
[1.6.0] - 2026-01-13
Added
- Cropping API - Zero-copy image cropping with multiple modes
crop()/cropSync()- Extract regions from images- Three cropping modes:
- Explicit coordinates:
{ x: 100, y: 50, width: 400, height: 300 } - Aspect ratio:
{ aspectRatio: "16:9" }or{ aspectRatio: "1:1" } - Dimensions with gravity:
{ width: 500, height: 500, gravity: "Center" }
- Explicit coordinates:
- 9 gravity options: Center, North, South, East, West, NorthWest, NorthEast, SouthWest, SouthEast
- Crop support in
transform()pipeline - crop is applied first for maximum performance
Performance
- Zero-copy cropping using
crop_imm()- essentially free operation (just pointer arithmetic) - Optimized transform pipeline - crop → resize order reduces pixels for subsequent operations
- Improved brightness adjustment - replaced manual loop with optimized
brighten()builtin (5x faster) - ThumbHash shrink-on-load - decode at 100x100 max before hash generation
Code Quality
- Added
#[inline(always)]to hot encode functions - Cleaner transform pipeline with crop-first architecture
Test Results
- 64 tests pass (8 new crop tests, 2 new transform+crop tests)
- All async and sync functions verified
[1.5.0] - 2026-01-10
Added
- ThumbHash Support - Generate smoother, more visually pleasing image placeholders
thumbhash()/thumbhashSync()- Generate ThumbHash from any imagethumbhashToRgba()/thumbhashToRgbaSync()- Decode ThumbHash to RGBA pixelsthumbhashToDataUrl()- Convert ThumbHash to data URL for inline use- Returns ready-to-use
dataUrlfor immediate display in HTML/CSS
ThumbHash vs BlurHash
| Feature | ThumbHash | BlurHash |
|---|---|---|
| Alpha channel | ✅ Yes | ❌ No |
| Aspect ratio preserved | ✅ Yes | ❌ No |
| Color accuracy | Better | Good |
| Hash size | ~25 bytes | ~28 chars |
Test Results
- 56 tests pass (including 12 new ThumbHash tests)
- All async and sync functions verified
[1.4.6] - 2026-01-09
Added
- Comprehensive Test Suite - Reorganized test structure
test/local/- Local development teststest/packages/- Package manager verification (bun, npm, yarn, pnpm)
Verified
- All Package Managers Working:
- Bun: 39 tests pass ✅
- npm: 32 tests pass ✅
- yarn: 32 tests pass ✅
- pnpm: 32 tests pass ✅
[1.4.5] - 2026-01-09
Fixed
- ESM/CJS Native Binding Loading - Fixed native module loading in Node.js ESM context
- Use
createRequire(import.meta.url)for ESM modules - Proper fallback to native
requirefor CJS context - Fixes "Cannot find package" errors when using
importin Node.js
- Use
[1.4.0] - 2026-01-08
Added
- WebP Shrink-on-Load Optimization - Decode WebP images directly to target resolution
- Uses libwebp's native
use_scalingfor 1.15-1.25x faster WebP resize operations - Memory usage scales with OUTPUT size, not INPUT size (up to 25x reduction)
- Uses libwebp's native
Performance
- WebP Resize now 1.15-1.25x faster than sharp on average
- Zero-copy pipeline reduces memory copies from 3-5 to 1-2 per operation
Fixed
- Issue #3: WebP resize slower than sharp - Now faster!
- Issue #3: macOS requires libheif for WebP - CI only installs libheif for ARM64
- Issue #3: Linux installation fails - Added optionalDependencies
[1.3.1] - 2026-01-08
Changed
- Code Reorganization - Refactored codebase for better maintainability
- Split
rust/src/decode.rsinto modulardecode/andmetadata/directories - Extracted Rust types to
rust/src/types.rs - Split
src/index.tsintoloader.ts,converters.ts, andapi/modules - No API changes - all functionality preserved
- Split
- Removed unused code and fixed Rust compiler warnings
[1.3.0] - 2026-01-07
Added
- EXIF Metadata Writing - Write EXIF metadata to JPEG and WebP images
writeExif()/writeExifSync()- Add EXIF metadata to imagesstripExif()/stripExifSync()- Remove all EXIF metadata from images- Perfect for AI-generated image attribution and metadata embedding
- Supports: ImageDescription, Artist, Copyright, Software, DateTime, UserComment, Make, Model, Orientation
- Use
transform()withexifoption to add metadata during processing
Technical Details
- Added
img-partscrate for EXIF chunk manipulation - EXIF data built using proper TIFF/IFD0 structure
- UserComment field supports JSON storage for AI generation parameters
- Full async and sync API support
[1.2.2] - 2025-12-12
Documentation
- New Architecture Guide - Deep dive into tech stack, processing pipeline, and key optimizations
- Fixed resize() documentation - Clarified that output is always PNG format
- Fixed transform() documentation -
outputis optional (defaults to PNG), added GIF/BMP examples - Fixed formats guide - Removed non-existent
toGif(), usetransform()instead - Enhanced performance guide - Added technical details about shrink-on-decode, multi-step resize, and adaptive algorithm selection
- Updated API reference - Added
version()function documentation - Fixed platform support tables - All platforms are supported, HEIC only on macOS ARM64
- Added VitePress documentation site - Professional docs with GitHub Pages deployment
Fixed
- ESM module configuration for VitePress 1.6+
[1.2.0] - 2024
Added
- HEIC/HEIF Support - Native support for Apple's modern image format (macOS ARM64)
- Blurhash Generation - Create compact image placeholder strings
- AVIF Support - Read AVIF images via libheif
Changed
- Improved metadata extraction performance (950x faster for WebP)
- Better error messages for unsupported formats
Platform Support
- macOS ARM64 (M1/M2/M3/M4/M5) - Full support including HEIC
- macOS x64 (Intel) - Full support except HEIC
- Linux x64 (glibc) - Full support except HEIC
- Linux x64 (musl/Alpine) - Full support except HEIC
- Linux ARM64 (glibc) - Full support except HEIC
- Windows x64 - Full support except HEIC
- Windows ARM64 - Full support except HEIC
[1.1.0] - 2024
Added
transform()function for multi-operation pipelines- Brightness and contrast adjustments
- Blur and sharpen effects
- Sync versions of all functions
Improved
- Resize quality with lanczos3 filter
- Memory usage optimization
- Better TypeScript types
[1.0.0] - 2024
Initial Release
metadata()- Fast image metadata extractionresize()- High-quality image resizingtoJpeg()- JPEG encoding with TurboJPEGtoPng()- PNG encodingtoWebp()- WebP encoding (lossy and lossless)- Grayscale conversion
- Rotation (90, 180, 270 degrees)
- Horizontal and vertical flip
Supported Formats
- JPEG (read/write)
- PNG (read/write)
- WebP (read/write)
- GIF (read/write)
- BMP (read/write)
- TIFF (read)
- ICO (read)