Ejemplo n.º 1
0
		/// <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);
				}
			}

			if (!_target.IsTaskValid(this))
				return GenerateResult.InvalidTarget;

			if (drawableWithResult.HasError)
			{
				// Show error placeholder
				await LoadPlaceHolderAsync(Parameters.ErrorPlaceholderPath, Parameters.ErrorPlaceholderSource, false).ConfigureAwait(false);
				return drawableWithResult.GenerateResult;
			}
				
			try
			{
				if (IsCancelled)
					return GenerateResult.Canceled;

				// Post on main thread
				await MainThreadDispatcher.PostAsync(() =>
					{
						_target.Set(this, drawableWithResult.Item, drawableWithResult.Result.IsLocalOrCachedResult(), false);
						Completed = true;
						Parameters?.OnSuccess(drawableWithResult.ImageInformation, drawableWithResult.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;
		}
Ejemplo n.º 2
0
        /// <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 (_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);
        }
Ejemplo n.º 3
0
        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));
        }
Ejemplo n.º 4
0
        /// <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 (_getNativeControl() == null)
            {
                return(GenerateResult.InvalidTarget);
            }

            try
            {
                // Post on main thread
                await MainThreadDispatcher.PostAsync(() =>
                {
                    if (IsCancelled)
                    {
                        return;
                    }

                    _doWithImage(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);
        }
Ejemplo n.º 5
0
        /// <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);
        }
Ejemplo n.º 6
0
        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));
        }
Ejemplo n.º 7
0
        protected virtual async Task <WithLoadingResult <WriteableBitmap> > GetImageAsync(string path, ImageSource source,
                                                                                          bool isPlaceholder, Stream originalStream = null)
        {
            if (IsCancelled)
            {
                return(new WithLoadingResult <WriteableBitmap>(LoadingResult.Canceled));
            }

            if (IsCancelled)
            {
                return(new WithLoadingResult <WriteableBitmap>(LoadingResult.Canceled));
            }

            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 <WriteableBitmap>(streamWithResult.Result));
            }

            stream = streamWithResult.Item;

            if (IsCancelled)
            {
                return(new WithLoadingResult <WriteableBitmap>(LoadingResult.Canceled));
            }

            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(new WithLoadingResult <WriteableBitmap>(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 <WriteableBitmap>(streamWithResult.Result));
                            }

                            stream = streamWithResult.Item;
                        }
                    }
                    else
                    {
                        stream.Seek(0, SeekOrigin.Begin);
                    }

                    if (IsCancelled)
                    {
                        return(new WithLoadingResult <WriteableBitmap>(LoadingResult.Canceled));
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error("Something wrong happened while asynchronously retrieving image size from file: " + path, ex);
                    return(new WithLoadingResult <WriteableBitmap>(LoadingResult.Failed));
                }

                WriteableBitmap writableBitmap = null;

                // Special case to handle WebP decoding
                if (path.ToLowerInvariant().EndsWith(".webp"))
                {
                    //TODO
                    Logger.Error("Webp is not implemented on Windows");
                    return(new WithLoadingResult <WriteableBitmap>(LoadingResult.Failed));
                }

                // Setting image informations
                var imageInformation = streamWithResult.ImageInformation ?? new ImageInformation();
                imageInformation.SetKey(path == "Stream" ? GetKey() : GetKey(path), Parameters.CustomCacheKey);

                bool transformPlaceholdersEnabled = Parameters.TransformPlaceholdersEnabled.HasValue ?
                                                    Parameters.TransformPlaceholdersEnabled.Value : ImageService.Instance.Config.TransformPlaceholders;

                if (Parameters.Transformations != null && Parameters.Transformations.Count > 0 &&
                    (!isPlaceholder || (isPlaceholder && transformPlaceholdersEnabled)))
                {
                    BitmapHolder imageIn = null;

                    try
                    {
                        imageIn = await stream.ToBitmapHolderAsync(Parameters.DownSampleSize, Parameters.DownSampleUseDipUnits, Parameters.DownSampleInterpolationMode, imageInformation).ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        Logger.Error("Something wrong happened while asynchronously loading/decoding image: " + path, ex);
                        return(new WithLoadingResult <WriteableBitmap>(LoadingResult.Failed));
                    }

                    foreach (var transformation in Parameters.Transformations.ToList() /* to prevent concurrency issues */)
                    {
                        if (IsCancelled)
                        {
                            return(new WithLoadingResult <WriteableBitmap>(LoadingResult.Canceled));
                        }

                        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
                {
                    try
                    {
                        writableBitmap = await stream.ToBitmapImageAsync(Parameters.DownSampleSize, Parameters.DownSampleUseDipUnits, Parameters.DownSampleInterpolationMode, imageInformation);
                    }
                    catch (Exception ex)
                    {
                        Logger.Error("Something wrong happened while asynchronously loading/decoding image: " + path, ex);
                        return(new WithLoadingResult <WriteableBitmap>(LoadingResult.Failed));
                    }
                }

                return(WithLoadingResult.Encapsulate(writableBitmap, streamWithResult.Result, imageInformation));
            }
            finally
            {
                if (stream != null)
                {
                    stream.Dispose();
                }
            }
        }
Ejemplo n.º 8
0
        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));
                }

                // Setting image informations
                var imageInformation = streamWithResult.ImageInformation ?? new ImageInformation();
                imageInformation.SetOriginalSize(options.OutWidth, options.OutHeight);
                imageInformation.SetCurrentSize(options.OutWidth, options.OutHeight);
                imageInformation.SetCacheKey(path == "Stream" ? GetKey() : GetKey(path));

                options.InPurgeable        = true;
                options.InJustDecodeBounds = false;

                if (!ImageService.Instance.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();
                        }

                        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);
                        }
                    }
                }
                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.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 <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, imageInformation));
                }
                else
                {
                    bool isFadeAnimationEnabled = Parameters.FadeAnimationEnabled.HasValue ?
                                                  Parameters.FadeAnimationEnabled.Value : ImageService.Instance.Config.FadeAnimationEnabled;

                    bool isFadeAnimationEnabledForCached = isFadeAnimationEnabled && (Parameters.FadeAnimationForCachedImages.HasValue ?
                                                                                      Parameters.FadeAnimationForCachedImages.Value : ImageService.Instance.Config.FadeAnimationForCachedImages);

                    int fadeDuration = Parameters.FadeAnimationDuration.HasValue ?
                                       Parameters.FadeAnimationDuration.Value : ImageService.Instance.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, imageInformation));
                    }

                    return(WithLoadingResult.Encapsulate <SelfDisposingBitmapDrawable>(
                               new FFBitmapDrawable(Context.Resources, bitmap, placeholderDrawable,
                                                    fadeDuration, isFadeAnimationEnabled),
                               streamWithResult.Result, imageInformation));
                }
            }
            finally
            {
                if (stream != null)
                {
                    stream.Dispose();
                }
            }
        }
Ejemplo n.º 9
0
        /// <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);
        }
Ejemplo n.º 10
0
        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));
        }
Ejemplo n.º 11
0
        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);
        }
Ejemplo n.º 12
0
        protected virtual async Task <WithLoadingResult <SelfDisposingBitmapDrawable> > GetDrawableAsync(string path, ImageSource source, bool isLoadingPlaceHolder, bool isPlaceholder, Stream originalStream = null)
        {
            if (CancellationToken.IsCancellationRequested)
            {
                return(null);
            }

            return(await Task.Run <WithLoadingResult <SelfDisposingBitmapDrawable> >(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)
                {
                    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;

                try
                {
                    try
                    {
                        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 (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

                            int downsampleWidth = Parameters.DownSampleSize.Item1;
                            int downsampleHeight = Parameters.DownSampleSize.Item2;

                            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 (CancellationToken.IsCancellationRequested)
                    {
                        return null;
                    }

                    Bitmap bitmap;
                    try
                    {
                        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 null;
                    }
                    catch (Exception ex)
                    {
                        Logger.Error("Something wrong happened while asynchronously loading/decoding image: " + path, ex);
                        return null;
                    }

                    if (bitmap == null || CancellationToken.IsCancellationRequested)
                    {
                        return null;
                    }

                    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 = 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.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
                    {
                        Drawable placeholderDrawable = null;
                        if (_loadingPlaceholderWeakReference != null)
                        {
                            _loadingPlaceholderWeakReference.TryGetTarget(out placeholderDrawable);
                        }

                        return WithLoadingResult.Encapsulate <SelfDisposingBitmapDrawable>(new FFBitmapDrawable(Context.Resources, bitmap, placeholderDrawable, FADE_TRANSITION_MILISECONDS, UseFadeInBitmap), streamWithResult.Result);
                    }
                }
                finally
                {
                    if (stream != null)
                    {
                        stream.Dispose();
                    }
                }
            }).ConfigureAwait(false));
        }