/// <summary> /// Loads the image from given stream asynchronously. /// </summary> /// <returns>An awaitable task.</returns> /// <param name="stream">The stream to get data from.</param> public override async Task <GenerateResult> LoadFromStreamAsync(Stream stream) { if (stream == null) { return(GenerateResult.Failed); } if (IsCancelled) { return(GenerateResult.Canceled); } var imageView = GetAttachedImageView(); if (imageView == null || imageView.Handle == IntPtr.Zero) { return(GenerateResult.InvalidTarget); } var resultWithDrawable = await GetDrawableAsync("Stream", ImageSource.Stream, false, false, stream).ConfigureAwait(false); if (resultWithDrawable.HasError) { // Show error placeholder await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource, imageView, false).ConfigureAwait(false); return(resultWithDrawable.GenerateResult); } if (CanUseMemoryCache()) { ImageCache.Instance.Add(GetKey(), resultWithDrawable.ImageInformation, resultWithDrawable.Item); } try { if (IsCancelled) { return(GenerateResult.Canceled); } // Post on main thread await MainThreadDispatcher.PostAsync(() => { SetImageDrawable(imageView, resultWithDrawable.Item); Completed = true; Parameters?.OnSuccess(resultWithDrawable.ImageInformation, resultWithDrawable.Result); }).ConfigureAwait(false); if (!Completed) { return(GenerateResult.Failed); } } catch (Exception ex2) { // Show error placeholder await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource, imageView, false).ConfigureAwait(false); throw ex2; } return(GenerateResult.Success); }
/// <summary> /// Tries to load requested image from the cache asynchronously. /// </summary> /// <returns>A boolean indicating if image was loaded from cache.</returns> public override async Task <CacheResult> TryLoadingFromCacheAsync() { try { if (!_target.IsValid) { return(CacheResult.NotFound); // weird situation, dunno what to do } if (IsCancelled) { return(CacheResult.NotFound); // not sure what to return in that case } var key = GetKey(); if (string.IsNullOrWhiteSpace(key)) { return(CacheResult.NotFound); } var cacheEntry = ImageCache.Instance.Get(key); if (cacheEntry == null) { return(CacheResult.NotFound); // not available in the cache } var value = cacheEntry.Item1; if (value == null) { return(CacheResult.NotFound); // not available in the cache } if (IsCancelled) { return(CacheResult.NotFound); // not sure what to return in that case } value.SetIsRetained(true); try { Logger.Debug(string.Format("Image from cache: {0}", key)); await MainThreadDispatcher.PostAsync(() => { if (IsCancelled) { return; } var ffDrawable = value as FFBitmapDrawable; if (ffDrawable != null) { ffDrawable.StopFadeAnimation(); } _target.Set(this, value, true, false); Completed = true; Parameters?.OnSuccess(cacheEntry.Item2, LoadingResult.MemoryCache); }).ConfigureAwait(false); if (!Completed) { return(CacheResult.NotFound); // not sure what to return in that case } return(CacheResult.Found); // found and loaded from cache } finally { value.SetIsRetained(false); } } catch (Exception ex) { Parameters?.OnError(ex); return(CacheResult.ErrorOccured); // weird, what can we do if loading from cache fails } }
/// <summary> /// Runs the image loading task: gets image from file, url, asset or cache. Then assign it to the imageView. /// </summary> protected override async Task <GenerateResult> TryGeneratingImageAsync() { WithLoadingResult <SelfDisposingBitmapDrawable> drawableWithResult; if (string.IsNullOrWhiteSpace(Parameters.Path)) { drawableWithResult = new WithLoadingResult <SelfDisposingBitmapDrawable>(LoadingResult.Failed); } else { try { drawableWithResult = await RetrieveDrawableAsync(Parameters.Path, Parameters.Source, false, false).ConfigureAwait(false); } catch (Exception ex) { Logger.Error("An error occured while retrieving drawable.", ex); drawableWithResult = new WithLoadingResult <SelfDisposingBitmapDrawable>(LoadingResult.Failed); } } var imageView = GetAttachedImageView(); if (imageView == null || imageView.Handle == IntPtr.Zero) { return(GenerateResult.InvalidTarget); } if (drawableWithResult.HasError) { // Show error placeholder await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource, imageView, false).ConfigureAwait(false); return(drawableWithResult.GenerateResult); } try { if (IsCancelled) { return(GenerateResult.Canceled); } // Post on main thread await MainThreadDispatcher.PostAsync(() => { SetImageDrawable(imageView, drawableWithResult.Item); Completed = true; Parameters?.OnSuccess(drawableWithResult.ImageInformation, drawableWithResult.Result); }).ConfigureAwait(false); if (!Completed) { return(GenerateResult.Failed); } } catch (Exception ex2) { await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource, imageView, false).ConfigureAwait(false); throw ex2; } return(GenerateResult.Success); }
public async Task RunAsync() { LoadingResult loadingResult = LoadingResult.Failed; bool success = false; try { // LOAD IMAGE if (!(await TryLoadFromMemoryCacheAsync().ConfigureAwait(false))) { if (Parameters.DelayInMs.HasValue && Parameters.DelayInMs.Value > 0) { await Task.Delay(Parameters.DelayInMs.Value).ConfigureAwait(false); } else if (!Parameters.Preload && Configuration.DelayInMs > 0) { await Task.Delay(Configuration.DelayInMs).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.LoadingResult; ImageInformation = imageData.ImageInformation; 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(); TImageContainer image; if (imageData.Stream != null) { using (imageData.Stream) { image = await GenerateImageAsync(Parameters.Path, Parameters.Source, imageData.Stream, imageData.ImageInformation, true, false).ConfigureAwait(false); } } else { image = await GenerateImageAsync(Parameters.Path, Parameters.Source, imageData.Decoded, imageData.ImageInformation, true, false).ConfigureAwait(false); } ThrowIfCancellationRequested(); try { BeforeLoading(image, false); if (image != default(TImageContainer) && CanUseMemoryCache) { MemoryCache.Add(Key, imageData.ImageInformation, image); } ThrowIfCancellationRequested(); bool isFadeAnimationEnabled = Parameters.FadeAnimationEnabled ?? Configuration.FadeAnimationEnabled; if (Target != null) { 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 (Configuration.ClearMemoryCacheOnOutOfMemory && 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); } } }
/// <summary> /// Runs the image loading task: gets image from file, url, asset or cache. Then assign it to the imageView. /// </summary> protected override async Task <GenerateResult> TryGeneratingImageAsync() { WithLoadingResult <UIImage> imageWithResult = null; UIImage image = null; try { imageWithResult = await RetrieveImageAsync(Parameters.Path, Parameters.Source, false).ConfigureAwait(false); image = imageWithResult == null ? null : imageWithResult.Item; } catch (Exception ex) { Logger.Error("An error occured while retrieving image.", ex); image = null; } if (image == null) { await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource).ConfigureAwait(false); return(GenerateResult.Failed); } if (CancellationToken.IsCancellationRequested) { return(GenerateResult.Canceled); } if (_getNativeControl() == null) { return(GenerateResult.InvalidTarget); } try { // Post on main thread await MainThreadDispatcher.PostAsync(() => { if (CancellationToken.IsCancellationRequested) { return; } _doWithImage(image, false); Completed = true; Parameters.OnSuccess(new ImageSize((int)image.Size.Width, (int)image.Size.Height), imageWithResult.Result); }).ConfigureAwait(false); if (!Completed) { return(GenerateResult.Failed); } } catch (Exception ex2) { await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource).ConfigureAwait(false); throw ex2; } return(GenerateResult.Success); }
/// <summary> /// Loads given placeHolder into the imageView. /// </summary> /// <returns>An awaitable task.</returns> /// <param name="placeholderPath">Full path to the placeholder.</param> /// <param name="source">Source for the path: local, web, assets</param> protected async Task <bool> LoadPlaceHolderAsync(string placeholderPath, ImageSource source, ImageView imageView, bool isLoadingPlaceholder) { if (string.IsNullOrWhiteSpace(placeholderPath)) { return(false); } if (imageView == null) { return(false); } var cacheEntry = ImageCache.Instance.Get(GetKey(placeholderPath)); BitmapDrawable drawable = cacheEntry == null ? null: cacheEntry.Item1; if (drawable != null && drawable.Handle != IntPtr.Zero && drawable.Bitmap != null && drawable.Bitmap.Handle != IntPtr.Zero && !drawable.Bitmap.IsRecycled) { // We should wrap drawable in an AsyncDrawable, nothing is deferred drawable = new SelfDisposingAsyncDrawable(Context.Resources, drawable.Bitmap, this); } else { // Here we asynchronously load our placeholder: it is deferred so we need a temporary AsyncDrawable drawable = new AsyncDrawable(Context.Resources, null, this); await MainThreadDispatcher.PostAsync(() => { if (imageView.Handle == IntPtr.Zero) { return; } imageView.SetImageDrawable(drawable); // temporary assign this AsyncDrawable }).ConfigureAwait(false); try { var drawableWithResult = await RetrieveDrawableAsync(placeholderPath, source, isLoadingPlaceholder, true).ConfigureAwait(false); drawable = drawableWithResult.Item; } catch (Exception ex) { Logger.Error("An error occured while retrieving drawable.", ex); return(false); } } if (drawable == null) { return(false); } _loadingPlaceholderWeakReference = new WeakReference <BitmapDrawable>(drawable); if (IsCancelled) { return(false); } await MainThreadDispatcher.PostAsync(() => { if (IsCancelled) { return; } if (imageView.Handle == IntPtr.Zero) { return; } SetImageDrawable(imageView, drawable); }).ConfigureAwait(false); return(true); }
public async virtual Task <bool> TryLoadFromMemoryCacheAsync() { try { if (Parameters.Preload && Parameters.CacheType.HasValue && (Parameters.CacheType.Value == CacheType.Disk || Parameters.CacheType.Value == CacheType.None)) { return(false); } ThrowIfCancellationRequested(); bool isFadeAnimationEnabledForCached = Parameters.FadeAnimationForCachedImagesEnabled.HasValue ? Parameters.FadeAnimationForCachedImagesEnabled.Value : Configuration.FadeAnimationForCachedImages; var result = await TryLoadFromMemoryCacheAsync(Key, true, isFadeAnimationEnabledForCached, false).ConfigureAwait(false); if (result) { Logger.Debug(string.Format("Image loaded from cache: {0}", Key)); IsCompleted = true; if (Configuration.ExecuteCallbacksOnUIThread && (Parameters?.OnSuccess != null || Parameters?.OnFinish != null)) { await MainThreadDispatcher.PostAsync(() => { Parameters?.OnSuccess?.Invoke(ImageInformation, LoadingResult.MemoryCache); Parameters?.OnFinish?.Invoke(this); }).ConfigureAwait(false); } else { Parameters?.OnSuccess?.Invoke(ImageInformation, LoadingResult.MemoryCache); Parameters?.OnFinish?.Invoke(this); } } else { ThrowIfCancellationRequested(); // Loading placeholder if enabled if (!_isLoadingPlaceholderLoaded && !string.IsNullOrWhiteSpace(Parameters.LoadingPlaceholderPath)) { await ShowPlaceholder(Parameters.LoadingPlaceholderPath, KeyForLoadingPlaceholder, Parameters.LoadingPlaceholderSource, true).ConfigureAwait(false); } } return(result); } catch (Exception ex) { if (Configuration.ClearMemoryCacheOnOutOfMemory && 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); if (Configuration.ExecuteCallbacksOnUIThread && Parameters?.OnError != null) { await MainThreadDispatcher.PostAsync(() => { Parameters?.OnError?.Invoke(ex); }).ConfigureAwait(false); } else { Parameters?.OnError?.Invoke(ex); } } } return(false); }
public override async Task <GenerateResult> LoadFromStreamAsync(Stream stream) { if (stream == null) { return(GenerateResult.Failed); } if (IsCancelled) { return(GenerateResult.Canceled); } WithLoadingResult <WriteableBitmap> resultWithImage; WriteableBitmap image = null; try { resultWithImage = await GetImageAsync("Stream", ImageSource.Stream, false, stream).ConfigureAwait(false); image = resultWithImage.Item; } catch (Exception ex) { Logger.Error("An error occured while retrieving image.", ex); resultWithImage = new WithLoadingResult <WriteableBitmap>(LoadingResult.Failed); image = null; } if (image == null) { await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource, false).ConfigureAwait(false); return(resultWithImage.GenerateResult); } if (CanUseMemoryCache()) { ImageCache.Instance.Add(GetKey(), resultWithImage.ImageInformation, image); } if (IsCancelled) { return(GenerateResult.Canceled); } if (_getNativeControl() == null) { return(GenerateResult.InvalidTarget); } try { int pixelWidth = 0; int pixelHeight = 0; // Post on main thread await MainThreadDispatcher.PostAsync(() => { if (IsCancelled) { return; } _doWithImage(image, true, false); pixelWidth = image.PixelWidth; pixelHeight = image.PixelHeight; Completed = true; Parameters?.OnSuccess(resultWithImage.ImageInformation, resultWithImage.Result); }).ConfigureAwait(false); if (!Completed) { return(GenerateResult.Failed); } } catch (Exception ex2) { await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource, false).ConfigureAwait(false); throw ex2; } return(GenerateResult.Success); }
protected override async Task <GenerateResult> TryGeneratingImageAsync() { WithLoadingResult <WriteableBitmap> imageWithResult; WriteableBitmap image = null; try { imageWithResult = await RetrieveImageAsync(Parameters.Path, Parameters.Source, false).ConfigureAwait(false); image = imageWithResult.Item; } catch (Exception ex) { Logger.Error("An error occured while retrieving image.", ex); imageWithResult = new WithLoadingResult <WriteableBitmap>(LoadingResult.Failed); image = null; } if (image == null) { await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource, false).ConfigureAwait(false); return(imageWithResult.GenerateResult); } if (IsCancelled) { return(GenerateResult.Canceled); } if (_getNativeControl() == null) { return(GenerateResult.InvalidTarget); } try { // Post on main thread await MainThreadDispatcher.PostAsync(() => { if (IsCancelled) { return; } _doWithImage(image, imageWithResult.Result.IsLocalOrCachedResult(), false); Completed = true; Parameters?.OnSuccess(imageWithResult.ImageInformation, imageWithResult.Result); }).ConfigureAwait(false); if (!Completed) { return(GenerateResult.Failed); } } catch (Exception ex2) { await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource, false).ConfigureAwait(false); throw ex2; } return(GenerateResult.Success); }
public override async Task <GenerateResult> LoadFromStreamAsync(Stream stream, bool isPlaceholder) { if (stream == null) { return(GenerateResult.Failed); } if (CancellationToken.IsCancellationRequested) { return(GenerateResult.Canceled); } WithLoadingResult <WriteableBitmap> imageWithResult = null; WriteableBitmap image = null; try { imageWithResult = await GetImageAsync("Stream", ImageSource.Stream, isPlaceholder, stream).ConfigureAwait(false); image = imageWithResult == null ? null : imageWithResult.Item; } catch (Exception ex) { Logger.Error("An error occured while retrieving image.", ex); image = null; } if (image == null) { await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource).ConfigureAwait(false); return(GenerateResult.Failed); } if (CancellationToken.IsCancellationRequested) { return(GenerateResult.Canceled); } if (_getNativeControl() == null) { return(GenerateResult.InvalidTarget); } try { int pixelWidth = 0; int pixelHeight = 0; // Post on main thread await MainThreadDispatcher.PostAsync(() => { if (CancellationToken.IsCancellationRequested) { return; } _doWithImage(image, false); pixelWidth = image.PixelWidth; pixelHeight = image.PixelHeight; Completed = true; Parameters.OnSuccess(new ImageSize(pixelWidth, pixelHeight), imageWithResult.Result); }).ConfigureAwait(false); if (!Completed) { return(GenerateResult.Failed); } } catch (Exception ex2) { await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource).ConfigureAwait(false); throw ex2; } return(GenerateResult.Success); }
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)); }
/// <summary> /// Tries to load requested image from the cache asynchronously. /// </summary> /// <returns>A boolean indicating if image was loaded from cache.</returns> private async Task <CacheResult> TryLoadingFromCacheAsync(ImageView imageView) { try { if (imageView == null) { return(CacheResult.NotFound); // weird situation, dunno what to do } if (IsCancelled) { return(CacheResult.NotFound); // not sure what to return in that case } var key = GetKey(); if (string.IsNullOrWhiteSpace(key)) { return(CacheResult.NotFound); } var value = ImageCache.Instance.Get(key); if (value == null) { return(CacheResult.NotFound); // not available in the cache } if (IsCancelled) { return(CacheResult.NotFound); // not sure what to return in that case } value.SetIsRetained(true); try { Logger.Debug(string.Format("Image from cache: {0}", key)); await MainThreadDispatcher.PostAsync(() => { if (IsCancelled) { return; } var ffDrawable = value as FFBitmapDrawable; if (ffDrawable != null) { ffDrawable.StopFadeAnimation(); } if (imageView == null || imageView.Handle == IntPtr.Zero) { return; } imageView.SetImageDrawable(value); if (Utils.HasJellyBean() && imageView.AdjustViewBounds) { imageView.LayoutParameters.Height = value.IntrinsicHeight; imageView.LayoutParameters.Width = value.IntrinsicWidth; } }).ConfigureAwait(false); if (IsCancelled) { return(CacheResult.NotFound); // not sure what to return in that case } Completed = true; if (Parameters.OnSuccess != null) { Parameters.OnSuccess(new ImageSize(value.IntrinsicWidth, value.IntrinsicHeight), LoadingResult.MemoryCache); } return(CacheResult.Found); // found and loaded from cache } finally { value.SetIsRetained(false); } } catch (Exception ex) { if (Parameters.OnError != null) { Parameters.OnError(ex); } return(CacheResult.ErrorOccured); // weird, what can we do if loading from cache fails } }
/// <summary> /// Loads the image from given stream asynchronously. /// </summary> /// <returns>An awaitable task.</returns> /// <param name="stream">The stream to get data from.</param> public override async Task <GenerateResult> LoadFromStreamAsync(Stream stream) { if (stream == null) { return(GenerateResult.Failed); } if (CancellationToken.IsCancellationRequested) { return(GenerateResult.Canceled); } var imageView = GetAttachedImageView(); if (imageView == null) { return(GenerateResult.InvalidTarget); } var resultWithDrawable = await GetDrawableAsync("Stream", ImageSource.Stream, false, false, stream).ConfigureAwait(false); if (resultWithDrawable == null || resultWithDrawable.Item == null) { // Show error placeholder await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource, imageView, false).ConfigureAwait(false); return(GenerateResult.Failed); } try { if (CancellationToken.IsCancellationRequested) { return(GenerateResult.Canceled); } // Post on main thread await MainThreadDispatcher.PostAsync(() => { if (CancellationToken.IsCancellationRequested) { return; } if (imageView == null || imageView.Handle == IntPtr.Zero) { return; } SetImageDrawable(imageView, resultWithDrawable.Item, UseFadeInBitmap); Completed = true; Parameters.OnSuccess(new ImageSize(resultWithDrawable.Item.IntrinsicWidth, resultWithDrawable.Item.IntrinsicHeight), resultWithDrawable.Result); }).ConfigureAwait(false); if (!Completed) { return(GenerateResult.Failed); } } catch (Exception ex2) { // Show error placeholder await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource, imageView, false).ConfigureAwait(false); throw ex2; } return(GenerateResult.Success); }
protected async override Task SetTargetAsync(SelfDisposingBitmapDrawable image, bool animated) { if (Target == null) { return; } ThrowIfCancellationRequested(); if (image is FFBitmapDrawable ffDrawable) { if (ffDrawable.IsFadeAnimationRunning) { var mut = new FFBitmapDrawable(Context.Resources, ffDrawable.Bitmap, ffDrawable); ffDrawable = mut as FFBitmapDrawable; image = ffDrawable; // old hacky workaround //await Task.Delay(ffDrawable.FadeDuration + 50).ConfigureAwait(false); } if (animated) { SelfDisposingBitmapDrawable placeholderDrawable = null; PlaceholderWeakReference?.TryGetTarget(out placeholderDrawable); if (placeholderDrawable == null) { // Enable fade animation when no placeholder is set and the previous image is not null var imageView = PlatformTarget.Control as ImageView; placeholderDrawable = imageView?.Drawable as SelfDisposingBitmapDrawable; } var fadeDuration = Parameters.FadeAnimationDuration ?? Configuration.FadeAnimationDuration; if (placeholderDrawable.IsValidAndHasValidBitmap()) { placeholderDrawable?.SetIsRetained(true); ffDrawable?.SetPlaceholder(placeholderDrawable, fadeDuration); placeholderDrawable?.SetIsRetained(false); } else if (ffDrawable.IsValidAndHasValidBitmap()) { var width = ffDrawable.Bitmap.Width; var height = ffDrawable.Bitmap.Height; var bitmap = Bitmap.CreateBitmap(width, height, Bitmap.Config.Argb8888); using (var canvas = new Canvas(bitmap)) using (var paint = new Paint() { Color = _placeholderHelperColor }) { canvas.DrawRect(0, 0, width, height, paint); } ffDrawable?.SetPlaceholder(new SelfDisposingBitmapDrawable(Context.Resources, bitmap), fadeDuration); } } else { ffDrawable?.SetPlaceholder(null, 0); } } await MainThreadDispatcher.PostAsync(() => { ThrowIfCancellationRequested(); PlatformTarget.Set(this, image, animated); }).ConfigureAwait(false); }
/// <summary> /// Runs the image loading task: gets image from file, url, asset or cache. Then assign it to the imageView. /// </summary> protected override async Task <GenerateResult> TryGeneratingImageAsync() { UIImage image = null; try { image = await RetrieveImageAsync(Parameters.Path, Parameters.Source).ConfigureAwait(false); } catch (Exception ex) { Logger.Error("An error occured while retrieving image.", ex); image = null; } if (image == null) { await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource).ConfigureAwait(false); return(GenerateResult.Failed); } if (CancellationToken.IsCancellationRequested) { return(GenerateResult.Canceled); } if (_getNativeControl() == null) { return(GenerateResult.InvalidTarget); } Exception trappedException = null; try { // Post on main thread await MainThreadDispatcher.PostAsync(() => { if (CancellationToken.IsCancellationRequested) { return; } _doWithImage(image); Completed = true; Parameters.OnSuccess((int)image.Size.Width, (int)image.Size.Height); }).ConfigureAwait(false); if (!Completed) { return(GenerateResult.Failed); } } catch (Exception ex2) { trappedException = ex2; // All this stupid stuff is necessary to compile with c# 5, since we can't await in a catch block... } // All this stupid stuff is necessary to compile with c# 5, since we can't await in a catch block... if (trappedException != null) { await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource).ConfigureAwait(false); throw trappedException; } return(GenerateResult.Success); }
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)); } if (Configuration.ExecuteCallbacksOnUIThread && Parameters?.OnSuccess != null) { await MainThreadDispatcher.PostAsync(() => { Parameters?.OnSuccess?.Invoke(ImageInformation, loadingResult); }); } else { 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); } } } if (Configuration.ExecuteCallbacksOnUIThread && Parameters?.OnSuccess != null) { await MainThreadDispatcher.PostAsync(() => { Parameters?.OnSuccess?.Invoke(ImageInformation, loadingResult); }); } else { Parameters?.OnSuccess?.Invoke(ImageInformation, loadingResult); } } catch (Exception ex) { if (_clearCacheOnOutOfMemory && ex is OutOfMemoryException) { MemoryCache.Clear(); } if (ex is OperationCanceledException || ex is ObjectDisposedException) { if (Configuration.VerboseLoadingCancelledLogging) { Logger.Debug(string.Format("Image loading cancelled: {0}", Key)); } } else { Logger.Error(string.Format("Image loading failed: {0}", Key), ex); if (Configuration.ExecuteCallbacksOnUIThread && Parameters?.OnError != null) { await MainThreadDispatcher.PostAsync(() => { Parameters?.OnError?.Invoke(ex); }); } 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 { using (Parameters) { if (Configuration.ExecuteCallbacksOnUIThread && Parameters?.OnFinish != null) { await MainThreadDispatcher.PostAsync(() => { Parameters?.OnFinish?.Invoke(this); }); } else { Parameters?.OnFinish?.Invoke(this); } ImageService.RemovePendingTask(this); } IsCompleted = true; } }