diff --git a/MapControl/Avalonia/ImageLoader.Avalonia.cs b/MapControl/Avalonia/ImageLoader.Avalonia.cs index 48971284..22a66132 100644 --- a/MapControl/Avalonia/ImageLoader.Avalonia.cs +++ b/MapControl/Avalonia/ImageLoader.Avalonia.cs @@ -42,9 +42,9 @@ namespace MapControl internal static async Task LoadMergedImageAsync(Uri uri1, Uri uri2, IProgress progress) { - var images = await LoadImagesAsync(uri1, uri2, progress); + WriteableBitmap mergedImage = null; - WriteableBitmap image = null; + var images = await LoadImagesAsync(uri1, uri2, progress); if (images.Length == 2 && images[0] is Bitmap image1 && @@ -70,12 +70,12 @@ namespace MapControl image1.CopyPixels(new PixelRect(image1.PixelSize), buffer, bufferSize, stride); image2.CopyPixels(new PixelRect(image2.PixelSize), buffer + stride1, bufferSize, stride); - image = new WriteableBitmap(image1.Format.Value, image1.AlphaFormat.Value, buffer, pixelSize, image1.Dpi, stride); + mergedImage = new WriteableBitmap(image1.Format.Value, image1.AlphaFormat.Value, buffer, pixelSize, image1.Dpi, stride); } } } - return image; + return mergedImage; } } } diff --git a/MapControl/WPF/ImageLoader.WPF.cs b/MapControl/WPF/ImageLoader.WPF.cs index d94dc4e4..8064b88a 100644 --- a/MapControl/WPF/ImageLoader.WPF.cs +++ b/MapControl/WPF/ImageLoader.WPF.cs @@ -54,9 +54,9 @@ namespace MapControl internal static async Task LoadMergedImageAsync(Uri uri1, Uri uri2, IProgress progress) { - var images = await LoadImagesAsync(uri1, uri2, progress); + WriteableBitmap mergedImage = null; - WriteableBitmap image = null; + var images = await LoadImagesAsync(uri1, uri2, progress); if (images.Length == 2 && images[0] is BitmapSource image1 && @@ -77,13 +77,13 @@ namespace MapControl image1.CopyPixels(buffer1, stride1, 0); image2.CopyPixels(buffer2, stride2, 0); - image = new WriteableBitmap(width1 + width2, height, 96, 96, format, null); - image.WritePixels(new Int32Rect(0, 0, width1, height), buffer1, stride1, 0); - image.WritePixels(new Int32Rect(width1, 0, width2, height), buffer2, stride2, 0); - image.Freeze(); + mergedImage = new WriteableBitmap(width1 + width2, height, 96, 96, format, null); + mergedImage.WritePixels(new Int32Rect(0, 0, width1, height), buffer1, stride1, 0); + mergedImage.WritePixels(new Int32Rect(width1, 0, width2, height), buffer2, stride2, 0); + mergedImage.Freeze(); } - return image; + return mergedImage; } } } diff --git a/MapControl/WinUI/GeoImage.WinUI.cs b/MapControl/WinUI/GeoImage.WinUI.cs index a0b357cf..cf3e0896 100644 --- a/MapControl/WinUI/GeoImage.WinUI.cs +++ b/MapControl/WinUI/GeoImage.WinUI.cs @@ -28,7 +28,7 @@ namespace MapControl { var decoder = await BitmapDecoder.CreateAsync(stream); - bitmapSource = await ImageLoader.LoadImageAsync(decoder); + bitmapSource = await ImageLoader.LoadWriteableBitmapAsync(decoder); var geoKeyDirectoryQuery = QueryString(GeoKeyDirectoryTag); var pixelScaleQuery = QueryString(ModelPixelScaleTag); diff --git a/MapControl/WinUI/ImageLoader.WinUI.cs b/MapControl/WinUI/ImageLoader.WinUI.cs index b2055079..ca0e931e 100644 --- a/MapControl/WinUI/ImageLoader.WinUI.cs +++ b/MapControl/WinUI/ImageLoader.WinUI.cs @@ -3,6 +3,7 @@ // Licensed under the Microsoft Public License (Ms-PL) using System; +using System.Diagnostics; using System.IO; using System.Runtime.InteropServices.WindowsRuntime; using System.Threading.Tasks; @@ -26,29 +27,11 @@ namespace MapControl return new BitmapImage(uri); } - public static async Task LoadImageAsync(BitmapDecoder decoder) - { - var image = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight); - var pixelData = await decoder.GetPixelDataAsync( - BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied, new BitmapTransform(), - ExifOrientationMode.IgnoreExifOrientation, ColorManagementMode.DoNotColorManage); - - pixelData.DetachPixelData().CopyTo(image.PixelBuffer); - - return image; - } - public static async Task LoadImageAsync(IRandomAccessStream stream) { - // WinUI BitmapImage produces visual artifacts with Bing Maps Aerial (or all JPEG?) - // images in a tile raster, where thin white lines may appear as gaps between tiles. - // Alternatives are SoftwareBitmapSource or WriteableBitmap. - // - // var image = new BitmapImage(); - // await image.SetSourceAsync(stream); - // return image; - - return await LoadImageAsync(await BitmapDecoder.CreateAsync(stream)); + var image = new BitmapImage(); + await image.SetSourceAsync(stream); + return image; } public static Task LoadImageAsync(Stream stream) @@ -75,27 +58,60 @@ namespace MapControl return image; } - internal static async Task LoadMergedImageAsync(Uri uri1, Uri uri2, IProgress progress) + internal static async Task LoadWriteableBitmapAsync(BitmapDecoder decoder) { - var images = await LoadImagesAsync(uri1, uri2, progress); + var image = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight); + var pixelData = await decoder.GetPixelDataAsync( + BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied, new BitmapTransform(), + ExifOrientationMode.IgnoreExifOrientation, ColorManagementMode.DoNotColorManage); + pixelData.DetachPixelData().CopyTo(image.PixelBuffer); + + return image; + } + + internal static async Task LoadWriteableBitmapAsync(Uri uri) + { WriteableBitmap image = null; - if (images.Length == 2 && - images[0] is WriteableBitmap image1 && - images[1] is WriteableBitmap image2 && - image1.PixelHeight == image2.PixelHeight) + try { - var buffer1 = image1.PixelBuffer; - var buffer2 = image2.PixelBuffer; - var stride1 = (uint)image1.PixelWidth * 4; - var stride2 = (uint)image2.PixelWidth * 4; + using (var stream = await RandomAccessStreamReference.CreateFromUri(uri).OpenReadAsync()) + { + image = await LoadWriteableBitmapAsync(await BitmapDecoder.CreateAsync(stream)); + } + } + catch (Exception ex) + { + Debug.WriteLine($"{nameof(ImageLoader)}: {uri}: {ex.Message}"); + } + + return image; + } + + internal static async Task LoadMergedImageAsync(Uri uri1, Uri uri2, IProgress progress) + { + WriteableBitmap mergedImage = null; + + progress?.Report(0d); + + var images = await Task.WhenAll(LoadWriteableBitmapAsync(uri1), LoadWriteableBitmapAsync(uri2)); + + if (images.Length == 2 && + images[0] != null && + images[1] != null && + images[0].PixelHeight == images[1].PixelHeight) + { + var buffer1 = images[0].PixelBuffer; + var buffer2 = images[1].PixelBuffer; + var stride1 = (uint)images[0].PixelWidth * 4; + var stride2 = (uint)images[1].PixelWidth * 4; var stride = stride1 + stride2; - var height = image1.PixelHeight; + var height = images[0].PixelHeight; - image = new WriteableBitmap(image1.PixelWidth + image2.PixelWidth, height); + mergedImage = new WriteableBitmap(images[0].PixelWidth + images[1].PixelWidth, height); - var buffer = image.PixelBuffer; + var buffer = mergedImage.PixelBuffer; for (uint y = 0; y < height; y++) { @@ -104,7 +120,9 @@ namespace MapControl } } - return image; + progress?.Report(1d); + + return mergedImage; } } } diff --git a/MapControl/WinUI/MapControl.WinUI.csproj b/MapControl/WinUI/MapControl.WinUI.csproj index e1458837..5f2fbb81 100644 --- a/MapControl/WinUI/MapControl.WinUI.csproj +++ b/MapControl/WinUI/MapControl.WinUI.csproj @@ -3,6 +3,7 @@ net8.0-windows10.0.17763.0 win-x86;win-x64;win-arm64 true + true WINUI MapControl XAML Map Control Library for WinUI