diff --git a/MapsforgeTiles/Avalonia/MapsforgeTileSource.Avalonia.cs b/MapsforgeTiles/Avalonia/MapsforgeTileSource.Avalonia.cs index 096e1980..fad2bb99 100644 --- a/MapsforgeTiles/Avalonia/MapsforgeTileSource.Avalonia.cs +++ b/MapsforgeTiles/Avalonia/MapsforgeTileSource.Avalonia.cs @@ -1,24 +1,43 @@ using Avalonia; +using Avalonia.Media; using Avalonia.Media.Imaging; using Avalonia.Platform; +using Microsoft.Extensions.Logging; using System; +using System.Threading.Tasks; namespace MapControl.MapsforgeTiles { public partial class MapsforgeTileSource { - private static Bitmap CreateImage(int[] pixels) + public override async Task LoadImageAsync(int zoomLevel, int column, int row) { - var size = (int)Math.Sqrt(pixels.Length); + Bitmap bitmap = null; - unsafe + try { - fixed (int* ptr = pixels) + var pixels = tileRenderer.RenderTile(zoomLevel, column, row); + + if (pixels != null) { - return new Bitmap(PixelFormat.Bgra8888, AlphaFormat.Opaque, (nint)ptr, - new PixelSize(size, size), new Vector(96d, 96d), size * 4); + var size = TileRenderer.TileSize; + + unsafe + { + fixed (int* ptr = pixels) + { + return new Bitmap(PixelFormat.Bgra8888, AlphaFormat.Opaque, (nint)ptr, + new PixelSize(size, size), new Vector(96d, 96d), size * 4); + } + } } } + catch (Exception ex) + { + Logger?.LogError(ex, "LoadImageAsync"); + } + + return bitmap; } } } diff --git a/MapsforgeTiles/Shared/MapsforgeTileSource.cs b/MapsforgeTiles/Shared/MapsforgeTileSource.cs index f49a8554..472e1e2d 100644 --- a/MapsforgeTiles/Shared/MapsforgeTileSource.cs +++ b/MapsforgeTiles/Shared/MapsforgeTileSource.cs @@ -1,17 +1,6 @@ using Microsoft.Extensions.Logging; -using System; using System.Collections.Generic; using System.IO; -using System.Threading.Tasks; -#if WPF -using System.Windows.Media; -#elif UWP -using Windows.UI.Xaml.Media; -#elif WINUI -using Microsoft.UI.Xaml.Media; -#elif AVALONIA -using ImageSource=Avalonia.Media.IImage; -#endif namespace MapControl.MapsforgeTiles { @@ -19,7 +8,7 @@ namespace MapControl.MapsforgeTiles { private static ILogger Logger => field ??= ImageLoader.LoggerFactory?.CreateLogger(); - private readonly TileRenderer renderer = new(theme, cacheCapacity, textScale); + private readonly TileRenderer tileRenderer = new(theme, cacheCapacity, textScale); public static void Initialize(string mapFilePath, float dpiScale) { @@ -41,26 +30,5 @@ namespace MapControl.MapsforgeTiles TileRenderer.Initialize(mapFiles, dpiScale); } - - public override Task LoadImageAsync(int zoomLevel, int column, int row) - { - ImageSource image = null; - - try - { - var pixels = renderer.RenderTile(zoomLevel, column, row); - - if (pixels != null) - { - image = CreateImage(pixels); - } - } - catch (Exception ex) - { - Logger?.LogError(ex, "LoadImageAsync"); - } - - return Task.FromResult(image); - } } } diff --git a/MapsforgeTiles/Shared/TileRenderer.cs b/MapsforgeTiles/Shared/TileRenderer.cs index 17eb3808..191f646b 100644 --- a/MapsforgeTiles/Shared/TileRenderer.cs +++ b/MapsforgeTiles/Shared/TileRenderer.cs @@ -14,7 +14,9 @@ namespace MapControl.MapsforgeTiles public class TileRenderer { private static DisplayModel displayModel; - private static MapDataStore dataStore; + private static MapDataStore mapDataStore; + + public static int TileSize => displayModel.getTileSize(); public static void Initialize(List mapFiles, float dpiScale) { @@ -23,12 +25,12 @@ namespace MapControl.MapsforgeTiles if (mapFiles.Count == 1) { - dataStore = new MapFile(mapFiles[0]); + mapDataStore = new MapFile(mapFiles[0]); } else { var multiMapDataStore = new MultiMapDataStore(MultiMapDataStore.DataPolicy.DEDUPLICATE); - dataStore = multiMapDataStore; + mapDataStore = multiMapDataStore; foreach (var mapFile in mapFiles) { @@ -56,7 +58,7 @@ namespace MapControl.MapsforgeTiles } tileCache = new InMemoryTileCache(cacheCapacity); - renderer = new DatabaseRenderer(dataStore, AwtGraphicFactory.INSTANCE, tileCache, null, true, false, null); + renderer = new DatabaseRenderer(mapDataStore, AwtGraphicFactory.INSTANCE, tileCache, null, true, false, null); renderThemeFuture = new RenderThemeFuture(AwtGraphicFactory.INSTANCE, renderTheme, displayModel); textScale = renderTextScale; } @@ -70,7 +72,7 @@ namespace MapControl.MapsforgeTiles int[] imageBuffer = null; var tile = new org.mapsforge.core.model.Tile(column, row, (byte)zoomLevel, displayModel.getTileSize()); - var job = new RendererJob(tile, dataStore, renderThemeFuture, displayModel, textScale, false, false); + var job = new RendererJob(tile, mapDataStore, renderThemeFuture, displayModel, textScale, false, false); var bitmap = tileCache.get(job) ?? renderer.executeJob(job); if (bitmap != null) diff --git a/MapsforgeTiles/WPF/MapsforgeTileSource.WPF.cs b/MapsforgeTiles/WPF/MapsforgeTileSource.WPF.cs index 0808903d..292008ea 100644 --- a/MapsforgeTiles/WPF/MapsforgeTileSource.WPF.cs +++ b/MapsforgeTiles/WPF/MapsforgeTileSource.WPF.cs @@ -1,4 +1,6 @@ -using System; +using Microsoft.Extensions.Logging; +using System; +using System.Threading.Tasks; using System.Windows.Media; using System.Windows.Media.Imaging; @@ -6,12 +8,28 @@ namespace MapControl.MapsforgeTiles { public partial class MapsforgeTileSource { - private static BitmapSource CreateImage(int[] pixels) + public override async Task LoadImageAsync(int zoomLevel, int column, int row) { - var size = (int)Math.Sqrt(pixels.Length); - var image = BitmapSource.Create(size, size, 96d, 96d, PixelFormats.Bgra32, null, pixels, size * 4); - image.Freeze(); - return image; + BitmapSource bitmap = null; + + try + { + var pixels = tileRenderer.RenderTile(zoomLevel, column, row); + + if (pixels != null) + { + var size = TileRenderer.TileSize; + + bitmap = BitmapSource.Create(size, size, 96d, 96d, PixelFormats.Bgra32, null, pixels, size * 4); + bitmap.Freeze(); + } + } + catch (Exception ex) + { + Logger?.LogError(ex, "LoadImageAsync"); + } + + return bitmap; } } } diff --git a/MapsforgeTiles/WinUI/MapsforgeTileSource.WinUI.cs b/MapsforgeTiles/WinUI/MapsforgeTileSource.WinUI.cs index 0b02bfba..ceddca52 100644 --- a/MapsforgeTiles/WinUI/MapsforgeTileSource.WinUI.cs +++ b/MapsforgeTiles/WinUI/MapsforgeTileSource.WinUI.cs @@ -1,9 +1,14 @@ using System; using System.IO; +using System.Runtime.InteropServices; using System.Runtime.InteropServices.WindowsRuntime; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; #if UWP +using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media.Imaging; #elif WINUI +using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Media.Imaging; #endif @@ -11,20 +16,34 @@ namespace MapControl.MapsforgeTiles { public partial class MapsforgeTileSource { - private static WriteableBitmap CreateImage(int[] pixels) + public override async Task LoadImageAsync(int zoomLevel, int column, int row) { - var size = (int)Math.Sqrt(pixels.Length); + ImageSource image = null; + var size = TileRenderer.TileSize; var bitmap = new WriteableBitmap(size, size); - using var stream = bitmap.PixelBuffer.AsStream(); - using var writer = new BinaryWriter(stream); - foreach (var pixel in pixels) + try { - writer.Write(pixel); + // Run a Task because in WinUI/UWP LoadImageAsync is called in the UI thread. + // + await Task.Run(() => + { + var pixels = tileRenderer.RenderTile(zoomLevel, column, row); + + if (pixels != null) + { + stream.Write(MemoryMarshal.AsBytes(pixels.AsSpan())); + image = bitmap; + } + }); + } + catch (Exception ex) + { + Logger?.LogError(ex, "LoadImageAsync"); } - return bitmap; + return image; } } }