public void TestCloneOrNull() { EncodedImage encodedImage = new EncodedImage(_byteBufferRef); encodedImage.Format = ImageFormat.JPEG; encodedImage.RotationAngle = 0; encodedImage.Width = 1; encodedImage.Height = 2; encodedImage.SampleSize = 4; EncodedImage encodedImage2 = EncodedImage.CloneOrNull(encodedImage); Assert.AreEqual(3, _byteBufferRef.GetUnderlyingReferenceTestOnly().GetRefCountTestOnly()); Assert.AreSame( encodedImage.GetByteBufferRef().GetUnderlyingReferenceTestOnly(), encodedImage2.GetByteBufferRef().GetUnderlyingReferenceTestOnly()); Assert.AreEqual(encodedImage.Format, encodedImage2.Format); Assert.AreEqual(encodedImage.RotationAngle, encodedImage2.RotationAngle); Assert.AreEqual(encodedImage.Height, encodedImage2.Height); Assert.AreEqual(encodedImage.Width, encodedImage2.Width); Assert.AreEqual(encodedImage.SampleSize, encodedImage2.SampleSize); encodedImage = new EncodedImage(_inputStreamSupplier, 100); encodedImage.Format = ImageFormat.JPEG; encodedImage.RotationAngle = 0; encodedImage.Width = 1; encodedImage.Height = 2; encodedImage2 = EncodedImage.CloneOrNull(encodedImage); Assert.AreSame(encodedImage.GetInputStream(), encodedImage2.GetInputStream()); Assert.AreEqual(encodedImage2.Size, encodedImage.Size); }
/// <summary> /// Writes to disk cache. /// </summary> private void WriteToDiskCache(ICacheKey key, EncodedImage encodedImage) { Debug.WriteLine($"About to write to disk-cache for key { key.ToString() }"); try { _fileCache.Insert(key, new WriterCallbackImpl(os => { _pooledByteStreams.Copy(encodedImage.GetInputStream(), os); })); Debug.WriteLine($"Successful disk-cache write for key { key.ToString() }"); } catch (IOException) { // Log failure // TODO: 3697790 Debug.WriteLine($"Failed to write to disk-cache for key { key.ToString() }"); } }
/// <summary> /// Decodes image. /// </summary> /// <param name="encodedImage"> /// Input image (encoded bytes plus meta data). /// </param> /// <param name="length"> /// If image type supports decoding incomplete image then /// determines where the image data should be cut for decoding. /// </param> /// <param name="qualityInfo"> /// Quality information for the image. /// </param> /// <param name="options"> /// Options that cange decode behavior. /// </param> public Task <CloseableImage> DecodeImageAsync( EncodedImage encodedImage, int length, IQualityInfo qualityInfo, ImageDecodeOptions options) { ImageFormat imageFormat = encodedImage.Format; if (imageFormat == ImageFormat.UNINITIALIZED || imageFormat == ImageFormat.UNKNOWN) { imageFormat = ImageFormatChecker.GetImageFormat_WrapIOException( encodedImage.GetInputStream()); encodedImage.Format = imageFormat; } switch (imageFormat) { case ImageFormat.UNKNOWN: throw new ArgumentException("unknown image format"); case ImageFormat.JPEG: return(DecodeJpegAsync(encodedImage, length, qualityInfo) .ContinueWith( task => ((CloseableImage)task.Result), TaskContinuationOptions.ExecuteSynchronously)); case ImageFormat.GIF: return(DecodeGifAsync(encodedImage, options)); case ImageFormat.WEBP_ANIMATED: return(DecodeAnimatedWebpAsync(encodedImage, options)); default: return(DecodeStaticImageAsync(encodedImage) .ContinueWith( task => ((CloseableImage)task.Result), TaskContinuationOptions.ExecuteSynchronously)); } }
/// <summary> /// If this is the first time calling this method, the buffer will /// be checked to make sure it starts with SOI marker (0xffd8). /// If the image has been identified as a non-JPEG, data will be /// ignored and false will be returned immediately on all /// subsequent calls. /// /// This object maintains state of the position of the last read /// byte. On repeated calls to this method, it will continue from /// where it left off. /// </summary> /// <param name="encodedImage"> /// Next set of bytes received by the caller. /// </param> /// <returns>true if a new full scan has been found.</returns> public bool ParseMoreData(EncodedImage encodedImage) { if (_parserState == NOT_A_JPEG) { return(false); } int dataBufferSize = encodedImage.Size; // Is there any new data to parse? // _bytesParsed might be greater than size of dataBuffer - that // happens when we skip more data than is available to read // inside DoParseMoreData method. if (dataBufferSize <= _bytesParsed) { return(false); } Stream bufferedDataStream = new PooledByteArrayBufferedInputStream( encodedImage.GetInputStream(), _byteArrayPool.Get(BUFFER_SIZE), _byteArrayPool); try { StreamUtil.Skip(bufferedDataStream, _bytesParsed); return(DoParseMoreData(encodedImage, bufferedDataStream)); } catch (IOException) { // Does not happen - streams returned by IPooledByteBuffers // do not throw IOExceptions. throw; } finally { Closeables.CloseQuietly(bufferedDataStream); } }
/// <summary> /// Creates a bitmap from encoded bytes. /// Supports JPEG but callers should use DecodeJPEGFromEncodedImage /// for partial JPEGs. /// </summary> /// <param name="encodedImage"> /// The reference to the encoded image with the reference to the /// encoded bytes. /// </param> /// <param name="bitmapConfig"> /// The <see cref="BitmapPixelFormat"/> used to create the decoded /// SoftwareBitmap. /// </param> /// <returns>The bitmap.</returns> /// <exception cref="OutOfMemoryException"> /// If the Bitmap cannot be allocated. /// </exception> public Task <CloseableReference <SoftwareBitmap> > DecodeFromEncodedImageAsync( EncodedImage encodedImage, BitmapPixelFormat bitmapConfig) { Stream inputStream = encodedImage.GetInputStream(); Preconditions.CheckNotNull(inputStream); return(_executor.Execute(async() => { BitmapDecoder decoder = await BitmapDecoder.CreateAsync( inputStream.AsRandomAccessStream()) .AsTask() .ConfigureAwait(false); SoftwareBitmap bitmap = await decoder .GetSoftwareBitmapAsync(bitmapConfig, BitmapAlphaMode.Premultiplied) .AsTask() .ConfigureAwait(false); return CloseableReference <SoftwareBitmap> .of(bitmap); }) .Unwrap()); }
/// <summary> /// Creates a bitmap from encoded JPEG bytes. /// Supports a partial JPEG image. /// </summary> /// <param name="encodedImage"> /// The reference to the encoded image with the reference to the /// encoded bytes. /// </param> /// <param name="bitmapConfig"> /// The <see cref="BitmapPixelFormat"/> used to create the decoded /// SoftwareBitmap. /// </param> /// <param name="length"> /// The number of encoded bytes in the buffer. /// </param> /// <returns>The bitmap.</returns> /// <exception cref="OutOfMemoryException"> /// If the Bitmap cannot be allocated. /// </exception> public Task <CloseableReference <SoftwareBitmap> > DecodeJPEGFromEncodedImageAsync( EncodedImage encodedImage, BitmapPixelFormat bitmapConfig, int length) { return(_executor.Execute(async() => { bool isJpegComplete = encodedImage.IsCompleteAt(length); Stream jpegDataStream = encodedImage.GetInputStream(); // At this point the Stream from the encoded image should not // be null since in the pipeline,this comes from a call stack where // this was checked before. Also this method needs the Stream to // decode the image so this can't be null. Preconditions.CheckNotNull(jpegDataStream); if (encodedImage.Size > length) { jpegDataStream = new LimitedInputStream(jpegDataStream, length); } if (!isJpegComplete) { jpegDataStream = new TailAppendingInputStream(jpegDataStream, EOI_TAIL); } BitmapDecoder decoder = await BitmapDecoder.CreateAsync( jpegDataStream.AsRandomAccessStream()) .AsTask() .ConfigureAwait(false); SoftwareBitmap bitmap = await decoder .GetSoftwareBitmapAsync(bitmapConfig, BitmapAlphaMode.Premultiplied) .AsTask() .ConfigureAwait(false); return CloseableReference <SoftwareBitmap> .of(bitmap); }) .Unwrap()); }
/// <summary> /// Decodes gif into CloseableImage. /// </summary> /// <param name="encodedImage"> /// Input image (encoded bytes plus meta data). /// </param> /// <param name="options">Decode options.</param> /// <returns>A CloseableImage.</returns> public Task <CloseableImage> DecodeGifAsync( EncodedImage encodedImage, ImageDecodeOptions options) { Stream inputStream = encodedImage.GetInputStream(); if (inputStream == null) { return(Task.FromResult(default(CloseableImage))); } try { // Phong Cao: always forceStaticImage return(DecodeStaticImageAsync(encodedImage) .ContinueWith( task => ((CloseableImage)task.Result), TaskContinuationOptions.ExecuteSynchronously)); } finally { Closeables.CloseQuietly(inputStream); } }
public void TestInputStream() { EncodedImage encodedImage = new EncodedImage(_inputStreamSupplier); Assert.AreSame(encodedImage.GetInputStream(), _inputStreamSupplier.Get()); }