private async Task<WithLoadingResult<WriteableBitmap>> RetrieveImageAsync(string sourcePath, ImageSource source, bool isPlaceholder) { // If the image cache is available and this task has not been cancelled by another // thread and the ImageView that was originally bound to this task is still bound back // to this task and our "exit early" flag is not set then try and fetch the bitmap from // the cache if (IsCancelled || _getNativeControl() == null || ImageService.ExitTasksEarly) return null; var imageWithResult = await GetImageAsync(sourcePath, source, isPlaceholder).ConfigureAwait(false); if (imageWithResult == null || imageWithResult.Item == null) return null; // FMT: even if it was canceled, if we have the bitmap we add it to the cache ImageCache.Instance.Add(GetKey(sourcePath), imageWithResult.Item); return imageWithResult; }
protected virtual async Task<WithLoadingResult<WriteableBitmap>> GetImageAsync(string path, ImageSource source, bool isPlaceholder, Stream originalStream = null) { if (IsCancelled) return null; return await Task.Run(async() => { if (CancellationToken.IsCancellationRequested) return null; Stream stream = null; WithLoadingResult<Stream> streamWithResult = null; if (originalStream != null) { streamWithResult = new WithLoadingResult<Stream>(originalStream, LoadingResult.Stream); } else { streamWithResult = await GetStreamAsync(path, source).ConfigureAwait(false); } if (streamWithResult == null) { return null; } if (streamWithResult.Item == null) { if (streamWithResult.Result == LoadingResult.NotFound) { Logger.Error(string.Format("Not found: {0} from {1}", path, source.ToString())); } return null; } stream = streamWithResult.Item; if (IsCancelled) return null; try { try { if (stream.Position != 0 && !stream.CanSeek) { if (originalStream != null) { // If we cannot seek the original stream then there's not much we can do return null; } else { // Assets stream can't be seeked to origin position stream.Dispose(); streamWithResult = await GetStreamAsync(path, source).ConfigureAwait(false); stream = streamWithResult == null ? null : streamWithResult.Item; if (stream == null) return null; } } else { stream.Seek(0, SeekOrigin.Begin); } if (CancellationToken.IsCancellationRequested) return null; } catch (Exception ex) { Logger.Error("Something wrong happened while asynchronously retrieving image size from file: " + path, ex); return null; } WriteableBitmap writableBitmap = null; // Special case to handle WebP decoding if (path.ToLowerInvariant().EndsWith(".webp")) { //TODO Logger.Error("Webp is not implemented on Windows"); return null; } bool transformPlaceholdersEnabled = Parameters.TransformPlaceholdersEnabled.HasValue ? Parameters.TransformPlaceholdersEnabled.Value : ImageService.Config.TransformPlaceholders; if (Parameters.Transformations != null && Parameters.Transformations.Count > 0 && (!isPlaceholder || (isPlaceholder && transformPlaceholdersEnabled))) { BitmapHolder imageIn = null; try { await _decodingLock.WaitAsync(); imageIn = await stream.ToBitmapHolderAsync(Parameters.DownSampleSize, Parameters.DownSampleUseDipUnits, Parameters.DownSampleInterpolationMode).ConfigureAwait(false); } catch (Exception ex) { Logger.Error("Something wrong happened while asynchronously loading/decoding image: " + path, ex); return null; } finally { _decodingLock.Release(); } foreach (var transformation in Parameters.Transformations.ToList() /* to prevent concurrency issues */) { if (IsCancelled) return null; try { var old = imageIn; try { await _decodingLock.WaitAsync(); IBitmap bitmapHolder = transformation.Transform(imageIn); imageIn = bitmapHolder.ToNative(); } finally { _decodingLock.Release(); } if (old != null && old != imageIn && old.Pixels != imageIn.Pixels) { old.FreePixels(); old = null; } } catch (Exception ex) { Logger.Error("Can't apply transformation " + transformation.Key + " to image " + path, ex); } } writableBitmap = await imageIn.ToBitmapImageAsync(); imageIn.FreePixels(); imageIn = null; } else { try { await _decodingLock.WaitAsync(); writableBitmap = await stream.ToBitmapImageAsync(Parameters.DownSampleSize, Parameters.DownSampleUseDipUnits, Parameters.DownSampleInterpolationMode); } catch (Exception ex) { Logger.Error("Something wrong happened while asynchronously loading/decoding image: " + path, ex); return null; } finally { _decodingLock.Release(); } } return WithLoadingResult.Encapsulate(writableBitmap, streamWithResult.Result); } finally { if (stream != null) stream.Dispose(); } }).ConfigureAwait(false); }
private async Task<bool> LoadPlaceHolderAsync(string placeholderPath, ImageSource source) { if (string.IsNullOrWhiteSpace(placeholderPath)) return false; WriteableBitmap image = ImageCache.Instance.Get(GetKey(placeholderPath)); if (image == null) { try { var imageWithResult = await RetrieveImageAsync(placeholderPath, source, true).ConfigureAwait(false); image = imageWithResult == null ? null : imageWithResult.Item; } catch (Exception ex) { Logger.Error("An error occured while retrieving placeholder's drawable.", ex); return false; } } if (image == null) return false; var view = _getNativeControl(); if (view == null) return false; if (IsCancelled) return false; // Post on main thread but don't wait for it MainThreadDispatcher.Post(() => { if (IsCancelled) return; _doWithImage(image, false); }); return true; }
/// <summary> /// Returns a <see cref="Image"/> from the <see cref="ImageSource"/> provided. /// </summary> /// <param name="source">The <see cref="ImageSource"/> to load the image from.</param> /// <param name="height">The height for the image (divides by 2 for the Windows Phone platform).</param> /// <param name="width">The width for the image (divides by 2 for the Windows Phone platform).</param> /// <returns>A properly sized image.</returns> private async static Task<System.Windows.Controls.Image> GetImageAsync(ImageSource source, int height, int width) { var image = new System.Windows.Controls.Image(); var handler = GetHandler(source); var imageSource = await handler.LoadImageAsync(source); image.Source = imageSource; image.Height = Convert.ToDouble(height / 2); image.Width = Convert.ToDouble(width / 2); return image; }
private async Task<WithLoadingResult<Stream>> GetStreamAsync(string path, ImageSource source) { if (string.IsNullOrWhiteSpace(path)) return null; try { using (var resolver = DataResolverFactory.GetResolver(source, Parameters, DownloadCache)) { return await resolver.GetStream(path, CancellationToken.Token).ConfigureAwait(false); } } catch (OperationCanceledException) { Logger.Debug(string.Format("Image request for {0} got cancelled.", path)); return null; } catch (Exception ex) { Logger.Error("Unable to retrieve image data", ex); return null; } }
protected virtual async Task<WithLoadingResult<WriteableBitmap>> GetImageAsync(string sourcePath, ImageSource source, bool isPlaceholder, Stream originalStream = null) { if (CancellationToken.IsCancellationRequested) return null; byte[] bytes = null; string path = sourcePath; LoadingResult? result = null; try { if (originalStream != null) { using (var ms = new MemoryStream()) { await originalStream.CopyToAsync(ms).ConfigureAwait(false); bytes = ms.ToArray(); path = sourcePath; result = LoadingResult.Stream; } } else { using (var resolver = DataResolverFactory.GetResolver(source, Parameters, DownloadCache)) { var data = await resolver.GetData(path, CancellationToken.Token).ConfigureAwait(false); if (data == null) return null; bytes = data.Data; path = data.ResultIdentifier; result = data.Result; } } } catch (OperationCanceledException) { Logger.Debug(string.Format("Image request for {0} got cancelled.", path)); return null; } catch (Exception ex) { var message = String.Format("Unable to retrieve image data from source: {0}", sourcePath); Logger.Error(message, ex); Parameters.OnError(ex); return null; } if (bytes == null) return null; var image = await Task.Run(async () => { if (CancellationToken.IsCancellationRequested) return null; WriteableBitmap writableBitmap = null; // Special case to handle WebP decoding if (sourcePath.ToLowerInvariant().EndsWith(".webp")) { //TODO throw new NotImplementedException("Webp is not implemented on Windows"); } bool transformPlaceholdersEnabled = Parameters.TransformPlaceholdersEnabled.HasValue ? Parameters.TransformPlaceholdersEnabled.Value : ImageService.Config.TransformPlaceholders; if (Parameters.Transformations != null && Parameters.Transformations.Count > 0 && (!isPlaceholder || (isPlaceholder && transformPlaceholdersEnabled))) { BitmapHolder imageIn = await bytes.ToBitmapHolderAsync(Parameters.DownSampleSize, Parameters.DownSampleUseDipUnits, Parameters.DownSampleInterpolationMode).ConfigureAwait(false); foreach (var transformation in Parameters.Transformations.ToList() /* to prevent concurrency issues */) { if (CancellationToken.IsCancellationRequested) return null; try { var old = imageIn; IBitmap bitmapHolder = transformation.Transform(imageIn); imageIn = bitmapHolder.ToNative(); if (old != null && old != imageIn && old.Pixels != imageIn.Pixels) { old.FreePixels(); old = null; } } catch (Exception ex) { Logger.Error("Can't apply transformation " + transformation.Key + " to image " + path, ex); } } writableBitmap = await imageIn.ToBitmapImageAsync(); imageIn.FreePixels(); imageIn = null; } else { writableBitmap = await bytes.ToBitmapImageAsync(Parameters.DownSampleSize, Parameters.DownSampleUseDipUnits, Parameters.DownSampleInterpolationMode); } bytes = null; return writableBitmap; }).ConfigureAwait(false); return WithLoadingResult.Encapsulate(image, result.Value); }
private void CreatePageWithImage(RadFixedDocument document, string imageExtension, EncodedImageData imageData, double[] decode = null) { RadFixedPage page = document.Pages.AddPage(); page.Size = PageSize; FixedContentEditor editor = new FixedContentEditor(page); editor.Position.Translate(Margins.Left, Margins.Top); Block block = new Block(); block.HorizontalAlignment = Telerik.Windows.Documents.Fixed.Model.Editing.Flow.HorizontalAlignment.Center; block.TextProperties.FontSize = 22; block.InsertText(string.Format("This is {0} image in {1} color space encoded with {2} filter.", imageExtension, imageData.ColorSpace, imageData.Filters.FirstOrDefault() ?? "None")); Size blockSize = block.Measure(RemainingPageSize); editor.DrawBlock(block, RemainingPageSize); editor.Position.Translate(Margins.Left, blockSize.Height + Margins.Top + 50); Block imageBlock = new Block(); imageBlock.HorizontalAlignment = Telerik.Windows.Documents.Fixed.Model.Editing.Flow.HorizontalAlignment.Center; ImageSource imageSource = new ImageSource(imageData); imageSource.DecodeArray = decode; imageBlock.InsertImage(imageSource, new Size(imageData.Width, imageData.Height)); editor.DrawBlock(imageBlock, RemainingPageSize); }
private void AddPageWithImage(string description, ImageSource imageSource) { RadFixedPage page = this.document.Pages.AddPage(); page.Size = PageSize; FixedContentEditor editor = new FixedContentEditor(page); editor.GraphicProperties.FillColor = new RgbColor(200, 200, 200); editor.DrawRectangle(new Rect(0, 0, PageSize.Width, PageSize.Height)); editor.Position.Translate(Margins.Left, Margins.Top); Block block = new Block(); block.HorizontalAlignment = Telerik.Windows.Documents.Fixed.Model.Editing.Flow.HorizontalAlignment.Center; block.TextProperties.FontSize = 22; block.InsertText(description); Size blockSize = block.Measure(RemainingPageSize); editor.DrawBlock(block, RemainingPageSize); editor.Position.Translate(Margins.Left, blockSize.Height + Margins.Top + 20); Block imageBlock = new Block(); imageBlock.HorizontalAlignment = Telerik.Windows.Documents.Fixed.Model.Editing.Flow.HorizontalAlignment.Center; imageBlock.InsertImage(imageSource); editor.DrawBlock(imageBlock, RemainingPageSize); }
private async Task<WithLoadingResult<WriteableBitmap>> RetrieveImageAsync(string sourcePath, ImageSource source, bool isPlaceholder) { if (string.IsNullOrWhiteSpace(sourcePath)) return new WithLoadingResult<WriteableBitmap>(LoadingResult.Failed); // If the image cache is available and this task has not been cancelled by another // thread and the ImageView that was originally bound to this task is still bound back // to this task and our "exit early" flag is not set then try and fetch the bitmap from // the cache if (IsCancelled || ImageService.Instance.ExitTasksEarly) return new WithLoadingResult<WriteableBitmap>(LoadingResult.Canceled); if (!_target.IsTaskValid(this)) return new WithLoadingResult<WriteableBitmap>(LoadingResult.InvalidTarget); var resultWithImage = await GetImageAsync(sourcePath, source, isPlaceholder).ConfigureAwait(false); if (resultWithImage.HasError) return resultWithImage; // FMT: even if it was canceled, if we have the bitmap we add it to the cache ImageCache.Instance.Add(GetKey(sourcePath), resultWithImage.ImageInformation, resultWithImage.Item); return resultWithImage; }
private async Task<bool> LoadPlaceHolderAsync(string placeholderPath, ImageSource source, bool isLoadingPlaceholder) { if (string.IsNullOrWhiteSpace(placeholderPath)) return false; var cacheEntry = ImageCache.Instance.Get(GetKey(placeholderPath)); WriteableBitmap image = cacheEntry == null ? null : cacheEntry.Item1; bool isLocalOrFromCache = true; if (image == null) { try { var imageWithResult = await RetrieveImageAsync(placeholderPath, source, true).ConfigureAwait(false); image = imageWithResult.Item; isLocalOrFromCache = imageWithResult.Result.IsLocalOrCachedResult(); } catch (Exception ex) { Logger.Error("An error occured while retrieving placeholder's drawable.", ex); return false; } } if (image == null) return false; if (!_target.IsValid) return false; if (IsCancelled) return false; // Post on main thread but don't wait for it MainThreadDispatcher.Post(() => _target.Set(this, image, isLocalOrFromCache, isLoadingPlaceholder)); return true; }