Repository navigation
Composition loaders pipelines and bitmap ownership - #48
Merged
Merged
Conversation
y0ung3r
reviewed
Aug 15, 2026
y0ung3r
reviewed
Aug 15, 2026
Member
Author
Migration GuideThis release replaces the inheritance-based loader API with a composable pipeline. Use the pipeline builderReplace the built-in loader facades with the corresponding presets:
Configure individual componentsInstead of inheriting from a loader and overriding methods, replace individual pipeline components: var loader = ImageLoaderPipelineBuilder.RamCached()
.UseSourceResolver(sourceResolver)
.UseTransport(transport)
.UseDecoder(decoder)
.UseMemoryCache(memoryCache)
.UseByteCache(byteCache)
.Build();Update custom loaders
Task<IImageLease?> LoadAsync(
ImageLoadRequest request,
CancellationToken cancellationToken = default);Use Update cache options
new MemoryImageCacheOptions
{
AbsoluteExpiration = TimeSpan.FromMinutes(10),
SlidingExpiration = TimeSpan.FromMinutes(2)
}More info in README.md |
This was referenced Sep 25, 2026
This was referenced Oct 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is a complete rework of internals of the library:
Instead current inheritance based loaders will be:
Image loading pipeline
ImageLoaderPipelineandImageLoaderPipelineBuilderare the primary APIs for configuring image loading. The pipeline composes source resolution, external transport, encoded byte caching, bitmap decoding and decoded image retention. Start with the closest builder preset, then replace only the components your application needs to customize:The available presets are:
Uncached()downloads and decodes each request without retaining the decoded image.RamCached(...)shares decoded images and retains them in the lease-aware RAM cache.DiskCached(...)adds a persistent encoded disk cache for HTTP and HTTPS sources.All presets use the same default source resolvers, HTTP transport and bitmap decoder. They are starting configurations, not separate extension hierarchies.
Set the resulting pipeline globally through
ImageLoader.AsyncImageLoaderorImageBrushLoader.AsyncImageLoader, or assign it to theLoaderproperty of an individualAdvancedImage. Dispose the previous global loader when replacing it.Pipeline components
ImageLoadRequestcarries the source string and optional Avalonia context (BaseUriandIStorageProvider) through the pipeline.IImageSourceResolverhandles non-network sources. The defaultCompositeImageSourceResolvertriesFileImageSourceResolver,StorageImageSourceResolverandAvaloniaAssetSourceResolverin order.IImageTransportretrieves external encoded data. The defaultHttpImageTransporthandles absolute HTTP and HTTPS sources usingHttpClient.IImageByteCachestores encoded image data before decoding.DiskImageByteCachepersists HTTP responses under hashed keys and is enabled by theDiskCached(...)preset.IBitmapDecoderconverts an encoded stream into an AvaloniaBitmap. The defaultBitmapDecoderreads non-seekable streams asynchronously before constructing the bitmap.IImageMemoryCachecoordinates concurrent requests and returns independent consumer leases.TransientImageCacheperforms no retention;MemoryImageCacheprovides RAM retention with absolute and sliding expiration.IImageLeaserepresents one consumer's ownership of an image. UI integrations release their lease when a source is replaced or detached, while the memory cache controls how long its own reference is retained.ImageLoaderPipelineorchestrates these components and implementsIAsyncImageLoader.The builder methods replace individual components:
UseSourceResolver(...)UseTransport(...)UseDecoder(...)UseMemoryCache(...)UseByteCache(...)UseHttpClient(...)The built pipeline owns and disposes its configured memory cache. A supplied
HttpClientremains caller-owned unlessUseHttpClient(client, disposeHttpClient: true)is used. A builder can build only one pipeline because ownership of its cache is transferred duringBuild().Compatibility loaders
The original ready-made loaders remain available as compatibility and convenience facades:
Uncached()preset.RamCached(...)preset and remains the default global loader.DiskCached(...)preset.These types delegate to the same pipeline presets. They are useful for existing applications and simple configurations, but new customization should use
ImageLoaderPipelineBuilderinstead of inheriting from a loader. On mobile, WASM and other restricted platforms, provide a valid writable cache path before using disk caching.Custom loaders
You can implement every component of the pipeline individually.
Or implement
IAsyncImageLoaderdirectly only when the complete built-in pipeline is not appropriate.LoadAsyncreceives anImageLoadRequestand returns anIImageLease; such an implementation replaces source resolution, transport, decoding and caching rather than customizing one pipeline stage.Use
ImageLease.Owned,ImageLease.NonOwningorImageLease.Createto make ownership explicit when implementing a custom loader.RAM retention
RAM retention can be configured when creating a loader. Expiration releases the loader's strong reference;
if the UI still uses the bitmap, it can be reused through a weak reference: