/// <summary>
        /// Called whenever a new value is ready to be retrieved from
        /// the IDataSource.
        /// </summary>
        public override async Task OnNewResultImpl(
            IDataSource <CloseableReference <CloseableImage> > dataSource)
        {
            if (!dataSource.IsFinished())
            {
                return;
            }

            CloseableReference <CloseableImage> closeableImageRef = dataSource.GetResult();
            SoftwareBitmap bitmap = null;

            if (closeableImageRef != null &&
                (closeableImageRef.Get().GetType() == typeof(CloseableBitmap) ||
                 closeableImageRef.Get().GetType() == typeof(CloseableStaticBitmap)))
            {
                bitmap = ((CloseableBitmap)closeableImageRef.Get()).UnderlyingBitmap;
            }

            try
            {
                await OnNewResultImpl(bitmap).ConfigureAwait(false);
            }
            finally
            {
                CloseableReference <CloseableImage> .CloseSafely(closeableImageRef);
            }
        }
        public void TestOnBitmapCreated()
        {
            _platformBitmapFactory.AddBitmapReference(_bitmapReference.Get(), null);
            object callerContext = null;

            Assert.IsTrue(_cache._otherEntries.TryGetValue(_bitmapReference.Get(), out callerContext));
        }
Exemplo n.º 3
0
        public void TestGet()
        {
            CloseableReference <byte[]> arrayRef = _array.Get(1);

            Assert.AreSame(_array._byteArraySoftRef.Get(), arrayRef.Get());
            Assert.AreEqual(4, arrayRef.Get().Length);
            Assert.AreEqual(0, _array._semaphore.CurrentCount);
        }
 /// <summary>
 /// Reads one byte.
 /// </summary>
 public byte Read(int offset)
 {
     lock (_poolGate)
     {
         EnsureValid();
         Preconditions.CheckArgument(offset >= 0);
         Preconditions.CheckArgument(offset < _size);
         return(_bufRef.Get().Read(offset));
     }
 }
Exemplo n.º 5
0
        public void TestGet_Realloc()
        {
            CloseableReference <byte[]> arrayRef = _pool.Get(1);

            byte[] smallArray = arrayRef.Get();
            arrayRef.Dispose();

            arrayRef = _pool.Get(7);
            Assert.AreEqual(8, arrayRef.Get().Length);
            Assert.AreNotSame(smallArray, arrayRef.Get());
        }
Exemplo n.º 6
0
        /// <summary>
        /// Writes <code>count</code> bytes from the byte array
        /// <code>buffer</code> starting  at position <code>offset</code>
        /// to this stream.
        /// The underlying stream MUST be valid.
        /// </summary>
        /// <param name="buffer">
        /// The source buffer to read from.
        /// </param>
        /// <param name="offset">
        /// The start position in <code>buffer</code> from where to
        /// get bytes.
        /// </param>
        /// <param name="count">
        /// The number of bytes from <code>buffer</code> to write to
        /// this stream.
        /// </param>
        /// <exception cref="IOException">
        /// If an error occurs while writing to this stream.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// if <code>offset &lt; 0</code> or <code>count &lt; 0</code>,
        /// or if <code>offset + count</code> is bigger than the length
        /// of <code>buffer</code>.
        /// </exception>
        /// <exception cref="InvalidStreamException">
        /// If the stream is invalid.
        /// </exception>
        public override void Write(byte[] buffer, int offset, int count)
        {
            if (offset < 0 || count < 0 || offset + count > buffer.Length)
            {
                throw new ArgumentOutOfRangeException(
                          $"length={ buffer.Length }; regionStart={ offset }; regionLength={ count }");
            }

            EnsureValid();
            Realloc(_count + count);
            _bufRef.Get().Write(_count, buffer, offset, count);
            _count += count;
        }
 /// <summary>
 /// Instantiates the <see cref="NativePooledByteBuffer"/>.
 /// </summary>
 public NativePooledByteBuffer(CloseableReference <NativeMemoryChunk> bufRef, int size)
 {
     Preconditions.CheckNotNull(bufRef);
     Preconditions.CheckArgument(size >= 0 && size <= bufRef.Get().Size);
     _bufRef = bufRef.Clone();
     _size   = size;
 }
Exemplo n.º 8
0
        public void TestTrimUnsuccessful()
        {
            CloseableReference <byte[]> arrayRef = _pool.Get(7);

            _delegatePool.Trim(MemoryTrimType.OnCloseToDalvikHeapLimit);
            Assert.IsNotNull(arrayRef.Get());
        }
Exemplo n.º 9
0
        public void TestGet()
        {
            CloseableReference <byte[]> arrayRef = _pool.Get(1);

            Assert.AreEqual(0, _delegatePool._freeCounter.NumBytes);
            Assert.AreEqual(MIN_BUFFER_SIZE, arrayRef.Get().Length);
        }
Exemplo n.º 10
0
        public void TestConvert()
        {
            CloseableReference <SoftwareBitmap> reference =
                _closeableStaticBitmap.ConvertToBitmapReference();

            Assert.AreSame(reference.Get(), _bitmap);
            Assert.IsTrue(_closeableStaticBitmap.IsClosed);
        }
Exemplo n.º 11
0
        public void TestTrimUnsuccessful()
        {
            CloseableReference <byte[]> arrayRef = _array.Get(7);

            _array.Trim(MemoryTrimType.OnCloseToDalvikHeapLimit);
            Assert.AreSame(arrayRef.Get(), _array._byteArraySoftRef.Get());
            Assert.AreEqual(0, _array._semaphore.CurrentCount);
        }
 public void TestAddBitmapReference()
 {
     using (CloseableReference <SoftwareBitmap> bitmapReference = _platformBitmapFactory.CreateBitmap(50, 50))
     {
         Assert.IsNotNull(bitmapReference);
         Assert.AreEqual(1, _platformBitmapFactory.AddBitmapReferenceCallCount);
         Assert.AreEqual(bitmapReference.Get(), _platformBitmapFactory.Bitmap);
     }
 }
 /// <summary>
 /// Creates a new instance of a CloseableStaticBitmap from an existing
 /// CloseableReference. The CloseableStaticBitmap will hold a reference
 /// to the bitmap until it's closed.
 /// </summary>
 public CloseableStaticBitmap(
     CloseableReference <SoftwareBitmap> bitmapReference,
     IQualityInfo qualityInfo,
     int rotationAngle)
 {
     _bitmapReference = Preconditions.CheckNotNull(bitmapReference.CloneOrNull());
     _bitmap          = _bitmapReference.Get();
     _qualityInfo     = qualityInfo;
     _rotationAngle   = rotationAngle;
 }
        public void getSize(string uriString, IPromise promise)
        {
            if (string.IsNullOrEmpty(uriString))
            {
                promise.Reject(ErrorInvalidUri, "Cannot get the size of an image for an empty URI.");
                return;
            }

            var uri            = new Uri(uriString);
            var imagePipeline  = ImagePipelineFactory.Instance.GetImagePipeline();
            var request        = ImageRequestBuilder.NewBuilderWithSource(uri).Build();
            var dataSource     = imagePipeline.FetchDecodedImage(request, null);
            var dataSubscriber = new BaseDataSubscriberImpl <CloseableReference <CloseableImage> >(
                response =>
            {
                if (!response.IsFinished())
                {
                    return(Task.CompletedTask);
                }

                CloseableReference <CloseableImage> reference = response.GetResult();
                if (reference != null)
                {
                    try
                    {
                        CloseableImage image = reference.Get();
                        promise.Resolve(new JObject
                        {
                            { "width", image.Width },
                            { "height", image.Height },
                        });
                    }
                    catch (Exception ex)
                    {
                        promise.Reject(ErrorGetSizeFailure, ex.Message);
                    }
                    finally
                    {
                        CloseableReference <CloseableImage> .CloseSafely(reference);
                    }
                }
                else
                {
                    promise.Reject(ErrorGetSizeFailure, Invariant($"Invalid URI '{uri}' provided."));
                }

                return(Task.CompletedTask);
            },
                response =>
            {
                promise.Reject(ErrorGetSizeFailure, response.GetFailureCause());
            });

            dataSource.Subscribe(dataSubscriber, FBCore.Concurrency.CallerThreadExecutor.Instance);
        }
        /// <summary>
        /// Creates a bitmap of the specified width and height.
        /// </summary>
        /// <param name="width">The width of the bitmap.</param>
        /// <param name="height">The height of the bitmap.</param>
        /// <param name="bitmapConfig">
        /// The bitmap config used to create the bitmap.
        /// </param>
        /// <param name="callerContext">
        /// The Tag to track who create the bitmap.
        /// </param>
        /// <returns>A reference to the bitmap.</returns>
        /// <exception cref="OutOfMemoryException">
        /// If the bitmap cannot be allocated.
        /// </exception>
        public CloseableReference <SoftwareBitmap> CreateBitmap(
            int width,
            int height,
            BitmapPixelFormat bitmapConfig,
            object callerContext)
        {
            CloseableReference <SoftwareBitmap> reference =
                CreateBitmapInternal(width, height, bitmapConfig);

            AddBitmapReference(reference.Get(), callerContext);
            return(reference);
        }
Exemplo n.º 16
0
            private void DoPostprocessing(
                CloseableReference <CloseableImage> sourceImageRef,
                bool isLast)
            {
                Preconditions.CheckArgument(CloseableReference <CloseableImage> .IsValid(sourceImageRef));
                if (!ShouldPostprocess(sourceImageRef.Get()))
                {
                    MaybeNotifyOnNewResult(sourceImageRef, isLast);
                    return;
                }

                _listener.OnProducerStart(_requestId, NAME);
                CloseableReference <CloseableImage> destImageRef = null;

                try
                {
                    try
                    {
                        destImageRef = PostprocessInternal(sourceImageRef.Get());
                    }
                    catch (Exception e)
                    {
                        _listener.OnProducerFinishWithFailure(
                            _requestId, NAME, e, GetExtraMap(_listener, _requestId, _postprocessor));

                        MaybeNotifyOnFailure(e);
                        return;
                    }

                    _listener.OnProducerFinishWithSuccess(
                        _requestId, NAME, GetExtraMap(_listener, _requestId, _postprocessor));

                    MaybeNotifyOnNewResult(destImageRef, isLast);
                }
                finally
                {
                    CloseableReference <CloseableImage> .CloseSafely(destImageRef);
                }
            }
Exemplo n.º 17
0
 private void AssertReferencesSame <T>(
     string errorMessage,
     CloseableReference <T> expectedRef,
     CloseableReference <T> actualRef)
 {
     if (expectedRef == null)
     {
         Assert.IsNull(actualRef, errorMessage);
     }
     else
     {
         Assert.AreSame(expectedRef.Get(), actualRef.Get(), errorMessage);
     }
 }
Exemplo n.º 18
0
        /// <summary>
        /// Clients should override this method if the post-processing cannot be
        /// done in place. If the post-processing can be done in place, clients
        /// should override the
        /// Process(byte[], int, int, BitmapPixelFormat, BitmapAlphaMode) method.
        ///
        /// <para />The provided destination bitmap is of the same size as the
        /// source bitmap. There are no guarantees on the initial content of the
        /// destination bitmap, so the implementation has to make sure that it
        /// properly populates it.
        ///
        /// <para />The source bitmap must not be modified as it may be shared
        /// by the other clients. The implementation must use the provided
        /// destination bitmap as its output.
        /// </summary>
        /// <param name="destBitmap">
        /// The destination bitmap to be used as output.
        /// </param>
        /// <param name="sourceBitmap">
        /// The source bitmap to be used as input.
        /// </param>
        /// <param name="flexByteArrayPool">
        /// The memory pool used for post process.
        /// </param>
        public unsafe virtual void Process(
            SoftwareBitmap destBitmap,
            SoftwareBitmap sourceBitmap,
            FlexByteArrayPool flexByteArrayPool)
        {
            Preconditions.CheckArgument(sourceBitmap.BitmapPixelFormat == destBitmap.BitmapPixelFormat);
            Preconditions.CheckArgument(!destBitmap.IsReadOnly);
            Preconditions.CheckArgument(destBitmap.PixelWidth == sourceBitmap.PixelWidth);
            Preconditions.CheckArgument(destBitmap.PixelHeight == sourceBitmap.PixelHeight);
            sourceBitmap.CopyTo(destBitmap);

            using (var buffer = destBitmap.LockBuffer(BitmapBufferAccessMode.Write))
                using (var reference = buffer.CreateReference())
                {
                    // Get input data
                    byte *srcData;
                    uint  capacity;
                    ((IMemoryBufferByteAccess)reference).GetBuffer(out srcData, out capacity);

                    // Allocate temp buffer for processing
                    byte[] desData = default(byte[]);
                    CloseableReference <byte[]> bytesArrayRef = default(CloseableReference <byte[]>);

                    try
                    {
                        bytesArrayRef = flexByteArrayPool.Get((int)capacity);
                        desData       = bytesArrayRef.Get();
                    }
                    catch (Exception)
                    {
                        // Allocates the byte array since the pool couldn't provide one
                        desData = new byte[capacity];
                    }

                    try
                    {
                        // Process output data
                        Marshal.Copy((IntPtr)srcData, desData, 0, (int)capacity);
                        Process(desData, destBitmap.PixelWidth, destBitmap.PixelHeight,
                                destBitmap.BitmapPixelFormat, destBitmap.BitmapAlphaMode);

                        Marshal.Copy(desData, 0, (IntPtr)srcData, (int)capacity);
                    }
                    finally
                    {
                        CloseableReference <byte[]> .CloseSafely(bytesArrayRef);
                    }
                }
        }
Exemplo n.º 19
0
        public void TestFetchDecodedImageSuccess()
        {
            var completion     = new ManualResetEvent(false);
            var dataSource     = _imagePipeline.FetchDecodedImage(ImageRequest.FromUri(IMAGE_URL), null);
            var dataSubscriber = new BaseDataSubscriberImpl <CloseableReference <CloseableImage> >(
                async response =>
            {
                CloseableReference <CloseableImage> reference = response.GetResult();
                if (reference != null)
                {
                    SoftwareBitmap bitmap = ((CloseableBitmap)reference.Get()).UnderlyingBitmap;

                    try
                    {
                        Assert.IsTrue(bitmap.PixelWidth != 0);
                        Assert.IsTrue(bitmap.PixelHeight != 0);
                        Assert.IsTrue(_imagePipeline.IsInBitmapMemoryCache(ImageRequest.FromUri(IMAGE_URL)));
                        Assert.IsTrue(await _imagePipeline.IsInDiskCacheAsync(IMAGE_URL).ConfigureAwait(false));
                    }
                    catch (Exception)
                    {
                        Assert.Fail();
                    }
                    finally
                    {
                        CloseableReference <CloseableImage> .CloseSafely(reference);
                        completion.Set();
                    }
                }
                else
                {
                    Assert.Fail();
                    completion.Set();
                }
            },
                response =>
            {
                Assert.Fail();
                completion.Set();
            });

            dataSource.Subscribe(dataSubscriber, CallerThreadExecutor.Instance);
            completion.WaitOne();
        }
Exemplo n.º 20
0
        public void TestFetchEncodedImageSuccess()
        {
            var completion     = new ManualResetEvent(false);
            var dataSource     = _imagePipeline.FetchEncodedImage(ImageRequest.FromUri(IMAGE_URL), null);
            var dataSubscriber = new BaseDataSubscriberImpl <CloseableReference <IPooledByteBuffer> >(
                async response =>
            {
                CloseableReference <IPooledByteBuffer> reference = response.GetResult();
                if (reference != null)
                {
                    IPooledByteBuffer inputStream = reference.Get();

                    try
                    {
                        Assert.IsTrue(inputStream.Size != 0);
                        Assert.IsTrue(await _imagePipeline.IsInDiskCacheAsync(IMAGE_URL).ConfigureAwait(false));
                    }
                    catch (Exception)
                    {
                        Assert.Fail();
                    }
                    finally
                    {
                        CloseableReference <IPooledByteBuffer> .CloseSafely(reference);
                        completion.Set();
                    }
                }
                else
                {
                    Assert.Fail();
                    completion.Set();
                }
            },
                response =>
            {
                Assert.Fail();
                completion.Set();
            });

            dataSource.Subscribe(dataSubscriber, CallerThreadExecutor.Instance);
            completion.WaitOne();
        }
Exemplo n.º 21
0
        /// <summary>
        /// Removes key-value from the StagingArea. Both key and value must match.
        /// </summary>
        /// <param name="key">The cache key.</param>
        /// <param name="encodedImage">Value corresponding to key.</param>
        /// <returns>true if item was removed.</returns>
        public bool Remove(ICacheKey key, EncodedImage encodedImage)
        {
            lock (_mapGate)
            {
                Preconditions.CheckNotNull(key);
                Preconditions.CheckNotNull(encodedImage);
                Preconditions.CheckArgument(EncodedImage.IsValid(encodedImage));

                EncodedImage oldValue = default(EncodedImage);
                if (!_map.TryGetValue(key, out oldValue))
                {
                    return(false);
                }

                CloseableReference <IPooledByteBuffer> oldReference = oldValue.GetByteBufferRef();
                CloseableReference <IPooledByteBuffer> reference    = encodedImage.GetByteBufferRef();

                try
                {
                    if (oldReference == null || reference == null || oldReference.Get() != reference.Get())
                    {
                        return(false);
                    }

                    _map.Remove(key);
                }
                finally
                {
                    CloseableReference <IPooledByteBuffer> .CloseSafely(reference);

                    CloseableReference <IPooledByteBuffer> .CloseSafely(oldReference);

                    EncodedImage.CloseSafely(oldValue);
                }

#if DEBUG_STAGING_AREA
                LogStats();
#endif // DEBUG_STAGING_AREA
                return(true);
            }
        }
Exemplo n.º 22
0
        /// <summary>
        /// Returns true if the image is a JPEG and its data is already complete
        /// at the specified length, false otherwise.
        /// </summary>
        public bool IsCompleteAt(int length)
        {
            if (Format != ImageFormat.JPEG)
            {
                return(true);
            }

            // If the image is backed by FileStream return true since they will
            // always be complete.
            if (_inputStreamSupplier != null)
            {
                return(true);
            }

            // The image should be backed by a ByteBuffer
            Preconditions.CheckNotNull(_pooledByteBufferRef);
            IPooledByteBuffer buf = _pooledByteBufferRef.Get();

            return((buf.Read(length - 2) == JfifUtil.MARKER_FIRST_BYTE) &&
                   (buf.Read(length - 1) == JfifUtil.MARKER_EOI));
        }
Exemplo n.º 23
0
        /// <summary>
        /// Clients should override this method only if the post-processed
        /// bitmap has to be of a different size than the source bitmap.
        /// If the post-processed bitmap is of the same size, clients should
        /// override one of the other two methods.
        ///
        /// <para />The source bitmap must not be modified as it may be shared
        /// by the other clients. The implementation must create a new bitmap
        /// that is safe to be modified and return a reference to it.
        /// Clients should use <code>bitmapFactory</code> to create a new bitmap.
        /// </summary>
        /// <param name="sourceBitmap">The source bitmap.</param>
        /// <param name="bitmapFactory">
        /// The factory to create a destination bitmap.
        /// </param>
        /// <param name="flexByteArrayPool">
        /// The memory pool used for post process.
        /// </param>
        /// <returns>
        /// A reference to the newly created bitmap.
        /// </returns>
        public CloseableReference <SoftwareBitmap> Process(
            SoftwareBitmap sourceBitmap,
            PlatformBitmapFactory bitmapFactory,
            FlexByteArrayPool flexByteArrayPool)
        {
            CloseableReference <SoftwareBitmap> destBitmapRef =
                bitmapFactory.CreateBitmapInternal(
                    sourceBitmap.PixelWidth,
                    sourceBitmap.PixelHeight,
                    sourceBitmap.BitmapPixelFormat);

            try
            {
                Process(destBitmapRef.Get(), sourceBitmap, flexByteArrayPool);
                return(CloseableReference <SoftwareBitmap> .CloneOrNull(destBitmapRef));
            }
            finally
            {
                CloseableReference <SoftwareBitmap> .CloseSafely(destBitmapRef);
            }
        }
        /// <summary>
        /// Caches the given key-value pair.
        ///
        /// <para />Important: the client should use the returned reference
        /// instead of the original one. It is the caller's responsibility
        /// to close the returned reference once not needed anymore.
        /// </summary>
        /// <returns>
        /// The new reference to be used, null if the value cannot be cached.
        /// </returns>
        public CloseableReference <V> Cache(
            K key,
            CloseableReference <V> valueRef,
            IEntryStateObserver <K> observer)
        {
            Preconditions.CheckNotNull(key);
            Preconditions.CheckNotNull(valueRef);

            MaybeUpdateCacheParams();

            Entry oldExclusive;
            CloseableReference <V> oldRefToClose = null;
            CloseableReference <V> clientRef     = null;

            lock (_cacheGate)
            {
                // Remove the old item (if any) as it is stale now
                oldExclusive = _exclusiveEntries.Remove(key);
                Entry oldEntry = _cachedEntries.Remove(key);
                if (oldEntry != null)
                {
                    MakeOrphan(oldEntry);
                    oldRefToClose = ReferenceToClose(oldEntry);
                }

                if (CanCacheNewValue(valueRef.Get()))
                {
                    Entry newEntry = Entry.of(key, valueRef, observer);
                    _cachedEntries.Put(key, newEntry);
                    clientRef = NewClientReference(newEntry);
                }
            }

            CloseableReference <V> .CloseSafely(oldRefToClose);

            MaybeNotifyExclusiveEntryRemoval(oldExclusive);

            MaybeEvictEntries();
            return(clientRef);
        }
Exemplo n.º 25
0
        /// <summary>
        /// Returns a stream from the internal stream supplier if it's not null.
        /// Otherwise returns an stream for the internal buffer reference if
        /// valid and null otherwise.
        ///
        /// <para />The caller has to close the stream after using it.
        /// </summary>
        public Stream GetInputStream()
        {
            if (_inputStreamSupplier != null)
            {
                return(_inputStreamSupplier.Get());
            }

            CloseableReference <IPooledByteBuffer> pooledByteBufferRef =
                CloseableReference <IPooledByteBuffer> .CloneOrNull(_pooledByteBufferRef);

            if (pooledByteBufferRef != null)
            {
                try
                {
                    return(new PooledByteBufferInputStream(pooledByteBufferRef.Get()));
                }
                finally
                {
                    CloseableReference <IPooledByteBuffer> .CloseSafely(pooledByteBufferRef);
                }
            }

            return(null);
        }
        /// <summary>
        /// Fetches the encoded BitmapImage.
        /// </summary>
        /// <param name="uri">The image uri.</param>
        /// <param name="token">The cancellation token.</param>
        /// <param name="dispatcher">
        /// The current view's dispatcher, used to create BitmapImage.
        /// </param>
        /// <returns>The encoded BitmapImage.</returns>
        /// <exception cref="IOException">
        /// If the image uri can't be found.
        /// </exception>
        public Task <BitmapImage> FetchEncodedBitmapImageAsync(
            Uri uri,
            CancellationToken token   = default(CancellationToken),
            CoreDispatcher dispatcher = null)
        {
            var taskCompletionSource = new TaskCompletionSource <BitmapImage>();
            var dataSource           = FetchEncodedImage(ImageRequest.FromUri(uri), null);
            var dataSubscriber       = new BaseDataSubscriberImpl <CloseableReference <IPooledByteBuffer> >(
                async response =>
            {
                CloseableReference <IPooledByteBuffer> reference = response.GetResult();
                if (reference != null)
                {
                    //----------------------------------------------------------------------
                    // Phong Cao: InMemoryRandomAccessStream can't write anything < 16KB.
                    // http://stackoverflow.com/questions/25928408/inmemoryrandomaccessstream-incorrect-behavior
                    //----------------------------------------------------------------------
                    IPooledByteBuffer inputStream = reference.Get();
                    int supportedSize             = Math.Max(16 * ByteConstants.KB, inputStream.Size);

                    // Allocate temp buffer for stream convert
                    byte[] bytesArray = default(byte[]);
                    CloseableReference <byte[]> bytesArrayRef = default(CloseableReference <byte[]>);

                    try
                    {
                        bytesArrayRef = _flexByteArrayPool.Get(supportedSize);
                        bytesArray    = bytesArrayRef.Get();
                    }
                    catch (Exception)
                    {
                        // Allocates the byte array since the pool couldn't provide one
                        bytesArray = new byte[supportedSize];
                    }

                    try
                    {
                        inputStream.Read(0, bytesArray, 0, inputStream.Size);
                        await DispatcherHelpers.CallOnDispatcherAsync(async() =>
                        {
                            using (var outStream = new InMemoryRandomAccessStream())
                                using (var writeStream = outStream.AsStreamForWrite())
                                {
                                    await writeStream.WriteAsync(bytesArray, 0, supportedSize);
                                    outStream.Seek(0);
                                    BitmapImage bitmapImage = new BitmapImage();
                                    await bitmapImage.SetSourceAsync(outStream).AsTask().ConfigureAwait(false);
                                    taskCompletionSource.SetResult(bitmapImage);
                                }
                        },
                                                                      dispatcher).ConfigureAwait(false);
                    }
                    catch (Exception e)
                    {
                        taskCompletionSource.SetException(e);
                    }
                    finally
                    {
                        CloseableReference <IPooledByteBuffer> .CloseSafely(reference);
                        CloseableReference <byte[]> .CloseSafely(bytesArrayRef);
                    }
                }
                else
                {
                    taskCompletionSource.SetResult(null);
                }
            },
                response =>
            {
                taskCompletionSource.SetException(response.GetFailureCause());
            });

            dataSource.Subscribe(dataSubscriber, _handleResultExecutor);
            token.Register(() =>
            {
                dataSource.Close();
                taskCompletionSource.TrySetCanceled();
            });

            return(taskCompletionSource.Task);
        }
        /// <summary>
        /// Start producing results for given context.
        /// Provided consumer is notified whenever progress is made
        /// (new value is ready or error occurs).
        /// </summary>
        public void ProduceResults(
            IConsumer <CloseableReference <CloseableImage> > consumer,
            IProducerContext producerContext)
        {
            IProducerListener listener  = producerContext.Listener;
            string            requestId = producerContext.Id;

            listener.OnProducerStart(requestId, ProducerName);
            ImageRequest imageRequest             = producerContext.ImageRequest;
            object       callerContext            = producerContext.CallerContext;
            ICacheKey    cacheKey                 = _cacheKeyFactory.GetBitmapCacheKey(imageRequest, callerContext);
            IDictionary <string, string> extraMap = default(IDictionary <string, string>);

            CloseableReference <CloseableImage> cachedReference = _memoryCache.Get(cacheKey);

            if (cachedReference != null)
            {
                bool isFinal = cachedReference.Get().QualityInfo.IsOfFullQuality;
                if (isFinal)
                {
                    extraMap = new Dictionary <string, string>()
                    {
                        { VALUE_FOUND, "true" }
                    };

                    listener.OnProducerFinishWithSuccess(
                        requestId,
                        ProducerName,
                        listener.RequiresExtraMap(requestId) ?
                        new ReadOnlyDictionary <string, string>(extraMap) :
                        null);

                    consumer.OnProgressUpdate(1f);
                }

                consumer.OnNewResult(cachedReference, isFinal);
                cachedReference.Dispose();
                if (isFinal)
                {
                    return;
                }
            }

            if (producerContext.LowestPermittedRequestLevel >= RequestLevel.BITMAP_MEMORY_CACHE)
            {
                extraMap = new Dictionary <string, string>()
                {
                    { VALUE_FOUND, "false" }
                };

                listener.OnProducerFinishWithSuccess(
                    requestId,
                    ProducerName,
                    listener.RequiresExtraMap(requestId) ?
                    new ReadOnlyDictionary <string, string>(extraMap) :
                    null);

                consumer.OnNewResult(null, true);
                return;
            }

            extraMap = new Dictionary <string, string>()
            {
                { VALUE_FOUND, "false" }
            };

            IConsumer <CloseableReference <CloseableImage> > wrappedConsumer =
                WrapConsumer(consumer, cacheKey);

            listener.OnProducerFinishWithSuccess(
                requestId,
                ProducerName,
                listener.RequiresExtraMap(requestId) ?
                new ReadOnlyDictionary <string, string>(extraMap) :
                null);

            _inputProducer.ProduceResults(wrappedConsumer, producerContext);
        }
            protected override void OnNewResultImpl(
                CloseableReference <CloseableImage> newResult,
                bool isLast)
            {
                // Ignore invalid intermediate results and forward the null result if last
                if (newResult == null)
                {
                    if (isLast)
                    {
                        Consumer.OnNewResult(null, true);
                    }

                    return;
                }

                // Stateful results cannot be cached and are just forwarded
                if (newResult.Get().Stateful)
                {
                    Consumer.OnNewResult(newResult, isLast);
                    return;
                }

                // If the intermediate result is not of a better quality than the cached
                // result, forward the already cached result and don't cache the new result.
                if (!isLast)
                {
                    CloseableReference <CloseableImage> currentCachedResult = _memoryCache.Get(_cacheKey);
                    if (currentCachedResult != null)
                    {
                        try
                        {
                            IQualityInfo newInfo    = newResult.Get().QualityInfo;
                            IQualityInfo cachedInfo = currentCachedResult.Get().QualityInfo;
                            if (cachedInfo.IsOfFullQuality || cachedInfo.Quality >= newInfo.Quality)
                            {
                                Consumer.OnNewResult(currentCachedResult, false);
                                return;
                            }
                        }
                        finally
                        {
                            CloseableReference <CloseableImage> .CloseSafely(currentCachedResult);
                        }
                    }
                }

                // Cache and forward the new result
                CloseableReference <CloseableImage> newCachedResult =
                    _memoryCache.Cache(_cacheKey, newResult);

                try
                {
                    if (isLast)
                    {
                        Consumer.OnProgressUpdate(1f);
                    }

                    Consumer.OnNewResult(
                        (newCachedResult != null) ? newCachedResult : newResult, isLast);
                }
                finally
                {
                    CloseableReference <CloseableImage> .CloseSafely(newCachedResult);
                }
            }