Not always we have a View to show content of animated GIF/WEBP (example: live wallpaper). For this, it's best to have a bit more manual control of the decoding pipeline.
Is there a way to get one frame after another (into a Bitmap instance), while knowing how much time to wait between them?
I've looked at the documentation and I couldn't find it:
https://frescolib.org/docs/animations.html
Hi! Yes, you can manually request the image, which gives you a CloseableImage (see https://frescolib.org/docs/using-image-pipeline.html). You can then create a bitmap animation backend according to what we do internally: https://github.com/facebook/fresco/blob/5d419bcc450bd0e4fbc27546e94ac55ad20a3e60/animated-base/src/main/java/com/facebook/fresco/animation/factory/ExperimentalBitmapAnimationDrawableFactory.java#L90
You can modify this to do whatever you need. If you need to render into an existing bitmap, you can for example only use this helper class: https://github.com/facebook/fresco/blob/5d419bcc450bd0e4fbc27546e94ac55ad20a3e60/animated-base/src/main/java/com/facebook/fresco/animation/bitmap/wrapper/AnimatedDrawableBackendFrameRenderer.java
If you need less control, you can use the BitmapAnimationBackend and animate according to what we do in AnimatedDrawable2.
The animation information class gives you info about loop count and frame durations. It is created like this: https://github.com/facebook/fresco/blob/5d419bcc450bd0e4fbc27546e94ac55ad20a3e60/animated-base/src/main/java/com/facebook/fresco/animation/factory/ExperimentalBitmapAnimationDrawableFactory.java#L115
@oprisnik I'm actually a newb with this library. I wanted to try out the samples, but it failed to import and run them. Wrote about this here .
I don't understand what you mean by those instructions. To me it seems that the API doesn't exist for this question, and that you tell me to copy code of Fresco and then modify it. Is it true? Do you have a working sample for this? Just the bare minimal of it? Or even a snippet?
Yes, this functionality doesn't exist out of the box. However, we do internally glue classes together that you can use to emulate that behavior. Manually request the CloseableImage (see https://frescolib.org/docs/using-image-pipeline.html) (which is the decoded GIF) and then use the raw GIF data in CloseableAnimatedImage however you like. I've listed some helper classes that make things easier and that we use internally to render GIFs.
Can you please demonstrate how to do it?
I think it could actually be useful for all and not just me, no?
A really naive solution for this (that's not too efficient) would be something like this:
fun loadImage(uri: String, frameNumber: Int) {
val result = Fresco.getImagePipeline().fetchDecodedImage(ImageRequest.fromUri(uri), "animatedImage")
result.subscribe(object : BaseDataSubscriber<CloseableReference<CloseableImage>>() {
override fun onNewResultImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
if (dataSource.hasResult()) {
dataSource.result?.get()?.use {
if (it is CloseableAnimatedImage) {
handleAnimatedImage(it, frameNumber)
}
}
}
}
override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
TODO("not implemented")
}
}, UiThreadImmediateExecutorService.getInstance())
}
fun handleAnimatedImage(animatedImage: CloseableAnimatedImage, frameNumber: Int) {
val frameCache = NoOpCache()
val backend = AnimatedDrawableBackendImpl(
AnimatedDrawableUtil(),
animatedImage.imageResult,
Rect(0, 0, animatedImage.width, animatedImage.height)
)
val renderer = AnimatedDrawableBackendFrameRenderer(frameCache, backend)
val bitmap = Bitmap.createBitmap(animatedImage.width, animatedImage.height, Bitmap.Config.ARGB_8888)
renderer.renderFrame(frameNumber, bitmap)
image.setImageBitmap(bitmap)
}
Keep in mind that if you need to hold on to the image, you need to properly handle the CloseableReference according to https://frescolib.org/docs/datasources-datasubscribers.html and https://frescolib.org/docs/closeable-references.html
Where is the part of "not too efficient" ? Because you keep creating more and more bitmaps, instead of using the previous one (or 2 : one for UI and one for decoding) ?
And what do you mean "hold on to the image"?
Yes, no caching, no frame preparation ahead of time on background threads, not using PlatformBitmapFactory.
"Hold on to the image" means keep the CloseableReference
@oprisnik Is there a better way, then?
Yes, use AnimatedDrawable2 / a DraweeView or manually do what that one does, see my comment above.
So I should copy what's in the AnimatedDrawable2 into a new class that provides Bitmap instances ?
Most helpful comment
A really naive solution for this (that's not too efficient) would be something like this:
Keep in mind that if you need to hold on to the image, you need to properly handle the
CloseableReferenceaccording to https://frescolib.org/docs/datasources-datasubscribers.html and https://frescolib.org/docs/closeable-references.html