TileImageLoader

This commit is contained in:
ClemensFischer 2025-11-13 19:25:11 +01:00
parent 76f920a053
commit b44018ac8f
2 changed files with 37 additions and 32 deletions

View file

@ -19,10 +19,11 @@ namespace MapControl
public int Y { get; } = y; public int Y { get; } = y;
public int Column { get; } = ((x % columnCount) + columnCount) % columnCount; public int Column { get; } = ((x % columnCount) + columnCount) % columnCount;
public int Row => Y; public int Row => Y;
public bool IsPending { get; set; } = true; public bool IsPending { get; set; } = true;
/// <summary> /// <summary>
/// Runs a tile image download Task and marshals the result to the UI thread. /// Runs a tile image download Task and passes the result to the UI thread.
/// </summary> /// </summary>
public abstract Task LoadImageAsync(Func<Task<ImageSource>> loadImageFunc); public abstract Task LoadImageAsync(Func<Task<ImageSource>> loadImageFunc);
} }

View file

@ -10,11 +10,14 @@ using System.Threading.Tasks;
namespace MapControl namespace MapControl
{ {
/// <summary>
/// Loads and optionally caches map tile images for a MapTilePyramidLayer.
/// </summary>
public interface ITileImageLoader public interface ITileImageLoader
{ {
/// <summary> /// <summary>
/// Loads all pending tiles from the tiles collection. Tile image caching is enabled /// Starts asynchronous loading of all pending tiles from the tiles collection.
/// when cacheName is a non-empty string and tiles are loaded from http or https Uris. /// Caching is enabled when cacheName is a non-empty string and tiles are loaded from http or https Uris.
/// </summary> /// </summary>
void BeginLoadTiles(IEnumerable<Tile> tiles, TileSource tileSource, string cacheName, IProgress<double> progress); void BeginLoadTiles(IEnumerable<Tile> tiles, TileSource tileSource, string cacheName, IProgress<double> progress);
@ -24,9 +27,6 @@ namespace MapControl
void CancelLoadTiles(); void CancelLoadTiles();
} }
/// <summary>
/// Loads and optionally caches map tile images for a MapTilePyramidLayer.
/// </summary>
public class TileImageLoader : ITileImageLoader public class TileImageLoader : ITileImageLoader
{ {
private static ILogger logger; private static ILogger logger;
@ -122,6 +122,7 @@ namespace MapControl
if (tileQueue.Count > 0) if (tileQueue.Count > 0)
{ {
tile = tileQueue.Dequeue(); tile = tileQueue.Dequeue();
tile.IsPending = false;
return true; return true;
} }
@ -135,35 +136,12 @@ namespace MapControl
while (TryDequeueTile(out Tile tile)) while (TryDequeueTile(out Tile tile))
{ {
tile.IsPending = false;
Logger?.LogDebug("Thread {thread,2}: Loading tile ({zoom}/{column}/{row})",
Environment.CurrentManagedThreadId, tile.ZoomLevel, tile.Column, tile.Row);
try try
{ {
// Pass image loading callbacks to platform-specific method Logger?.LogDebug("Thread {thread,2}: Loading tile ({zoom}/{column}/{row})",
// tile.LoadImageAsync(Func<Task<ImageSource>>) for completion in the UI thread. Environment.CurrentManagedThreadId, tile.ZoomLevel, tile.Column, tile.Row);
var uri = tileSource.GetUri(tile.ZoomLevel, tile.Column, tile.Row); await LoadTileImage(tile, tileSource, cacheName);
if (uri == null)
{
await tile.LoadImageAsync(() => tileSource.LoadImageAsync(tile.ZoomLevel, tile.Column, tile.Row)).ConfigureAwait(false);
}
else if (uri.Scheme != "http" && uri.Scheme != "https" || string.IsNullOrEmpty(cacheName))
{
await tile.LoadImageAsync(() => ImageLoader.LoadImageAsync(uri)).ConfigureAwait(false);
}
else
{
var buffer = await LoadCachedBuffer(tile, uri, cacheName).ConfigureAwait(false);
if (buffer != null)
{
await tile.LoadImageAsync(() => ImageLoader.LoadImageAsync(buffer)).ConfigureAwait(false);
}
}
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -174,6 +152,32 @@ namespace MapControl
} }
} }
private static async Task LoadTileImage(Tile tile, TileSource tileSource, string cacheName)
{
// Pass image loading callbacks to platform-specific method
// tile.LoadImageAsync(Func<Task<ImageSource>>) for completion in the UI thread.
var uri = tileSource.GetUri(tile.ZoomLevel, tile.Column, tile.Row);
if (uri == null)
{
await tile.LoadImageAsync(() => tileSource.LoadImageAsync(tile.ZoomLevel, tile.Column, tile.Row)).ConfigureAwait(false);
}
else if (uri.Scheme != "http" && uri.Scheme != "https" || string.IsNullOrEmpty(cacheName))
{
await tile.LoadImageAsync(() => ImageLoader.LoadImageAsync(uri)).ConfigureAwait(false);
}
else
{
var buffer = await LoadCachedBuffer(tile, uri, cacheName).ConfigureAwait(false);
if (buffer != null)
{
await tile.LoadImageAsync(() => ImageLoader.LoadImageAsync(buffer)).ConfigureAwait(false);
}
}
}
private static async Task<byte[]> LoadCachedBuffer(Tile tile, Uri uri, string cacheName) private static async Task<byte[]> LoadCachedBuffer(Tile tile, Uri uri, string cacheName)
{ {
var extension = Path.GetExtension(uri.LocalPath).ToLower(); var extension = Path.GetExtension(uri.LocalPath).ToLower();