/* * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.imagepipeline.decoder; import javax.annotation.Nullable; import android.graphics.Bitmap; import com.facebook.common.references.CloseableReference; import com.facebook.imageformat.ImageFormat; import com.facebook.imageformat.ImageFormatChecker; import com.facebook.imagepipeline.animated.factory.AnimatedImageFactory; import com.facebook.imagepipeline.bitmaps.PlatformBitmapFactory; import com.facebook.imagepipeline.common.ImageDecodeOptions; import com.facebook.imagepipeline.image.CloseableImage; import com.facebook.imagepipeline.image.CloseableStaticBitmap; import com.facebook.imagepipeline.image.ImmutableQualityInfo; import com.facebook.imagepipeline.image.QualityInfo; import com.facebook.imagepipeline.memory.PooledByteBuffer; /** * Decodes images. * * <p> ImageDecoder implements image type recognition and passes decode requests to * specialized methods implemented by subclasses. * * On dalvik, it produces 'pinned' purgeable bitmaps. * * <p> Pinned purgeables behave as specified in * {@link android.graphics.BitmapFactory.Options#inPurgeable} with one modification. The bitmap is * 'pinned' so is never purged. * * <p> For API 21 and higher, this class produces standard Bitmaps, as purgeability is not supported * on the most recent versions of Android. */ public class ImageDecoder { private final AnimatedImageFactory mAnimatedImageFactory; private final PlatformBitmapFactory mBitmapFactoryWithPool; public ImageDecoder( final AnimatedImageFactory animatedImageFactory, final PlatformBitmapFactory bitmapFactoryWithPool) { mAnimatedImageFactory = animatedImageFactory; mBitmapFactoryWithPool = bitmapFactoryWithPool; } /** * Decodes image. * * @param pooledByteBufferRef buffer containing image data * @param imageFormat if not null and not UNKNOWN, then format check is skipped and this one is * assumed. * @param length if image type supports decoding incomplete image then determines where * the image data should be cut for decoding. * @param qualityInfo quality information for the image * @param options options that cange decode behavior */ public CloseableImage decodeImage( final CloseableReference<PooledByteBuffer> pooledByteBufferRef, @Nullable ImageFormat imageFormat, final int length, final QualityInfo qualityInfo, final ImageDecodeOptions options) { if (imageFormat == null || imageFormat == ImageFormat.UNKNOWN) { imageFormat = ImageFormatChecker.getImageFormat_WrapIOException( pooledByteBufferRef.get().getStream()); } switch (imageFormat) { case UNKNOWN: throw new IllegalArgumentException("unknown image format"); case JPEG: return decodeJpeg(pooledByteBufferRef, length, qualityInfo); case GIF: return decodeAnimatedGif(pooledByteBufferRef, options); case WEBP_ANIMATED: return decodeAnimatedWebp(pooledByteBufferRef, options); default: return decodeStaticImage(pooledByteBufferRef); } } /** * Decodes gif into CloseableImage. * * @param pooledByteBufferRef * @return a CloseableGifImage */ public CloseableImage decodeAnimatedGif( CloseableReference<PooledByteBuffer> pooledByteBufferRef, ImageDecodeOptions options) { return mAnimatedImageFactory.decodeGif(pooledByteBufferRef, options); } /** * @param pooledByteBufferRef input image (encoded bytes) * @return a CloseableStaticBitmap */ public synchronized CloseableStaticBitmap decodeStaticImage( final CloseableReference<PooledByteBuffer> pooledByteBufferRef) { CloseableReference<Bitmap> bitmapReference = mBitmapFactoryWithPool.decodeFromPooledByteBuffer(pooledByteBufferRef); try { return new CloseableStaticBitmap(bitmapReference, ImmutableQualityInfo.FULL_QUALITY); } finally { bitmapReference.close(); } } /** * Decodes a partial jpeg. * * @param pooledByteBufferRef * @param length amount of currently available data in bytes * @param qualityInfo quality info for the image * @return a CloseableStaticBitmap */ public synchronized CloseableStaticBitmap decodeJpeg( final CloseableReference<PooledByteBuffer> pooledByteBufferRef, int length, QualityInfo qualityInfo) { CloseableReference<Bitmap> bitmapReference = mBitmapFactoryWithPool.decodeJPEGFromPooledByteBuffer(pooledByteBufferRef, length); try { return new CloseableStaticBitmap(bitmapReference, qualityInfo); } finally { bitmapReference.close(); } } /** * Decode a webp animated image into a CloseableImage. * * <p> The image is decoded into a 'pinned' purgeable bitmap. * * @param pooledByteBufferRef input image (encoded bytes) * @param options * @return a {@link CloseableImage} */ public CloseableImage decodeAnimatedWebp( final CloseableReference<PooledByteBuffer> pooledByteBufferRef, final ImageDecodeOptions options) { return mAnimatedImageFactory.decodeWebP(pooledByteBufferRef, options); } }