2025-04-01 16:11:53 +02:00
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
|
using System;
|
2018-08-15 23:29:03 +02:00
|
|
|
|
using System.Threading.Tasks;
|
2024-05-22 11:25:32 +02:00
|
|
|
|
#if WPF
|
|
|
|
|
|
using System.Windows;
|
2021-11-17 23:46:48 +01:00
|
|
|
|
#elif UWP
|
2017-10-07 17:43:28 +02:00
|
|
|
|
using Windows.UI.Xaml;
|
2024-05-22 11:25:32 +02:00
|
|
|
|
#elif WINUI
|
|
|
|
|
|
using Microsoft.UI.Xaml;
|
2024-05-27 17:30:58 +02:00
|
|
|
|
#elif AVALONIA
|
|
|
|
|
|
using DependencyProperty = Avalonia.AvaloniaProperty;
|
2017-10-07 17:43:28 +02:00
|
|
|
|
#endif
|
|
|
|
|
|
|
2018-12-09 17:14:32 +01:00
|
|
|
|
namespace MapControl.MBTiles
|
2017-10-07 17:43:28 +02:00
|
|
|
|
{
|
2019-07-17 17:56:46 +02:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// MapTileLayer that uses an MBTiles SQLite Database. See https://wiki.openstreetmap.org/wiki/MBTiles.
|
|
|
|
|
|
/// </summary>
|
2017-10-07 17:43:28 +02:00
|
|
|
|
public class MBTileLayer : MapTileLayer
|
|
|
|
|
|
{
|
2025-08-31 14:30:20 +02:00
|
|
|
|
private static ILogger logger;
|
|
|
|
|
|
private static ILogger Logger => logger ?? (logger = ImageLoader.LoggerFactory?.CreateLogger<MBTileLayer>());
|
|
|
|
|
|
|
2024-05-23 18:08:14 +02:00
|
|
|
|
public static readonly DependencyProperty FileProperty =
|
2024-05-23 19:21:28 +02:00
|
|
|
|
DependencyPropertyHelper.Register<MBTileLayer, string>(nameof(File), null,
|
2024-05-23 18:08:14 +02:00
|
|
|
|
async (layer, oldValue, newValue) => await layer.FilePropertyChanged(newValue));
|
2017-10-07 17:43:28 +02:00
|
|
|
|
|
|
|
|
|
|
public string File
|
|
|
|
|
|
{
|
2022-08-06 11:04:49 +02:00
|
|
|
|
get => (string)GetValue(FileProperty);
|
|
|
|
|
|
set => SetValue(FileProperty, value);
|
2017-10-07 17:43:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2019-11-17 00:10:08 +01:00
|
|
|
|
/// <summary>
|
2021-11-10 22:31:06 +01:00
|
|
|
|
/// May be overridden to create a derived MBTileSource that handles other tile formats than png and jpg.
|
2019-11-17 00:10:08 +01:00
|
|
|
|
/// </summary>
|
2024-08-20 18:00:04 +02:00
|
|
|
|
protected virtual async Task<MBTileSource> CreateTileSourceAsync(string file)
|
2019-11-17 00:10:08 +01:00
|
|
|
|
{
|
2024-08-20 18:00:04 +02:00
|
|
|
|
var tileSource = new MBTileSource();
|
|
|
|
|
|
|
|
|
|
|
|
await tileSource.OpenAsync(file);
|
|
|
|
|
|
|
|
|
|
|
|
if (tileSource.Metadata.TryGetValue("format", out string format) && format != "png" && format != "jpg")
|
|
|
|
|
|
{
|
|
|
|
|
|
tileSource.Dispose();
|
|
|
|
|
|
|
|
|
|
|
|
throw new NotSupportedException($"Tile image format {format} is not supported.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return tileSource;
|
2019-11-17 00:10:08 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2018-08-15 23:29:03 +02:00
|
|
|
|
private async Task FilePropertyChanged(string file)
|
2017-10-07 17:43:28 +02:00
|
|
|
|
{
|
2024-08-20 18:00:04 +02:00
|
|
|
|
(TileSource as MBTileSource)?.Close();
|
2017-10-07 17:43:28 +02:00
|
|
|
|
|
2019-11-14 23:21:08 +01:00
|
|
|
|
ClearValue(TileSourceProperty);
|
|
|
|
|
|
ClearValue(SourceNameProperty);
|
|
|
|
|
|
ClearValue(DescriptionProperty);
|
|
|
|
|
|
ClearValue(MinZoomLevelProperty);
|
|
|
|
|
|
ClearValue(MaxZoomLevelProperty);
|
2018-08-15 23:29:03 +02:00
|
|
|
|
|
2024-08-20 18:00:04 +02:00
|
|
|
|
if (!string.IsNullOrEmpty(file))
|
2017-10-07 17:43:28 +02:00
|
|
|
|
{
|
2024-08-20 18:00:04 +02:00
|
|
|
|
try
|
2017-10-07 17:43:28 +02:00
|
|
|
|
{
|
2024-08-20 18:00:04 +02:00
|
|
|
|
var tileSource = await CreateTileSourceAsync(file);
|
2017-10-07 17:43:28 +02:00
|
|
|
|
|
2024-08-20 18:00:04 +02:00
|
|
|
|
TileSource = tileSource;
|
2017-10-07 17:43:28 +02:00
|
|
|
|
|
2024-08-20 18:00:04 +02:00
|
|
|
|
if (tileSource.Metadata.TryGetValue("name", out string value))
|
|
|
|
|
|
{
|
|
|
|
|
|
SourceName = value;
|
|
|
|
|
|
}
|
2017-10-07 17:43:28 +02:00
|
|
|
|
|
2024-08-20 18:00:04 +02:00
|
|
|
|
if (tileSource.Metadata.TryGetValue("description", out value))
|
|
|
|
|
|
{
|
|
|
|
|
|
Description = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (tileSource.Metadata.TryGetValue("minzoom", out value) && int.TryParse(value, out int zoomLevel))
|
|
|
|
|
|
{
|
|
|
|
|
|
MinZoomLevel = zoomLevel;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (tileSource.Metadata.TryGetValue("maxzoom", out value) && int.TryParse(value, out zoomLevel))
|
|
|
|
|
|
{
|
|
|
|
|
|
MaxZoomLevel = zoomLevel;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
2017-10-07 17:43:28 +02:00
|
|
|
|
{
|
2025-08-31 14:30:20 +02:00
|
|
|
|
Logger?.LogError(ex, "Invalid file: {file}", file);
|
2017-10-07 17:43:28 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|