public async Task <WithLoadingResult <Stream> > GetStream(string identifier, CancellationToken token) { var cachedStream = await DownloadCache.GetStreamAsync(identifier, token, Parameters.CacheDuration).ConfigureAwait(false); return(WithLoadingResult.Encapsulate(cachedStream.ImageStream, cachedStream.RetrievedFromDiskCache ? LoadingResult.DiskCache : LoadingResult.Disk)); }
public Task <WithLoadingResult <Stream> > GetStream(string identifier, CancellationToken token) { try { var imageInformation = new ImageInformation(); imageInformation.SetPath(identifier); imageInformation.SetFilePath(null); var result = WithLoadingResult.Encapsulate(Context.Assets.Open(identifier, Access.Streaming), LoadingResult.ApplicationBundle, imageInformation); return(Task.FromResult(result)); } catch (Java.IO.FileNotFoundException) { return(Task.FromResult(WithLoadingResult.Encapsulate((Stream)null, LoadingResult.NotFound))); } catch (Java.IO.IOException) { return(Task.FromResult(WithLoadingResult.Encapsulate((Stream)null, LoadingResult.NotFound))); } catch (FileNotFoundException) { return(Task.FromResult(WithLoadingResult.Encapsulate((Stream)null, LoadingResult.NotFound))); } catch (IOException) { return(Task.FromResult(WithLoadingResult.Encapsulate((Stream)null, LoadingResult.NotFound))); } }
public async Task <WithLoadingResult <Stream> > GetStream(string identifier, CancellationToken token) { StorageFile file = null; try { var filePath = Path.GetDirectoryName(identifier); if (!string.IsNullOrWhiteSpace(filePath)) { file = await StorageFile.GetFileFromPathAsync(identifier); } } catch (Exception) { } if (file != null) { var imageInformation = new ImageInformation(); imageInformation.SetPath(identifier); imageInformation.SetFilePath(identifier); return(WithLoadingResult.Encapsulate(await file.OpenStreamForReadAsync(), LoadingResult.Disk, imageInformation)); } return(WithLoadingResult.Encapsulate <Stream>(null, LoadingResult.Disk)); }
public Task <WithLoadingResult <Stream> > GetStream(string identifier, CancellationToken token) { // Resource name is always without extension string resourceName = Path.GetFileNameWithoutExtension(identifier); int resourceId = 0; if (!_resourceIdentifiersCache.TryGetValue(resourceName, out resourceId)) { resourceId = Context.Resources.GetIdentifier(resourceName.ToLower(), "drawable", Context.PackageName); _resourceIdentifiersCache.TryAdd(resourceName.ToLower(), resourceId); } Stream stream = null; if (resourceId != 0) { stream = Context.Resources.OpenRawResource(resourceId); } else { return(Task.FromResult(WithLoadingResult.Encapsulate((Stream)null, LoadingResult.NotFound))); } var imageInformation = new ImageInformation(); imageInformation.SetPath(identifier); imageInformation.SetFilePath(null); var result = WithLoadingResult.Encapsulate(stream, LoadingResult.CompiledResource, imageInformation); return(Task.FromResult(result)); }
public Task <WithLoadingResult <Stream> > GetStream(string identifier, CancellationToken token) { if (!FileStore.Exists(identifier)) { return(Task.FromResult(WithLoadingResult.Encapsulate((Stream)null, LoadingResult.NotFound))); } var result = WithLoadingResult.Encapsulate(FileStore.GetInputStream(identifier), LoadingResult.Disk); return(Task.FromResult(result)); }
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(new ImageSize(image.PixelWidth, image.PixelHeight), 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 async Task <WithLoadingResult <Stream> > GetStream(string identifier, CancellationToken token) { var cachedStream = await DownloadCache.GetStreamAsync(identifier, token, Parameters.CacheDuration, Parameters.CustomCacheKey).ConfigureAwait(false); var imageInformation = new ImageInformation(); imageInformation.SetPath(identifier); imageInformation.SetFilePath(await DownloadCache.GetDiskCacheFilePathAsync(identifier, Parameters.CustomCacheKey)); return(WithLoadingResult.Encapsulate(cachedStream.ImageStream, cachedStream.RetrievedFromDiskCache ? LoadingResult.DiskCache : LoadingResult.Internet, imageInformation)); }
/// <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; UIImage 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<UIImage>(LoadingResult.Failed); image = null; } if (image == null) { await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource, true).ConfigureAwait(false); return imageWithResult.GenerateResult; } if (IsCancelled) return GenerateResult.Canceled; if (!_target.IsTaskValid(this)) return GenerateResult.InvalidTarget; try { // Post on main thread await MainThreadDispatcher.PostAsync(() => { if (IsCancelled) return; _target.Set(this, 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 Task <WithLoadingResult <Stream> > GetStream(string identifier, CancellationToken token) { if (!FileStore.Exists(identifier)) { return(Task.FromResult(WithLoadingResult.Encapsulate((Stream)null, LoadingResult.NotFound))); } var imageInformation = new ImageInformation(); imageInformation.SetPath(identifier); imageInformation.SetFilePath(identifier); var result = WithLoadingResult.Encapsulate(FileStore.GetInputStream(identifier), LoadingResult.Disk, imageInformation); return(Task.FromResult(result)); }
public async Task <WithLoadingResult <Stream> > GetStream(string identifier, CancellationToken token) { StorageFile file = null; try { string resPath = identifier.TrimStart('\\', '/'); if (!resPath.StartsWith(@"Assets\") && !resPath.StartsWith("Assets/")) { resPath = @"Assets\" + resPath; } var imgUri = new Uri("ms-appx:///" + resPath); file = await StorageFile.GetFileFromApplicationUriAsync(imgUri); } catch (Exception) { try { var imgUri = new Uri("ms-appx:///" + identifier); file = await StorageFile.GetFileFromApplicationUriAsync(imgUri); } catch (Exception) { } } if (file != null) { var imageInformation = new ImageInformation(); imageInformation.SetPath(identifier); imageInformation.SetFilePath(file.Path); return(WithLoadingResult.Encapsulate(await file.OpenStreamForReadAsync(), LoadingResult.CompiledResource, imageInformation)); } return(WithLoadingResult.Encapsulate <Stream>(null, LoadingResult.CompiledResource)); }
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); }
public override async Task<GenerateResult> LoadFromStreamAsync(Stream stream) { if (stream == null) return GenerateResult.Failed; if (IsCancelled) return GenerateResult.Canceled; WithLoadingResult<WriteableBitmap> imageWithResult; WriteableBitmap image = null; try { imageWithResult = await GetImageAsync("Stream", ImageSource.Stream, false, stream).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 (CanUseMemoryCache()) { ImageCache.Instance.Add(GetKey(), 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(new ImageSize(pixelWidth, pixelHeight), 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; }
protected virtual async Task<WithLoadingResult<SelfDisposingBitmapDrawable>> GetDrawableAsync(string path, ImageSource source, bool isLoadingPlaceHolder, bool isPlaceholder, Stream originalStream = null) { if (IsCancelled) return new WithLoadingResult<SelfDisposingBitmapDrawable>(LoadingResult.Canceled); // First decode with inJustDecodeBounds=true to check dimensions var options = new BitmapFactory.Options { InJustDecodeBounds = true }; Stream stream = null; WithLoadingResult<Stream> streamWithResult; if (originalStream != null) { streamWithResult = new WithLoadingResult<Stream>(originalStream, LoadingResult.Stream); } else { streamWithResult = await GetStreamAsync(path, source).ConfigureAwait(false); } if (streamWithResult.HasError) { if (streamWithResult.Result == LoadingResult.NotFound) { Logger.Error(string.Format("Not found: {0} from {1}", path, source.ToString())); } return new WithLoadingResult<SelfDisposingBitmapDrawable>(streamWithResult.Result); } stream = streamWithResult.Item; try { try { // NOTE: CURRENTLY NOT NEEDED // if (streamWithResult.Result == LoadingResult.Internet) // { // // When loading from internet stream we shouldn't block otherwise other downloads will be paused // BitmapFactory.DecodeStream(stream, null, options); // } // else // { lock (_decodingLock) { BitmapFactory.DecodeStream(stream, null, options); } // } if (!stream.CanSeek) { if (stream == originalStream) { // If we cannot seek the original stream then there's not much we can do return new WithLoadingResult<SelfDisposingBitmapDrawable>(LoadingResult.Failed); } else { // Assets stream can't be seeked to origin position stream.Dispose(); streamWithResult = await GetStreamAsync(path, source).ConfigureAwait(false); if (streamWithResult.HasError) { return new WithLoadingResult<SelfDisposingBitmapDrawable>(streamWithResult.Result); } stream = streamWithResult.Item; } } else { stream.Seek(0, SeekOrigin.Begin); } } catch (Exception ex) { Logger.Error("Something wrong happened while asynchronously retrieving image size from file: " + path, ex); return new WithLoadingResult<SelfDisposingBitmapDrawable>(LoadingResult.Failed); } if (IsCancelled) return new WithLoadingResult<SelfDisposingBitmapDrawable>(LoadingResult.Canceled); options.InPurgeable = true; options.InJustDecodeBounds = false; if (!ImageService.Config.LoadWithTransparencyChannel || Parameters.LoadTransparencyChannel == null || !Parameters.LoadTransparencyChannel.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; } // CHECK IF BITMAP IS EXIF ROTATED int exifRotation = 0; if (source == ImageSource.Filepath) { exifRotation = path.GetExifRotationDegrees(); } try { 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(); } if (Parameters.DownSampleUseDipUnits) { downsampleWidth = downsampleWidth.DpToPixels(); downsampleHeight = downsampleHeight.DpToPixels(); } options.InSampleSize = CalculateInSampleSize(options, downsampleWidth, downsampleHeight); // If we're running on Honeycomb or newer, try to use inBitmap if (Utils.HasHoneycomb()) AddInBitmapOptions(options); } } catch (Exception ex) { Logger.Error("Something wrong happened while adding decoding options to image: " + path, ex); } if (IsCancelled) return new WithLoadingResult<SelfDisposingBitmapDrawable>(LoadingResult.Canceled); Bitmap bitmap; try { // NOTE: CURRENTLY NOT NEEDED // if (streamWithResult.Result == LoadingResult.Internet) // { // // When loading from internet stream we shouldn't block otherwise other downloads will be paused // bitmap = BitmapFactory.DecodeStream(stream, null, options); // } // else // { lock (_decodingLock) { bitmap = BitmapFactory.DecodeStream(stream, null, options); } // } } catch (Java.Lang.Throwable vme) { if (vme.Class == Java.Lang.Class.FromType(typeof(Java.Lang.OutOfMemoryError))) { ImageCache.Instance.Clear(); // Clear will also force a Garbage collection } return new WithLoadingResult<SelfDisposingBitmapDrawable>(LoadingResult.Failed); } catch (Exception ex) { Logger.Error("Something wrong happened while asynchronously loading/decoding image: " + path, ex); return new WithLoadingResult<SelfDisposingBitmapDrawable>(LoadingResult.Failed); } if (bitmap == null) return new WithLoadingResult<SelfDisposingBitmapDrawable>(LoadingResult.Failed); if (IsCancelled) return new WithLoadingResult<SelfDisposingBitmapDrawable>(LoadingResult.Canceled); // APPLY EXIF ORIENTATION IF NEEDED if (exifRotation != 0) bitmap = bitmap.ToRotatedBitmap(exifRotation); 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 (IsCancelled) return new WithLoadingResult<SelfDisposingBitmapDrawable>(LoadingResult.Canceled); try { var old = bitmap; // Applying a transformation is both CPU and memory intensive lock (_decodingLock) { var bitmapHolder = transformation.Transform(new BitmapHolder(bitmap)); bitmap = bitmapHolder.ToNative(); } // 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(); } } catch (Exception ex) { Logger.Error("Can't apply transformation " + transformation.Key + " to image " + path, ex); } } } if (isLoadingPlaceHolder) { return WithLoadingResult.Encapsulate<SelfDisposingBitmapDrawable>(new SelfDisposingAsyncDrawable(Context.Resources, bitmap, this), streamWithResult.Result); } else { bool isFadeAnimationEnabled = Parameters.FadeAnimationEnabled.HasValue ? Parameters.FadeAnimationEnabled.Value : ImageService.Config.FadeAnimationEnabled; bool isFadeAnimationEnabledForCached = isFadeAnimationEnabled && (Parameters.FadeAnimationForCachedImages.HasValue ? Parameters.FadeAnimationForCachedImages.Value : ImageService.Config.FadeAnimationForCachedImages); int fadeDuration = Parameters.FadeAnimationDuration.HasValue ? Parameters.FadeAnimationDuration.Value : ImageService.Config.FadeAnimationDuration; bool isLocalOrCached = streamWithResult.Result.IsLocalOrCachedResult(); BitmapDrawable placeholderDrawable = null; if (_loadingPlaceholderWeakReference != null) { _loadingPlaceholderWeakReference.TryGetTarget(out placeholderDrawable); } if (isLocalOrCached) { return WithLoadingResult.Encapsulate<SelfDisposingBitmapDrawable>( new FFBitmapDrawable(Context.Resources, bitmap, placeholderDrawable, fadeDuration, isFadeAnimationEnabled && isFadeAnimationEnabledForCached), streamWithResult.Result); } return WithLoadingResult.Encapsulate<SelfDisposingBitmapDrawable>( new FFBitmapDrawable(Context.Resources, bitmap, placeholderDrawable, fadeDuration, isFadeAnimationEnabled), streamWithResult.Result); } } finally { if (stream != null) stream.Dispose(); } }
/// <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) 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(() => { if (IsCancelled) return; if (imageView.Handle == IntPtr.Zero) return; SetImageDrawable(imageView, drawableWithResult.Item); Completed = true; Parameters?.OnSuccess(new ImageSize(drawableWithResult.Item.IntrinsicWidth, drawableWithResult.Item.IntrinsicHeight), 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; }
protected virtual async Task<WithLoadingResult<BitmapDrawable>> GetDrawableAsync(string path, ImageSource source, bool isLoadingPlaceHolder, Stream originalStream = null) { if (CancellationToken.IsCancellationRequested) return null; return await Task.Run<WithLoadingResult<BitmapDrawable>>(async() => { if (CancellationToken.IsCancellationRequested) return null; // First decode with inJustDecodeBounds=true to check dimensions var options = new BitmapFactory.Options { InJustDecodeBounds = true }; 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 || streamWithResult.Item == null) return null; stream = streamWithResult.Item; try { try { lock (_decodingLock) { BitmapFactory.DecodeStream(stream, null, options); } if (!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); } } catch (Exception ex) { Logger.Error("Something wrong happened while asynchronously retrieving image size from file: " + path, ex); return null; } if (CancellationToken.IsCancellationRequested) return null; options.InPurgeable = true; options.InJustDecodeBounds = false; if (!ImageService.Config.LoadWithTransparencyChannel || Parameters.LoadTransparencyChannel == null || !Parameters.LoadTransparencyChannel.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; } try { if (Parameters.DownSampleSize != null && (Parameters.DownSampleSize.Item1 > 0 || Parameters.DownSampleSize.Item2 > 0)) { // Calculate inSampleSize options.InSampleSize = CalculateInSampleSize(options, (int)Parameters.DownSampleSize.Item1, (int)Parameters.DownSampleSize.Item2); } // If we're running on Honeycomb or newer, try to use inBitmap if (Utils.HasHoneycomb()) AddInBitmapOptions(options); } catch (Exception ex) { Logger.Error("Something wrong happened while adding decoding options to image: " + path, ex); } if (CancellationToken.IsCancellationRequested) return null; Bitmap bitmap; try { lock (_decodingLock) { bitmap = BitmapFactory.DecodeStream(stream, null, options); } } catch (Java.Lang.Throwable vme) { if (vme.Class == Java.Lang.Class.FromType(typeof(Java.Lang.OutOfMemoryError))) { ImageCache.Instance.Clear(); // Clear will also force a Garbage collection } return null; } catch (Exception ex) { Logger.Error("Something wrong happened while asynchronously loading/decoding image: " + path, ex); return null; } try { if (bitmap == null || CancellationToken.IsCancellationRequested) return null; if (Parameters.Transformations != null && Parameters.Transformations.Count > 0) { foreach (var transformation in Parameters.Transformations.ToList() /* to prevent concurrency issues */) { if (CancellationToken.IsCancellationRequested) return null; try { var old = bitmap; var bitmapHolder = transformation.Transform(new BitmapHolder(bitmap)); bitmap = bitmapHolder.ToNative(); // Transformation succeeded, so garbage the source old.Recycle(); old.Dispose(); } catch (Exception ex) { Logger.Error("Can't apply transformation " + transformation.Key + " to image " + path, ex); } } } if (isLoadingPlaceHolder) { return WithLoadingResult.Encapsulate<BitmapDrawable>(new AsyncDrawable(Context.Resources, bitmap, this), streamWithResult.Result); } else { Drawable placeholderDrawable = null; if (_loadingPlaceholderWeakReference != null) { _loadingPlaceholderWeakReference.TryGetTarget(out placeholderDrawable); } return WithLoadingResult.Encapsulate<BitmapDrawable>(new FFBitmapDrawable(Context.Resources, bitmap, placeholderDrawable, FADE_TRANSITION_MILISECONDS, UseFadeInBitmap), streamWithResult.Result); } } finally { if (bitmap != null) bitmap.Dispose(); // .NET space no longer needs to care about the Bitmap. It should exist in Java world only so we break the relationship .NET/Java for the object. } } finally { if (stream != null) stream.Dispose(); } }); }
/// <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; WithLoadingResult<UIImage> resultWithImage; UIImage 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<UIImage>(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 (!_target.IsTaskValid(this)) return GenerateResult.InvalidTarget; try { // Post on main thread await MainThreadDispatcher.PostAsync(() => { if (IsCancelled) return; _target.Set(this, image, true, false); 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; }