diff --git a/MapsforgeTiles/Avalonia/MapsforgeTileSource.Avalonia.cs b/MapsforgeTiles/Avalonia/MapsforgeTileSource.Avalonia.cs new file mode 100644 index 00000000..53b374ff --- /dev/null +++ b/MapsforgeTiles/Avalonia/MapsforgeTileSource.Avalonia.cs @@ -0,0 +1,24 @@ +using System; +using Avalonia; +using Avalonia.Media.Imaging; +using Avalonia.Platform; + +namespace MapControl.MapsforgeTiles +{ + public partial class MapsforgeTileSource + { + private static Bitmap CreateImage(int[] pixels) + { + var size = (int)Math.Sqrt(pixels.Length); + + unsafe + { + fixed (int* ptr = pixels) + { + return new Bitmap(PixelFormat.Bgra8888, AlphaFormat.Opaque, (nint)ptr, + new PixelSize(size, size), new Vector(96d, 96d), size * 4); + } + } + } + } +} diff --git a/MapsforgeTiles/Avalonia/MapsforgeTiles.Avalonia.csproj b/MapsforgeTiles/Avalonia/MapsforgeTiles.Avalonia.csproj new file mode 100644 index 00000000..505b81fb --- /dev/null +++ b/MapsforgeTiles/Avalonia/MapsforgeTiles.Avalonia.csproj @@ -0,0 +1,29 @@ + + + net10.0 + AVALONIA + MapControl.MapsforgeTiles + XAML Map Control Mapsforge Library for Avalonia + true + + + + + + + + + + + + + + + + + + + + + + diff --git a/MapsforgeTiles/Shared/MapsforgeTileSource.cs b/MapsforgeTiles/Shared/MapsforgeTileSource.cs new file mode 100644 index 00000000..bfaf6fd7 --- /dev/null +++ b/MapsforgeTiles/Shared/MapsforgeTileSource.cs @@ -0,0 +1,32 @@ +using System.Threading.Tasks; +using TileRenderer; +#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 +{ + public partial class MapsforgeTileSource(string mapDirectory, string theme, int cacheCapacity = 200) : TileSource + { + private readonly MapsforgeTileRenderer renderer = new(mapDirectory, theme, cacheCapacity); + + public static void SetDpiScale(float scale) + { + MapsforgeTileRenderer.SetDpiScale(scale); + } + + public override Task LoadImageAsync(int zoomLevel, int column, int row) + { + var pixels = renderer.RenderTile(zoomLevel, column, row); + ImageSource image = pixels != null ? CreateImage(pixels) : null; + + return Task.FromResult(image); + } + } +} diff --git a/MapsforgeTiles/UWP/MapsforgeTiles.UWP.csproj b/MapsforgeTiles/UWP/MapsforgeTiles.UWP.csproj new file mode 100644 index 00000000..7fe611c5 --- /dev/null +++ b/MapsforgeTiles/UWP/MapsforgeTiles.UWP.csproj @@ -0,0 +1,33 @@ + + + net10.0-windows10.0.26100.0 + 10.0.17763.0 + true + UWP + MapControl.MapsforgeTiles + XAML Map Control Mapsforge Library for UWP + true + en-US + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MapsforgeTiles/WPF/MapsforgeTileSource.WPF.cs b/MapsforgeTiles/WPF/MapsforgeTileSource.WPF.cs new file mode 100644 index 00000000..0808903d --- /dev/null +++ b/MapsforgeTiles/WPF/MapsforgeTileSource.WPF.cs @@ -0,0 +1,17 @@ +using System; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace MapControl.MapsforgeTiles +{ + public partial class MapsforgeTileSource + { + private static BitmapSource CreateImage(int[] pixels) + { + 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; + } + } +} diff --git a/MapsforgeTiles/WPF/MapsforgeTiles.WPF.csproj b/MapsforgeTiles/WPF/MapsforgeTiles.WPF.csproj new file mode 100644 index 00000000..89c3bcef --- /dev/null +++ b/MapsforgeTiles/WPF/MapsforgeTiles.WPF.csproj @@ -0,0 +1,29 @@ + + + net10.0-windows + true + WPF + MapControl.MapsforgeTiles + XAML Map Control Mapsforge Library for WPF + + + + + + + + + + + + + + + + + + + + + + diff --git a/MapsforgeTiles/WinUI/MapsforgeTileSource.WinUI.cs b/MapsforgeTiles/WinUI/MapsforgeTileSource.WinUI.cs new file mode 100644 index 00000000..0b02bfba --- /dev/null +++ b/MapsforgeTiles/WinUI/MapsforgeTileSource.WinUI.cs @@ -0,0 +1,30 @@ +using System; +using System.IO; +using System.Runtime.InteropServices.WindowsRuntime; +#if UWP +using Windows.UI.Xaml.Media.Imaging; +#elif WINUI +using Microsoft.UI.Xaml.Media.Imaging; +#endif + +namespace MapControl.MapsforgeTiles +{ + public partial class MapsforgeTileSource + { + private static WriteableBitmap CreateImage(int[] pixels) + { + var size = (int)Math.Sqrt(pixels.Length); + var bitmap = new WriteableBitmap(size, size); + + using var stream = bitmap.PixelBuffer.AsStream(); + using var writer = new BinaryWriter(stream); + + foreach (var pixel in pixels) + { + writer.Write(pixel); + } + + return bitmap; + } + } +} diff --git a/MapsforgeTiles/WinUI/MapsforgeTiles.WinUI.csproj b/MapsforgeTiles/WinUI/MapsforgeTiles.WinUI.csproj new file mode 100644 index 00000000..976e01d3 --- /dev/null +++ b/MapsforgeTiles/WinUI/MapsforgeTiles.WinUI.csproj @@ -0,0 +1,29 @@ + + + net10.0-windows10.0.17763.0 + true + WINUI + MapControl.MapsforgeTiles + XAML Map Control Mapsforge Library for WinUI + + + + + + + + + + + + + + + + + + + + + + diff --git a/MapsforgeTiles/pom.xml b/MapsforgeTiles/pom.xml new file mode 100644 index 00000000..f3292283 --- /dev/null +++ b/MapsforgeTiles/pom.xml @@ -0,0 +1,61 @@ + + + 4.0.0 + + xaml.mapcontrol + mapsforge-tilerenderer + 0.1.0 + + + 8 + UTF-8 + + + + + jitpack.io + https://jitpack.io + + + + + + com.github.mapsforge.mapsforge + mapsforge-core + 0.27.0 + + + com.github.mapsforge.mapsforge + mapsforge-map-awt + 0.27.0 + + + com.github.mapsforge.mapsforge + mapsforge-themes + 0.27.0 + + + + + + + maven-assembly-plugin + + + jar-with-dependencies + + + + + package + + single + + + + + + + diff --git a/MapsforgeTiles/src/main/java/TileRenderer/MapsforgeTileRenderer.java b/MapsforgeTiles/src/main/java/TileRenderer/MapsforgeTileRenderer.java new file mode 100644 index 00000000..bf76cef2 --- /dev/null +++ b/MapsforgeTiles/src/main/java/TileRenderer/MapsforgeTileRenderer.java @@ -0,0 +1,74 @@ +package TileRenderer; + +import org.mapsforge.core.graphics.TileBitmap; +import org.mapsforge.core.model.Tile; +import org.mapsforge.map.awt.graphics.AwtGraphicFactory; +import org.mapsforge.map.datastore.MapDataStore; +import org.mapsforge.map.datastore.MultiMapDataStore; +import org.mapsforge.map.layer.cache.InMemoryTileCache; +import org.mapsforge.map.layer.renderer.DatabaseRenderer; +import org.mapsforge.map.layer.renderer.RendererJob; +import org.mapsforge.map.model.DisplayModel; +import org.mapsforge.map.reader.MapFile; +import org.mapsforge.map.rendertheme.internal.MapsforgeThemes; +import org.mapsforge.map.rendertheme.rule.RenderThemeFuture; + +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +public class MapsforgeTileRenderer { + + public static void SetDpiScale(float scale) { + DisplayModel.setDeviceScaleFactor(scale); + } + + private final MapDataStore dataStore; + private final DisplayModel displayModel; + private final InMemoryTileCache tileCache; + private final DatabaseRenderer renderer; + private final RenderThemeFuture renderThemeFuture; + + public MapsforgeTileRenderer(String mapFilePath, String theme, int cacheCapacity) { + if (mapFilePath.endsWith(".map")) { + dataStore = new MapFile(mapFilePath); + } else { + MultiMapDataStore multiMapDataStore = new MultiMapDataStore(MultiMapDataStore.DataPolicy.DEDUPLICATE); + File dir = new File(mapFilePath); + for (File mapFile : dir.listFiles((file, name) -> name.endsWith(".map"))) { + multiMapDataStore.addMapDataStore(new MapFile(mapFile), false, false); + } + dataStore = multiMapDataStore; + } + + displayModel = new DisplayModel(); + tileCache = new InMemoryTileCache(cacheCapacity); + renderer = new DatabaseRenderer(dataStore, AwtGraphicFactory.INSTANCE, tileCache, null, true, false, null); + renderThemeFuture = new RenderThemeFuture(AwtGraphicFactory.INSTANCE, MapsforgeThemes.valueOf(theme.toUpperCase()), displayModel); + } + + public int[] RenderTile(int zoomLevel, int x, int y) throws IOException { + if (!renderThemeFuture.isDone()) { + renderThemeFuture.run(); + } + + int[] imageBuffer = null; + Tile tile = new Tile(x, y, (byte) zoomLevel, displayModel.getTileSize()); + RendererJob job = new RendererJob(tile, dataStore, renderThemeFuture, displayModel, 1f, false, false); + TileBitmap bitmap = tileCache.get(job); + + if (bitmap == null) { + bitmap = renderer.executeJob(job); + } + + if (bitmap != null) { + BufferedImage image = AwtGraphicFactory.getBitmap(bitmap); + + if (image != null) { + imageBuffer = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth()); + } + } + + return imageBuffer; + } +}