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; } }
public void Initialize() { // Initializes the IFileCache _fileCacheFactory = new DiskStorageCacheFactory(new DynamicDefaultDiskStorageFactory()); _fileCache = _fileCacheFactory.Get(DiskCacheConfig.NewBuilder().Build()); // Initializes the IPooledByteBufferFactory and PooledByteStreams _poolFactory = new PoolFactory(PoolConfig.NewBuilder().Build()); _byteBufferFactory = _poolFactory.PooledByteBufferFactory; _pooledByteStreams = _poolFactory.PooledByteStreams; // Initializes the IPooledByteBuffer from an image var file = StorageFile.GetFileFromApplicationUriAsync( new Uri("ms-appx:///Assets/SplashScreen.scale-200.png")).GetAwaiter().GetResult(); using (var stream = file.OpenReadAsync().GetAwaiter().GetResult()) { _pooledByteBuffer = _byteBufferFactory.NewByteBuffer( ByteStreams.ToByteArray(stream.AsStream())); } _closeableReference = CloseableReference <IPooledByteBuffer> .of(_pooledByteBuffer); _encodedImage = new EncodedImage(_closeableReference); _stagingArea = StagingArea.Instance; _imageCacheStatsTracker = NoOpImageCacheStatsTracker.Instance; // Initializes the cache keys IList <ICacheKey> keys = new List <ICacheKey>(); keys.Add(new SimpleCacheKey("http://test.uri")); keys.Add(new SimpleCacheKey("http://tyrone.uri")); keys.Add(new SimpleCacheKey("http://ian.uri")); _cacheKey = new MultiCacheKey(keys); // Initializes the executors _isCancelled = new AtomicBoolean(false); _readPriorityExecutor = Executors.NewFixedThreadPool(1); _writePriorityExecutor = Executors.NewFixedThreadPool(1); // Initializes the disk cache _bufferedDiskCache = new BufferedDiskCache( _fileCache, _byteBufferFactory, _pooledByteStreams, _readPriorityExecutor, _writePriorityExecutor, _imageCacheStatsTracker); }
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 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> /// 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)); }
/// <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 <EncodedImage> consumer, IProducerContext producerContext) { IProducerListener listener = producerContext.Listener; string requestId = producerContext.Id; ImageRequest imageRequest = producerContext.ImageRequest; StatefulProducerRunnable <EncodedImage> cancellableProducerRunnable = new StatefulProducerRunnableImpl <EncodedImage>( consumer, listener, PRODUCER_NAME, requestId, null, null, null, (result) => { IDictionary <string, string> extraMap = new Dictionary <string, string>() { { CREATED_THUMBNAIL, (result != null).ToString() } }; return(new ReadOnlyDictionary <string, string>(extraMap)); }, null, null, (result) => { EncodedImage.CloseSafely(result); }, async() => { Uri sourceUri = imageRequest.SourceUri; StorageFile file = await StorageFile .GetFileFromApplicationUriAsync(sourceUri) .AsTask() .ConfigureAwait(false); using (var fileStream = await file.OpenReadAsync().AsTask().ConfigureAwait(false)) { byte[] bytes = await BitmapUtil .GetThumbnailAsync(fileStream) .ConfigureAwait(false); if (bytes != null) { IPooledByteBuffer pooledByteBuffer = _pooledByteBufferFactory.NewByteBuffer(bytes); return(await BuildEncodedImage(pooledByteBuffer, fileStream) .ConfigureAwait(false)); } else { return(null); } } }); producerContext.AddCallbacks( new BaseProducerContextCallbacks( () => { cancellableProducerRunnable.Cancel(); }, () => { }, () => { }, () => { })); _executor.Execute(cancellableProducerRunnable.Runnable); }
/// <summary> /// Creates a new inputstream instance over the specific buffer. /// </summary> /// <param name="pooledByteBuffer"> /// The buffer to read from. /// </param> public PooledByteBufferInputStream(IPooledByteBuffer pooledByteBuffer) { Preconditions.CheckArgument(!pooledByteBuffer.IsClosed); _pooledByteBuffer = Preconditions.CheckNotNull(pooledByteBuffer); _currentOffset = 0; }