ironpress 0.2.0
ironpress: ^0.2.0 copied to clipboard
High-performance Rust-powered Flutter image compression for JPEG, PNG, and WebP with batch processing, target-size compression, and metadata probing.
0.2.0 #
Performance #
- Targeted isolate offload — single-item APIs use per-call
Isolate.run()for failure isolation, while batch work uses an ephemeral event-driven isolate withTransferableTypedDatato keep cross-isolate overhead low - Direct PNG optimization — PNG-to-PNG compression without resize now skips the full decode/re-encode cycle and goes straight through oxipng, significantly faster for lossless workflows
- Format-hinted decoding — image decoding uses explicit format hints instead of
with_guessed_format(), removing a redundant header scan on every call - Zero-copy batch input — Rust batch path uses
Cow<[u8]>for memory-buffer inputs, avoiding a needless copy TransferableTypedData— cross-isolate data transfer avoids copying bytes through the message port- Smarter thread allocation — Rayon thread count is capped to the batch size, preventing over-allocation for small batches
- Keyed thread pool cache — Rust thread pools are cached by requested thread count instead of a single static pool, so different
threadCountvalues reuse their own pool without rebuilding OS threads
Bug fixes #
ImageFormat.fromValueno longer silently defaults to JPEG — unknown native format values now throwStateErrorinstead of returning a wrong format, preventing subtle data corruption- Batch cancellation reworked — cancellation now propagates reliably from Dart through the worker isolate via
SendPort, fixing a race where the nativeAtomicU32progress pointer could be freed while still in use probe_bytesheader detection fixed — usesImageReader::with_formatwith an explicit format hint instead ofwith_guessed_format, which could fail on certain PNG and WebP variants
Robustness #
- Input validation hardened —
maxWidth,maxHeight,maxFileSize,threadCount,chunkSize, andpng.optimizationLevelare now validated before crossing the FFI boundary, with clearArgumentErrormessages including the parameter name and allowed range - Native uint32 overflow protection — all numeric parameters are checked against the
u32ceiling before being passed to native code - Batch pre-cancellation check —
compressBatchreturns empty results immediately if the token is already cancelled - APNG detection — PNG files containing
acTLchunks (animated PNG) are routed through the full decode path instead of direct oxipng optimization, which would silently drop animation frames
Native loader #
- Multi-candidate library loading — desktop platforms now probe multiple locations (bundled name, repo
libs/directories up to 3 parent levels) before failing, with clear per-candidate error messages showing exactly which paths were tried and why each failed
Breaking changes #
ImageFormat.fromValuethrowsStateErroron unknown values instead of returningImageFormat.jpegBatchCompressResult.elapsedMsis now measured on the Dart side for the full batch operation, not inside Rust (excludes FFI overhead was misleading for chunked batches)CancellationToken.addListeneris a new public method (non-breaking for consumers, but notable for subclasses)
Tests #
- Batch event-order regression test
- Batch contract tests: monotonic progress, cancellation with/without progress, mixed success/failure, output paths
- Benchmark integration tests for
benchmarkBytesandbenchmarkFile keepMetadataround-trip test (preserve EXIF for JPEG, drop for PNG)- Numeric argument validation tests for all boundary conditions
CancellationTokenlistener and disposer tests
0.1.0 #
Initial release.
Compression engines #
- JPEG compression via mozjpeg-rs — pure Rust, trellis quantization, progressive encoding
- PNG optimization via oxipng — pure Rust, lossless, multithreaded
- WebP support (lossy + lossless) via the
webpcrate
API #
Ironpress.compressFile— compress a file path, return bytes + statsIronpress.compressFileToFile— compress file-to-file with no in-memory byte copyIronpress.compressBytes— compress an in-memoryUint8ListIronpress.compressBatch— parallel batch compression with progress callbacks and cancellation supportIronpress.probeFile/Ironpress.probeBytes— read image dimensions and format without decoding pixelsIronpress.benchmarkFile/Ironpress.benchmarkBytes— sweep quality levels to generate a compression/size curveIronpress.nativeVersion— verify the loaded native library version
Robustness #
ReceivePorts incompressBatchwith progress callbacks are always closed in afinallyblockcompressFile,compressFileToFile,compressBytes, andcompressBatchthrowArgumentErrorimmediately whenqualityorminQualityis outside 0–100JpegOptions,PngOptions, andCompressPresetare annotated@immutable
Example app #
- Comprehensive example with 9 demo screens covering 100% of the public API
- Visual before/after comparisons, interactive sliders, bar charts, and progress indicators
- Screens: basic compression, quality presets, target file size, format comparison, batch processing, probe metadata, benchmark, advanced options (JPEG/PNG), file I/O
Key features #
- Binary-search target file size (
maxFileSize): the engine loops entirely in Rust — single FFI call, no round-trips - Auto-resize fallback: if quality alone can't reach
maxFileSize, image is downscaled and retried - Aspect-ratio-preserving resize via
maxWidth/maxHeight - Batch panic safety: one corrupt image never crashes the batch; other items continue normally
- ABI version checking: prevents stale native library mismatches from causing silent bugs
- EXIF metadata preservation for JPEG→JPEG (
keepMetadata: true) - Format conversion: auto-detect input, choose output format (JPEG / PNG / WebP lossy / WebP lossless)
Platform support #
- Android:
arm64-v8a,armeabi-v7a,x86,x86_64(precompiled.so) - iOS: device + simulator (precompiled
xcframework) - Windows:
x86_64(precompiled.dll) - Linux:
x86_64(precompiled.so) - macOS:
arm64+x86_64universal (precompiled.dylib) - Web: not supported (
dart:ffiis unavailable on Flutter Web)