Exemplo n.º 1
0
        private async void LoadImage()
        {
            var decoder    = new WebP.Touch.WebPCodec();
            var httpClient = new HttpClient();

            using (var stream = await httpClient.GetStreamAsync("https://res.cloudinary.com/demo/image/upload/w_300/sample.webp").ConfigureAwait(false))
            {
                var image = decoder.Decode(stream);
                InvokeOnMainThread(() =>
                {
                    View = new UIImageView(image);
                });
            }
        }
Exemplo n.º 2
0
        private async void LoadImage()
        {
            var decoder    = new WebP.Touch.WebPCodec();
            var httpClient = new HttpClient();

            using (var stream = await httpClient.GetStreamAsync("http://www.gstatic.com/webp/gallery/1.webp").ConfigureAwait(false))
            {
                var image = decoder.Decode(stream);
                InvokeOnMainThread(() =>
                {
                    View = new UIImageView(image);
                });
            }
        }
Exemplo n.º 3
0
        protected async override Task <PImage> GenerateImageAsync(string path, ImageSource source, Stream imageData, ImageInformation imageInformation, bool enableTransformations, bool isPlaceholder)
        {
            PImage imageIn = null;

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

            ThrowIfCancellationRequested();

            try
            {
                int  downsampleWidth  = Parameters.DownSampleSize?.Item1 ?? 0;
                int  downsampleHeight = Parameters.DownSampleSize?.Item2 ?? 0;
                bool allowUpscale     = Parameters.AllowUpscale ?? Configuration.AllowUpscale;

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

                // Special case to handle WebP decoding on iOS
                if (source != ImageSource.Stream && imageInformation.Type == ImageInformation.ImageType.WEBP)
                {
#if __IOS__
                    await _webpLock.WaitAsync(CancellationTokenSource.Token).ConfigureAwait(false);

                    ThrowIfCancellationRequested();
                    try
                    {
                        var decoder = _webpDecoder as WebP.Touch.WebPCodec;
                        if (decoder == null)
                        {
                            decoder      = new WebP.Touch.WebPCodec();
                            _webpDecoder = decoder;
                        }
                        var decodedWebP = decoder.Decode(imageData);
                        //TODO Add WebP images downsampling!
                        imageIn = decodedWebP;
                    }
                    finally
                    {
                        _webpLock.Release();
                    }
#else
                    throw new NotImplementedException();
#endif
                }
                else
                {
                    var nsdata = NSData.FromStream(imageData);
                    imageIn = nsdata.ToImage(new CoreGraphics.CGSize(downsampleWidth, downsampleHeight), ScaleHelper.Scale, Configuration, Parameters, NSDataExtensions.RCTResizeMode.ScaleAspectFill, imageInformation, allowUpscale);
                }
            }
            finally
            {
                imageData.TryDispose();
            }

            ThrowIfCancellationRequested();

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

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

                ThrowIfCancellationRequested();

                try
                {
                    bool isAnimation = false;
#if __IOS__
                    if (imageIn.Images != null)
                    {
                        isAnimation = true;
                    }
#endif
                    if (!isAnimation)
                    {
                        foreach (var transformation in transformations)
                        {
                            ThrowIfCancellationRequested();

                            var old = imageIn;

                            try
                            {
                                var bitmapHolder = transformation.Transform(new BitmapHolder(imageIn), path, source, isPlaceholder, Key);
                                imageIn = bitmapHolder.ToNative();
                            }
                            catch (Exception ex)
                            {
                                Logger.Error(string.Format("Transformation failed: {0}", transformation.Key), ex);
                                throw;
                            }
                            finally
                            {
                                if (old != null && old != imageIn && old.Handle != imageIn.Handle)
                                {
                                    old.TryDispose();
                                }
                            }
                        }
                    }
                    else
                    {
                        // no animted image support for mac implemented
#if __IOS__
                        var animatedImages = imageIn.Images.ToArray();

                        for (int i = 0; i < animatedImages.Length; i++)
                        {
                            var tempImage = animatedImages[i];

                            if (tempImage.CGImage == null)
                            {
                                continue;
                            }

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

                                var old = tempImage;

                                try
                                {
                                    var bitmapHolder = transformation.Transform(new BitmapHolder(tempImage), path, source, isPlaceholder, Key);
                                    tempImage = bitmapHolder.ToNative();
                                }
                                catch (Exception ex)
                                {
                                    Logger.Error(string.Format("Transformation failed: {0}", transformation.Key), ex);
                                    throw;
                                }
                                finally
                                {
                                    if (old != null && old != tempImage && old.Handle != tempImage.Handle)
                                    {
                                        old.TryDispose();
                                    }
                                }
                            }

                            animatedImages[i] = tempImage;
                        }

                        var oldImageIn = imageIn;
                        imageIn = PImage.CreateAnimatedImage(animatedImages.Where(v => v.CGImage != null).ToArray(), imageIn.Duration);
                        oldImageIn.TryDispose();
#endif
                    }
                }
                finally
                {
                    _decodingLock.Release();
                }
            }

            return(imageIn);
        }
Exemplo n.º 4
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));
        }
        protected async override Task <UIImage> GenerateImageAsync(string path, ImageSource source, Stream imageData, ImageInformation imageInformation, bool enableTransformations, bool isPlaceholder)
        {
            UIImage imageIn = null;

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

            ThrowIfCancellationRequested();

            try
            {
                // Special case to handle WebP decoding on iOS
                if (source != ImageSource.Stream && path.ToLowerInvariant().EndsWith(".webp", StringComparison.InvariantCulture))
                {
                    imageIn = new WebP.Touch.WebPCodec().Decode(imageData);
                }
                else
                {
                    var nsdata           = NSData.FromStream(imageData);
                    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), ScaleHelper.Scale, NSDataExtensions.RCTResizeMode.ScaleAspectFill, imageInformation);
                }
            }
            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 = imageIn;

                        try
                        {
                            var bitmapHolder = transformation.Transform(new BitmapHolder(imageIn));
                            imageIn = bitmapHolder.ToNative();
                        }
                        catch (Exception ex)
                        {
                            Logger.Error(string.Format("Transformation failed: {0}", transformation.Key), ex);
                            throw;
                        }
                        finally
                        {
                            if (old != null && old != imageIn && old.Handle != imageIn.Handle)
                            {
                                old.Dispose();
                            }
                        }
                    }
                }
                finally
                {
                    _decodingLock.Release();
                }
            }

            return(imageIn);
        }
Exemplo 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;

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

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

						imageIn = tempImage.ResizeUIImage(downsampleWidth, downsampleHeight, 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 != imageIn && old.Handle != imageIn.Handle)
									old.Dispose();
							}
							catch (Exception ex)
							{
								Logger.Error("Can't apply transformation " + transformation.Key + " to image " + path, ex);
							}
						}
					}

					return imageIn;
				}).ConfigureAwait(false);

			bytes = null;

			return WithLoadingResult.Encapsulate(imageToDisplay, result.Value);
		}
Exemplo n.º 7
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));
        }
Exemplo n.º 8
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.SetKey(path == "Stream" ? GetKey() : GetKey(sourcePath), Parameters.CustomCacheKey);

			// 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), ScaleHelper.Scale, 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);
		}