diff --git a/MBTiles/Shared/MBTileData.cs b/MBTiles/Shared/MBTileData.cs index 6ec120be..997aea6a 100644 --- a/MBTiles/Shared/MBTileData.cs +++ b/MBTiles/Shared/MBTileData.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Threading.Tasks; #if WINDOWS_UWP using SQLiteCommand = Microsoft.Data.Sqlite.SqliteCommand; @@ -21,7 +22,7 @@ namespace MapControl.MBTiles public MBTileData(string file) { - connection = new SQLiteConnection("Data Source=" + file); + connection = new SQLiteConnection("Data Source=" + Path.GetFullPath(file)); } public Task OpenAsync() diff --git a/MapControl/Shared/ImageLoader.cs b/MapControl/Shared/ImageLoader.cs index c88d09ee..e9242177 100644 --- a/MapControl/Shared/ImageLoader.cs +++ b/MapControl/Shared/ImageLoader.cs @@ -32,7 +32,7 @@ namespace MapControl { if (!uri.IsAbsoluteUri || uri.Scheme == "file") { - image = await LoadLocalImageAsync(uri); + image = await LoadImageAsync(uri.IsAbsoluteUri ? uri.LocalPath : uri.OriginalString); } else if (uri.Scheme == "http" || uri.Scheme == "https") { diff --git a/MapControl/Shared/MapImageLayer.cs b/MapControl/Shared/MapImageLayer.cs index 641d8540..0a128119 100644 --- a/MapControl/Shared/MapImageLayer.cs +++ b/MapControl/Shared/MapImageLayer.cs @@ -230,13 +230,13 @@ namespace MapControl UpdateBoundingBox(); - ImageSource imageSource = null; + ImageSource image = null; if (BoundingBox != null) { try { - imageSource = await GetImageAsync(); + image = await GetImageAsync(); } catch (Exception ex) { @@ -244,7 +244,7 @@ namespace MapControl } } - SwapImages(imageSource); + SwapImages(image); updateInProgress = false; } @@ -321,7 +321,7 @@ namespace MapControl } } - private void SwapImages(ImageSource imageSource) + private void SwapImages(ImageSource image) { var topImage = (Image)Children[0]; var bottomImage = (Image)Children[1]; @@ -329,7 +329,7 @@ namespace MapControl Children.RemoveAt(0); Children.Insert(1, topImage); - topImage.Source = imageSource; + topImage.Source = image; SetBoundingBox(topImage, BoundingBox?.Clone()); topImage.BeginAnimation(OpacityProperty, new DoubleAnimation diff --git a/MapControl/Shared/TileImageLoader.cs b/MapControl/Shared/TileImageLoader.cs index 613e320d..9371d4d2 100644 --- a/MapControl/Shared/TileImageLoader.cs +++ b/MapControl/Shared/TileImageLoader.cs @@ -6,7 +6,6 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -57,7 +56,7 @@ namespace MapControl /// If the UriFormat of TileSource starts with "http" and SourceName is a non-empty string, /// tile images will be cached in the TileImageLoader's Cache. /// - public async void LoadTilesAsync(IEnumerable tiles) + public void LoadTilesAsync(IEnumerable tiles) { tileQueue.Clear(); tileQueue.Enqueue(tiles); @@ -68,9 +67,10 @@ namespace MapControl { Interlocked.Add(ref taskCount, newTasks); - await Task - .WhenAll(Enumerable.Range(0, newTasks).Select(n => LoadTilesFromQueueAsync())) - .ConfigureAwait(false); + while (--newTasks >= 0) + { + Task.Run(() => LoadTilesFromQueueAsync()); + } } } diff --git a/MapControl/Shared/WmsImageLayer.cs b/MapControl/Shared/WmsImageLayer.cs index cf0a8ba1..fad30030 100644 --- a/MapControl/Shared/WmsImageLayer.cs +++ b/MapControl/Shared/WmsImageLayer.cs @@ -119,9 +119,9 @@ namespace MapControl protected override async Task GetImageAsync() { - var imageUri = GetImageUri(); + var uri = GetImageUri(); - return imageUri != null ? await ImageLoader.LoadImageAsync(imageUri) : null; + return uri != null ? await ImageLoader.LoadImageAsync(uri) : null; } /// diff --git a/MapControl/UWP/ImageLoader.UWP.cs b/MapControl/UWP/ImageLoader.UWP.cs index 848ec312..80255757 100644 --- a/MapControl/UWP/ImageLoader.UWP.cs +++ b/MapControl/UWP/ImageLoader.UWP.cs @@ -31,28 +31,18 @@ namespace MapControl { await stream.WriteAsync(buffer.AsBuffer()); stream.Seek(0); + return await LoadImageAsync(stream); } } - private static async Task LoadImageAsync(IHttpContent content) - { - using (var stream = new InMemoryRandomAccessStream()) - { - await content.WriteToStreamAsync(stream); - stream.Seek(0); - return await LoadImageAsync(stream); - } - } - - private static async Task LoadLocalImageAsync(Uri uri) + public static async Task LoadImageAsync(string path) { ImageSource image = null; - var path = uri.IsAbsoluteUri ? uri.LocalPath : uri.OriginalString; if (File.Exists(path)) { - var file = await StorageFile.GetFileFromPathAsync(path); + var file = await StorageFile.GetFileFromPathAsync(Path.GetFullPath(path)); using (var stream = await file.OpenReadAsync()) { @@ -63,6 +53,17 @@ namespace MapControl return image; } + private static async Task LoadImageAsync(IHttpContent content) + { + using (var stream = new InMemoryRandomAccessStream()) + { + await content.WriteToStreamAsync(stream); + stream.Seek(0); + + return await LoadImageAsync(stream); + } + } + internal class HttpBufferResponse { public readonly IBuffer Buffer; diff --git a/MapControl/UWP/Tile.UWP.cs b/MapControl/UWP/Tile.UWP.cs index 57846566..6614cd05 100644 --- a/MapControl/UWP/Tile.UWP.cs +++ b/MapControl/UWP/Tile.UWP.cs @@ -12,18 +12,18 @@ namespace MapControl { public partial class Tile { - public void SetImage(ImageSource imageSource, bool fadeIn = true) + public void SetImage(ImageSource image, bool fadeIn = true) { Pending = false; if (fadeIn && FadeDuration > TimeSpan.Zero) { - var bitmapImage = imageSource as BitmapImage; + var bitmap = image as BitmapImage; - if (bitmapImage?.UriSource != null) + if (bitmap?.UriSource != null) { - bitmapImage.ImageOpened += BitmapImageOpened; - bitmapImage.ImageFailed += BitmapImageFailed; + bitmap.ImageOpened += BitmapImageOpened; + bitmap.ImageFailed += BitmapImageFailed; } else { @@ -35,25 +35,25 @@ namespace MapControl Image.Opacity = 1d; } - Image.Source = imageSource; + Image.Source = image; } private void BitmapImageOpened(object sender, RoutedEventArgs e) { - var bitmapImage = (BitmapImage)sender; + var bitmap = (BitmapImage)sender; - bitmapImage.ImageOpened -= BitmapImageOpened; - bitmapImage.ImageFailed -= BitmapImageFailed; + bitmap.ImageOpened -= BitmapImageOpened; + bitmap.ImageFailed -= BitmapImageFailed; FadeIn(); } private void BitmapImageFailed(object sender, ExceptionRoutedEventArgs e) { - var bitmapImage = (BitmapImage)sender; + var bitmap = (BitmapImage)sender; - bitmapImage.ImageOpened -= BitmapImageOpened; - bitmapImage.ImageFailed -= BitmapImageFailed; + bitmap.ImageOpened -= BitmapImageOpened; + bitmap.ImageFailed -= BitmapImageFailed; Image.Source = null; } diff --git a/MapControl/UWP/TileImageLoader.UWP.cs b/MapControl/UWP/TileImageLoader.UWP.cs index b53e6694..5f93c09d 100644 --- a/MapControl/UWP/TileImageLoader.UWP.cs +++ b/MapControl/UWP/TileImageLoader.UWP.cs @@ -27,6 +27,7 @@ namespace MapControl /// public static Caching.IImageCache Cache { get; set; } + private async Task LoadCachedTileImageAsync(Tile tile, Uri uri, string cacheKey) { var cacheItem = await Cache.GetAsync(cacheKey).ConfigureAwait(false); @@ -78,7 +79,13 @@ namespace MapControl { try { - tile.SetImage(await loadImageFunc()); + var image = await loadImageFunc(); + + if (image != null) + { + tile.SetImage(image); + } + tcs.SetResult(null); } catch (Exception ex) diff --git a/MapControl/WPF/ImageLoader.WPF.cs b/MapControl/WPF/ImageLoader.WPF.cs index e9253551..d2128560 100644 --- a/MapControl/WPF/ImageLoader.WPF.cs +++ b/MapControl/WPF/ImageLoader.WPF.cs @@ -28,11 +28,6 @@ namespace MapControl return bitmapImage; } - public static Task LoadImageAsync(Stream stream) - { - return Task.Run(() => LoadImage(stream)); - } - public static ImageSource LoadImage(byte[] buffer) { using (var stream = new MemoryStream(buffer)) @@ -41,26 +36,9 @@ namespace MapControl } } - public static Task LoadImageAsync(byte[] buffer) - { - return Task.Run(() => LoadImage(buffer)); - } - - private static async Task LoadImageAsync(HttpContent content) - { - using (var stream = new MemoryStream()) - { - await content.CopyToAsync(stream); - stream.Seek(0, SeekOrigin.Begin); - - return await LoadImageAsync(stream); - } - } - - private static ImageSource LoadLocalImage(Uri uri) + public static ImageSource LoadImage(string path) { ImageSource image = null; - var path = uri.IsAbsoluteUri ? uri.LocalPath : uri.OriginalString; if (File.Exists(path)) { @@ -73,9 +51,30 @@ namespace MapControl return image; } - private static Task LoadLocalImageAsync(Uri uri) + public static Task LoadImageAsync(Stream stream) { - return Task.Run(() => LoadLocalImage(uri)); + return Task.Run(() => LoadImage(stream)); + } + + public static Task LoadImageAsync(byte[] buffer) + { + return Task.Run(() => LoadImage(buffer)); + } + + public static Task LoadImageAsync(string path) + { + return Task.Run(() => LoadImage(path)); + } + + private static async Task LoadImageAsync(HttpContent content) + { + using (var stream = new MemoryStream()) + { + await content.CopyToAsync(stream); + stream.Seek(0, SeekOrigin.Begin); + + return LoadImage(stream); + } } internal class HttpStreamResponse @@ -96,7 +95,7 @@ namespace MapControl try { - using (var responseMessage = await HttpClient.GetAsync(uri)) + using (var responseMessage = await HttpClient.GetAsync(uri).ConfigureAwait(false)) { if (responseMessage.IsSuccessStatusCode) { @@ -106,7 +105,7 @@ namespace MapControl if (ImageAvailable(responseMessage.Headers)) { stream = new MemoryStream(); - await responseMessage.Content.CopyToAsync(stream); + await responseMessage.Content.CopyToAsync(stream).ConfigureAwait(false); stream.Seek(0, SeekOrigin.Begin); maxAge = responseMessage.Headers.CacheControl?.MaxAge; diff --git a/MapControl/WPF/Tile.WPF.cs b/MapControl/WPF/Tile.WPF.cs index dcb42e3a..8945624c 100644 --- a/MapControl/WPF/Tile.WPF.cs +++ b/MapControl/WPF/Tile.WPF.cs @@ -11,18 +11,18 @@ namespace MapControl { public partial class Tile { - public void SetImage(ImageSource imageSource, bool fadeIn = true) + public void SetImage(ImageSource image, bool fadeIn = true) { Pending = false; if (fadeIn && FadeDuration > TimeSpan.Zero) { - var bitmapSource = imageSource as BitmapSource; + var bitmap = image as BitmapSource; - if (bitmapSource != null && !bitmapSource.IsFrozen && bitmapSource.IsDownloading) + if (bitmap != null && !bitmap.IsFrozen && bitmap.IsDownloading) { - bitmapSource.DownloadCompleted += BitmapDownloadCompleted; - bitmapSource.DownloadFailed += BitmapDownloadFailed; + bitmap.DownloadCompleted += BitmapDownloadCompleted; + bitmap.DownloadFailed += BitmapDownloadFailed; } else { @@ -34,25 +34,25 @@ namespace MapControl Image.Opacity = 1d; } - Image.Source = imageSource; + Image.Source = image; } private void BitmapDownloadCompleted(object sender, EventArgs e) { - var bitmapSource = (BitmapSource)sender; + var bitmap = (BitmapSource)sender; - bitmapSource.DownloadCompleted -= BitmapDownloadCompleted; - bitmapSource.DownloadFailed -= BitmapDownloadFailed; + bitmap.DownloadCompleted -= BitmapDownloadCompleted; + bitmap.DownloadFailed -= BitmapDownloadFailed; FadeIn(); } private void BitmapDownloadFailed(object sender, ExceptionEventArgs e) { - var bitmapSource = (BitmapSource)sender; + var bitmap = (BitmapSource)sender; - bitmapSource.DownloadCompleted -= BitmapDownloadCompleted; - bitmapSource.DownloadFailed -= BitmapDownloadFailed; + bitmap.DownloadCompleted -= BitmapDownloadCompleted; + bitmap.DownloadFailed -= BitmapDownloadFailed; Image.Source = null; } diff --git a/MapControl/WPF/TileImageLoader.WPF.cs b/MapControl/WPF/TileImageLoader.WPF.cs index da673138..406f29f5 100644 --- a/MapControl/WPF/TileImageLoader.WPF.cs +++ b/MapControl/WPF/TileImageLoader.WPF.cs @@ -27,8 +27,10 @@ namespace MapControl /// public static ObjectCache Cache { get; set; } = MemoryCache.Default; + private async Task LoadCachedTileImageAsync(Tile tile, Uri uri, string cacheKey) { + ImageSource image = null; DateTime expiration; var cacheBuffer = GetCachedImage(cacheKey, out expiration); @@ -44,7 +46,7 @@ namespace MapControl { using (var stream = response.Stream) { - LoadTileImage(tile, stream); + image = ImageLoader.LoadImage(stream); SetCachedImage(cacheKey, stream, GetExpiration(response.MaxAge)); } } @@ -53,26 +55,28 @@ namespace MapControl if (cacheBuffer != null) // cached image not expired or download failed { - using (var stream = new MemoryStream(cacheBuffer)) - { - LoadTileImage(tile, stream); - } + image = ImageLoader.LoadImage(cacheBuffer); + } + + if (image != null) + { + SetTileImage(tile, image); } } private async Task LoadTileImageAsync(Tile tile, TileSource tileSource) { - SetTileImage(tile, await tileSource.LoadImageAsync(tile.XIndex, tile.Y, tile.ZoomLevel).ConfigureAwait(false)); + var image = await tileSource.LoadImageAsync(tile.XIndex, tile.Y, tile.ZoomLevel).ConfigureAwait(false); + + if (image != null) + { + SetTileImage(tile, image); + } } - private void LoadTileImage(Tile tile, Stream stream) + private void SetTileImage(Tile tile, ImageSource image) { - SetTileImage(tile, ImageLoader.LoadImage(stream)); - } - - private void SetTileImage(Tile tile, ImageSource imageSource) - { - tile.Image.Dispatcher.InvokeAsync(() => tile.SetImage(imageSource)); + tile.Image.Dispatcher.InvokeAsync(() => tile.SetImage(image)); } private static byte[] GetCachedImage(string cacheKey, out DateTime expiration) diff --git a/MapImages/Shared/WorldFileImage.cs b/MapImages/Shared/WorldFileImage.cs index 7a63dd1f..ece16622 100644 --- a/MapImages/Shared/WorldFileImage.cs +++ b/MapImages/Shared/WorldFileImage.cs @@ -2,6 +2,7 @@ // © 2019 Clemens Fischer // Licensed under the Microsoft Public License (Ms-PL) +using MapControl.Projections; using System; using System.Globalization; using System.IO; @@ -19,7 +20,6 @@ using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; #endif -using MapControl.Projections; namespace MapControl.Images { @@ -79,24 +79,11 @@ namespace MapControl.Images public static async Task ReadWorldFileImage(string imagePath, string worldFilePath, string projFilePath = null) { - BitmapSource bitmap; - - using (var stream = File.OpenRead(imagePath)) - { -#if WINDOWS_UWP - bitmap = (BitmapSource)await ImageLoader.LoadImageAsync(stream.AsRandomAccessStream()); -#else - bitmap = (BitmapSource)await ImageLoader.LoadImageAsync(stream); -#endif - } - + var bitmap = (BitmapSource)await ImageLoader.LoadImageAsync(imagePath); var transform = ReadWorldFile(worldFilePath); - MapProjection projection = null; - - if (projFilePath != null && File.Exists(projFilePath)) - { - projection = new GeoApiProjection { WKT = File.ReadAllText(projFilePath) }; - } + var projection = (projFilePath != null && File.Exists(projFilePath)) + ? new GeoApiProjection { WKT = File.ReadAllText(projFilePath) } + : null; return new WorldFileImage(bitmap, transform, projection); } @@ -124,16 +111,18 @@ namespace MapControl.Images throw new ArgumentException("World file \"" + path + "\"not found."); } - var parameters = File.ReadLines(path).Take(6).Select((line, i) => - { - double p; - if (!double.TryParse(line, NumberStyles.Float, CultureInfo.InvariantCulture, out p)) + var parameters = File.ReadLines(path) + .Take(6) + .Select((line, i) => { - throw new ArgumentException("Failed parsing line " + (i + 1) + " in world file \"" + path + "\"."); - } - return p; - }) - .ToList(); + double p; + if (!double.TryParse(line, NumberStyles.Float, CultureInfo.InvariantCulture, out p)) + { + throw new ArgumentException("Failed parsing line " + (i + 1) + " in world file \"" + path + "\"."); + } + return p; + }) + .ToList(); if (parameters.Count != 6) { diff --git a/MapImages/UWP/GroundOverlayPanel.UWP.cs b/MapImages/UWP/GroundOverlayPanel.UWP.cs index 640a5686..17bb4ef1 100644 --- a/MapImages/UWP/GroundOverlayPanel.UWP.cs +++ b/MapImages/UWP/GroundOverlayPanel.UWP.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; @@ -21,28 +20,21 @@ namespace MapControl.Images UseLayoutRounding = false; } - private async Task> ReadGroundOverlaysFromFile(string docFile) + private async Task> ReadGroundOverlaysFromFile(string docFile) { - if (!Path.IsPathRooted(docFile)) + docFile = Path.GetFullPath(docFile); + + var file = await StorageFile.GetFileFromPathAsync(docFile); + var kmlDocument = new XmlDocument(); + + using (var stream = await file.OpenReadAsync()) { - docFile = Path.Combine(Directory.GetCurrentDirectory(), docFile); + kmlDocument.Load(stream.AsStreamForRead()); } + var imageOverlays = ReadGroundOverlays(kmlDocument).ToList(); var docUri = new Uri(docFile); - var imageOverlays = await Task.Run(async () => - { - var file = await StorageFile.GetFileFromPathAsync(docFile); - var kmlDocument = new XmlDocument(); - - using (var stream = await file.OpenReadAsync()) - { - kmlDocument.Load(stream.AsStreamForRead()); - } - - return ReadGroundOverlays(kmlDocument).ToList(); - }); - foreach (var imageOverlay in imageOverlays) { imageOverlay.ImageSource = await ImageLoader.LoadImageAsync(new Uri(docUri, imageOverlay.ImagePath)); @@ -51,7 +43,7 @@ namespace MapControl.Images return imageOverlays; } - private async Task> ReadGroundOverlaysFromArchive(string archiveFile) + private async Task> ReadGroundOverlaysFromArchive(string archiveFile) { using (var archive = ZipFile.OpenRead(archiveFile)) { @@ -63,17 +55,14 @@ namespace MapControl.Images throw new ArgumentException("No KML entry found in " + archiveFile); } - var imageOverlays = await Task.Run(() => + var kmlDocument = new XmlDocument(); + + using (var docStream = docEntry.Open()) { - var kmlDocument = new XmlDocument(); + kmlDocument.Load(docStream); + } - using (var docStream = docEntry.Open()) - { - kmlDocument.Load(docStream); - } - - return ReadGroundOverlays(kmlDocument).ToList(); - }); + var imageOverlays = ReadGroundOverlays(kmlDocument).ToList(); foreach (var imageOverlay in imageOverlays) { diff --git a/MapImages/WPF/GroundOverlayPanel.WPF.cs b/MapImages/WPF/GroundOverlayPanel.WPF.cs index b2a6b3f4..9c150546 100644 --- a/MapImages/WPF/GroundOverlayPanel.WPF.cs +++ b/MapImages/WPF/GroundOverlayPanel.WPF.cs @@ -14,23 +14,16 @@ namespace MapControl.Images { public partial class GroundOverlayPanel { - private async Task> ReadGroundOverlaysFromFile(string docFile) + private async Task> ReadGroundOverlaysFromFile(string docFile) { - if (!Path.IsPathRooted(docFile)) - { - docFile = Path.Combine(Directory.GetCurrentDirectory(), docFile); - } + docFile = Path.GetFullPath(docFile); + var kmlDocument = new XmlDocument(); + kmlDocument.Load(docFile); + + var imageOverlays = ReadGroundOverlays(kmlDocument).ToList(); var docUri = new Uri(docFile); - var imageOverlays = await Task.Run(() => - { - var kmlDocument = new XmlDocument(); - kmlDocument.Load(docUri.ToString()); - - return ReadGroundOverlays(kmlDocument).ToList(); - }); - foreach (var imageOverlay in imageOverlays) { imageOverlay.ImageSource = await ImageLoader.LoadImageAsync(new Uri(docUri, imageOverlay.ImagePath)); @@ -39,48 +32,45 @@ namespace MapControl.Images return imageOverlays; } - private Task> ReadGroundOverlaysFromArchive(string archiveFile) + private async Task> ReadGroundOverlaysFromArchive(string archiveFile) { - return Task.Run(() => + using (var archive = ZipFile.OpenRead(archiveFile)) { - using (var archive = ZipFile.OpenRead(archiveFile)) + var docEntry = archive.GetEntry("doc.kml") + ?? archive.Entries.FirstOrDefault(e => e.Name.EndsWith(".kml")); + + if (docEntry == null) { - var docEntry = archive.GetEntry("doc.kml") - ?? archive.Entries.FirstOrDefault(e => e.Name.EndsWith(".kml")); + throw new ArgumentException("No KML entry found in " + archiveFile); + } - if (docEntry == null) + var kmlDocument = new XmlDocument(); + + using (var docStream = docEntry.Open()) + { + kmlDocument.Load(docStream); + } + + var imageOverlays = ReadGroundOverlays(kmlDocument).ToList(); + + foreach (var imageOverlay in imageOverlays) + { + var imageEntry = archive.GetEntry(imageOverlay.ImagePath); + + if (imageEntry != null) { - throw new ArgumentException("No KML entry found in " + archiveFile); - } - - var kmlDocument = new XmlDocument(); - - using (var docStream = docEntry.Open()) - { - kmlDocument.Load(docStream); - } - - var imageOverlays = ReadGroundOverlays(kmlDocument).ToList(); - - foreach (var imageOverlay in imageOverlays) - { - var imageEntry = archive.GetEntry(imageOverlay.ImagePath); - - if (imageEntry != null) + using (var zipStream = imageEntry.Open()) + using (var memoryStream = new MemoryStream()) { - using (var zipStream = imageEntry.Open()) - using (var memoryStream = new MemoryStream()) - { - zipStream.CopyTo(memoryStream); - memoryStream.Position = 0; - imageOverlay.ImageSource = ImageLoader.LoadImage(memoryStream); - } + await zipStream.CopyToAsync(memoryStream); + memoryStream.Position = 0; + imageOverlay.ImageSource = await ImageLoader.LoadImageAsync(memoryStream); } } - - return imageOverlays; } - }); + + return imageOverlays; + } } } }