flutter_image_compress_lite 2.5.0
flutter_image_compress_lite: ^2.5.0 copied to clipboard
Minimal, legacy-free image compression for Flutter (Android + iOS) — no CocoaPods, SPM-only, minimal native deps. Replacement for flutter_image_compress.
2.5.0 #
- BREAKING: removed the
inSampleSizeparameter fromcompressWithList,compressWithFile, andcompressAndGetFile. It was an Android-onlyBitmapFactory.Optionsknob (iOS ignored it) from the 32-bit ART / 128 MB-heap era. On modern Android (API 26+) bitmaps live in native heap and devices with 50 MP cameras have 8–12 GB RAM, so the memory savings no longer pay for the leaky abstraction or the silent quality loss when callers pick a value that under-samples small inputs. TheOutOfMemoryErrorcatch added in 2.4.0 still surfaces decode-time OOM as aCOMPRESS_ERRORPlatformException. Callers that passed the argument need to drop it. - BREAKING: removed
CompressFormat.nativeValue. It was a getter that just returnedindex— the wire value is the enum's built-in ordinal. Callers readingformat.nativeValueneed to switch toformat.index. - BREAKING:
CompressErrornow implementsExceptioninstead of extendingError. The failures it carries (empty bytes, missing source file, same source-and-target path) are recoverable user-input conditions, not programming bugs. Code usingtry { … } on Exceptionwill now catch it (previously had to useon Erroror the barecatch (e)). - Internal: inlined the
FlutterImageCompressValidatorclass into a private top-level function in the main library — one less file, one less indirection, no public-API change. - iOS internal: dropped the dead
@objconImageCompressPlugin.showLog. No Obj-C consumer existed; the annotation was carried over from the 2.2.0 Obj-C→Swift rewrite. The class itself is still@objc(ImageCompressPlugin)because Flutter's plugin discovery requires it.
2.4.4 #
- Android: unified the wire-format error code with iOS —
UNKNOWN_FORMATis renamed toBAD_ARGS, and a malformed channel argument list (wrong type, missing element, null) now also surfaces asBAD_ARGSinstead of crashing the executor thread and hanging the Dart Future. Real callers can't trip this — the Dart side constrains both shape and enum range — so the rename is documentation-only in practice.
2.4.3 #
- Docs-only — added the missing library /
CompressFormat/CompressErrordoc comments, anexample/main.dart, and a note on the class-level doc thatminWidth/minHeightare lower bounds on the output (image is downscaled with aspect ratio preserved so both axes end up ≥ the requested minimum; never upscaled). No API or behavior change.
2.4.2 #
- Removed the debug-mode filename-extension assert (and the
CompressFormat.suffixesfield that backed it). The check only fired in debug; release builds were never affected.
2.4.1 #
- Accept
.heifas a valid target extension for HEIC encoding alongside.heic— same container bytes, different naming convention. Previously tripped the debug-mode filename assert.
2.4.0 #
- BREAKING: removed the
androidOomRetriesparameter fromcompressWithFileandcompressAndGetFile. The old retry-on-OOM logic was Android-only and silently produced an empty result when retries exhausted; now anOutOfMemoryErrorsurfaces as aCOMPRESS_ERRORPlatformExceptionlike other native failures. Callers that passed the argument need to drop it.
2.3.1 #
- Docs and metadata only — README cleanup, package description, and a fork copyright line. No API or behavior changes.
2.3.0 #
Internal cleanup — no public API changes.
- Android (behavior change): read/decode/write failures now throw a
PlatformExceptioninstead of silently resolving tonull, matching iOS. New wire codes:FILE_NOT_FOUND,BAD_IMAGE,WRITE_FAILED, plus a catch-allCOMPRESS_ERROR. Callers that previously branched on anullresult will now see an exception for genuinely broken input. See the README "Errors" section. - Android: the three
compress*handlers now share a single index-drivenCompressArgsparser (mirroring the iOSCompressParams) and areplyCatchinghelper, replacing the per-handler positional unpacking and try/catch. No wire-format change. - Dart:
compressWithFile/compressAndGetFilenow check source existence with asyncFile.exists()instead ofexistsSync(), so the entry points no longer block the isolate on filesystem I/O. - iOS: migrated the method-channel handlers to Swift structured concurrency (Swift 6.2). The manual
DispatchQueue.global(qos:).async { … }hop is replaced by aTaskcalling a single@concurrentrun(_:)worker; the three near-identical handlers collapse into aSendableRequestparser plus that one worker. Arguments are now read out ofFlutterMethodCallsynchronously on the calling thread, so no non-SendableFlutter type crosses the concurrency boundary. Builds under the Swift 6 language mode with strict concurrency. - iOS BUILD REQUIREMENT: building for iOS now requires Xcode 26+ (Swift 6.2 toolchain). The runtime floor is unchanged — still iOS 15+ (Swift concurrency back-deploys; no iOS-18-only APIs such as
Mutexare used).
2.2.0 #
Internal cleanup — no public API or behavior changes.
- iOS: rewrote the plugin in Swift. The 6 Obj-C
.mfiles + 7.hheaders are replaced by 4 Swift files (ImageCompressPlugin.swift,Compressor.swift,ExifKeeper.swift,UIImage+Scale.swift). No__bridgecasts, no manualCFRelease, noinclude/public-headers folder, no// Created by cjl …fork comments. The two near-identicalcompressWithUIImage:/compressDataWithUIImage:methods collapse into one. File-existence and image-decode failures now surface asFlutterError(FILE_NOT_FOUND,BAD_IMAGE) instead of propagating nil.UIGraphicsBeginImageContext(deprecated since iOS 10) is replaced withUIGraphicsImageRenderer; the rotated bounding box is now computed viaCGRect.applying(_:)instead of allocating aUIView. - Android:
ResultHandler's thread pool is now owned by the plugin instance andshutdown()inonDetachedFromEngine(was acompanion objectExecutors.newFixedThreadPool(8)that lived for the process lifetime). Re-armed on re-attach. - Android: dropped the
androidx.exifinterfacedependency in favor of the platformandroid.media.ExifInterface(available since API 24, our minSdk). EXIF reads/writes go through the framework class with a 6-line orientation→degrees mapping.androidx.heifwriter:heifwriter:1.1.0remains — HEIC encoding still goes through it (no platform-native HEIC encoder exists inBitmap.CompressFormat). - Android: collapsed 13 Kotlin files into 3 —
ImageCompressPlugin.kt,Compressor.kt,Exif.kt— to mirror the iOS Swift layout. Dropped the unusedFormatHandlerinterface,FormatRegistermap, and the never-thrownCompressError. - Android:
BitmapFactorydecode now usesARGB_8888for PNG/WebP/HEIC and keepsRGB_565for JPEG. Previously all formats decoded asRGB_565, silently dropping the alpha channel for transparency-capable outputs. - Android:
CompressFileHandler.handlereads EXIF rotation fromFile(path)directly instead of loading the full file into aByteArrayfirst. - Android: unknown format index now responds with
result.error("UNKNOWN_FORMAT", …)instead ofresult.success(null). In practice unreachable because the Dart enum can't produce an unknown index, but no longer fails invisibly if the wire format ever desyncs. - Android: bumped
compileSdk36 → 37 (Android 17). NominSdkchange. CI environments may need the API 37 platform package installed.
2.1.1 #
- iOS: fix iOS build failure introduced in 2.1.0 — corrected selector capitalization to
HEIFRepresentationOfImage:format:colorSpace:options:(washeifRepresentationOfImage:, which doesn't exist onCIContext).
2.1.0 #
User-visible fixes:
- BREAKING:
numberOfRetriesparameter oncompressWithFile/compressAndGetFilerenamed toandroidOomRetries. The retry behavior was always Android-only (decode OOM → doubleinSampleSizeand recurse); the new name reflects that. iOS ignores the value as before. - iOS: WebP encoding now throws
UnsupportedErrorup front instead of silently returningnull(decoding still works on iOS 14+). - iOS: HEIC encoding no longer writes through
NSTemporaryDirectory()— usesheifRepresentationOfImage:directly. Removes a per-call temp-file leak. - Dart: validator contract is now consistent — every entry point throws
UnsupportedErrorfor unsupported encodings (previously some returnednull). The validator only checks the output format; input formats are auto-detected by the native decoder.
Internal cleanup:
- Android: introduced
CompressFormatenum to replace0/1/2/3magic numbers throughout the handlers andFormatRegister. - Android:
ExifKeeperported from Java to Kotlin;settings.gradle→settings.gradle.kts. - Android: bumped Gradle wrapper to 9.5.0,
compileSdkto 36. - Android: removed dead code paths (
ResultHandler.replyError,ExifKeeper.copyExifToFile, duplicateBitmap.compressextensions,System.gc()in OOM retry, pre-MarshmallowinDitherbranch). - iOS: introduced
ImageCompressFormatNS_ENUMmirroring the Dart/Android enums. - iOS: removed dead
getSystemVersionObj-C handler (Dart only calls Android for the API 28 check). - Dart: dropped
part/part ofin favor of regular libraries withimport/export;CompressFormat.nativeValuegetter replaces the private_convertTypeToInthelper; default param values centralized in a private_Defaultsclass.
2.0.3 #
Merged flutter_image_compress + flutter_image_compress_common into a single standalone package.
No federated plugin architecture, no transitive dependencies with podspecs, no CocoaPods required.
- BREAKING: New package name
flutter_image_compress_lite— change import - BREAKING: Remove WebP encoding on iOS (decoding works natively on iOS 14+)
- BREAKING: Require Dart ^3.11.0, Flutter >=3.41.0, iOS 15.0+, Android minSdk 24, AGP 9+
- iOS: SPM only, zero third-party deps
- iOS: keepExif via native ImageIO (no Mantle)
- Android: Kotlin DSL, removed commons-io, bumped exifinterface 1.4.2, heifwriter 1.1.0