/// <summary> /// Verification helpers /// </summary> private void VerifyState( bool isFinished, bool hasResult, CloseableReference <object> resultRef, bool hasFailed, Exception failureCause) { IDataSource <CloseableReference <object> > dataSource = _dataSource; Assert.IsTrue(isFinished == dataSource.IsFinished(), "isFinished"); Assert.IsTrue(hasResult == dataSource.HasResult(), "hasResult"); CloseableReference <object> dataSourceRef = dataSource.GetResult(); AssertReferencesSame("getResult", resultRef, dataSourceRef); CloseableReference <object> .CloseSafely(dataSourceRef); Assert.IsTrue(hasFailed == dataSource.HasFailed(), "hasFailed"); if (failureCause == NPE) { Assert.IsNotNull(dataSource.GetFailureCause(), "failure"); Assert.IsTrue(dataSource.GetFailureCause().GetType() == typeof(NullReferenceException), "failure"); } else { Assert.AreSame(failureCause, dataSource.GetFailureCause(), "failure"); } }
/// <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); } }
/// <summary> /// Creates a memory-backed encoded image from the stream. /// The stream is closed. /// </summary> protected EncodedImage GetByteBufferBackedEncodedImage(Stream inputStream, int length) { var reference = default(CloseableReference <IPooledByteBuffer>); try { if (length <= 0) { reference = CloseableReference <IPooledByteBuffer> .of( _pooledByteBufferFactory.NewByteBuffer(inputStream)); } else { reference = CloseableReference <IPooledByteBuffer> .of( _pooledByteBufferFactory.NewByteBuffer(inputStream, length)); } return(new EncodedImage(reference)); } finally { Closeables.CloseQuietly(inputStream); CloseableReference <IPooledByteBuffer> .CloseSafely(reference); } }
private void SubmitPostprocessing() { _parent._executor.Execute(() => { CloseableReference <CloseableImage> closeableImageRef; bool isLast; lock (_gate) { // instead of cloning and closing the reference, we do a more // efficient move. closeableImageRef = _sourceImageRef; isLast = _isLast; _sourceImageRef = null; _isDirty = false; } if (CloseableReference <CloseableImage> .IsValid(closeableImageRef)) { try { DoPostprocessing(closeableImageRef, isLast); } finally { CloseableReference <CloseableImage> .CloseSafely(closeableImageRef); } } ClearRunningAndStartIfDirty(); }); }
/// <summary> /// Returns a new CloseableReference to the same underlying /// SharedReference or null if invalid. The SharedReference /// ref-count is incremented. /// </summary> public EncodedImage CloneOrNull() { EncodedImage encodedImage; if (_inputStreamSupplier != null) { encodedImage = new EncodedImage(_inputStreamSupplier, StreamSize); } else { CloseableReference <IPooledByteBuffer> pooledByteBufferRef = CloseableReference <IPooledByteBuffer> .CloneOrNull(_pooledByteBufferRef); try { encodedImage = (pooledByteBufferRef == null) ? null : new EncodedImage(pooledByteBufferRef); } finally { // Close the recently created reference since it will be // cloned again in the constructor. CloseableReference <IPooledByteBuffer> .CloseSafely(pooledByteBufferRef); } } if (encodedImage != null) { encodedImage.CopyMetaDataFrom(this); } return(encodedImage); }
private void UpdateSourceImageRef( CloseableReference <CloseableImage> sourceImageRef, bool isLast) { CloseableReference <CloseableImage> oldSourceImageRef; bool shouldSubmit; lock (_gate) { if (_isClosed) { return; } oldSourceImageRef = _sourceImageRef; _sourceImageRef = CloseableReference <CloseableImage> .CloneOrNull(sourceImageRef); _isLast = isLast; _isDirty = true; shouldSubmit = SetRunningIfDirtyAndNotRunning(); } CloseableReference <CloseableImage> .CloseSafely(oldSourceImageRef); if (shouldSubmit) { SubmitPostprocessing(); } }
/// <summary> /// Closes the stream. Owned resources are released back to the pool. /// It is not allowed to call ToByteBuffer after call to this method. /// </summary> protected override void Dispose(bool disposing) { base.Dispose(disposing); CloseableReference <NativeMemoryChunk> .CloseSafely(_bufRef); _bufRef = null; _count = -1; }
/// <summary> /// Cleanup resources. /// </summary> private void Dispose(bool disposing) { lock (_poolGate) { CloseableReference <NativeMemoryChunk> .CloseSafely(_bufRef); _bufRef = null; } }
/// <summary> /// Notifies the client that the cache no longer tracks the given items. /// /// <para />This method invokes the external /// <see cref="CloseableReference{V}.Dispose"/> method, so it must not /// be called while holding the <code>_cacheGate</code> lock. /// </summary> private void MaybeClose(IList <Entry> oldEntries) { if (oldEntries != null) { foreach (Entry oldEntry in oldEntries) { CloseableReference <V> .CloseSafely(ReferenceToClose(oldEntry)); } } }
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); }
private Task <EncodedImage> GetAsync(ICacheKey key, AtomicBoolean isCancelled) { try { if (isCancelled.Value) { throw new OperationCanceledException(); } EncodedImage result = _stagingArea.Get(key); if (result != null) { Debug.WriteLine($"Found image for { key.ToString() } in staging area"); _imageCacheStatsTracker.OnStagingAreaHit(); } else { Debug.WriteLine($"Did not find image for { key.ToString() } in staging area"); _imageCacheStatsTracker.OnStagingAreaMiss(); try { IPooledByteBuffer buffer = ReadFromDiskCache(key); if (buffer == null) { return(Task.FromResult(default(EncodedImage))); } CloseableReference <IPooledByteBuffer> reference = CloseableReference <IPooledByteBuffer> .of(buffer); try { result = new EncodedImage(reference); } finally { CloseableReference <IPooledByteBuffer> .CloseSafely(reference); } } catch (Exception) { return(Task.FromResult(default(EncodedImage))); } } return(Task.FromResult(result)); } catch (Exception) { // Log failure // TODO: 3697790 Debug.WriteLine($"Failed to schedule disk-cache read for { key.ToString() }"); throw; } }
protected override void OnNewResultImpl(EncodedImage newResult, bool isLast) { // Intermediate or null results are not cached, so we just forward them if (!isLast || newResult == null) { Consumer.OnNewResult(newResult, isLast); return; } // Cache and forward the last result CloseableReference <IPooledByteBuffer> reference = newResult.GetByteBufferRef(); if (reference != null) { CloseableReference <IPooledByteBuffer> cachedResult; try { cachedResult = _memoryCache.Cache(_cacheKey, reference); } finally { CloseableReference <IPooledByteBuffer> .CloseSafely(reference); } if (cachedResult != null) { EncodedImage cachedEncodedImage; try { cachedEncodedImage = new EncodedImage(cachedResult); cachedEncodedImage.CopyMetaDataFrom(newResult); } finally { CloseableReference <IPooledByteBuffer> .CloseSafely(cachedResult); } try { Consumer.OnProgressUpdate(1f); Consumer.OnNewResult(cachedEncodedImage, true); return; } finally { EncodedImage.CloseSafely(cachedEncodedImage); } } } Consumer.OnNewResult(newResult, true); }
/// <summary> /// Notifies consumer of new result and finishes if the result /// is final. /// </summary> private void HandleResult(CloseableImage decodedImage, bool isFinal) { var decodedImageRef = CloseableReference <CloseableImage> .of(decodedImage); try { MaybeFinish(isFinal); Consumer.OnNewResult(decodedImageRef, isFinal); } finally { CloseableReference <CloseableImage> .CloseSafely(decodedImageRef); } }
/// <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); } } }
private void SetSourceImageRef(CloseableReference <CloseableImage> sourceImageRef) { CloseableReference <CloseableImage> oldSourceImageRef; lock (_gate) { if (_isClosed) { return; } oldSourceImageRef = _sourceImageRef; _sourceImageRef = CloseableReference <CloseableImage> .CloneOrNull(sourceImageRef); } CloseableReference <CloseableImage> .CloseSafely(oldSourceImageRef); }
protected override void OnNewResultImpl(EncodedImage newResult, bool isLast) { CloseableReference <IPooledByteBuffer> ret = null; try { if (EncodedImage.IsValid(newResult)) { ret = newResult.GetByteBufferRef(); } Consumer.OnNewResult(ret, isLast); } finally { CloseableReference <IPooledByteBuffer> .CloseSafely(ret); } }
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(); }
/// <summary> /// Called whenever a new value is ready to be retrieved from /// the IDataSource. /// </summary> public override async Task OnNewResultImpl( IDataSource <IList <CloseableReference <CloseableImage> > > dataSource) { if (!dataSource.IsFinished()) { return; } IList <CloseableReference <CloseableImage> > imageRefList = dataSource.GetResult(); if (imageRefList == null) { await OnNewResultListImpl(null).ConfigureAwait(false); return; } try { IList <SoftwareBitmap> bitmapList = new List <SoftwareBitmap>(imageRefList.Count); foreach (var closeableImageRef in imageRefList) { if (closeableImageRef != null && closeableImageRef.Get().GetType() == typeof(CloseableBitmap)) { bitmapList.Add(((CloseableBitmap)closeableImageRef.Get()).UnderlyingBitmap); } else { //This is so that client gets list with same length bitmapList.Add(null); } } await OnNewResultListImpl(bitmapList).ConfigureAwait(false); } finally { foreach (var closeableImageRef in imageRefList) { CloseableReference <CloseableImage> .CloseSafely(closeableImageRef); } } }
/// <summary> /// Returns whether the image is stored in the bitmap memory cache. /// </summary> /// <param name="imageRequest"> /// The imageRequest for the image to be looked up. /// </param> /// <returns> /// true if the image was found in the bitmap memory cache, /// false otherwise. /// </returns> public bool IsInBitmapMemoryCache(ImageRequest imageRequest) { if (imageRequest == null) { return(false); } ICacheKey cacheKey = _cacheKeyFactory.GetBitmapCacheKey(imageRequest, null); CloseableReference <CloseableImage> reference = _bitmapMemoryCache.Get(cacheKey); try { return(CloseableReference <CloseableImage> .IsValid(reference)); } finally { CloseableReference <CloseableImage> .CloseSafely(reference); } }
/// <summary> /// Called when the client closes its reference. /// </summary> private void ReleaseClientReference(Entry entry) { Preconditions.CheckNotNull(entry); bool isExclusiveAdded; CloseableReference <V> oldRefToClose; lock (_cacheGate) { DecreaseClientCount(entry); isExclusiveAdded = MaybeAddToExclusives(entry); oldRefToClose = ReferenceToClose(entry); } CloseableReference <V> .CloseSafely(oldRefToClose); MaybeNotifyExclusiveEntryInsertion(isExclusiveAdded ? entry : null); MaybeUpdateCacheParams(); MaybeEvictEntries(); }
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(); }
private bool Close() { CloseableReference <CloseableImage> oldSourceImageRef; lock (_gate) { if (_isClosed) { return(false); } oldSourceImageRef = _sourceImageRef; _sourceImageRef = null; _isClosed = true; } CloseableReference <CloseableImage> .CloseSafely(oldSourceImageRef); return(true); }
private async Task <EncodedImage> BuildEncodedImage( IPooledByteBuffer imageBytes, IRandomAccessStream imageStream) { using (var stream = imageStream.AsStream()) { Tuple <int, int> dimensions = await BitmapUtil .DecodeDimensionsAsync(stream) .ConfigureAwait(false); int rotationAngle = GetRotationAngle(stream); int width = dimensions != default(Tuple <int, int>) ? dimensions.Item1 : EncodedImage.UNKNOWN_WIDTH; int height = dimensions != default(Tuple <int, int>) ? dimensions.Item2 : EncodedImage.UNKNOWN_HEIGHT; EncodedImage encodedImage; CloseableReference <IPooledByteBuffer> closeableByteBuffer = CloseableReference <IPooledByteBuffer> .of(imageBytes); try { encodedImage = new EncodedImage(closeableByteBuffer); } finally { CloseableReference <IPooledByteBuffer> .CloseSafely( closeableByteBuffer); } encodedImage.Format = ImageFormat.JPEG; encodedImage.RotationAngle = rotationAngle; encodedImage.Width = width; encodedImage.Height = height; return(encodedImage); } }
/// <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); } }
/// <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); }
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); } }
private CloseableReference <CloseableImage> PostprocessInternal(CloseableImage sourceImage) { CloseableStaticBitmap staticBitmap = (CloseableStaticBitmap)sourceImage; SoftwareBitmap sourceBitmap = staticBitmap.UnderlyingBitmap; CloseableReference <SoftwareBitmap> bitmapRef = _postprocessor.Process( sourceBitmap, _parent._bitmapFactory, _parent._flexByteArrayPool); int rotationAngle = staticBitmap.RotationAngle; try { return(CloseableReference <CloseableImage> .of( new CloseableStaticBitmap(bitmapRef, sourceImage.QualityInfo, rotationAngle))); } finally { CloseableReference <SoftwareBitmap> .CloseSafely(bitmapRef); } }
private void NotifyConsumer( PooledByteBufferOutputStream pooledOutputStream, bool isFinal, IConsumer <EncodedImage> consumer) { CloseableReference <IPooledByteBuffer> result = CloseableReference <IPooledByteBuffer> .of(pooledOutputStream.ToByteBuffer()); EncodedImage encodedImage = null; try { encodedImage = new EncodedImage(result); encodedImage.ParseMetaDataAsync().Wait(); consumer.OnNewResult(encodedImage, isFinal); } finally { EncodedImage.CloseSafely(encodedImage); CloseableReference <IPooledByteBuffer> .CloseSafely(result); } }
private void UpdateInternal() { CloseableReference <CloseableImage> sourceImageRef; lock (_gate) { if (_isClosed) { return; } sourceImageRef = CloseableReference <CloseableImage> .CloneOrNull(_sourceImageRef); } try { Consumer.OnNewResult(sourceImageRef, false /* isLast */); } finally { CloseableReference <CloseableImage> .CloseSafely(sourceImageRef); } }