private async Task <WithLoadingResult <Stream> > GetStreamAsync(string path, ImageSource source) { if (string.IsNullOrWhiteSpace(path)) { return(new WithLoadingResult <Stream>(LoadingResult.Failed)); } 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(new WithLoadingResult <Stream>(LoadingResult.Canceled)); } catch (Exception ex) { Logger.Error("Unable to retrieve image data", ex); return(new WithLoadingResult <Stream>(LoadingResult.Failed)); } }
protected virtual async Task ShowPlaceholder(string path, string key, ImageSource source, bool isLoadingPlaceholder) { if (!await TryLoadFromMemoryCacheAsync(key, false, false, isLoadingPlaceholder).ConfigureAwait(false)) { var loadResolver = DataResolverFactory.GetResolver(path, source, Parameters, Configuration); var loadImageData = await loadResolver.Resolve(path, Parameters, CancellationTokenSource.Token).ConfigureAwait(false); using (loadImageData.Item1) { ThrowIfCancellationRequested(); var loadImage = await GenerateImageAsync(path, source, loadImageData.Item1, loadImageData.Item3, TransformPlaceholders, true).ConfigureAwait(false); if (loadImage != default(TImageContainer)) { MemoryCache.Add(key, loadImageData.Item3, loadImage); } ThrowIfCancellationRequested(); if (isLoadingPlaceholder) { PlaceholderWeakReference = new WeakReference <TImageContainer>(loadImage); } await SetTargetAsync(loadImage, false).ConfigureAwait(false); } } }
protected virtual async Task ShowPlaceholder(string path, string key, ImageSource source, bool isLoadingPlaceholder) { if (Parameters.Preload) { return; } if (!await TryLoadFromMemoryCacheAsync(key, false, false, isLoadingPlaceholder).ConfigureAwait(false)) { try { var customResolver = isLoadingPlaceholder ? Parameters.CustomLoadingPlaceholderDataResolver : Parameters.CustomErrorPlaceholderDataResolver; var loadResolver = customResolver ?? DataResolverFactory.GetResolver(path, source, Parameters, Configuration); var loadImageData = await loadResolver.Resolve(path, Parameters, CancellationTokenSource.Token).ConfigureAwait(false); using (loadImageData.Item1) { ThrowIfCancellationRequested(); var loadImage = await GenerateImageAsync(path, source, loadImageData.Item1, loadImageData.Item3, TransformPlaceholders, true).ConfigureAwait(false); if (loadImage != default(TImageContainer)) { MemoryCache.Add(key, loadImageData.Item3, loadImage); } ThrowIfCancellationRequested(); if (isLoadingPlaceholder) { PlaceholderWeakReference = new WeakReference <TImageContainer>(loadImage); } await SetTargetAsync(loadImage, false).ConfigureAwait(false); } if (isLoadingPlaceholder) { _isLoadingPlaceholderLoaded = true; } } catch (Exception ex) { Logger.Error("Setting placeholder failed", ex); } } else if (isLoadingPlaceholder) { _isLoadingPlaceholderLoaded = true; } }
public async Task RunAsync() { LoadingResult loadingResult = LoadingResult.Failed; bool success = false; try { if (IsCompleted || IsCancelled || ImageService.ExitTasksEarly) { throw new OperationCanceledException(); } ThrowIfCancellationRequested(); // LOAD IMAGE if (!(await TryLoadFromMemoryCacheAsync().ConfigureAwait(false))) { Logger.Debug(string.Format("Generating/retrieving image: {0}", Key)); var resolver = Parameters.CustomDataResolver ?? DataResolverFactory.GetResolver(Parameters.Path, Parameters.Source, Parameters, Configuration); resolver = new WrappedDataResolver(resolver); var imageData = await resolver.Resolve(Parameters.Path, Parameters, CancellationTokenSource.Token).ConfigureAwait(false); loadingResult = imageData.Item2; using (imageData.Item1) { ImageInformation = imageData.Item3; ImageInformation.SetKey(Key, Parameters.CustomCacheKey); ImageInformation.SetPath(Parameters.Path); ThrowIfCancellationRequested(); // Preload if (Parameters.Preload && Parameters.CacheType.HasValue && Parameters.CacheType.Value == CacheType.Disk) { if (loadingResult == LoadingResult.Internet) { Logger?.Debug(string.Format("DownloadOnly success: {0}", Key)); } success = true; return; } ThrowIfCancellationRequested(); var image = await GenerateImageAsync(Parameters.Path, Parameters.Source, imageData.Item1, imageData.Item3, true, false).ConfigureAwait(false); ThrowIfCancellationRequested(); try { BeforeLoading(image, false); if (image != default(TImageContainer) && CanUseMemoryCache) { MemoryCache.Add(Key, imageData.Item3, image); } ThrowIfCancellationRequested(); bool isFadeAnimationEnabled = Parameters.FadeAnimationEnabled ?? Configuration.FadeAnimationEnabled; await SetTargetAsync(image, isFadeAnimationEnabled).ConfigureAwait(false); } finally { AfterLoading(image, false); } } } success = true; } catch (Exception ex) { if (ex is OperationCanceledException || ex is ObjectDisposedException) { if (Configuration.VerboseLoadingCancelledLogging) { Logger.Debug(string.Format("Image loading cancelled: {0}", Key)); } } else { if (_clearCacheOnOutOfMemory && ex is OutOfMemoryException) { MemoryCache.Clear(); } Logger.Error(string.Format("Image loading failed: {0}", Key), ex); if (Configuration.ExecuteCallbacksOnUIThread && Parameters?.OnError != null) { await MainThreadDispatcher.PostAsync(() => { Parameters?.OnError?.Invoke(ex); }).ConfigureAwait(false); } else { Parameters?.OnError?.Invoke(ex); } try { // Error placeholder if enabled if (!Parameters.Preload && !string.IsNullOrWhiteSpace(Parameters.ErrorPlaceholderPath)) { await ShowPlaceholder(Parameters.ErrorPlaceholderPath, KeyForErrorPlaceholder, Parameters.ErrorPlaceholderSource, false).ConfigureAwait(false); } } catch (Exception ex2) { if (!(ex2 is OperationCanceledException)) { Logger.Error(string.Format("Image loading failed: {0}", Key), ex); } } } } finally { try { if (CancellationTokenSource?.IsCancellationRequested == false) { CancellationTokenSource.Cancel(); } } catch (Exception) { } IsCompleted = true; using (Parameters) { if (Configuration.ExecuteCallbacksOnUIThread && Parameters?.OnFinish != null) { await MainThreadDispatcher.PostAsync(() => { if (success) { Parameters?.OnSuccess?.Invoke(ImageInformation, loadingResult); } Parameters?.OnFinish?.Invoke(this); }).ConfigureAwait(false); } else { if (success) { Parameters?.OnSuccess?.Invoke(ImageInformation, loadingResult); } Parameters?.OnFinish?.Invoke(this); } ImageService.RemovePendingTask(this); } } }
protected virtual async Task ShowPlaceholder(string path, string key, ImageSource source, bool isLoadingPlaceholder) { if (Parameters.Preload) { return; } if (!await TryLoadFromMemoryCacheAsync(key, false, false, isLoadingPlaceholder).ConfigureAwait(false)) { try { var customResolver = isLoadingPlaceholder ? Parameters.CustomLoadingPlaceholderDataResolver : Parameters.CustomErrorPlaceholderDataResolver; var loadResolver = customResolver ?? DataResolverFactory.GetResolver(path, source, Parameters, Configuration); loadResolver = new WrappedDataResolver(loadResolver); Tuple <Stream, LoadingResult, ImageInformation> loadImageData; bool hasMutex = false; TImageContainer loadImage; try { hasMutex = await _placeholdersResolveLock.WaitAsync(TimeSpan.FromSeconds(3), CancellationTokenSource.Token).ConfigureAwait(false); ThrowIfCancellationRequested(); if (await TryLoadFromMemoryCacheAsync(key, false, false, isLoadingPlaceholder).ConfigureAwait(false)) { if (isLoadingPlaceholder) { _isLoadingPlaceholderLoaded = true; } return; } ThrowIfCancellationRequested(); loadImageData = await loadResolver.Resolve(path, Parameters, CancellationTokenSource.Token).ConfigureAwait(false); ThrowIfCancellationRequested(); using (loadImageData.Item1) { loadImage = await GenerateImageAsync(path, source, loadImageData.Item1, loadImageData.Item3, TransformPlaceholders, true).ConfigureAwait(false); if (loadImage != default(TImageContainer)) { MemoryCache.Add(key, loadImageData.Item3, loadImage); } } } finally { if (hasMutex) { _placeholdersResolveLock.Release(); } } ThrowIfCancellationRequested(); if (isLoadingPlaceholder) { PlaceholderWeakReference = new WeakReference <TImageContainer>(loadImage); } await SetTargetAsync(loadImage, false).ConfigureAwait(false); if (isLoadingPlaceholder) { _isLoadingPlaceholderLoaded = true; } } catch (Exception ex) { Logger.Error("Setting placeholder failed", ex); } } else if (isLoadingPlaceholder) { _isLoadingPlaceholderLoaded = true; } }
async Task <ISelfDisposingBitmapDrawable> PlatformGenerateImageAsync(string path, ImageSource source, Stream imageData, ImageInformation imageInformation, bool enableTransformations, bool isPlaceholder) { Bitmap bitmap = null; if (imageData == null) { throw new ArgumentNullException(nameof(imageData)); } ThrowIfCancellationRequested(); // First decode with inJustDecodeBounds=true to check dimensions var options = new BitmapFactory.Options { InJustDecodeBounds = true }; try { await BitmapFactory.DecodeStreamAsync(imageData, null, options).ConfigureAwait(false); ThrowIfCancellationRequested(); options.InPurgeable = true; options.InJustDecodeBounds = false; options.InDither = true; imageInformation.SetOriginalSize(options.OutWidth, options.OutHeight); imageInformation.SetCurrentSize(options.OutWidth, options.OutHeight); if (!Configuration.BitmapOptimizations || (Parameters.BitmapOptimizationsEnabled.HasValue && !Parameters.BitmapOptimizationsEnabled.Value)) { // Same quality but no transparency channel. This allows to save 50% of memory: 1 pixel=2bytes instead of 4. options.InPreferredConfig = Bitmap.Config.Rgb565; options.InPreferQualityOverSpeed = false; } // CHECK IF BITMAP IS EXIF ROTATED int exifRotation = 0; if (source == ImageSource.Filepath) { exifRotation = path.GetExifRotationDegrees(); } ThrowIfCancellationRequested(); // DOWNSAMPLE if (Parameters.DownSampleSize != null && (Parameters.DownSampleSize.Item1 > 0 || Parameters.DownSampleSize.Item2 > 0)) { // Calculate inSampleSize int downsampleWidth = Parameters.DownSampleSize.Item1; int downsampleHeight = Parameters.DownSampleSize.Item2; // if image is rotated, swap width/height if (exifRotation == 90 || exifRotation == 270) { downsampleWidth = Parameters.DownSampleSize.Item2; downsampleHeight = Parameters.DownSampleSize.Item1; } if (Parameters.DownSampleUseDipUnits) { downsampleWidth = downsampleWidth.DpToPixels(); downsampleHeight = downsampleHeight.DpToPixels(); } options.InSampleSize = CalculateInSampleSize(options, downsampleWidth, downsampleHeight); if (options.InSampleSize > 1) { imageInformation.SetCurrentSize( (int)((double)options.OutWidth / options.InSampleSize), (int)((double)options.OutHeight / options.InSampleSize)); } // If we're running on Honeycomb or newer, try to use inBitmap if (Utils.HasHoneycomb()) { AddInBitmapOptions(options); } } ThrowIfCancellationRequested(); if (!imageData.CanSeek || imageData.Position != 0) { if (imageData.CanSeek) { imageData.Position = 0; } else { var resolver = DataResolverFactory.GetResolver(path, source, Parameters, Configuration); var resolved = await resolver.Resolve(path, Parameters, CancellationTokenSource.Token).ConfigureAwait(false); imageData?.Dispose(); imageData = resolved.Item1; } } ThrowIfCancellationRequested(); bitmap = await BitmapFactory.DecodeStreamAsync(imageData, null, options).ConfigureAwait(false); } finally { imageData?.Dispose(); } ThrowIfCancellationRequested(); if (enableTransformations && Parameters.Transformations != null && Parameters.Transformations.Count > 0) { var transformations = Parameters.Transformations.ToList(); await _decodingLock.WaitAsync().ConfigureAwait(false); // Applying transformations is both CPU and memory intensive try { foreach (var transformation in transformations) { ThrowIfCancellationRequested(); var old = bitmap; try { var bitmapHolder = transformation.Transform(new BitmapHolder(bitmap)); bitmap = bitmapHolder.ToNative(); } catch (Exception ex) { Logger.Error(string.Format("Transformation failed: {0}", transformation.Key), ex); throw; } finally { // Transformation succeeded, so garbage the source if (old != null && old.Handle != IntPtr.Zero && !old.IsRecycled && old != bitmap && old.Handle != bitmap.Handle) { old?.Recycle(); old?.Dispose(); } } } } finally { _decodingLock.Release(); } } if (isPlaceholder) { return(new SelfDisposingBitmapDrawable(Context.Resources, bitmap)); } //var imageDrawable = new SelfDisposingBitmapDrawable(Context.Resources, bitmap); //ISelfDisposingBitmapDrawable placeholderDrawable = null; //if (_loadingPlaceholderWeakReference != null && _loadingPlaceholderWeakReference.TryGetTarget(out placeholderDrawable) && placeholderDrawable != null) //{ // return new SelfDisposingTransitionDrawable(imageDrawable, placeholderDrawable as SelfDisposingBitmapDrawable); //} //return imageDrawable; return(new FFBitmapDrawable(Context.Resources, bitmap)); }
protected virtual async Task <WithLoadingResult <UIImage> > GetImageAsync(string sourcePath, ImageSource source, bool isPlaceholder, Stream originalStream = null) { if (IsCancelled) { return(new WithLoadingResult <UIImage>(LoadingResult.Canceled)); } LoadingResult?result = null; UIImage image = null; byte[] bytes = null; string path = sourcePath; ImageInformation imageInformation = null; try { if (originalStream != null) { try { // check is stream is memorystream var ms = originalStream as MemoryStream; if (ms != null) { bytes = ms.ToArray(); } else if (originalStream.CanSeek) { bytes = new byte[originalStream.Length]; await originalStream.ReadAsync(bytes, 0, (int)originalStream.Length, CancellationToken.Token).ConfigureAwait(false); } else { using (var ms2 = new MemoryStream()) { await originalStream.CopyToAsync(ms2).ConfigureAwait(false); bytes = ms2.ToArray(); } } path = sourcePath; result = LoadingResult.Stream; } finally { originalStream.Dispose(); } } else { using (var resolver = DataResolverFactory.GetResolver(source, Parameters, DownloadCache, MainThreadDispatcher)) { var data = await resolver.GetData(path, CancellationToken.Token).ConfigureAwait(false); if (data == null) { return(new WithLoadingResult <UIImage>(LoadingResult.Failed)); } image = data.Image; bytes = data.Data; path = data.ResultIdentifier; result = data.Result; imageInformation = data.ImageInformation; } } } catch (OperationCanceledException) { Logger.Debug(string.Format("Image request for {0} got cancelled.", path)); return(new WithLoadingResult <UIImage>(LoadingResult.Canceled)); } catch (Exception ex) { var message = String.Format("Unable to retrieve image data from source: {0}", sourcePath); Logger.Error(message, ex); Parameters.OnError(ex); return(new WithLoadingResult <UIImage>(LoadingResult.Failed)); } if (bytes == null && image == null) { if (result != null && (int)result < 0) // it's below zero if it's an error { return(new WithLoadingResult <UIImage>(result.Value)); } else { return(new WithLoadingResult <UIImage>(LoadingResult.Failed)); } } if (IsCancelled) { return(new WithLoadingResult <UIImage>(LoadingResult.Canceled)); } UIImage imageIn = image; NSData nsdata = null; if (imageIn == null) { // Special case to handle WebP decoding on iOS if (sourcePath.ToLowerInvariant().EndsWith(".webp", StringComparison.InvariantCulture)) { imageIn = new WebP.Touch.WebPCodec().Decode(bytes); } else { // nfloat scale = _imageScale >= 1 ? _imageScale : ScaleHelper.Scale; nsdata = NSData.FromArray(bytes); if (nsdata == null) { return(new WithLoadingResult <UIImage>(LoadingResult.Failed)); } } } bytes = null; // Setting image informations if (imageInformation == null) { imageInformation = new ImageInformation(); } imageInformation.SetCacheKey(path == "Stream" ? GetKey() : GetKey(sourcePath)); // We rely on ImageIO for all datasources except AssetCatalog, this way we don't generate temporary UIImage // furthermore we can do all the work in a thread safe way and in threadpool if (nsdata != null) { int downsampleWidth = Parameters.DownSampleSize?.Item1 ?? 0; int downsampleHeight = Parameters.DownSampleSize?.Item2 ?? 0; if (Parameters.DownSampleUseDipUnits) { downsampleWidth = downsampleWidth.PointsToPixels(); downsampleHeight = downsampleHeight.PointsToPixels(); } imageIn = nsdata.ToImage(new CoreGraphics.CGSize(downsampleWidth, downsampleHeight), _imageScale, NSDataExtensions.RCTResizeMode.ScaleAspectFill, imageInformation); } else if (Parameters.DownSampleSize != null && imageIn != null) { // if we already have the UIImage in memory it doesn't really matter to resize it // furthermore this will only happen for AssetCatalog images (yet) } bool transformPlaceholdersEnabled = Parameters.TransformPlaceholdersEnabled.HasValue ? Parameters.TransformPlaceholdersEnabled.Value : ImageService.Instance.Config.TransformPlaceholders; if (Parameters.Transformations != null && Parameters.Transformations.Count > 0 && (!isPlaceholder || (isPlaceholder && transformPlaceholdersEnabled))) { foreach (var transformation in Parameters.Transformations.ToList() /* to prevent concurrency issues */) { if (IsCancelled) { return(new WithLoadingResult <UIImage>(LoadingResult.Canceled)); } try { var old = imageIn; var bitmapHolder = transformation.Transform(new BitmapHolder(imageIn)); imageIn = bitmapHolder.ToNative(); // Transformation succeeded, so garbage the source if (old != null && old != imageIn && old.Handle != imageIn.Handle) { old.Dispose(); } } catch (Exception ex) { Logger.Error("Can't apply transformation " + transformation.Key + " to image " + path, ex); } } } return(WithLoadingResult.Encapsulate(imageIn, result.Value, imageInformation)); }
protected virtual async Task ShowPlaceholder(string path, string key, ImageSource source, bool isLoadingPlaceholder) { if (Parameters.Preload) { return; } if (!await TryLoadFromMemoryCacheAsync(key, false, false, isLoadingPlaceholder).ConfigureAwait(false)) { try { var customResolver = isLoadingPlaceholder ? Parameters.CustomLoadingPlaceholderDataResolver : Parameters.CustomErrorPlaceholderDataResolver; var loadResolver = customResolver ?? DataResolverFactory.GetResolver(path, source, Parameters, Configuration); loadResolver = new WrappedDataResolver(loadResolver); DataResolverResult loadImageData; TImageContainer loadImage; if (!await _placeholdersResolveLock.WaitAsync(TimeSpan.FromSeconds(10), CancellationTokenSource.Token).ConfigureAwait(false)) { return; } try { ThrowIfCancellationRequested(); if (await TryLoadFromMemoryCacheAsync(key, false, false, isLoadingPlaceholder).ConfigureAwait(false)) { if (isLoadingPlaceholder) { _isLoadingPlaceholderLoaded = true; Parameters.OnLoadingPlaceholderSet?.Invoke(); } return; } ThrowIfCancellationRequested(); loadImageData = await loadResolver.Resolve(path, Parameters, CancellationTokenSource.Token).ConfigureAwait(false); ThrowIfCancellationRequested(); if (loadImageData.Stream != null) { using (loadImageData.Stream) { loadImage = await GenerateImageAsync(path, source, loadImageData.Stream, loadImageData.ImageInformation, TransformPlaceholders, true).ConfigureAwait(false); } } else { loadImage = loadImageData.ImageContainer as TImageContainer; } if (loadImage != default(TImageContainer)) { MemoryCache.Add(key, loadImageData.ImageInformation, loadImage); } } finally { _placeholdersResolveLock.Release(); } ThrowIfCancellationRequested(); if (isLoadingPlaceholder) { PlaceholderWeakReference = new WeakReference <TImageContainer>(loadImage); } if (Target != null) { await SetTargetAsync(loadImage, false).ConfigureAwait(false); } if (isLoadingPlaceholder) { _isLoadingPlaceholderLoaded = true; Parameters.OnLoadingPlaceholderSet?.Invoke(); } } catch (Exception ex) { if (ex is OperationCanceledException) { throw; } Logger.Error("Setting placeholder failed", ex); } } else if (isLoadingPlaceholder) { _isLoadingPlaceholderLoaded = true; Parameters.OnLoadingPlaceholderSet?.Invoke(); } }
protected virtual async Task <WithLoadingResult <UIImage> > GetImageAsync(string sourcePath, ImageSource source, bool isPlaceholder, Stream originalStream = null) { if (CancellationToken.IsCancellationRequested) { return(null); } UIImage image = null; byte[] bytes = null; string path = sourcePath; LoadingResult?result = null; try { if (originalStream != null) { try { using (var ms = new MemoryStream()) { await originalStream.CopyToAsync(ms).ConfigureAwait(false); bytes = ms.ToArray(); path = sourcePath; result = LoadingResult.Stream; } } finally { originalStream.Dispose(); } } else { using (var resolver = DataResolverFactory.GetResolver(source, Parameters, DownloadCache, MainThreadDispatcher)) { var data = await resolver.GetData(path, CancellationToken.Token).ConfigureAwait(false); if (data == null) { return(null); } image = data.Image; bytes = data.Data; path = data.ResultIdentifier; result = data.Result; } } } catch (System.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 && image == null) { return(null); } var imageToDisplay = await Task.Run(() => { if (CancellationToken.IsCancellationRequested) { return(null); } UIImage imageIn = image; if (imageIn == null) { // Special case to handle WebP decoding on iOS if (sourcePath.ToLowerInvariant().EndsWith(".webp", StringComparison.InvariantCulture)) { imageIn = new WebP.Touch.WebPCodec().Decode(bytes); } else { nfloat scale = _imageScale >= 1 ? _imageScale : _screenScale; imageIn = new UIImage(NSData.FromArray(bytes), scale); } } if (Parameters.DownSampleSize != null && ((Parameters.DownSampleSize.Item1 > 0 && imageIn.Size.Width > Parameters.DownSampleSize.Item1) || (Parameters.DownSampleSize.Item2 > 0 && imageIn.Size.Height > Parameters.DownSampleSize.Item2))) { var tempImage = imageIn; imageIn = tempImage.ResizeUIImage(Parameters.DownSampleSize.Item1, Parameters.DownSampleSize.Item2, Parameters.DownSampleInterpolationMode); tempImage.Dispose(); } bool transformPlaceholdersEnabled = Parameters.TransformPlaceholdersEnabled.HasValue ? Parameters.TransformPlaceholdersEnabled.Value : ImageService.Config.TransformPlaceholders; if (Parameters.Transformations != null && Parameters.Transformations.Count > 0 && (!isPlaceholder || (isPlaceholder && transformPlaceholdersEnabled))) { foreach (var transformation in Parameters.Transformations.ToList() /* to prevent concurrency issues */) { if (CancellationToken.IsCancellationRequested) { return(null); } try { var old = imageIn; var bitmapHolder = transformation.Transform(new BitmapHolder(imageIn)); imageIn = bitmapHolder.ToNative(); // Transformation succeeded, so garbage the source if (old != null) { old.Dispose(); } } catch (Exception ex) { Logger.Error("Can't apply transformation " + transformation.Key + " to image " + path, ex); } } } return(imageIn); }).ConfigureAwait(false); return(WithLoadingResult.Encapsulate(imageToDisplay, result.Value)); }
public async Task RunAsync() { try { if (IsCompleted || IsCancelled || ImageService.ExitTasksEarly) { throw new OperationCanceledException(); } ThrowIfCancellationRequested(); LoadingResult loadingResult = LoadingResult.Failed; // LOAD IMAGE if (!(await TryLoadFromMemoryCacheAsync().ConfigureAwait(false))) { Logger.Debug(string.Format("Generating/retrieving image: {0}", Key)); var resolver = DataResolverFactory.GetResolver(Parameters.Path, Parameters.Source, Parameters, Configuration); var imageData = await resolver.Resolve(Parameters.Path, Parameters, CancellationTokenSource.Token).ConfigureAwait(false); loadingResult = imageData.Item2; using (imageData.Item1) { ImageInformation = imageData.Item3; ThrowIfCancellationRequested(); // Preload if (Parameters.Preload && Parameters.CacheType.HasValue && Parameters.CacheType.Value == CacheType.Disk) { if (Parameters.Source != ImageSource.Url) { throw new InvalidOperationException("DownloadOnly: Only Url ImageSource is supported."); } if (loadingResult == LoadingResult.Internet) { Logger?.Debug(string.Format("DownloadOnly success: {0}", Key)); } Parameters?.OnSuccess?.Invoke(ImageInformation, loadingResult); return; } ThrowIfCancellationRequested(); var image = await GenerateImageAsync(Parameters.Path, Parameters.Source, imageData.Item1, imageData.Item3, TransformPlaceholders, false).ConfigureAwait(false); try { BeforeLoading(image, false); if (image != default(TImageContainer) && CanUseMemoryCache) { MemoryCache.Add(Key, imageData.Item3, image); } ThrowIfCancellationRequested(); bool isFadeAnimationEnabled = Parameters.FadeAnimationEnabled ?? Configuration.FadeAnimationEnabled; await SetTargetAsync(image, isFadeAnimationEnabled).ConfigureAwait(false); } finally { AfterLoading(image, false); } } } Parameters?.OnSuccess?.Invoke(ImageInformation, loadingResult); } catch (Exception ex) { if (_clearCacheOnOutOfMemory && ex is OutOfMemoryException) { MemoryCache.Clear(); } if (ex is OperationCanceledException) { if (Configuration.VerboseLoadingCancelledLogging) { Logger.Debug(string.Format("Image loading cancelled: {0}", Key)); } } else { Logger.Error(string.Format("Image loading failed: {0}", Key), ex); Parameters?.OnError?.Invoke(ex); try { // Error placeholder if enabled if (!Parameters.Preload && !string.IsNullOrWhiteSpace(Parameters.ErrorPlaceholderPath)) { await ShowPlaceholder(Parameters.ErrorPlaceholderPath, KeyForErrorPlaceholder, Parameters.ErrorPlaceholderSource, false).ConfigureAwait(false); } } catch (Exception ex2) { if (!(ex2 is OperationCanceledException)) { Logger.Error(string.Format("Image loading failed: {0}", Key), ex); } } } } finally { using (Parameters) { Parameters?.OnFinish?.Invoke(this); ImageService.RemovePendingTask(this); } IsCompleted = true; } }
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.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(); // old = null; // PLEASE NOTE! In Windows we could reuse int array (less memory usage) so we don't need that } catch (Exception ex) { Logger.Error("Can't apply transformation " + transformation.Key + " to image " + path, ex); } } await MainThreadDispatcher.PostAsync(async() => { writableBitmap = await imageIn.ToBitmapImageAsync(); }).ConfigureAwait(false); } else { writableBitmap = await bytes.ToBitmapImageAsync(Parameters.DownSampleSize, Parameters.DownSampleInterpolationMode).ConfigureAwait(false); } return(writableBitmap); }).ConfigureAwait(false); return(WithLoadingResult.Encapsulate(image, result.Value)); }