Is it possible to get the new ImageDecoder class to return Bitmaps, one frame after another, manually?









up vote
12
down vote

favorite
1












Background



I'm trying to go over bitmaps of animated GIF&WEBP files manually (frame by frame), so that it would work not just for Views, but on other cases too (such as a live wallpaper).



The problem



Animated GIF/WEBP files are supported only from Android P, using ImageDecoder API (example here) .



For GIF, I wanted to try Glide for the task, but I've failed, so I've tried overcoming this, by using a library that allows to load them (here, solution here). I think it works fine.



For WebP, I thought I've found another library that could work on older Android versions (here, made fork here), but it seems that it can't handle WebP files well in some cases (reported here). I tried to figure out what's the issue and how to solve it, but I didn't succeed.



So, assuming that some day Google will support GIF&WEBP animation for older Android versions via the support library (they wrote it here), I've decided to try to use ImageDecoder for the task.



Thing is, looking in the entire API of ImageDecoder , it's quite restricted in how we should use it. I don't see how I can overcome its limitations.



What I've found



This is how ImageDecoder can be used to show an animated WebP on an ImageView (just a sample, of course, available here) :



class MainActivity : AppCompatActivity() 
@SuppressLint("StaticFieldLeak")

override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val source = ImageDecoder.createSource(resources, R.raw.test)
object : AsyncTask<Void, Void, Drawable?>()
override fun doInBackground(vararg params: Void?): Drawable?
return try
ImageDecoder.decodeDrawable(source)
catch (e: Exception)
null



override fun onPostExecute(result: Drawable?)
super.onPostExecute(result)
imageView.setImageDrawable(result)
if (result is AnimatedImageDrawable)
result.start()



.execute()





I've tried to read all of the documentations of ImageDecoder and AnimatedImageDrawable, and also look at its code, but I don't see how it's possible to manually go over each frame, and have the time that needs to be waited between them.



The questions



  1. Is there a way to use ImageDecoder API to go over each frame manually, getting a Bitmap to draw and knowing how much time it's needed to wait between frames? Any workaround available? Maybe even using AnimatedImageDrawable ?


  2. I'd like to do the same on older Android versions. Is it possible? If so how? Maybe on a different API/library? Google wrote it works on a way to use ImageDecoder on older Android versions, but I don't see it being mentioned anywhere (except for the link I've provided). Probably not ready yet... Android P didn't even reach 0.1% of users yet... Maybe Fresco can do it? I've tried to check it there too, but I don't see that it's capable of such a thing either, and it's a huge library to use just for this task, so I'd prefer to use a different library instead... I also know that libwebp is available, but it's in C/C++ and not sure if it's suited for Android, and whether there is a port for it on Java/Kotlin for Android.



EDIT:



Since I think I got what I wanted, for both a third party library and for ImageDecoder, to be able to get bitmaps out of animated WebP, I'd still want to know how to get the frame count and current frame using ImageDecoder, if that's possible. I tried using ImageDecoder.decodeDrawable(source, object : ImageDecoder.OnHeaderDecodedListener... , but it doesn't provide frame count information, and there is no way in the API that I can see that I can go to a specific frame index and start from there, or to know for a specific frame how long it needs to go to the next frame. So I made a reuqest about those here.



Sadly I also could not find that Google has ImageDecoder available for older Android versions, either.



It's also interesting if there is some kind of way to do the same as I did for the relatively new animation file of HEIC. Currently it's supported only on Android P.










share|improve this question

















This question has an open bounty worth +400
reputation from android developer ending ending at 2018-11-14 19:28:12Z">in 4 days.


Looking for an answer drawing from credible and/or official sources.











  • 1




    I`ve got a solution for GIFs, but unfortunately it`s implemented as a C header. Don`t know how hard it would be to port to Java.
    – hidefromkgb
    Oct 30 at 18:58







  • 1




    @hidefromkgb If you don't like Java, you can use Kotlin instead :) . Google has shown that it's now easier to use C/C++ from Java/Kotlin world. I suggest you to try...
    – android developer
    Oct 30 at 19:00






  • 2




    Well, OK. This is what I was talking about. Low-level low-levelness all along.
    – hidefromkgb
    Oct 30 at 19:02






  • 1




    @hidefromkgb Nice. Maybe you could look at the links I've provided then. They have implementation for both animated GIF and animated WEBP.
    – android developer
    Oct 30 at 19:31














up vote
12
down vote

favorite
1












Background



I'm trying to go over bitmaps of animated GIF&WEBP files manually (frame by frame), so that it would work not just for Views, but on other cases too (such as a live wallpaper).



The problem



Animated GIF/WEBP files are supported only from Android P, using ImageDecoder API (example here) .



For GIF, I wanted to try Glide for the task, but I've failed, so I've tried overcoming this, by using a library that allows to load them (here, solution here). I think it works fine.



For WebP, I thought I've found another library that could work on older Android versions (here, made fork here), but it seems that it can't handle WebP files well in some cases (reported here). I tried to figure out what's the issue and how to solve it, but I didn't succeed.



So, assuming that some day Google will support GIF&WEBP animation for older Android versions via the support library (they wrote it here), I've decided to try to use ImageDecoder for the task.



Thing is, looking in the entire API of ImageDecoder , it's quite restricted in how we should use it. I don't see how I can overcome its limitations.



What I've found



This is how ImageDecoder can be used to show an animated WebP on an ImageView (just a sample, of course, available here) :



class MainActivity : AppCompatActivity() 
@SuppressLint("StaticFieldLeak")

override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val source = ImageDecoder.createSource(resources, R.raw.test)
object : AsyncTask<Void, Void, Drawable?>()
override fun doInBackground(vararg params: Void?): Drawable?
return try
ImageDecoder.decodeDrawable(source)
catch (e: Exception)
null



override fun onPostExecute(result: Drawable?)
super.onPostExecute(result)
imageView.setImageDrawable(result)
if (result is AnimatedImageDrawable)
result.start()



.execute()





I've tried to read all of the documentations of ImageDecoder and AnimatedImageDrawable, and also look at its code, but I don't see how it's possible to manually go over each frame, and have the time that needs to be waited between them.



The questions



  1. Is there a way to use ImageDecoder API to go over each frame manually, getting a Bitmap to draw and knowing how much time it's needed to wait between frames? Any workaround available? Maybe even using AnimatedImageDrawable ?


  2. I'd like to do the same on older Android versions. Is it possible? If so how? Maybe on a different API/library? Google wrote it works on a way to use ImageDecoder on older Android versions, but I don't see it being mentioned anywhere (except for the link I've provided). Probably not ready yet... Android P didn't even reach 0.1% of users yet... Maybe Fresco can do it? I've tried to check it there too, but I don't see that it's capable of such a thing either, and it's a huge library to use just for this task, so I'd prefer to use a different library instead... I also know that libwebp is available, but it's in C/C++ and not sure if it's suited for Android, and whether there is a port for it on Java/Kotlin for Android.



EDIT:



Since I think I got what I wanted, for both a third party library and for ImageDecoder, to be able to get bitmaps out of animated WebP, I'd still want to know how to get the frame count and current frame using ImageDecoder, if that's possible. I tried using ImageDecoder.decodeDrawable(source, object : ImageDecoder.OnHeaderDecodedListener... , but it doesn't provide frame count information, and there is no way in the API that I can see that I can go to a specific frame index and start from there, or to know for a specific frame how long it needs to go to the next frame. So I made a reuqest about those here.



Sadly I also could not find that Google has ImageDecoder available for older Android versions, either.



It's also interesting if there is some kind of way to do the same as I did for the relatively new animation file of HEIC. Currently it's supported only on Android P.










share|improve this question

















This question has an open bounty worth +400
reputation from android developer ending ending at 2018-11-14 19:28:12Z">in 4 days.


Looking for an answer drawing from credible and/or official sources.











  • 1




    I`ve got a solution for GIFs, but unfortunately it`s implemented as a C header. Don`t know how hard it would be to port to Java.
    – hidefromkgb
    Oct 30 at 18:58







  • 1




    @hidefromkgb If you don't like Java, you can use Kotlin instead :) . Google has shown that it's now easier to use C/C++ from Java/Kotlin world. I suggest you to try...
    – android developer
    Oct 30 at 19:00






  • 2




    Well, OK. This is what I was talking about. Low-level low-levelness all along.
    – hidefromkgb
    Oct 30 at 19:02






  • 1




    @hidefromkgb Nice. Maybe you could look at the links I've provided then. They have implementation for both animated GIF and animated WEBP.
    – android developer
    Oct 30 at 19:31












up vote
12
down vote

favorite
1









up vote
12
down vote

favorite
1






1





Background



I'm trying to go over bitmaps of animated GIF&WEBP files manually (frame by frame), so that it would work not just for Views, but on other cases too (such as a live wallpaper).



The problem



Animated GIF/WEBP files are supported only from Android P, using ImageDecoder API (example here) .



For GIF, I wanted to try Glide for the task, but I've failed, so I've tried overcoming this, by using a library that allows to load them (here, solution here). I think it works fine.



For WebP, I thought I've found another library that could work on older Android versions (here, made fork here), but it seems that it can't handle WebP files well in some cases (reported here). I tried to figure out what's the issue and how to solve it, but I didn't succeed.



So, assuming that some day Google will support GIF&WEBP animation for older Android versions via the support library (they wrote it here), I've decided to try to use ImageDecoder for the task.



Thing is, looking in the entire API of ImageDecoder , it's quite restricted in how we should use it. I don't see how I can overcome its limitations.



What I've found



This is how ImageDecoder can be used to show an animated WebP on an ImageView (just a sample, of course, available here) :



class MainActivity : AppCompatActivity() 
@SuppressLint("StaticFieldLeak")

override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val source = ImageDecoder.createSource(resources, R.raw.test)
object : AsyncTask<Void, Void, Drawable?>()
override fun doInBackground(vararg params: Void?): Drawable?
return try
ImageDecoder.decodeDrawable(source)
catch (e: Exception)
null



override fun onPostExecute(result: Drawable?)
super.onPostExecute(result)
imageView.setImageDrawable(result)
if (result is AnimatedImageDrawable)
result.start()



.execute()





I've tried to read all of the documentations of ImageDecoder and AnimatedImageDrawable, and also look at its code, but I don't see how it's possible to manually go over each frame, and have the time that needs to be waited between them.



The questions



  1. Is there a way to use ImageDecoder API to go over each frame manually, getting a Bitmap to draw and knowing how much time it's needed to wait between frames? Any workaround available? Maybe even using AnimatedImageDrawable ?


  2. I'd like to do the same on older Android versions. Is it possible? If so how? Maybe on a different API/library? Google wrote it works on a way to use ImageDecoder on older Android versions, but I don't see it being mentioned anywhere (except for the link I've provided). Probably not ready yet... Android P didn't even reach 0.1% of users yet... Maybe Fresco can do it? I've tried to check it there too, but I don't see that it's capable of such a thing either, and it's a huge library to use just for this task, so I'd prefer to use a different library instead... I also know that libwebp is available, but it's in C/C++ and not sure if it's suited for Android, and whether there is a port for it on Java/Kotlin for Android.



EDIT:



Since I think I got what I wanted, for both a third party library and for ImageDecoder, to be able to get bitmaps out of animated WebP, I'd still want to know how to get the frame count and current frame using ImageDecoder, if that's possible. I tried using ImageDecoder.decodeDrawable(source, object : ImageDecoder.OnHeaderDecodedListener... , but it doesn't provide frame count information, and there is no way in the API that I can see that I can go to a specific frame index and start from there, or to know for a specific frame how long it needs to go to the next frame. So I made a reuqest about those here.



Sadly I also could not find that Google has ImageDecoder available for older Android versions, either.



It's also interesting if there is some kind of way to do the same as I did for the relatively new animation file of HEIC. Currently it's supported only on Android P.










share|improve this question















Background



I'm trying to go over bitmaps of animated GIF&WEBP files manually (frame by frame), so that it would work not just for Views, but on other cases too (such as a live wallpaper).



The problem



Animated GIF/WEBP files are supported only from Android P, using ImageDecoder API (example here) .



For GIF, I wanted to try Glide for the task, but I've failed, so I've tried overcoming this, by using a library that allows to load them (here, solution here). I think it works fine.



For WebP, I thought I've found another library that could work on older Android versions (here, made fork here), but it seems that it can't handle WebP files well in some cases (reported here). I tried to figure out what's the issue and how to solve it, but I didn't succeed.



So, assuming that some day Google will support GIF&WEBP animation for older Android versions via the support library (they wrote it here), I've decided to try to use ImageDecoder for the task.



Thing is, looking in the entire API of ImageDecoder , it's quite restricted in how we should use it. I don't see how I can overcome its limitations.



What I've found



This is how ImageDecoder can be used to show an animated WebP on an ImageView (just a sample, of course, available here) :



class MainActivity : AppCompatActivity() 
@SuppressLint("StaticFieldLeak")

override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val source = ImageDecoder.createSource(resources, R.raw.test)
object : AsyncTask<Void, Void, Drawable?>()
override fun doInBackground(vararg params: Void?): Drawable?
return try
ImageDecoder.decodeDrawable(source)
catch (e: Exception)
null



override fun onPostExecute(result: Drawable?)
super.onPostExecute(result)
imageView.setImageDrawable(result)
if (result is AnimatedImageDrawable)
result.start()



.execute()





I've tried to read all of the documentations of ImageDecoder and AnimatedImageDrawable, and also look at its code, but I don't see how it's possible to manually go over each frame, and have the time that needs to be waited between them.



The questions



  1. Is there a way to use ImageDecoder API to go over each frame manually, getting a Bitmap to draw and knowing how much time it's needed to wait between frames? Any workaround available? Maybe even using AnimatedImageDrawable ?


  2. I'd like to do the same on older Android versions. Is it possible? If so how? Maybe on a different API/library? Google wrote it works on a way to use ImageDecoder on older Android versions, but I don't see it being mentioned anywhere (except for the link I've provided). Probably not ready yet... Android P didn't even reach 0.1% of users yet... Maybe Fresco can do it? I've tried to check it there too, but I don't see that it's capable of such a thing either, and it's a huge library to use just for this task, so I'd prefer to use a different library instead... I also know that libwebp is available, but it's in C/C++ and not sure if it's suited for Android, and whether there is a port for it on Java/Kotlin for Android.



EDIT:



Since I think I got what I wanted, for both a third party library and for ImageDecoder, to be able to get bitmaps out of animated WebP, I'd still want to know how to get the frame count and current frame using ImageDecoder, if that's possible. I tried using ImageDecoder.decodeDrawable(source, object : ImageDecoder.OnHeaderDecodedListener... , but it doesn't provide frame count information, and there is no way in the API that I can see that I can go to a specific frame index and start from there, or to know for a specific frame how long it needs to go to the next frame. So I made a reuqest about those here.



Sadly I also could not find that Google has ImageDecoder available for older Android versions, either.



It's also interesting if there is some kind of way to do the same as I did for the relatively new animation file of HEIC. Currently it's supported only on Android P.







android animated-gif imagedecoder animated-webp






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 13 hours ago

























asked Oct 27 at 17:02









android developer

57k95452829




57k95452829






This question has an open bounty worth +400
reputation from android developer ending ending at 2018-11-14 19:28:12Z">in 4 days.


Looking for an answer drawing from credible and/or official sources.








This question has an open bounty worth +400
reputation from android developer ending ending at 2018-11-14 19:28:12Z">in 4 days.


Looking for an answer drawing from credible and/or official sources.









  • 1




    I`ve got a solution for GIFs, but unfortunately it`s implemented as a C header. Don`t know how hard it would be to port to Java.
    – hidefromkgb
    Oct 30 at 18:58







  • 1




    @hidefromkgb If you don't like Java, you can use Kotlin instead :) . Google has shown that it's now easier to use C/C++ from Java/Kotlin world. I suggest you to try...
    – android developer
    Oct 30 at 19:00






  • 2




    Well, OK. This is what I was talking about. Low-level low-levelness all along.
    – hidefromkgb
    Oct 30 at 19:02






  • 1




    @hidefromkgb Nice. Maybe you could look at the links I've provided then. They have implementation for both animated GIF and animated WEBP.
    – android developer
    Oct 30 at 19:31












  • 1




    I`ve got a solution for GIFs, but unfortunately it`s implemented as a C header. Don`t know how hard it would be to port to Java.
    – hidefromkgb
    Oct 30 at 18:58







  • 1




    @hidefromkgb If you don't like Java, you can use Kotlin instead :) . Google has shown that it's now easier to use C/C++ from Java/Kotlin world. I suggest you to try...
    – android developer
    Oct 30 at 19:00






  • 2




    Well, OK. This is what I was talking about. Low-level low-levelness all along.
    – hidefromkgb
    Oct 30 at 19:02






  • 1




    @hidefromkgb Nice. Maybe you could look at the links I've provided then. They have implementation for both animated GIF and animated WEBP.
    – android developer
    Oct 30 at 19:31







1




1




I`ve got a solution for GIFs, but unfortunately it`s implemented as a C header. Don`t know how hard it would be to port to Java.
– hidefromkgb
Oct 30 at 18:58





I`ve got a solution for GIFs, but unfortunately it`s implemented as a C header. Don`t know how hard it would be to port to Java.
– hidefromkgb
Oct 30 at 18:58





1




1




@hidefromkgb If you don't like Java, you can use Kotlin instead :) . Google has shown that it's now easier to use C/C++ from Java/Kotlin world. I suggest you to try...
– android developer
Oct 30 at 19:00




@hidefromkgb If you don't like Java, you can use Kotlin instead :) . Google has shown that it's now easier to use C/C++ from Java/Kotlin world. I suggest you to try...
– android developer
Oct 30 at 19:00




2




2




Well, OK. This is what I was talking about. Low-level low-levelness all along.
– hidefromkgb
Oct 30 at 19:02




Well, OK. This is what I was talking about. Low-level low-levelness all along.
– hidefromkgb
Oct 30 at 19:02




1




1




@hidefromkgb Nice. Maybe you could look at the links I've provided then. They have implementation for both animated GIF and animated WEBP.
– android developer
Oct 30 at 19:31




@hidefromkgb Nice. Maybe you could look at the links I've provided then. They have implementation for both animated GIF and animated WEBP.
– android developer
Oct 30 at 19:31












2 Answers
2






active

oldest

votes

















up vote
1
down vote



accepted










OK, I got a possible solution, using Glide library, together with GlideWebpDecoder library .



I'm not sure if that's the best way to do it, but I think it should work fine. The next code shows how it's possible to make the drawable draw into the Bitmap instance that I create, for each frame that the animation needs to show. It's not exactly what I asked, but it might help others.



Here's the code (project available here) :



MyAppGlideModule.kt



@GlideModule
class MyAppGlideModule : AppGlideModule()


MainActivity.kt



class MainActivity : AppCompatActivity() {

var webpDrawable: WebpDrawable? = null

override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val imageView = findViewById<ImageView>(R.id.imageView)
Glide.with(this)
.load("https://res.cloudinary.com/demo/image/upload/fl_awebp/bored_animation.webp")
.into(object : SimpleTarget<Drawable>()
override fun onResourceReady(drawable: Drawable, transition: Transition<in Drawable>?)
if (drawable is WebpDrawable)
webpDrawable = drawable
val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, bitmap.width, bitmap.height)
val originalCallback = drawable.callback
drawable.setLoopCount(-1)
drawable.callback = object : Drawable.Callback
override fun unscheduleDrawable(who: Drawable, what: Runnable)
originalCallback?.unscheduleDrawable(who, what)
Log.d("AppLog", "unscheduleDrawable")


override fun invalidateDrawable(who: Drawable)
originalCallback?.invalidateDrawable(who)
who.draw(canvas)
imageView.setImageBitmap(bitmap)
Log.d("AppLog", "invalidateDrawable $drawable.frameIndex/$drawable.frameCount")


override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long)
originalCallback?.scheduleDrawable(who, what, `when`)
Log.d("AppLog", "scheduleDrawable $`when`")


drawable.start()


)


override fun onStart()
super.onStart()
webpDrawable?.start()


override fun onStop()
super.onStop()
webpDrawable?.stop()


override fun onDestroy()
super.onDestroy()
webpDrawable?.recycle()





Not sure why SimpleTarget is marked as deprecated, and what I should use instead, though.



Using a similar technique, I've also found out how to do it using ImageDecoder, but not with the same functionality for some reason. A sample project available here.



Here's the code:



MainActivity.kt



class MainActivity : AppCompatActivity() 
var webpDrawable: AnimatedImageDrawable? = null

@SuppressLint("StaticFieldLeak")
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val source = ImageDecoder.createSource(resources, R.raw.test)
object : AsyncTask<Void, Void, Drawable?>()
override fun doInBackground(vararg params: Void?): Drawable?
return try
ImageDecoder.decodeDrawable(source)
catch (e: Exception)
null



override fun onPostExecute(drawable: Drawable?)
super.onPostExecute(drawable)
// imageView.setImageDrawable(result)
if (drawable is AnimatedImageDrawable)
webpDrawable = drawable
val bitmap =
Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
drawable.setBounds(0, 0, bitmap.width, bitmap.height)
drawable.repeatCount = AnimatedImageDrawable.REPEAT_INFINITE
drawable.callback = object : Drawable.Callback
val handler = Handler()
override fun unscheduleDrawable(who: Drawable, what: Runnable)
Log.d("AppLog", "unscheduleDrawable")


override fun invalidateDrawable(who: Drawable)
who.draw(canvas)
imageView.setImageBitmap(bitmap)
Log.d("AppLog", "invalidateDrawable")


override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long)
Log.d("AppLog", "scheduleDrawable next frame in $`when` - SystemClock.uptimeMillis() ms")
handler.postAtTime(what, `when`)


drawable.start()


.execute()


override fun onStart()
super.onStart()
webpDrawable?.start()


override fun onStop()
super.onStop()
webpDrawable?.stop()








share|improve this answer





























    up vote
    1
    down vote













    see ImageDecoder.Source ...



    one needs to first create a source, with either:



    // source from file
    val source = ImageDecoder.createSource(file)

    // source from byte buffer
    val source = ImageDecoder.createSource(byteBuffer)

    // source from resource
    val source = ImageDecoder.createSource(resources, resId)

    // source from URI
    val source = ImageDecoder.createSource(contentResolver, uri)

    // source from asset file
    val source = ImageDecoder.createSource(assetManager, assetFileName)


    and then decode, with either:



    // create bitmap
    val bitmap = ImageDecoder.decodeBitmap(source)

    // create drawable
    val drawable = ImageDecoder.decodeDrawable(source)


    the resulting AnimatedImageDrawable has two methods: getNumberOfFrames() and getFrame(int).



    eg.



    if (drawable is AnimatedImageDrawable) 
    for (i in 1..drawable.getNumberOfFrames())
    val preview = drawable.getFrame(i)
    val bitmap = ...

    else
    /* regular Drawable */



    caching the previews might save on image processing - because repeated processing of many images may only drain the battery unnecessarily and affects performance.






    share|improve this answer






















    • I see. I thought this information is available before full decoding. Since I've already found the main solutions, yet I still have a bounty to grant, I'd like to ask if you know some other things: How to skip to specific frame and start animation from it? How to know for how long will a frame be needed to be shown and then get the next? Bonus: How to check if the animation has transparency or not (they have color space, but not sure if this helps) ? For now you get +1 for what you've found.
      – android developer
      10 hours ago










    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53024304%2fis-it-possible-to-get-the-new-imagedecoder-class-to-return-bitmaps-one-frame-af%23new-answer', 'question_page');

    );

    Post as a guest






























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    1
    down vote



    accepted










    OK, I got a possible solution, using Glide library, together with GlideWebpDecoder library .



    I'm not sure if that's the best way to do it, but I think it should work fine. The next code shows how it's possible to make the drawable draw into the Bitmap instance that I create, for each frame that the animation needs to show. It's not exactly what I asked, but it might help others.



    Here's the code (project available here) :



    MyAppGlideModule.kt



    @GlideModule
    class MyAppGlideModule : AppGlideModule()


    MainActivity.kt



    class MainActivity : AppCompatActivity() {

    var webpDrawable: WebpDrawable? = null

    override fun onCreate(savedInstanceState: Bundle?)
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val imageView = findViewById<ImageView>(R.id.imageView)
    Glide.with(this)
    .load("https://res.cloudinary.com/demo/image/upload/fl_awebp/bored_animation.webp")
    .into(object : SimpleTarget<Drawable>()
    override fun onResourceReady(drawable: Drawable, transition: Transition<in Drawable>?)
    if (drawable is WebpDrawable)
    webpDrawable = drawable
    val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)
    drawable.setBounds(0, 0, bitmap.width, bitmap.height)
    val originalCallback = drawable.callback
    drawable.setLoopCount(-1)
    drawable.callback = object : Drawable.Callback
    override fun unscheduleDrawable(who: Drawable, what: Runnable)
    originalCallback?.unscheduleDrawable(who, what)
    Log.d("AppLog", "unscheduleDrawable")


    override fun invalidateDrawable(who: Drawable)
    originalCallback?.invalidateDrawable(who)
    who.draw(canvas)
    imageView.setImageBitmap(bitmap)
    Log.d("AppLog", "invalidateDrawable $drawable.frameIndex/$drawable.frameCount")


    override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long)
    originalCallback?.scheduleDrawable(who, what, `when`)
    Log.d("AppLog", "scheduleDrawable $`when`")


    drawable.start()


    )


    override fun onStart()
    super.onStart()
    webpDrawable?.start()


    override fun onStop()
    super.onStop()
    webpDrawable?.stop()


    override fun onDestroy()
    super.onDestroy()
    webpDrawable?.recycle()





    Not sure why SimpleTarget is marked as deprecated, and what I should use instead, though.



    Using a similar technique, I've also found out how to do it using ImageDecoder, but not with the same functionality for some reason. A sample project available here.



    Here's the code:



    MainActivity.kt



    class MainActivity : AppCompatActivity() 
    var webpDrawable: AnimatedImageDrawable? = null

    @SuppressLint("StaticFieldLeak")
    override fun onCreate(savedInstanceState: Bundle?)
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val source = ImageDecoder.createSource(resources, R.raw.test)
    object : AsyncTask<Void, Void, Drawable?>()
    override fun doInBackground(vararg params: Void?): Drawable?
    return try
    ImageDecoder.decodeDrawable(source)
    catch (e: Exception)
    null



    override fun onPostExecute(drawable: Drawable?)
    super.onPostExecute(drawable)
    // imageView.setImageDrawable(result)
    if (drawable is AnimatedImageDrawable)
    webpDrawable = drawable
    val bitmap =
    Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)
    drawable.setBounds(0, 0, bitmap.width, bitmap.height)
    drawable.repeatCount = AnimatedImageDrawable.REPEAT_INFINITE
    drawable.callback = object : Drawable.Callback
    val handler = Handler()
    override fun unscheduleDrawable(who: Drawable, what: Runnable)
    Log.d("AppLog", "unscheduleDrawable")


    override fun invalidateDrawable(who: Drawable)
    who.draw(canvas)
    imageView.setImageBitmap(bitmap)
    Log.d("AppLog", "invalidateDrawable")


    override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long)
    Log.d("AppLog", "scheduleDrawable next frame in $`when` - SystemClock.uptimeMillis() ms")
    handler.postAtTime(what, `when`)


    drawable.start()


    .execute()


    override fun onStart()
    super.onStart()
    webpDrawable?.start()


    override fun onStop()
    super.onStop()
    webpDrawable?.stop()








    share|improve this answer


























      up vote
      1
      down vote



      accepted










      OK, I got a possible solution, using Glide library, together with GlideWebpDecoder library .



      I'm not sure if that's the best way to do it, but I think it should work fine. The next code shows how it's possible to make the drawable draw into the Bitmap instance that I create, for each frame that the animation needs to show. It's not exactly what I asked, but it might help others.



      Here's the code (project available here) :



      MyAppGlideModule.kt



      @GlideModule
      class MyAppGlideModule : AppGlideModule()


      MainActivity.kt



      class MainActivity : AppCompatActivity() {

      var webpDrawable: WebpDrawable? = null

      override fun onCreate(savedInstanceState: Bundle?)
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)
      val imageView = findViewById<ImageView>(R.id.imageView)
      Glide.with(this)
      .load("https://res.cloudinary.com/demo/image/upload/fl_awebp/bored_animation.webp")
      .into(object : SimpleTarget<Drawable>()
      override fun onResourceReady(drawable: Drawable, transition: Transition<in Drawable>?)
      if (drawable is WebpDrawable)
      webpDrawable = drawable
      val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
      val canvas = Canvas(bitmap)
      drawable.setBounds(0, 0, bitmap.width, bitmap.height)
      val originalCallback = drawable.callback
      drawable.setLoopCount(-1)
      drawable.callback = object : Drawable.Callback
      override fun unscheduleDrawable(who: Drawable, what: Runnable)
      originalCallback?.unscheduleDrawable(who, what)
      Log.d("AppLog", "unscheduleDrawable")


      override fun invalidateDrawable(who: Drawable)
      originalCallback?.invalidateDrawable(who)
      who.draw(canvas)
      imageView.setImageBitmap(bitmap)
      Log.d("AppLog", "invalidateDrawable $drawable.frameIndex/$drawable.frameCount")


      override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long)
      originalCallback?.scheduleDrawable(who, what, `when`)
      Log.d("AppLog", "scheduleDrawable $`when`")


      drawable.start()


      )


      override fun onStart()
      super.onStart()
      webpDrawable?.start()


      override fun onStop()
      super.onStop()
      webpDrawable?.stop()


      override fun onDestroy()
      super.onDestroy()
      webpDrawable?.recycle()





      Not sure why SimpleTarget is marked as deprecated, and what I should use instead, though.



      Using a similar technique, I've also found out how to do it using ImageDecoder, but not with the same functionality for some reason. A sample project available here.



      Here's the code:



      MainActivity.kt



      class MainActivity : AppCompatActivity() 
      var webpDrawable: AnimatedImageDrawable? = null

      @SuppressLint("StaticFieldLeak")
      override fun onCreate(savedInstanceState: Bundle?)
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)
      val source = ImageDecoder.createSource(resources, R.raw.test)
      object : AsyncTask<Void, Void, Drawable?>()
      override fun doInBackground(vararg params: Void?): Drawable?
      return try
      ImageDecoder.decodeDrawable(source)
      catch (e: Exception)
      null



      override fun onPostExecute(drawable: Drawable?)
      super.onPostExecute(drawable)
      // imageView.setImageDrawable(result)
      if (drawable is AnimatedImageDrawable)
      webpDrawable = drawable
      val bitmap =
      Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
      val canvas = Canvas(bitmap)
      drawable.setBounds(0, 0, bitmap.width, bitmap.height)
      drawable.repeatCount = AnimatedImageDrawable.REPEAT_INFINITE
      drawable.callback = object : Drawable.Callback
      val handler = Handler()
      override fun unscheduleDrawable(who: Drawable, what: Runnable)
      Log.d("AppLog", "unscheduleDrawable")


      override fun invalidateDrawable(who: Drawable)
      who.draw(canvas)
      imageView.setImageBitmap(bitmap)
      Log.d("AppLog", "invalidateDrawable")


      override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long)
      Log.d("AppLog", "scheduleDrawable next frame in $`when` - SystemClock.uptimeMillis() ms")
      handler.postAtTime(what, `when`)


      drawable.start()


      .execute()


      override fun onStart()
      super.onStart()
      webpDrawable?.start()


      override fun onStop()
      super.onStop()
      webpDrawable?.stop()








      share|improve this answer
























        up vote
        1
        down vote



        accepted







        up vote
        1
        down vote



        accepted






        OK, I got a possible solution, using Glide library, together with GlideWebpDecoder library .



        I'm not sure if that's the best way to do it, but I think it should work fine. The next code shows how it's possible to make the drawable draw into the Bitmap instance that I create, for each frame that the animation needs to show. It's not exactly what I asked, but it might help others.



        Here's the code (project available here) :



        MyAppGlideModule.kt



        @GlideModule
        class MyAppGlideModule : AppGlideModule()


        MainActivity.kt



        class MainActivity : AppCompatActivity() {

        var webpDrawable: WebpDrawable? = null

        override fun onCreate(savedInstanceState: Bundle?)
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val imageView = findViewById<ImageView>(R.id.imageView)
        Glide.with(this)
        .load("https://res.cloudinary.com/demo/image/upload/fl_awebp/bored_animation.webp")
        .into(object : SimpleTarget<Drawable>()
        override fun onResourceReady(drawable: Drawable, transition: Transition<in Drawable>?)
        if (drawable is WebpDrawable)
        webpDrawable = drawable
        val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, bitmap.width, bitmap.height)
        val originalCallback = drawable.callback
        drawable.setLoopCount(-1)
        drawable.callback = object : Drawable.Callback
        override fun unscheduleDrawable(who: Drawable, what: Runnable)
        originalCallback?.unscheduleDrawable(who, what)
        Log.d("AppLog", "unscheduleDrawable")


        override fun invalidateDrawable(who: Drawable)
        originalCallback?.invalidateDrawable(who)
        who.draw(canvas)
        imageView.setImageBitmap(bitmap)
        Log.d("AppLog", "invalidateDrawable $drawable.frameIndex/$drawable.frameCount")


        override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long)
        originalCallback?.scheduleDrawable(who, what, `when`)
        Log.d("AppLog", "scheduleDrawable $`when`")


        drawable.start()


        )


        override fun onStart()
        super.onStart()
        webpDrawable?.start()


        override fun onStop()
        super.onStop()
        webpDrawable?.stop()


        override fun onDestroy()
        super.onDestroy()
        webpDrawable?.recycle()





        Not sure why SimpleTarget is marked as deprecated, and what I should use instead, though.



        Using a similar technique, I've also found out how to do it using ImageDecoder, but not with the same functionality for some reason. A sample project available here.



        Here's the code:



        MainActivity.kt



        class MainActivity : AppCompatActivity() 
        var webpDrawable: AnimatedImageDrawable? = null

        @SuppressLint("StaticFieldLeak")
        override fun onCreate(savedInstanceState: Bundle?)
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val source = ImageDecoder.createSource(resources, R.raw.test)
        object : AsyncTask<Void, Void, Drawable?>()
        override fun doInBackground(vararg params: Void?): Drawable?
        return try
        ImageDecoder.decodeDrawable(source)
        catch (e: Exception)
        null



        override fun onPostExecute(drawable: Drawable?)
        super.onPostExecute(drawable)
        // imageView.setImageDrawable(result)
        if (drawable is AnimatedImageDrawable)
        webpDrawable = drawable
        val bitmap =
        Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, bitmap.width, bitmap.height)
        drawable.repeatCount = AnimatedImageDrawable.REPEAT_INFINITE
        drawable.callback = object : Drawable.Callback
        val handler = Handler()
        override fun unscheduleDrawable(who: Drawable, what: Runnable)
        Log.d("AppLog", "unscheduleDrawable")


        override fun invalidateDrawable(who: Drawable)
        who.draw(canvas)
        imageView.setImageBitmap(bitmap)
        Log.d("AppLog", "invalidateDrawable")


        override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long)
        Log.d("AppLog", "scheduleDrawable next frame in $`when` - SystemClock.uptimeMillis() ms")
        handler.postAtTime(what, `when`)


        drawable.start()


        .execute()


        override fun onStart()
        super.onStart()
        webpDrawable?.start()


        override fun onStop()
        super.onStop()
        webpDrawable?.stop()








        share|improve this answer














        OK, I got a possible solution, using Glide library, together with GlideWebpDecoder library .



        I'm not sure if that's the best way to do it, but I think it should work fine. The next code shows how it's possible to make the drawable draw into the Bitmap instance that I create, for each frame that the animation needs to show. It's not exactly what I asked, but it might help others.



        Here's the code (project available here) :



        MyAppGlideModule.kt



        @GlideModule
        class MyAppGlideModule : AppGlideModule()


        MainActivity.kt



        class MainActivity : AppCompatActivity() {

        var webpDrawable: WebpDrawable? = null

        override fun onCreate(savedInstanceState: Bundle?)
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val imageView = findViewById<ImageView>(R.id.imageView)
        Glide.with(this)
        .load("https://res.cloudinary.com/demo/image/upload/fl_awebp/bored_animation.webp")
        .into(object : SimpleTarget<Drawable>()
        override fun onResourceReady(drawable: Drawable, transition: Transition<in Drawable>?)
        if (drawable is WebpDrawable)
        webpDrawable = drawable
        val bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, bitmap.width, bitmap.height)
        val originalCallback = drawable.callback
        drawable.setLoopCount(-1)
        drawable.callback = object : Drawable.Callback
        override fun unscheduleDrawable(who: Drawable, what: Runnable)
        originalCallback?.unscheduleDrawable(who, what)
        Log.d("AppLog", "unscheduleDrawable")


        override fun invalidateDrawable(who: Drawable)
        originalCallback?.invalidateDrawable(who)
        who.draw(canvas)
        imageView.setImageBitmap(bitmap)
        Log.d("AppLog", "invalidateDrawable $drawable.frameIndex/$drawable.frameCount")


        override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long)
        originalCallback?.scheduleDrawable(who, what, `when`)
        Log.d("AppLog", "scheduleDrawable $`when`")


        drawable.start()


        )


        override fun onStart()
        super.onStart()
        webpDrawable?.start()


        override fun onStop()
        super.onStop()
        webpDrawable?.stop()


        override fun onDestroy()
        super.onDestroy()
        webpDrawable?.recycle()





        Not sure why SimpleTarget is marked as deprecated, and what I should use instead, though.



        Using a similar technique, I've also found out how to do it using ImageDecoder, but not with the same functionality for some reason. A sample project available here.



        Here's the code:



        MainActivity.kt



        class MainActivity : AppCompatActivity() 
        var webpDrawable: AnimatedImageDrawable? = null

        @SuppressLint("StaticFieldLeak")
        override fun onCreate(savedInstanceState: Bundle?)
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val source = ImageDecoder.createSource(resources, R.raw.test)
        object : AsyncTask<Void, Void, Drawable?>()
        override fun doInBackground(vararg params: Void?): Drawable?
        return try
        ImageDecoder.decodeDrawable(source)
        catch (e: Exception)
        null



        override fun onPostExecute(drawable: Drawable?)
        super.onPostExecute(drawable)
        // imageView.setImageDrawable(result)
        if (drawable is AnimatedImageDrawable)
        webpDrawable = drawable
        val bitmap =
        Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, bitmap.width, bitmap.height)
        drawable.repeatCount = AnimatedImageDrawable.REPEAT_INFINITE
        drawable.callback = object : Drawable.Callback
        val handler = Handler()
        override fun unscheduleDrawable(who: Drawable, what: Runnable)
        Log.d("AppLog", "unscheduleDrawable")


        override fun invalidateDrawable(who: Drawable)
        who.draw(canvas)
        imageView.setImageBitmap(bitmap)
        Log.d("AppLog", "invalidateDrawable")


        override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long)
        Log.d("AppLog", "scheduleDrawable next frame in $`when` - SystemClock.uptimeMillis() ms")
        handler.postAtTime(what, `when`)


        drawable.start()


        .execute()


        override fun onStart()
        super.onStart()
        webpDrawable?.start()


        override fun onStop()
        super.onStop()
        webpDrawable?.stop()









        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 17 hours ago

























        answered yesterday









        android developer

        57k95452829




        57k95452829






















            up vote
            1
            down vote













            see ImageDecoder.Source ...



            one needs to first create a source, with either:



            // source from file
            val source = ImageDecoder.createSource(file)

            // source from byte buffer
            val source = ImageDecoder.createSource(byteBuffer)

            // source from resource
            val source = ImageDecoder.createSource(resources, resId)

            // source from URI
            val source = ImageDecoder.createSource(contentResolver, uri)

            // source from asset file
            val source = ImageDecoder.createSource(assetManager, assetFileName)


            and then decode, with either:



            // create bitmap
            val bitmap = ImageDecoder.decodeBitmap(source)

            // create drawable
            val drawable = ImageDecoder.decodeDrawable(source)


            the resulting AnimatedImageDrawable has two methods: getNumberOfFrames() and getFrame(int).



            eg.



            if (drawable is AnimatedImageDrawable) 
            for (i in 1..drawable.getNumberOfFrames())
            val preview = drawable.getFrame(i)
            val bitmap = ...

            else
            /* regular Drawable */



            caching the previews might save on image processing - because repeated processing of many images may only drain the battery unnecessarily and affects performance.






            share|improve this answer






















            • I see. I thought this information is available before full decoding. Since I've already found the main solutions, yet I still have a bounty to grant, I'd like to ask if you know some other things: How to skip to specific frame and start animation from it? How to know for how long will a frame be needed to be shown and then get the next? Bonus: How to check if the animation has transparency or not (they have color space, but not sure if this helps) ? For now you get +1 for what you've found.
              – android developer
              10 hours ago














            up vote
            1
            down vote













            see ImageDecoder.Source ...



            one needs to first create a source, with either:



            // source from file
            val source = ImageDecoder.createSource(file)

            // source from byte buffer
            val source = ImageDecoder.createSource(byteBuffer)

            // source from resource
            val source = ImageDecoder.createSource(resources, resId)

            // source from URI
            val source = ImageDecoder.createSource(contentResolver, uri)

            // source from asset file
            val source = ImageDecoder.createSource(assetManager, assetFileName)


            and then decode, with either:



            // create bitmap
            val bitmap = ImageDecoder.decodeBitmap(source)

            // create drawable
            val drawable = ImageDecoder.decodeDrawable(source)


            the resulting AnimatedImageDrawable has two methods: getNumberOfFrames() and getFrame(int).



            eg.



            if (drawable is AnimatedImageDrawable) 
            for (i in 1..drawable.getNumberOfFrames())
            val preview = drawable.getFrame(i)
            val bitmap = ...

            else
            /* regular Drawable */



            caching the previews might save on image processing - because repeated processing of many images may only drain the battery unnecessarily and affects performance.






            share|improve this answer






















            • I see. I thought this information is available before full decoding. Since I've already found the main solutions, yet I still have a bounty to grant, I'd like to ask if you know some other things: How to skip to specific frame and start animation from it? How to know for how long will a frame be needed to be shown and then get the next? Bonus: How to check if the animation has transparency or not (they have color space, but not sure if this helps) ? For now you get +1 for what you've found.
              – android developer
              10 hours ago












            up vote
            1
            down vote










            up vote
            1
            down vote









            see ImageDecoder.Source ...



            one needs to first create a source, with either:



            // source from file
            val source = ImageDecoder.createSource(file)

            // source from byte buffer
            val source = ImageDecoder.createSource(byteBuffer)

            // source from resource
            val source = ImageDecoder.createSource(resources, resId)

            // source from URI
            val source = ImageDecoder.createSource(contentResolver, uri)

            // source from asset file
            val source = ImageDecoder.createSource(assetManager, assetFileName)


            and then decode, with either:



            // create bitmap
            val bitmap = ImageDecoder.decodeBitmap(source)

            // create drawable
            val drawable = ImageDecoder.decodeDrawable(source)


            the resulting AnimatedImageDrawable has two methods: getNumberOfFrames() and getFrame(int).



            eg.



            if (drawable is AnimatedImageDrawable) 
            for (i in 1..drawable.getNumberOfFrames())
            val preview = drawable.getFrame(i)
            val bitmap = ...

            else
            /* regular Drawable */



            caching the previews might save on image processing - because repeated processing of many images may only drain the battery unnecessarily and affects performance.






            share|improve this answer














            see ImageDecoder.Source ...



            one needs to first create a source, with either:



            // source from file
            val source = ImageDecoder.createSource(file)

            // source from byte buffer
            val source = ImageDecoder.createSource(byteBuffer)

            // source from resource
            val source = ImageDecoder.createSource(resources, resId)

            // source from URI
            val source = ImageDecoder.createSource(contentResolver, uri)

            // source from asset file
            val source = ImageDecoder.createSource(assetManager, assetFileName)


            and then decode, with either:



            // create bitmap
            val bitmap = ImageDecoder.decodeBitmap(source)

            // create drawable
            val drawable = ImageDecoder.decodeDrawable(source)


            the resulting AnimatedImageDrawable has two methods: getNumberOfFrames() and getFrame(int).



            eg.



            if (drawable is AnimatedImageDrawable) 
            for (i in 1..drawable.getNumberOfFrames())
            val preview = drawable.getFrame(i)
            val bitmap = ...

            else
            /* regular Drawable */



            caching the previews might save on image processing - because repeated processing of many images may only drain the battery unnecessarily and affects performance.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited 12 hours ago

























            answered 12 hours ago









            Martin Zeitler

            11k33559




            11k33559











            • I see. I thought this information is available before full decoding. Since I've already found the main solutions, yet I still have a bounty to grant, I'd like to ask if you know some other things: How to skip to specific frame and start animation from it? How to know for how long will a frame be needed to be shown and then get the next? Bonus: How to check if the animation has transparency or not (they have color space, but not sure if this helps) ? For now you get +1 for what you've found.
              – android developer
              10 hours ago
















            • I see. I thought this information is available before full decoding. Since I've already found the main solutions, yet I still have a bounty to grant, I'd like to ask if you know some other things: How to skip to specific frame and start animation from it? How to know for how long will a frame be needed to be shown and then get the next? Bonus: How to check if the animation has transparency or not (they have color space, but not sure if this helps) ? For now you get +1 for what you've found.
              – android developer
              10 hours ago















            I see. I thought this information is available before full decoding. Since I've already found the main solutions, yet I still have a bounty to grant, I'd like to ask if you know some other things: How to skip to specific frame and start animation from it? How to know for how long will a frame be needed to be shown and then get the next? Bonus: How to check if the animation has transparency or not (they have color space, but not sure if this helps) ? For now you get +1 for what you've found.
            – android developer
            10 hours ago




            I see. I thought this information is available before full decoding. Since I've already found the main solutions, yet I still have a bounty to grant, I'd like to ask if you know some other things: How to skip to specific frame and start animation from it? How to know for how long will a frame be needed to be shown and then get the next? Bonus: How to check if the animation has transparency or not (they have color space, but not sure if this helps) ? For now you get +1 for what you've found.
            – android developer
            10 hours ago

















             

            draft saved


            draft discarded















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53024304%2fis-it-possible-to-get-the-new-imagedecoder-class-to-return-bitmaps-one-frame-af%23new-answer', 'question_page');

            );

            Post as a guest














































































            Popular posts from this blog

            27

            Top Tejano songwriter Luis Silva dead of heart attack at 64

            Category:Rhetoric