private static ImageSource CreateImage(TileSource tileSource, Tile tile) { ImageSource image = null; try { image = BitmapFrame.Create(tileSource.GetUri(tile.XIndex, tile.Y, tile.ZoomLevel)); } catch (Exception ex) { Trace.TraceWarning("Creating tile image failed: {0}", ex.Message); } return(image); }
private void LoadPendingTiles(Dispatcher dispatcher, TileSource tileSource, string sourceName, bool animateOpacity) { var setImageAction = new Action <Tile, ImageSource>((t, i) => t.SetImageSource(i, animateOpacity)); var imageTileSource = tileSource as ImageTileSource; Tile tile; while (pendingTiles.TryDequeue(out tile)) { byte[] buffer = null; ImageSource image = null; if (imageTileSource != null) { image = LoadImage(imageTileSource, tile); } else { var uri = tileSource.GetUri(tile.XIndex, tile.Y, tile.ZoomLevel); if (uri != null) { if (uri.Scheme == "file") // create from FileStream as creating from URI leaves the file open { image = CreateImage(uri.AbsolutePath); } else { buffer = DownloadImage(uri); image = CreateImage(buffer); } } } if (image != null || !tile.HasImageSource) // do not set null if tile already has an image (from cache) { dispatcher.BeginInvoke(setImageAction, DispatcherPriority.Render, tile, image); } if (buffer != null && image != null) { Cache.Set(GetCacheKey(sourceName, tile), buffer, new CacheItemPolicy { SlidingExpiration = CacheExpiration }); } } Interlocked.Decrement(ref threadCount); }
private void GetTiles(List <Tile> tiles, Dispatcher dispatcher, TileSource tileSource, string sourceName, int maxDownloads, bool animateOpacity) { var imageTileSource = tileSource as ImageTileSource; if (imageTileSource != null) { if (!imageTileSource.CanLoadAsync) // call LoadImage in UI thread { var setImageAction = new Action <Tile, ImageTileSource>((t, ts) => t.SetImageSource(LoadImage(ts, t), animateOpacity)); foreach (var tile in tiles) { dispatcher.BeginInvoke(setImageAction, DispatcherPriority.Render, tile, imageTileSource); } return; } } else if (!tileSource.UriFormat.StartsWith("file:")) // load local image files asynchronously, without caching { if (Cache == null || string.IsNullOrWhiteSpace(sourceName)) { // no caching here: use default asynchronous downloading and caching done by WPF var setImageAction = new Action <Tile, TileSource>((t, ts) => t.SetImageSource(CreateImage(ts, t), animateOpacity)); foreach (var tile in tiles) { dispatcher.BeginInvoke(setImageAction, DispatcherPriority.Render, tile, tileSource); } return; } else { var setImageAction = new Action <Tile, ImageSource>((t, i) => t.SetImageSource(i, animateOpacity)); var outdatedTiles = new List <Tile>(tiles.Count); foreach (var tile in tiles) { var key = GetCacheKey(sourceName, tile); var buffer = Cache.Get(key) as byte[]; var image = CreateImage(buffer); if (image != null) { var creationTime = BitConverter.ToInt64(buffer, 0); if (DateTime.FromBinary(creationTime) + CacheUpdateAge < DateTime.UtcNow) { dispatcher.Invoke(setImageAction, DispatcherPriority.Render, tile, image); // synchronously before enqueuing outdatedTiles.Add(tile); // update outdated cache } else { dispatcher.BeginInvoke(setImageAction, DispatcherPriority.Render, tile, image); } } else { pendingTiles.Enqueue(tile); // not yet cached } } tiles = outdatedTiles; // enqueue outdated tiles at last } } foreach (var tile in tiles) { pendingTiles.Enqueue(tile); } while (threadCount < Math.Min(pendingTiles.Count, maxDownloads)) { Interlocked.Increment(ref threadCount); ThreadPool.QueueUserWorkItem(o => LoadPendingTiles(dispatcher, tileSource, sourceName, animateOpacity)); } }