XNZImage
English | 中文
A Flutter image loading package with unified rendering and cache management. It supports network, memory, file, and asset image sources, and provides an extensible architecture for extra formats.
Overview
This repository uses a core + extension architecture:
xnz_image: main public API (XNZNetworkImage,XNZMemoryImage,XNZFileImage,XNZAssetImage,XNZCacheManager, etc.)xnz_image_core: internal capabilities (cache, downloader, extension mechanism)xnz_image_svg: SVG support extensionxnz_image_avif: AVIF support extension
Component Reference
For a code-level component behavior analysis (Chinese), see:
Installation
1) Base package
dependencies:
xnz_image: ^0.2.5
2) Optional extensions
dependencies:
xnz_image: ^0.2.5
xnz_image_svg: ^0.2.5
xnz_image_avif: ^0.2.5
For local development in this monorepo, you may use path dependencies.
Register Extensions
import 'package:flutter/widgets.dart';
import 'package:xnz_image/xnz_image.dart';
import 'package:xnz_image_svg/xnz_image_svg.dart';
import 'package:xnz_image_avif/xnz_image_avif.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
XNZImageLogs.showLogs = true;
XNZImageMemoryObserver().init();
XNZImage.support(XNZImageSvg());
XNZImage.support(XNZImageAvif());
runApp(const MyApp());
}
Logging
Runtime logs are now normalized to:
[module][action][module][action][key=value,...]
Example:
[XNZImageDownloader][task_start][requestKey=...,url=https://...]
XNZImageLogs.event(module, action, fields: {...}) is recommended for internal/extension code.
XNZImageLogs.setInterceptor(...) supports both interceptor signatures:
void Function(String tag, String message)(legacy compatible)bool Function(String tag, String message)(truemeans default output is intercepted)
XNZImageLogs.logFilter supports quick category filtering:
XNZImageLogFilter.all(default)XNZImageLogFilter.successXNZImageLogFilter.failure
XNZImageLogs.showLogs = true;
XNZImageLogs.logFilter = XNZImageLogFilter.failure; // only failure logs
Observable Events By Source
- Network (
XNZNetworkImage/XNZNetworkImageProvider)- load status:
load_status_downloading,load_status_complete,load_status_failed - cache path:
get_memory_cache_hit|miss,get_disk_cache_hit|miss - download path:
task_start,task_complete,task_failed,task_reuse_shared - decode path:
decode_probe,decode_success,decode_failed,decode_failed_final
- load status:
- Memory (
XNZMemoryImage/XNZMemoryImageProvider)- widget flow:
build_start,resolve_complete,display_failed - decode path:
decode_probe,decode_success,decode_failed,load_failed
- widget flow:
- File (
XNZFileImage/XNZFileImageProvider)- widget flow:
build_start,resolve_complete,display_failed - decode path:
decode_probe,decode_success,decode_failed,load_failed
- widget flow:
- Asset (
XNZAssetImage/XNZAssetImageProvider)- widget flow:
build_start,resolve_complete,display_failed - decode path:
decode_probe,decode_success,decode_failed,load_failed
- widget flow:
Notes:
download_*and network cache hit/miss events are network-only by design.decode_probeincludesformatandlikelyImage, useful for quick format mismatch diagnosis.- delegated/custom provider display failures emit
XNZProxyImageStreamCompleter.display_failed.
Supported Formats
- Default (
xnz_imageonly): common bitmap formats such aspng,jpg,jpeg,gif,webp,bmp - With
xnz_image_svgregistered:svg,svgz - With
xnz_image_avifregistered:avif,avifs(including animated AVIF duration override)
Basic Widgets
Network
XNZNetworkImage(
imageUrl: 'https://picsum.photos/800/480',
width: 300,
height: 180,
fit: BoxFit.cover,
)
Memory
XNZMemoryImage(
bytes: yourBytes,
width: 300,
height: 180,
fit: BoxFit.cover,
)
File
XNZFileImage(
file: File('/path/to/local/image.avif'),
width: 300,
height: 180,
fit: BoxFit.cover,
)
Asset
XNZAssetImage(
assetName: 'assets/images/banner.avif',
width: 300,
height: 180,
fit: BoxFit.cover,
)
Use With Flutter Image
Image(
image: XNZNetworkImageProvider('https://picsum.photos/800/480'),
width: 300,
height: 180,
fit: BoxFit.cover,
)
Authenticated Network Requests
XNZNetworkImage and XNZNetworkImageProvider support optional headers.
XNZNetworkImage(
imageUrl: 'https://example.com/private/image.png',
headers: {'Authorization': 'Bearer <token>'},
cacheKeyStrategy: XNZCacheKeyStrategy.urlAndHeaders,
)
Cache Key Strategy
cacheKeyStrategy controls cache isolation behavior:
XNZCacheKeyStrategy.urlOnly(default): URL-only cache key, better hit-rateXNZCacheKeyStrategy.urlAndHeaders: URL+headers cache key, safer isolation
Note: request de-duplication always uses URL+headers internally to avoid mixing in-flight downloads from different header contexts.
Animated Image Playback
XNZAnimatedImage decodes frames and plays on a timeline. It is suitable for GIF / Animated WebP / APNG,
and can also decode animated AVIF when AVIF support is registered.
Highlights
- Timeline sync:
position,progress,frameIndex - Playback control:
play,pause,resume,replay - Callbacks:
onLoaded,onCompleted - Loop control:
loop - Error fallback:
errorBuilder
Maintenance Updates (2026-05-12)
- Cache-key hashing now uses SHA-256 full-length lowercase hex on all runtimes.
- Animated network bytes loading on IO now goes through the same downloader/cache pipeline as normal network images (
XNZUrlRequest+XNZImageDownloader+XNZCacheManager), socacheKeyStrategybehavior is consistent. - AVIF codec keys now use process-local monotonically increasing integers instead of object-hash-derived values, reducing native decoder key-collision risk.
- AVIF async init/decode guardrails were improved (explicit init error propagation and safer completer handling).
- Added regression tests for:
- unified IO animated cache-path loading;
- AVIF codec key monotonicity.
Maintenance Updates (2026-05-11)
- Optimized animated memory cache-key generation: memory bytes fingerprints are now cached by bytes identity to avoid repeated full-byte hashing on frequent rebuilds.
- Refactored
XNZAnimatedImageinternals intolib/src/animated/modules (loader/decoder/cache-key/provider-context/models/controller/cache) to reduce single-file complexity. - Unified resolve/render flow for
XNZAssetImage,XNZMemoryImage,XNZFileImage, andXNZNetworkImagevia shared helpers, reducing template duplication and future drift risk. - Public API remains backward compatible.
Example
final controller = XNZAnimatedImageController();
XNZAnimatedImage(
image: XNZNetworkImageProvider('https://example.com/demo.gif'),
controller: controller,
autoPlay: true,
loop: true,
fit: BoxFit.contain,
onLoaded: (duration, fps, frameCount) {
debugPrint('duration=$duration fps=$fps frames=$frameCount');
},
onCompleted: (completedLoops) {
debugPrint('completedLoops=$completedLoops');
},
loadingBuilder: (_) => const Center(child: CircularProgressIndicator()),
errorBuilder: (context, error, stackTrace) {
return const Center(child: Text('Animated image load failed'));
},
)
Unified Render Hook (renderBuilder)
Use renderBuilder to wrap default rendering behavior for bitmap and custom formats:
XNZNetworkImage(
imageUrl: url,
renderBuilder: (context, child) {
return ClipRRect(
borderRadius: BorderRadius.circular(12),
child: child,
);
},
)
If renderBuilder returns null, the widget falls back to default rendering.
Cache Manager
import 'dart:typed_data';
import 'package:xnz_image/xnz_image.dart';
Future<void> printCacheUsage() async {
final cacheManager = XNZCacheManager();
final memoryBytes = cacheManager.getMemoryCacheBytes();
final memoryMaxBytes = cacheManager.getMemoryCacheMaxBytes();
final diskBytes = await cacheManager.getDiskCacheBytes();
print('Memory cache: $memoryBytes B');
print('Memory cache max: $memoryMaxBytes B');
print('Disk cache: $diskBytes B');
}
Future<void> clearAllCache() async {
await XNZCacheManager().clearAll();
}
Future<void> clearUnusedDiskCache() async {
// Delete disk cache entries not used for 30 days.
final deleted = await XNZCacheManager().clearUnusedDiskCache(
const Duration(days: 30),
);
print('Deleted disk cache files: $deleted');
}
Future<void> configureDiskCacheTtl() async {
final cacheManager = XNZCacheManager();
// Global default TTL for disk cache writes.
cacheManager.setDiskCacheDefaultTtl(const Duration(hours: 24));
// Per-write override.
await cacheManager.setCache(
XNZUrlRequest('https://example.com/avatar.png'),
Uint8List(0),
ttlOverride: const Duration(hours: 1),
);
}
Platform Notes
- Web supports
XNZNetworkImage,XNZMemoryImage,XNZAssetImage, andXNZAnimatedImage. - Web enables memory cache only (disk cache is disabled).
- Web memory cache defaults to 48MB (native platforms default to 300MB).
XNZFileImage/XNZFileImageProviderare not supported on Web and throwUnsupportedError.
Run Example
Minimal pub example:
flutter run -t example/main.dart
More complete demo apps are under:
examples/example_bitmapexamples/example_bitmap_svgexamples/example_bitmap_avifexamples/example_bitmap_svg_avif
Libraries
- xnz_image
- Public entrypoint for the
xnz_imagepackage.