koni_jxl_flutter
Display and encode JPEG XL (.jxl) images in Flutter with a pure Dart
codec — no native libraries, no FFI, no platform channels. Works on
Android, iOS, macOS, Windows and Linux out of the box (and on the web,
with reduced lossy-decode speed).
import 'package:koni_jxl_flutter/koni_jxl_flutter.dart';
// Like any other ImageProvider:
Image(image: JxlImageProvider.asset('assets/page.jxl'))
Image(image: JxlImageProvider.file(File('/comics/page-042.jxl')))
Image(image: JxlImageProvider.memory(jxlBytes))
// Or decode to a ui.Image directly:
final ui.Image image = await decodeJxlToUiImage(bytes);
Decoding runs through Flutter's compute — a background isolate on
native platforms, so the UI thread never blocks; on the web, which has
no isolates, the decode runs on the UI thread. Decoded images
participate in Flutter's ImageCache normally.
What's included
-
JxlImageProvider(.asset/.file/.memory) anddecodeJxlToUiImage— decode an image; animated files play through plainImagewidgets with correct timing and loop count. -
jxlAwareDecodeanddecodeJxlToUiCodec— for apps with customImageProviders over mixed formats (readers, caches, archives): sniff JPEG XL by content and decode it to aui.Codecfor the standardMultiFrameImageStreamCompletermachinery, handing everything else to the engine callback unchanged:Future<ui.Codec> _loadCodec(ImageDecoderCallback decode) async { final bytes = await _readBytes(); return jxlAwareDecode(bytes, decode); }Pass
cacheWidth/cacheHeighttodecodeJxlToUiImage,decodeJxlToUiCodecorjxlAwareDecodefor a reduced-resolution decode (a thumbnail, an oversized-page safety cap). Wrapping a JXL-backedImageProviderinResizeImagehas no effect — JXL bytes never reach the engine'sdecodecallback thatResizeImagerelies on — so the target size must be passed here explicitly instead. -
JxlAnimationViewanddecodeJxlAnimation— play animated JPEG XL with correct per-frame timing and loop count. -
JxlProgressiveImageanddecodeJxlProgressive— show a blurry 1:8 preview while bytes stream in (e.g. from the network), then swap in the sharp final image. -
encodeJxlFromRgba/encodeJxlFromUiImage— lossless JPEG XL encoding in a background isolate. -
encodeJxlLossyFromRgba/encodeJxlLossyFromUiImage— lossy (VarDCT) encoding in a background isolate (RGB-only; alpha is dropped). -
JxlPagePrefetcher— decodes upcoming pages of a sequential reader (manga chapters, documents) on background isolates ahead of display, keeping a window of pages decoded around the current one and cancelling/evicting as the reader navigates:final prefetcher = JxlPagePrefetcher.fromFiles(pageFiles); prefetcher.setCurrentIndex(currentPage); final ui.Image page = await prefetcher.imageFor(currentPage);
Full lossless (bit-exact) and lossy (VarDCT) decoding, animation,
splines and streaming come from the underlying
koni_jxl package, which also has
the details on lossy encoding's current trade-offs (correct and
djxl-verified, but not yet compression-competitive with cjxl).
Unsupported files throw JxlUnsupportedException with a stable feature
id, so you can fall back to another pipeline per file.
See the example/ app for a small gallery.
License
MIT — see LICENSE and NOTICE.
Libraries
- koni_jxl_flutter
- Flutter bindings for the pure-Dart JPEG XL decoder
koni_jxl.