private async Task <WithLoadingResult <Stream> > GetStreamAsync(string path, ImageSource source)
        {
            if (string.IsNullOrWhiteSpace(path))
            {
                return(new WithLoadingResult <Stream>(LoadingResult.Failed));
            }

            try
            {
                using (var resolver = DataResolverFactory.GetResolver(source, Parameters, DownloadCache))
                {
                    return(await resolver.GetStream(path, CancellationToken.Token).ConfigureAwait(false));
                }
            }
            catch (OperationCanceledException)
            {
                Logger.Debug(string.Format("Image request for {0} got cancelled.", path));
                return(new WithLoadingResult <Stream>(LoadingResult.Canceled));
            }
            catch (Exception ex)
            {
                Logger.Error("Unable to retrieve image data", ex);
                return(new WithLoadingResult <Stream>(LoadingResult.Failed));
            }
        }
        protected virtual async Task ShowPlaceholder(string path, string key, ImageSource source, bool isLoadingPlaceholder)
        {
            if (!await TryLoadFromMemoryCacheAsync(key, false, false, isLoadingPlaceholder).ConfigureAwait(false))
            {
                var loadResolver  = DataResolverFactory.GetResolver(path, source, Parameters, Configuration);
                var loadImageData = await loadResolver.Resolve(path, Parameters, CancellationTokenSource.Token).ConfigureAwait(false);

                using (loadImageData.Item1)
                {
                    ThrowIfCancellationRequested();

                    var loadImage = await GenerateImageAsync(path, source, loadImageData.Item1, loadImageData.Item3, TransformPlaceholders, true).ConfigureAwait(false);

                    if (loadImage != default(TImageContainer))
                    {
                        MemoryCache.Add(key, loadImageData.Item3, loadImage);
                    }

                    ThrowIfCancellationRequested();

                    if (isLoadingPlaceholder)
                    {
                        PlaceholderWeakReference = new WeakReference <TImageContainer>(loadImage);
                    }

                    await SetTargetAsync(loadImage, false).ConfigureAwait(false);
                }
            }
        }
        protected virtual async Task ShowPlaceholder(string path, string key, ImageSource source, bool isLoadingPlaceholder)
        {
            if (Parameters.Preload)
            {
                return;
            }

            if (!await TryLoadFromMemoryCacheAsync(key, false, false, isLoadingPlaceholder).ConfigureAwait(false))
            {
                try
                {
                    var customResolver = isLoadingPlaceholder ? Parameters.CustomLoadingPlaceholderDataResolver : Parameters.CustomErrorPlaceholderDataResolver;
                    var loadResolver   = customResolver ?? DataResolverFactory.GetResolver(path, source, Parameters, Configuration);
                    var loadImageData  = await loadResolver.Resolve(path, Parameters, CancellationTokenSource.Token).ConfigureAwait(false);

                    using (loadImageData.Item1)
                    {
                        ThrowIfCancellationRequested();

                        var loadImage = await GenerateImageAsync(path, source, loadImageData.Item1, loadImageData.Item3, TransformPlaceholders, true).ConfigureAwait(false);

                        if (loadImage != default(TImageContainer))
                        {
                            MemoryCache.Add(key, loadImageData.Item3, loadImage);
                        }

                        ThrowIfCancellationRequested();

                        if (isLoadingPlaceholder)
                        {
                            PlaceholderWeakReference = new WeakReference <TImageContainer>(loadImage);
                        }

                        await SetTargetAsync(loadImage, false).ConfigureAwait(false);
                    }

                    if (isLoadingPlaceholder)
                    {
                        _isLoadingPlaceholderLoaded = true;
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error("Setting placeholder failed", ex);
                }
            }
            else if (isLoadingPlaceholder)
            {
                _isLoadingPlaceholderLoaded = true;
            }
        }
示例#4
0
        public async Task RunAsync()
        {
            LoadingResult loadingResult = LoadingResult.Failed;
            bool          success       = false;

            try
            {
                if (IsCompleted || IsCancelled || ImageService.ExitTasksEarly)
                {
                    throw new OperationCanceledException();
                }

                ThrowIfCancellationRequested();

                // LOAD IMAGE
                if (!(await TryLoadFromMemoryCacheAsync().ConfigureAwait(false)))
                {
                    Logger.Debug(string.Format("Generating/retrieving image: {0}", Key));
                    var resolver = Parameters.CustomDataResolver ?? DataResolverFactory.GetResolver(Parameters.Path, Parameters.Source, Parameters, Configuration);
                    resolver = new WrappedDataResolver(resolver);
                    var imageData = await resolver.Resolve(Parameters.Path, Parameters, CancellationTokenSource.Token).ConfigureAwait(false);

                    loadingResult = imageData.Item2;

                    using (imageData.Item1)
                    {
                        ImageInformation = imageData.Item3;
                        ImageInformation.SetKey(Key, Parameters.CustomCacheKey);
                        ImageInformation.SetPath(Parameters.Path);
                        ThrowIfCancellationRequested();

                        // Preload
                        if (Parameters.Preload && Parameters.CacheType.HasValue && Parameters.CacheType.Value == CacheType.Disk)
                        {
                            if (loadingResult == LoadingResult.Internet)
                            {
                                Logger?.Debug(string.Format("DownloadOnly success: {0}", Key));
                            }

                            success = true;

                            return;
                        }

                        ThrowIfCancellationRequested();

                        var image = await GenerateImageAsync(Parameters.Path, Parameters.Source, imageData.Item1, imageData.Item3, true, false).ConfigureAwait(false);

                        ThrowIfCancellationRequested();

                        try
                        {
                            BeforeLoading(image, false);

                            if (image != default(TImageContainer) && CanUseMemoryCache)
                            {
                                MemoryCache.Add(Key, imageData.Item3, image);
                            }

                            ThrowIfCancellationRequested();

                            bool isFadeAnimationEnabled = Parameters.FadeAnimationEnabled ?? Configuration.FadeAnimationEnabled;
                            await SetTargetAsync(image, isFadeAnimationEnabled).ConfigureAwait(false);
                        }
                        finally
                        {
                            AfterLoading(image, false);
                        }
                    }
                }

                success = true;
            }
            catch (Exception ex)
            {
                if (ex is OperationCanceledException || ex is ObjectDisposedException)
                {
                    if (Configuration.VerboseLoadingCancelledLogging)
                    {
                        Logger.Debug(string.Format("Image loading cancelled: {0}", Key));
                    }
                }
                else
                {
                    if (_clearCacheOnOutOfMemory && ex is OutOfMemoryException)
                    {
                        MemoryCache.Clear();
                    }

                    Logger.Error(string.Format("Image loading failed: {0}", Key), ex);

                    if (Configuration.ExecuteCallbacksOnUIThread && Parameters?.OnError != null)
                    {
                        await MainThreadDispatcher.PostAsync(() =>
                        {
                            Parameters?.OnError?.Invoke(ex);
                        }).ConfigureAwait(false);
                    }
                    else
                    {
                        Parameters?.OnError?.Invoke(ex);
                    }

                    try
                    {
                        // Error placeholder if enabled
                        if (!Parameters.Preload && !string.IsNullOrWhiteSpace(Parameters.ErrorPlaceholderPath))
                        {
                            await ShowPlaceholder(Parameters.ErrorPlaceholderPath, KeyForErrorPlaceholder,
                                                  Parameters.ErrorPlaceholderSource, false).ConfigureAwait(false);
                        }
                    }
                    catch (Exception ex2)
                    {
                        if (!(ex2 is OperationCanceledException))
                        {
                            Logger.Error(string.Format("Image loading failed: {0}", Key), ex);
                        }
                    }
                }
            }
            finally
            {
                try
                {
                    if (CancellationTokenSource?.IsCancellationRequested == false)
                    {
                        CancellationTokenSource.Cancel();
                    }
                }
                catch (Exception)
                {
                }

                IsCompleted = true;

                using (Parameters)
                {
                    if (Configuration.ExecuteCallbacksOnUIThread && Parameters?.OnFinish != null)
                    {
                        await MainThreadDispatcher.PostAsync(() =>
                        {
                            if (success)
                            {
                                Parameters?.OnSuccess?.Invoke(ImageInformation, loadingResult);
                            }
                            Parameters?.OnFinish?.Invoke(this);
                        }).ConfigureAwait(false);
                    }
                    else
                    {
                        if (success)
                        {
                            Parameters?.OnSuccess?.Invoke(ImageInformation, loadingResult);
                        }
                        Parameters?.OnFinish?.Invoke(this);
                    }

                    ImageService.RemovePendingTask(this);
                }
            }
        }
示例#5
0
        protected virtual async Task ShowPlaceholder(string path, string key, ImageSource source, bool isLoadingPlaceholder)
        {
            if (Parameters.Preload)
            {
                return;
            }

            if (!await TryLoadFromMemoryCacheAsync(key, false, false, isLoadingPlaceholder).ConfigureAwait(false))
            {
                try
                {
                    var customResolver = isLoadingPlaceholder ? Parameters.CustomLoadingPlaceholderDataResolver : Parameters.CustomErrorPlaceholderDataResolver;
                    var loadResolver   = customResolver ?? DataResolverFactory.GetResolver(path, source, Parameters, Configuration);
                    loadResolver = new WrappedDataResolver(loadResolver);
                    Tuple <Stream, LoadingResult, ImageInformation> loadImageData;
                    bool            hasMutex = false;
                    TImageContainer loadImage;

                    try
                    {
                        hasMutex = await _placeholdersResolveLock.WaitAsync(TimeSpan.FromSeconds(3), CancellationTokenSource.Token).ConfigureAwait(false);

                        ThrowIfCancellationRequested();

                        if (await TryLoadFromMemoryCacheAsync(key, false, false, isLoadingPlaceholder).ConfigureAwait(false))
                        {
                            if (isLoadingPlaceholder)
                            {
                                _isLoadingPlaceholderLoaded = true;
                            }

                            return;
                        }

                        ThrowIfCancellationRequested();
                        loadImageData = await loadResolver.Resolve(path, Parameters, CancellationTokenSource.Token).ConfigureAwait(false);

                        ThrowIfCancellationRequested();

                        using (loadImageData.Item1)
                        {
                            loadImage = await GenerateImageAsync(path, source, loadImageData.Item1, loadImageData.Item3, TransformPlaceholders, true).ConfigureAwait(false);

                            if (loadImage != default(TImageContainer))
                            {
                                MemoryCache.Add(key, loadImageData.Item3, loadImage);
                            }
                        }
                    }
                    finally
                    {
                        if (hasMutex)
                        {
                            _placeholdersResolveLock.Release();
                        }
                    }

                    ThrowIfCancellationRequested();

                    if (isLoadingPlaceholder)
                    {
                        PlaceholderWeakReference = new WeakReference <TImageContainer>(loadImage);
                    }

                    await SetTargetAsync(loadImage, false).ConfigureAwait(false);

                    if (isLoadingPlaceholder)
                    {
                        _isLoadingPlaceholderLoaded = true;
                    }
                }
                catch (Exception ex)
                {
                    Logger.Error("Setting placeholder failed", ex);
                }
            }
            else if (isLoadingPlaceholder)
            {
                _isLoadingPlaceholderLoaded = true;
            }
        }
示例#6
0
        async Task <ISelfDisposingBitmapDrawable> PlatformGenerateImageAsync(string path, ImageSource source, Stream imageData, ImageInformation imageInformation, bool enableTransformations, bool isPlaceholder)
        {
            Bitmap bitmap = null;

            if (imageData == null)
            {
                throw new ArgumentNullException(nameof(imageData));
            }

            ThrowIfCancellationRequested();

            // First decode with inJustDecodeBounds=true to check dimensions
            var options = new BitmapFactory.Options
            {
                InJustDecodeBounds = true
            };

            try
            {
                await BitmapFactory.DecodeStreamAsync(imageData, null, options).ConfigureAwait(false);

                ThrowIfCancellationRequested();

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

                imageInformation.SetOriginalSize(options.OutWidth, options.OutHeight);
                imageInformation.SetCurrentSize(options.OutWidth, options.OutHeight);

                if (!Configuration.BitmapOptimizations || (Parameters.BitmapOptimizationsEnabled.HasValue && !Parameters.BitmapOptimizationsEnabled.Value))
                {
                    // Same quality but no transparency channel. This allows to save 50% of memory: 1 pixel=2bytes instead of 4.
                    options.InPreferredConfig        = Bitmap.Config.Rgb565;
                    options.InPreferQualityOverSpeed = false;
                }

                // CHECK IF BITMAP IS EXIF ROTATED
                int exifRotation = 0;
                if (source == ImageSource.Filepath)
                {
                    exifRotation = path.GetExifRotationDegrees();
                }

                ThrowIfCancellationRequested();

                // DOWNSAMPLE
                if (Parameters.DownSampleSize != null && (Parameters.DownSampleSize.Item1 > 0 || Parameters.DownSampleSize.Item2 > 0))
                {
                    // Calculate inSampleSize
                    int downsampleWidth  = Parameters.DownSampleSize.Item1;
                    int downsampleHeight = Parameters.DownSampleSize.Item2;

                    // if image is rotated, swap width/height
                    if (exifRotation == 90 || exifRotation == 270)
                    {
                        downsampleWidth  = Parameters.DownSampleSize.Item2;
                        downsampleHeight = Parameters.DownSampleSize.Item1;
                    }

                    if (Parameters.DownSampleUseDipUnits)
                    {
                        downsampleWidth  = downsampleWidth.DpToPixels();
                        downsampleHeight = downsampleHeight.DpToPixels();
                    }

                    options.InSampleSize = CalculateInSampleSize(options, downsampleWidth, downsampleHeight);

                    if (options.InSampleSize > 1)
                    {
                        imageInformation.SetCurrentSize(
                            (int)((double)options.OutWidth / options.InSampleSize),
                            (int)((double)options.OutHeight / options.InSampleSize));
                    }

                    // If we're running on Honeycomb or newer, try to use inBitmap
                    if (Utils.HasHoneycomb())
                    {
                        AddInBitmapOptions(options);
                    }
                }

                ThrowIfCancellationRequested();

                if (!imageData.CanSeek || imageData.Position != 0)
                {
                    if (imageData.CanSeek)
                    {
                        imageData.Position = 0;
                    }
                    else
                    {
                        var resolver = DataResolverFactory.GetResolver(path, source, Parameters, Configuration);
                        var resolved = await resolver.Resolve(path, Parameters, CancellationTokenSource.Token).ConfigureAwait(false);

                        imageData?.Dispose();
                        imageData = resolved.Item1;
                    }
                }

                ThrowIfCancellationRequested();

                bitmap = await BitmapFactory.DecodeStreamAsync(imageData, null, options).ConfigureAwait(false);
            }
            finally
            {
                imageData?.Dispose();
            }

            ThrowIfCancellationRequested();

            if (enableTransformations && Parameters.Transformations != null && Parameters.Transformations.Count > 0)
            {
                var transformations = Parameters.Transformations.ToList();

                await _decodingLock.WaitAsync().ConfigureAwait(false); // Applying transformations is both CPU and memory intensive

                try
                {
                    foreach (var transformation in transformations)
                    {
                        ThrowIfCancellationRequested();

                        var old = bitmap;

                        try
                        {
                            var bitmapHolder = transformation.Transform(new BitmapHolder(bitmap));
                            bitmap = bitmapHolder.ToNative();
                        }
                        catch (Exception ex)
                        {
                            Logger.Error(string.Format("Transformation failed: {0}", transformation.Key), ex);
                            throw;
                        }
                        finally
                        {
                            // Transformation succeeded, so garbage the source
                            if (old != null && old.Handle != IntPtr.Zero && !old.IsRecycled && old != bitmap && old.Handle != bitmap.Handle)
                            {
                                old?.Recycle();
                                old?.Dispose();
                            }
                        }
                    }
                }
                finally
                {
                    _decodingLock.Release();
                }
            }

            if (isPlaceholder)
            {
                return(new SelfDisposingBitmapDrawable(Context.Resources, bitmap));
            }

            //var imageDrawable = new SelfDisposingBitmapDrawable(Context.Resources, bitmap);
            //ISelfDisposingBitmapDrawable placeholderDrawable = null;
            //if (_loadingPlaceholderWeakReference != null && _loadingPlaceholderWeakReference.TryGetTarget(out placeholderDrawable) && placeholderDrawable != null)
            //{
            //    return new SelfDisposingTransitionDrawable(imageDrawable, placeholderDrawable as SelfDisposingBitmapDrawable);
            //}

            //return imageDrawable;
            return(new FFBitmapDrawable(Context.Resources, bitmap));
        }
        protected virtual async Task <WithLoadingResult <UIImage> > GetImageAsync(string sourcePath, ImageSource source,
                                                                                  bool isPlaceholder, Stream originalStream = null)
        {
            if (IsCancelled)
            {
                return(new WithLoadingResult <UIImage>(LoadingResult.Canceled));
            }

            LoadingResult?result = null;
            UIImage       image  = null;

            byte[]           bytes            = null;
            string           path             = sourcePath;
            ImageInformation imageInformation = null;

            try
            {
                if (originalStream != null)
                {
                    try
                    {
                        // check is stream is memorystream
                        var ms = originalStream as MemoryStream;
                        if (ms != null)
                        {
                            bytes = ms.ToArray();
                        }
                        else if (originalStream.CanSeek)
                        {
                            bytes = new byte[originalStream.Length];
                            await originalStream.ReadAsync(bytes, 0, (int)originalStream.Length, CancellationToken.Token).ConfigureAwait(false);
                        }
                        else
                        {
                            using (var ms2 = new MemoryStream())
                            {
                                await originalStream.CopyToAsync(ms2).ConfigureAwait(false);

                                bytes = ms2.ToArray();
                            }
                        }

                        path   = sourcePath;
                        result = LoadingResult.Stream;
                    }
                    finally
                    {
                        originalStream.Dispose();
                    }
                }
                else
                {
                    using (var resolver = DataResolverFactory.GetResolver(source, Parameters, DownloadCache, MainThreadDispatcher))
                    {
                        var data = await resolver.GetData(path, CancellationToken.Token).ConfigureAwait(false);

                        if (data == null)
                        {
                            return(new WithLoadingResult <UIImage>(LoadingResult.Failed));
                        }

                        image            = data.Image;
                        bytes            = data.Data;
                        path             = data.ResultIdentifier;
                        result           = data.Result;
                        imageInformation = data.ImageInformation;
                    }
                }
            }
            catch (OperationCanceledException)
            {
                Logger.Debug(string.Format("Image request for {0} got cancelled.", path));
                return(new WithLoadingResult <UIImage>(LoadingResult.Canceled));
            }
            catch (Exception ex)
            {
                var message = String.Format("Unable to retrieve image data from source: {0}", sourcePath);
                Logger.Error(message, ex);
                Parameters.OnError(ex);
                return(new WithLoadingResult <UIImage>(LoadingResult.Failed));
            }

            if (bytes == null && image == null)
            {
                if (result != null && (int)result < 0)               // it's below zero if it's an error
                {
                    return(new WithLoadingResult <UIImage>(result.Value));
                }
                else
                {
                    return(new WithLoadingResult <UIImage>(LoadingResult.Failed));
                }
            }

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

            UIImage imageIn = image;
            NSData  nsdata  = null;

            if (imageIn == null)
            {
                // Special case to handle WebP decoding on iOS
                if (sourcePath.ToLowerInvariant().EndsWith(".webp", StringComparison.InvariantCulture))
                {
                    imageIn = new WebP.Touch.WebPCodec().Decode(bytes);
                }
                else
                {
                    // nfloat scale = _imageScale >= 1 ? _imageScale : ScaleHelper.Scale;
                    nsdata = NSData.FromArray(bytes);
                    if (nsdata == null)
                    {
                        return(new WithLoadingResult <UIImage>(LoadingResult.Failed));
                    }
                }
            }

            bytes = null;

            // Setting image informations
            if (imageInformation == null)
            {
                imageInformation = new ImageInformation();
            }

            imageInformation.SetCacheKey(path == "Stream" ? GetKey() : GetKey(sourcePath));

            // We rely on ImageIO for all datasources except AssetCatalog, this way we don't generate temporary UIImage
            // furthermore we can do all the work in a thread safe way and in threadpool
            if (nsdata != null)
            {
                int downsampleWidth  = Parameters.DownSampleSize?.Item1 ?? 0;
                int downsampleHeight = Parameters.DownSampleSize?.Item2 ?? 0;

                if (Parameters.DownSampleUseDipUnits)
                {
                    downsampleWidth  = downsampleWidth.PointsToPixels();
                    downsampleHeight = downsampleHeight.PointsToPixels();
                }

                imageIn = nsdata.ToImage(new CoreGraphics.CGSize(downsampleWidth, downsampleHeight), _imageScale, NSDataExtensions.RCTResizeMode.ScaleAspectFill, imageInformation);
            }
            else if (Parameters.DownSampleSize != null && imageIn != null)
            {
                // if we already have the UIImage in memory it doesn't really matter to resize it
                // furthermore this will only happen for AssetCatalog images (yet)
            }

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

            if (Parameters.Transformations != null && Parameters.Transformations.Count > 0 &&
                (!isPlaceholder || (isPlaceholder && transformPlaceholdersEnabled)))
            {
                foreach (var transformation in Parameters.Transformations.ToList() /* to prevent concurrency issues */)
                {
                    if (IsCancelled)
                    {
                        return(new WithLoadingResult <UIImage>(LoadingResult.Canceled));
                    }

                    try
                    {
                        var old          = imageIn;
                        var bitmapHolder = transformation.Transform(new BitmapHolder(imageIn));
                        imageIn = bitmapHolder.ToNative();

                        // Transformation succeeded, so garbage the source
                        if (old != null && old != imageIn && old.Handle != imageIn.Handle)
                        {
                            old.Dispose();
                        }
                    }
                    catch (Exception ex)
                    {
                        Logger.Error("Can't apply transformation " + transformation.Key + " to image " + path, ex);
                    }
                }
            }

            return(WithLoadingResult.Encapsulate(imageIn, result.Value, imageInformation));
        }
示例#8
0
        protected virtual async Task ShowPlaceholder(string path, string key, ImageSource source, bool isLoadingPlaceholder)
        {
            if (Parameters.Preload)
            {
                return;
            }

            if (!await TryLoadFromMemoryCacheAsync(key, false, false, isLoadingPlaceholder).ConfigureAwait(false))
            {
                try
                {
                    var customResolver = isLoadingPlaceholder ? Parameters.CustomLoadingPlaceholderDataResolver : Parameters.CustomErrorPlaceholderDataResolver;
                    var loadResolver   = customResolver ?? DataResolverFactory.GetResolver(path, source, Parameters, Configuration);
                    loadResolver = new WrappedDataResolver(loadResolver);
                    DataResolverResult loadImageData;
                    TImageContainer    loadImage;

                    if (!await _placeholdersResolveLock.WaitAsync(TimeSpan.FromSeconds(10), CancellationTokenSource.Token).ConfigureAwait(false))
                    {
                        return;
                    }

                    try
                    {
                        ThrowIfCancellationRequested();

                        if (await TryLoadFromMemoryCacheAsync(key, false, false, isLoadingPlaceholder).ConfigureAwait(false))
                        {
                            if (isLoadingPlaceholder)
                            {
                                _isLoadingPlaceholderLoaded = true;
                                Parameters.OnLoadingPlaceholderSet?.Invoke();
                            }

                            return;
                        }

                        ThrowIfCancellationRequested();
                        loadImageData = await loadResolver.Resolve(path, Parameters, CancellationTokenSource.Token).ConfigureAwait(false);

                        ThrowIfCancellationRequested();

                        if (loadImageData.Stream != null)
                        {
                            using (loadImageData.Stream)
                            {
                                loadImage = await GenerateImageAsync(path, source, loadImageData.Stream, loadImageData.ImageInformation, TransformPlaceholders, true).ConfigureAwait(false);
                            }
                        }
                        else
                        {
                            loadImage = loadImageData.ImageContainer as TImageContainer;
                        }

                        if (loadImage != default(TImageContainer))
                        {
                            MemoryCache.Add(key, loadImageData.ImageInformation, loadImage);
                        }
                    }
                    finally
                    {
                        _placeholdersResolveLock.Release();
                    }

                    ThrowIfCancellationRequested();

                    if (isLoadingPlaceholder)
                    {
                        PlaceholderWeakReference = new WeakReference <TImageContainer>(loadImage);
                    }

                    if (Target != null)
                    {
                        await SetTargetAsync(loadImage, false).ConfigureAwait(false);
                    }

                    if (isLoadingPlaceholder)
                    {
                        _isLoadingPlaceholderLoaded = true;
                        Parameters.OnLoadingPlaceholderSet?.Invoke();
                    }
                }
                catch (Exception ex)
                {
                    if (ex is OperationCanceledException)
                    {
                        throw;
                    }

                    Logger.Error("Setting placeholder failed", ex);
                }
            }
            else if (isLoadingPlaceholder)
            {
                _isLoadingPlaceholderLoaded = true;
                Parameters.OnLoadingPlaceholderSet?.Invoke();
            }
        }
示例#9
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));
        }
示例#10
0
        public async Task RunAsync()
        {
            try
            {
                if (IsCompleted || IsCancelled || ImageService.ExitTasksEarly)
                {
                    throw new OperationCanceledException();
                }

                ThrowIfCancellationRequested();
                LoadingResult loadingResult = LoadingResult.Failed;

                // LOAD IMAGE
                if (!(await TryLoadFromMemoryCacheAsync().ConfigureAwait(false)))
                {
                    Logger.Debug(string.Format("Generating/retrieving image: {0}", Key));
                    var resolver  = DataResolverFactory.GetResolver(Parameters.Path, Parameters.Source, Parameters, Configuration);
                    var imageData = await resolver.Resolve(Parameters.Path, Parameters, CancellationTokenSource.Token).ConfigureAwait(false);

                    loadingResult = imageData.Item2;

                    using (imageData.Item1)
                    {
                        ImageInformation = imageData.Item3;
                        ThrowIfCancellationRequested();

                        // Preload
                        if (Parameters.Preload && Parameters.CacheType.HasValue && Parameters.CacheType.Value == CacheType.Disk)
                        {
                            if (Parameters.Source != ImageSource.Url)
                            {
                                throw new InvalidOperationException("DownloadOnly: Only Url ImageSource is supported.");
                            }

                            if (loadingResult == LoadingResult.Internet)
                            {
                                Logger?.Debug(string.Format("DownloadOnly success: {0}", Key));
                            }

                            Parameters?.OnSuccess?.Invoke(ImageInformation, loadingResult);
                            return;
                        }

                        ThrowIfCancellationRequested();

                        var image = await GenerateImageAsync(Parameters.Path, Parameters.Source, imageData.Item1, imageData.Item3, TransformPlaceholders, false).ConfigureAwait(false);

                        try
                        {
                            BeforeLoading(image, false);

                            if (image != default(TImageContainer) && CanUseMemoryCache)
                            {
                                MemoryCache.Add(Key, imageData.Item3, image);
                            }

                            ThrowIfCancellationRequested();

                            bool isFadeAnimationEnabled = Parameters.FadeAnimationEnabled ?? Configuration.FadeAnimationEnabled;
                            await SetTargetAsync(image, isFadeAnimationEnabled).ConfigureAwait(false);
                        }
                        finally
                        {
                            AfterLoading(image, false);
                        }
                    }
                }

                Parameters?.OnSuccess?.Invoke(ImageInformation, loadingResult);
            }
            catch (Exception ex)
            {
                if (_clearCacheOnOutOfMemory && ex is OutOfMemoryException)
                {
                    MemoryCache.Clear();
                }

                if (ex is OperationCanceledException)
                {
                    if (Configuration.VerboseLoadingCancelledLogging)
                    {
                        Logger.Debug(string.Format("Image loading cancelled: {0}", Key));
                    }
                }
                else
                {
                    Logger.Error(string.Format("Image loading failed: {0}", Key), ex);
                    Parameters?.OnError?.Invoke(ex);

                    try
                    {
                        // Error placeholder if enabled
                        if (!Parameters.Preload && !string.IsNullOrWhiteSpace(Parameters.ErrorPlaceholderPath))
                        {
                            await ShowPlaceholder(Parameters.ErrorPlaceholderPath, KeyForErrorPlaceholder,
                                                  Parameters.ErrorPlaceholderSource, false).ConfigureAwait(false);
                        }
                    }
                    catch (Exception ex2)
                    {
                        if (!(ex2 is OperationCanceledException))
                        {
                            Logger.Error(string.Format("Image loading failed: {0}", Key), ex);
                        }
                    }
                }
            }
            finally
            {
                using (Parameters)
                {
                    Parameters?.OnFinish?.Invoke(this);
                    ImageService.RemovePendingTask(this);
                }

                IsCompleted = true;
            }
        }
示例#11
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));
        }