From 4a7e384152b514321f39426846a00b261c7ec9d5 Mon Sep 17 00:00:00 2001 From: ClemensF Date: Sat, 13 Jul 2019 08:49:49 +0200 Subject: [PATCH] Version 4.12.2 Improved ImageLoader/TileImageLoader --- MapControl/Shared/ImageLoader.cs | 73 ++++++++++++--------------- MapControl/Shared/TileImageLoader.cs | 6 ++- MapControl/UWP/TileImageLoader.UWP.cs | 16 +++--- MapControl/WPF/TileImageLoader.WPF.cs | 16 +++--- 4 files changed, 54 insertions(+), 57 deletions(-) diff --git a/MapControl/Shared/ImageLoader.cs b/MapControl/Shared/ImageLoader.cs index 7aadf7bd..c2085cbb 100644 --- a/MapControl/Shared/ImageLoader.cs +++ b/MapControl/Shared/ImageLoader.cs @@ -8,7 +8,6 @@ using System.Diagnostics; using System.Linq; using System.IO; using System.Net.Http; -using System.Net.Http.Headers; using System.Threading.Tasks; #if WINDOWS_UWP using Windows.UI.Xaml.Media; @@ -23,10 +22,11 @@ namespace MapControl public static partial class ImageLoader { /// - /// The HttpClient instance used when image data is downloaded from a web resource. + /// The System.Net.Http.HttpClient instance used when image data is downloaded via a http or https Uri. /// public static HttpClient HttpClient { get; set; } = new HttpClient(); + public static async Task LoadImageAsync(Uri uri) { ImageSource image = null; @@ -39,24 +39,13 @@ namespace MapControl } else if (uri.Scheme == "http" || uri.Scheme == "https") { - using (var response = await HttpClient.GetAsync(uri)) - { - if (response.IsSuccessStatusCode) - { - if (ImageAvailable(response.Headers)) - { - using (var stream = new MemoryStream()) - { - await response.Content.CopyToAsync(stream); - stream.Seek(0, SeekOrigin.Begin); + var response = await GetHttpResponseAsync(uri); - image = await LoadImageAsync(stream); - } - } - } - else + if (response?.Stream != null) + { + using (var stream = response.Stream) { - Debug.WriteLine("ImageLoader: {0}: {1} {2}", uri, (int)response.StatusCode, response.ReasonPhrase); + image = await LoadImageAsync(stream); } } } @@ -73,34 +62,21 @@ namespace MapControl return image; } - internal class ImageStream : MemoryStream + internal static async Task GetHttpResponseAsync(Uri uri, bool continueOnCapturedContext = true) { - public TimeSpan? MaxAge { get; set; } - } - - internal static async Task LoadImageStreamAsync(Uri uri) - { - ImageStream stream = null; + HttpResponse response = null; try { - using (var response = await HttpClient.GetAsync(uri).ConfigureAwait(false)) + using (var responseMessage = await HttpClient.GetAsync(uri).ConfigureAwait(continueOnCapturedContext)) { - if (response.IsSuccessStatusCode) + if (responseMessage.IsSuccessStatusCode) { - stream = new ImageStream(); - - if (ImageAvailable(response.Headers)) - { - await response.Content.CopyToAsync(stream).ConfigureAwait(false); - stream.Seek(0, SeekOrigin.Begin); - - stream.MaxAge = response.Headers.CacheControl?.MaxAge; - } + response = await HttpResponse.Create(responseMessage, continueOnCapturedContext); } else { - Debug.WriteLine("ImageLoader: {0}: {1} {2}", uri, (int)response.StatusCode, response.ReasonPhrase); + Debug.WriteLine("ImageLoader: {0}: {1} {2}", uri, (int)responseMessage.StatusCode, responseMessage.ReasonPhrase); } } } @@ -109,14 +85,29 @@ namespace MapControl Debug.WriteLine("ImageLoader: {0}: {1}", uri, ex.Message); } - return stream; + return response; } - private static bool ImageAvailable(HttpResponseHeaders responseHeaders) + internal class HttpResponse { - IEnumerable tileInfo; + public MemoryStream Stream { get; private set; } + public TimeSpan? MaxAge { get; private set; } - return !responseHeaders.TryGetValues("X-VE-Tile-Info", out tileInfo) || !tileInfo.Contains("no-tile"); + internal static async Task Create(HttpResponseMessage message, bool continueOnCapturedContext) + { + var response = new HttpResponse(); + IEnumerable tileInfo; + + if (!message.Headers.TryGetValues("X-VE-Tile-Info", out tileInfo) || !tileInfo.Contains("no-tile")) + { + response.Stream = new MemoryStream(); + await message.Content.CopyToAsync(response.Stream).ConfigureAwait(continueOnCapturedContext); + response.Stream.Seek(0, SeekOrigin.Begin); + response.MaxAge = message.Headers.CacheControl?.MaxAge; + } + + return response; + } } } } \ No newline at end of file diff --git a/MapControl/Shared/TileImageLoader.cs b/MapControl/Shared/TileImageLoader.cs index e3275c04..b9ca462c 100644 --- a/MapControl/Shared/TileImageLoader.cs +++ b/MapControl/Shared/TileImageLoader.cs @@ -107,6 +107,8 @@ namespace MapControl try { + Debug.WriteLine("TileImageLoader: loading {0}/{1}/{2} in thread {3}", tile.ZoomLevel, tile.XIndex, tile.Y, Environment.CurrentManagedThreadId); + await loadTileImage(tile).ConfigureAwait(false); } catch (Exception ex) @@ -125,7 +127,7 @@ namespace MapControl tileSource.UriFormat.StartsWith("http") && !string.IsNullOrEmpty(sourceName)) { - loadTileImage = tile => LoadTileImageAsync(tile, tileSource, sourceName); + loadTileImage = tile => LoadCachedTileImageAsync(tile, tileSource, sourceName); } else { @@ -133,7 +135,7 @@ namespace MapControl } } - private static async Task LoadTileImageAsync(Tile tile, TileSource tileSource, string sourceName) + private static async Task LoadCachedTileImageAsync(Tile tile, TileSource tileSource, string sourceName) { var uri = tileSource.GetUri(tile.XIndex, tile.Y, tile.ZoomLevel); diff --git a/MapControl/UWP/TileImageLoader.UWP.cs b/MapControl/UWP/TileImageLoader.UWP.cs index 12fb60d7..1c8c3cdf 100644 --- a/MapControl/UWP/TileImageLoader.UWP.cs +++ b/MapControl/UWP/TileImageLoader.UWP.cs @@ -36,17 +36,19 @@ namespace MapControl if (cacheBuffer == null || cacheItem.Expiration < DateTime.UtcNow) { - using (var stream = await ImageLoader.LoadImageStreamAsync(uri).ConfigureAwait(false)) - { - if (stream != null) // download succeeded - { - cacheBuffer = null; // discard cached image + var response = await ImageLoader.GetHttpResponseAsync(uri, false).ConfigureAwait(false); - if (stream.Length > 0) // tile image available + if (response != null) // download succeeded + { + cacheBuffer = null; // discard cached image + + if (response.Stream != null) // tile image available + { + using (var stream = response.Stream) { await SetTileImageAsync(tile, () => ImageLoader.LoadImageAsync(stream)).ConfigureAwait(false); - await Cache.SetAsync(cacheKey, stream.ToArray().AsBuffer(), GetExpiration(stream.MaxAge)).ConfigureAwait(false); + await Cache.SetAsync(cacheKey, stream.ToArray().AsBuffer(), GetExpiration(response.MaxAge)).ConfigureAwait(false); } } } diff --git a/MapControl/WPF/TileImageLoader.WPF.cs b/MapControl/WPF/TileImageLoader.WPF.cs index efb19097..9ff273d1 100644 --- a/MapControl/WPF/TileImageLoader.WPF.cs +++ b/MapControl/WPF/TileImageLoader.WPF.cs @@ -38,17 +38,19 @@ namespace MapControl if (cacheBuffer == null || expiration < DateTime.UtcNow) { - using (var stream = await ImageLoader.LoadImageStreamAsync(uri).ConfigureAwait(false)) - { - if (stream != null) // download succeeded - { - cacheBuffer = null; // discard cached image + var response = await ImageLoader.GetHttpResponseAsync(uri, false).ConfigureAwait(false); - if (stream.Length > 0) // tile image available + if (response != null) // download succeeded + { + cacheBuffer = null; // discard cached image + + if (response.Stream != null) // tile image available + { + using (var stream = response.Stream) { image = ImageLoader.LoadImage(stream); - SetCachedImage(cacheKey, stream, GetExpiration(stream.MaxAge)); + SetCachedImage(cacheKey, stream, GetExpiration(response.MaxAge)); } } }