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;
+ }
+}