From 4912fa1e405c0246ef2cb46a3bbd0a029e82aa7d Mon Sep 17 00:00:00 2001 From: ClemensFischer Date: Thu, 13 Nov 2025 17:06:33 +0100 Subject: [PATCH] TileSource/TileImageLoader --- MBTiles/Shared/MBTileSource.cs | 41 +++++++++++----------------- MapControl/Shared/TileImageLoader.cs | 29 ++++++++++---------- MapControl/Shared/TileSource.cs | 33 ++++------------------ 3 files changed, 37 insertions(+), 66 deletions(-) diff --git a/MBTiles/Shared/MBTileSource.cs b/MBTiles/Shared/MBTileSource.cs index 38c210a0..7f9c2a82 100644 --- a/MBTiles/Shared/MBTileSource.cs +++ b/MBTiles/Shared/MBTileSource.cs @@ -24,8 +24,6 @@ namespace MapControl.MBTiles public IDictionary Metadata { get; } = new Dictionary(); - public override bool Cacheable => false; - public async Task OpenAsync(string file) { Close(); @@ -34,14 +32,13 @@ namespace MapControl.MBTiles await connection.OpenAsync(); - using (var command = new SQLiteCommand("select * from metadata", connection)) - { - var reader = await command.ExecuteReaderAsync(); + using var command = new SQLiteCommand("select * from metadata", connection); - while (await reader.ReadAsync()) - { - Metadata[(string)reader["name"]] = (string)reader["value"]; - } + var reader = await command.ExecuteReaderAsync(); + + while (await reader.ReadAsync()) + { + Metadata[(string)reader["name"]] = (string)reader["value"]; } } @@ -66,18 +63,17 @@ namespace MapControl.MBTiles try { - using (var command = new SQLiteCommand("select tile_data from tiles where zoom_level=@z and tile_column=@x and tile_row=@y", connection)) + using var command = new SQLiteCommand("select tile_data from tiles where zoom_level=@z and tile_column=@x and tile_row=@y", connection); + + command.Parameters.AddWithValue("@z", zoomLevel); + command.Parameters.AddWithValue("@x", x); + command.Parameters.AddWithValue("@y", (1 << zoomLevel) - y - 1); + + var buffer = (byte[])await command.ExecuteScalarAsync(); + + if (buffer?.Length > 0) { - command.Parameters.AddWithValue("@z", zoomLevel); - command.Parameters.AddWithValue("@x", x); - command.Parameters.AddWithValue("@y", (1 << zoomLevel) - y - 1); - - var buffer = (byte[])await command.ExecuteScalarAsync(); - - if (buffer?.Length > 0) - { - image = await LoadImageAsync(buffer); - } + image = await ImageLoader.LoadImageAsync(buffer); } } catch (Exception ex) @@ -87,10 +83,5 @@ namespace MapControl.MBTiles return image; } - - public override Uri GetUri(int zoomLevel, int column, int row) - { - throw new NotSupportedException(); - } } } diff --git a/MapControl/Shared/TileImageLoader.cs b/MapControl/Shared/TileImageLoader.cs index d83162e3..d566f29b 100644 --- a/MapControl/Shared/TileImageLoader.cs +++ b/MapControl/Shared/TileImageLoader.cs @@ -13,13 +13,13 @@ namespace MapControl public interface ITileImageLoader { /// - /// Loads all pending tiles from the tiles collection. - /// Tile image caching is enabled when tileSource.UriFormat starts with "http" and cacheName is a non-empty string. + /// Loads all pending tiles from the tiles collection. Tile image caching is enabled + /// when cacheName is a non-empty string and tiles are loaded from http or https Uris. /// void BeginLoadTiles(IEnumerable tiles, TileSource tileSource, string cacheName, IProgress progress); /// - /// Cancels a potentially ongoing tile loading task. + /// Terminates all running tile loading tasks. /// void CancelLoadTiles(); } @@ -76,7 +76,7 @@ namespace MapControl public void BeginLoadTiles(IEnumerable tiles, TileSource tileSource, string cacheName, IProgress progress) { - if (Cache == null || !tileSource.Cacheable) + if (Cache == null) { cacheName = null; // disable caching } @@ -142,25 +142,26 @@ namespace MapControl try { - // Pass tileSource.LoadImageAsync calls to platform-specific method + // Pass image loading callbacks to platform-specific method // tile.LoadImageAsync(Func>) for completion in the UI thread. - if (string.IsNullOrEmpty(cacheName)) + 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 uri = tileSource.GetUri(tile.ZoomLevel, tile.Column, tile.Row); + var buffer = await LoadCachedBuffer(tile, uri, cacheName).ConfigureAwait(false); - if (uri != null) + if (buffer?.Length > 0) { - var buffer = await LoadCachedBuffer(tile, uri, cacheName).ConfigureAwait(false); - - if (buffer?.Length > 0) - { - await tile.LoadImageAsync(() => tileSource.LoadImageAsync(buffer)).ConfigureAwait(false); - } + await tile.LoadImageAsync(() => ImageLoader.LoadImageAsync(buffer)).ConfigureAwait(false); } } } diff --git a/MapControl/Shared/TileSource.cs b/MapControl/Shared/TileSource.cs index 667fdd32..8d0cb03b 100644 --- a/MapControl/Shared/TileSource.cs +++ b/MapControl/Shared/TileSource.cs @@ -21,30 +21,18 @@ namespace MapControl #else [System.ComponentModel.TypeConverter(typeof(TileSourceConverter))] #endif - public abstract class TileSource + public class TileSource { /// - /// Indicates whether tile images from this source should be cached. + /// Gets the image request Uri for the specified zoom level and tile indices. + /// May return null when the image shall be loaded by the LoadImageAsync method. /// - public abstract bool Cacheable { get; } + public virtual Uri GetUri(int zoomLevel, int column, int row) => null; /// - /// Gets the image Uri for the specified zoom level and tile indices. + /// Loads a tile image without an Uri. /// - public abstract Uri GetUri(int zoomLevel, int column, int row); - - /// - /// Loads a tile image whithout caching. - /// - public abstract Task LoadImageAsync(int zoomLevel, int column, int row); - - /// - /// Loads a cacheable tile image from an encoded frame buffer. - /// - public virtual Task LoadImageAsync(byte[] buffer) - { - return ImageLoader.LoadImageAsync(buffer); - } + public virtual Task LoadImageAsync(int zoomLevel, int column, int row) => null; /// /// Creates a TileSource instance from an Uri template string. @@ -78,8 +66,6 @@ namespace MapControl public string[] Subdomains { get; set; } - public override bool Cacheable => UriTemplate != null && UriTemplate.StartsWith("http"); - public override Uri GetUri(int zoomLevel, int column, int row) { Uri uri = null; @@ -103,13 +89,6 @@ namespace MapControl return uri; } - public override Task LoadImageAsync(int zoomLevel, int column, int row) - { - var uri = GetUri(zoomLevel, column, row); - - return uri != null ? ImageLoader.LoadImageAsync(uri) : Task.FromResult((ImageSource)null); - } - public override string ToString() { return UriTemplate;