private Drawable createDrawableFromFetchedResult(Context context, CloseableImage image) { if (image instanceof CloseableStaticBitmap) { CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) image; BitmapDrawable bitmapDrawable = createBitmapDrawable(context, closeableStaticBitmap.getUnderlyingBitmap()); return (closeableStaticBitmap.getRotationAngle() != 0 && closeableStaticBitmap.getRotationAngle() != -1 ? new OrientedDrawable(bitmapDrawable, closeableStaticBitmap.getRotationAngle()) : bitmapDrawable); } else if (image instanceof CloseableAnimatedImage) { AnimatedDrawableFactory animatedDrawableFactory = Fresco.getImagePipelineFactory().getAnimatedFactory().getAnimatedDrawableFactory(context); if (animatedDrawableFactory != null) { AnimatedDrawable animatedDrawable = (AnimatedDrawable) animatedDrawableFactory.create(image); if (animatedDrawable != null) { return animatedDrawable; } } } throw new UnsupportedOperationException("Unrecognized image class: " + image); }
@Override public Drawable createDrawable(CloseableImage closeableImage) { if (closeableImage instanceof CloseableStaticBitmap) { CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) closeableImage; Drawable bitmapDrawable = new BitmapDrawable(mResources, closeableStaticBitmap.getUnderlyingBitmap()); if (!hasTransformableRotationAngle(closeableStaticBitmap) && !hasTransformableExifOrientation(closeableStaticBitmap)) { // Return the bitmap drawable directly as there's nothing to transform in it return bitmapDrawable; } else { return new OrientedDrawable( bitmapDrawable, closeableStaticBitmap.getRotationAngle(), closeableStaticBitmap.getExifOrientation()); } } else if (mAnimatedDrawableFactory != null && mAnimatedDrawableFactory.supportsImageType(closeableImage)) { return mAnimatedDrawableFactory.createDrawable(closeableImage); } return null; }
/** * Converts the given image reference to a bitmap reference * and closes the original image reference. * * @param closeableImage the image to convert. It will be closed afterwards and will be invalid * @return the closeable bitmap reference to be used */ @VisibleForTesting @Nullable static CloseableReference<Bitmap> convertToBitmapReferenceAndClose( final @Nullable CloseableReference<CloseableImage> closeableImage) { try { if (CloseableReference.isValid(closeableImage) && closeableImage.get() instanceof CloseableStaticBitmap) { CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) closeableImage.get(); if (closeableStaticBitmap != null) { // We return a clone of the underlying bitmap reference that has to be manually closed // and then close the passed CloseableStaticBitmap in order to preserve correct // cache size calculations. return closeableStaticBitmap.cloneUnderlyingBitmapReference(); } } // Not a bitmap reference, so we return null return null; } finally { CloseableReference.closeSafely(closeableImage); } }
private void verifyNewResultProcessed(int index, Bitmap destBitmap) { mInOrder.verify(mProducerListener).onProducerStart(mRequestId, PostprocessorProducer.NAME); mInOrder.verify(mPostprocessor).process(mSourceBitmap, mPlatformBitmapFactory); mInOrder.verify(mProducerListener).requiresExtraMap(mRequestId); mInOrder.verify(mProducerListener) .onProducerFinishWithSuccess(mRequestId, PostprocessorProducer.NAME, mExtraMap); mInOrder.verify(mConsumer).onNewResult(any(CloseableReference.class), eq(Consumer.NO_FLAGS)); mInOrder.verifyNoMoreInteractions(); assertEquals(index + 1, mResults.size()); CloseableReference<CloseableImage> res0 = mResults.get(index); assertTrue(CloseableReference.isValid(res0)); assertSame(destBitmap, ((CloseableStaticBitmap) res0.get()).getUnderlyingBitmap()); res0.close(); verify(mBitmapResourceReleaser).release(destBitmap); }
/** * @param encodedImage input image (encoded bytes plus meta data) * @return a CloseableStaticBitmap */ public CloseableStaticBitmap decodeStaticImage( final EncodedImage encodedImage, ImageDecodeOptions options) { CloseableReference<Bitmap> bitmapReference = mPlatformDecoder.decodeFromEncodedImage(encodedImage, options.bitmapConfig, null); try { return new CloseableStaticBitmap( bitmapReference, ImmutableQualityInfo.FULL_QUALITY, encodedImage.getRotationAngle(), encodedImage.getExifOrientation()); } finally { bitmapReference.close(); } }
/** * Decodes a partial jpeg. * * @param encodedImage input image (encoded bytes plus meta data) * @param length amount of currently available data in bytes * @param qualityInfo quality info for the image * @return a CloseableStaticBitmap */ public CloseableStaticBitmap decodeJpeg( final EncodedImage encodedImage, int length, QualityInfo qualityInfo, ImageDecodeOptions options) { CloseableReference<Bitmap> bitmapReference = mPlatformDecoder.decodeJPEGFromEncodedImage( encodedImage, options.bitmapConfig, null, length); try { return new CloseableStaticBitmap( bitmapReference, qualityInfo, encodedImage.getRotationAngle(), encodedImage.getExifOrientation()); } finally { bitmapReference.close(); } }
@Test public void testSuccess() { SingleUsePostprocessorConsumer postprocessorConsumer = produceResults(); doReturn(mDestinationCloseableBitmapRef) .when(mPostprocessor).process(mSourceBitmap, mPlatformBitmapFactory); postprocessorConsumer.onNewResult(mSourceCloseableImageRef, Consumer.IS_LAST); mSourceCloseableImageRef.close(); mTestExecutorService.runUntilIdle(); mInOrder.verify(mProducerListener).onProducerStart(mRequestId, PostprocessorProducer.NAME); mInOrder.verify(mPostprocessor).process(mSourceBitmap, mPlatformBitmapFactory); mInOrder.verify(mProducerListener).requiresExtraMap(mRequestId); mInOrder.verify(mProducerListener) .onProducerFinishWithSuccess(mRequestId, PostprocessorProducer.NAME, mExtraMap); mInOrder.verify(mConsumer).onNewResult(any(CloseableReference.class), eq(Consumer.IS_LAST)); mInOrder.verifyNoMoreInteractions(); assertEquals(1, mResults.size()); CloseableReference<CloseableImage> res0 = mResults.get(0); assertTrue(CloseableReference.isValid(res0)); assertSame(mDestinationBitmap, ((CloseableStaticBitmap) res0.get()).getUnderlyingBitmap()); res0.close(); verify(mBitmapResourceReleaser).release(mDestinationBitmap); verify(mSourceCloseableStaticBitmap).close(); }
@Nullable private static CloseableReference<CloseableImage> createImageReference( CloseableReference<Bitmap> bitmapReference) { // The given CloseableStaticBitmap will be cached and then released by the resource releaser // of the closeable reference CloseableImage closeableImage = new CloseableStaticBitmap(bitmapReference, ImmutableQualityInfo.FULL_QUALITY, 0); return CloseableReference.of(closeableImage); }
private CloseableImage getCloseableImage( ImageDecodeOptions options, AnimatedImage image, Bitmap.Config bitmapConfig) { List<CloseableReference<Bitmap>> decodedFrames = null; CloseableReference<Bitmap> previewBitmap = null; try { final int frameForPreview = options.useLastFrameForPreview ? image.getFrameCount() - 1 : 0; if (options.forceStaticImage) { return new CloseableStaticBitmap( createPreviewBitmap(image, bitmapConfig, frameForPreview), ImmutableQualityInfo.FULL_QUALITY, 0); } if (options.decodeAllFrames) { decodedFrames = decodeAllFrames(image, bitmapConfig); previewBitmap = CloseableReference.cloneOrNull(decodedFrames.get(frameForPreview)); } if (options.decodePreviewFrame && previewBitmap == null) { previewBitmap = createPreviewBitmap(image, bitmapConfig, frameForPreview); } AnimatedImageResult animatedImageResult = AnimatedImageResult.newBuilder(image) .setPreviewBitmap(previewBitmap) .setFrameForPreview(frameForPreview) .setDecodedFrames(decodedFrames) .build(); return new CloseableAnimatedImage(animatedImageResult); } finally { CloseableReference.closeSafely(previewBitmap); CloseableReference.closeSafely(decodedFrames); } }
@Before public void setUp() { MockitoAnnotations.initMocks(this); mTestExecutorService = new TestExecutorService(new FakeClock()); mPostprocessorProducer = new PostprocessorProducer( mInputProducer, mPlatformBitmapFactory, mTestExecutorService); when(mImageRequest.getPostprocessor()).thenReturn(mPostprocessor); when(mProducerContext.getId()).thenReturn(mRequestId); when(mProducerContext.getListener()).thenReturn(mProducerListener); when(mProducerContext.getImageRequest()).thenReturn(mImageRequest); mResults = new ArrayList<>(); when(mPostprocessor.getName()).thenReturn(POSTPROCESSOR_NAME); when(mProducerListener.requiresExtraMap(mRequestId)).thenReturn(true); doAnswer( new Answer<Object>() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { mResults.add( ((CloseableReference<CloseableImage>) invocation.getArguments()[0]).clone()); return null; } } ).when(mConsumer).onNewResult(any(CloseableReference.class), anyInt()); mInOrder = inOrder(mPostprocessor, mProducerListener, mConsumer); mSourceBitmap = mock(Bitmap.class); mSourceCloseableStaticBitmap = mock(CloseableStaticBitmap.class); when(mSourceCloseableStaticBitmap.getUnderlyingBitmap()).thenReturn(mSourceBitmap); mSourceCloseableImageRef = CloseableReference.<CloseableImage>of(mSourceCloseableStaticBitmap); mDestinationBitmap = mock(Bitmap.class); mDestinationCloseableBitmapRef = CloseableReference.of(mDestinationBitmap, mBitmapResourceReleaser); }
private void setupNewSourceImage() { mSourceBitmap = mock(Bitmap.class); mSourceCloseableStaticBitmap = mock(CloseableStaticBitmap.class); when(mSourceCloseableStaticBitmap.getUnderlyingBitmap()).thenReturn(mSourceBitmap); mSourceCloseableImageRef = CloseableReference.<CloseableImage>of(mSourceCloseableStaticBitmap); }
private CloseableReference<CloseableImage> postprocessInternal(CloseableImage sourceImage) { CloseableStaticBitmap staticBitmap = (CloseableStaticBitmap) sourceImage; Bitmap sourceBitmap = staticBitmap.getUnderlyingBitmap(); CloseableReference<Bitmap> bitmapRef = mPostprocessor.process(sourceBitmap, mBitmapFactory); int rotationAngle = staticBitmap.getRotationAngle(); int exifOrientation = staticBitmap.getExifOrientation(); try { return CloseableReference.<CloseableImage>of( new CloseableStaticBitmap( bitmapRef, sourceImage.getQualityInfo(), rotationAngle, exifOrientation)); } finally { CloseableReference.closeSafely(bitmapRef); } }
private void internalPrepareBitmap(CloseableReference<CloseableImage> newResult) { if (newResult == null || !newResult.isValid()) { return; } final CloseableImage closeableImage = newResult.get(); if (closeableImage == null || closeableImage.isClosed()) { return; } if (closeableImage instanceof CloseableStaticBitmap) { final CloseableStaticBitmap staticBitmap = (CloseableStaticBitmap) closeableImage; final Bitmap bitmap = staticBitmap.getUnderlyingBitmap(); if (bitmap == null) { return; } final int bitmapByteCount = bitmap.getRowBytes() * bitmap.getHeight(); if (bitmapByteCount < mMinBitmapSizeBytes) { return; } if (bitmapByteCount > mMaxBitmapSizeBytes) { return; } bitmap.prepareToDraw(); } }
/** * 加载远程图片 * * @param url * @param imageSize */ private void displayImage(Uri url, ResizeOptions imageSize, final ImageView imageView, final DraweeHolder<GenericDraweeHierarchy> draweeHolder) { ImageRequest imageRequest = ImageRequestBuilder .newBuilderWithSource(url) .setResizeOptions(imageSize)//图片目标大小 .build(); ImagePipeline imagePipeline = Fresco.getImagePipeline(); final DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, this); DraweeController controller = Fresco.newDraweeControllerBuilder() .setOldController(draweeHolder.getController()) .setImageRequest(imageRequest) .setControllerListener(new BaseControllerListener<ImageInfo>() { @Override public void onFinalImageSet(String s, ImageInfo imageInfo, Animatable animatable) { CloseableReference<CloseableImage> imageReference = null; try { imageReference = dataSource.getResult(); if (imageReference != null) { CloseableImage image = imageReference.get(); if (image != null && image instanceof CloseableStaticBitmap) { CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) image; Bitmap bitmap = closeableStaticBitmap.getUnderlyingBitmap(); if (bitmap != null && imageView != null) { imageView.setImageBitmap(bitmap); } } } } finally { dataSource.close(); CloseableReference.closeSafely(imageReference); } } }) .setTapToRetryEnabled(true) .build(); draweeHolder.setController(controller); }
@Override public void onFinalImageSet( String id, @Nullable final ImageInfo imageInfo, @Nullable Animatable animatable) { CloseableReference<CloseableImage> imageReference = null; try { imageReference = dataSource.getResult(); if (imageReference != null) { CloseableImage image = imageReference.get(); if (image != null && image instanceof CloseableStaticBitmap) { CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) image; Bitmap bitmap = closeableStaticBitmap.getUnderlyingBitmap(); if (bitmap != null) { bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true); iconBitmap = bitmap; iconBitmapDescriptor = BitmapDescriptorFactory.fromBitmap(bitmap); } } } } finally { dataSource.close(); if (imageReference != null) { CloseableReference.closeSafely(imageReference); } } update(); }
public void setImageUri(String url) { ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(url)).build(); ImagePipeline imagePipeline = Fresco.getImagePipeline(); final DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, this); DraweeController controller = Fresco.newDraweeControllerBuilder() .setOldController(mDraweeHolder.getController()) .setImageRequest(imageRequest) .setControllerListener(new BaseControllerListener<ImageInfo>() { @Override public void onFinalImageSet(String s, @Nullable ImageInfo imageInfo, @Nullable Animatable animatable) { try { imageReference = dataSource.getResult(); if (imageReference != null) { CloseableImage image = imageReference.get(); // do something with the image if (image != null && image instanceof CloseableStaticBitmap) { CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) image; Bitmap bitmap = closeableStaticBitmap.getUnderlyingBitmap(); if (bitmap != null) { setImageBitmap(bitmap); } } } } finally { dataSource.close(); CloseableReference.closeSafely(imageReference); } } }) .setTapToRetryEnabled(true) .build(); mDraweeHolder.setController(controller); }
public void setImageUri(String uri, int width, int height) { ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(Uri.parse(uri)) .setAutoRotateEnabled(true) .setResizeOptions(new ResizeOptions(width, height)) .build(); ImagePipeline imagePipeline = Fresco.getImagePipeline(); final DataSource<CloseableReference<CloseableImage>> dataSource = imagePipeline.fetchDecodedImage(imageRequest, this); DraweeController controller = Fresco.newDraweeControllerBuilder() .setOldController(mDraweeHolder.getController()) .setImageRequest(imageRequest) .setControllerListener(new BaseControllerListener<ImageInfo>() { @Override public void onFinalImageSet(String s, @Nullable ImageInfo imageInfo, @Nullable Animatable animatable) { try { imageReference = dataSource.getResult(); if (imageReference != null) { CloseableImage image = imageReference.get(); if (image != null && image instanceof CloseableStaticBitmap) { CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) image; Bitmap bitmap = closeableStaticBitmap.getUnderlyingBitmap(); if (bitmap != null) { setImageBitmap(bitmap); } } } } finally { dataSource.close(); CloseableReference.closeSafely(imageReference); } } }) .setTapToRetryEnabled(true) .build(); mDraweeHolder.setController(controller); }
private static boolean hasTransformableRotationAngle( CloseableStaticBitmap closeableStaticBitmap) { return closeableStaticBitmap.getRotationAngle() != 0 && closeableStaticBitmap.getRotationAngle() != EncodedImage.UNKNOWN_ROTATION_ANGLE; }