and*_*per 17 android animated-gif imagedecoder animated-webp
我试图手动(逐帧)查看动画GIF和WEBP文件的位图,这样它不仅可以用于视图,还可以用于其他情况(例如动态壁纸).
仅使用ImageDecoder API(此处为示例)从Android P支持动画GIF/WEBP文件.
对于GIF,我想尝试滑翔的任务,但我失败了,所以我试图克服这一,通过使用一个库,允许(加载它们在这里,解决方案在这里).我认为它运作正常.
对于WebP,我以为我找到了另一个可以在较旧的Android版本上运行的库(这里,在这里制作了fork ),但似乎在某些情况下它无法很好地处理WebP文件(在此报道).我试图弄清楚问题是什么以及如何解决,但我没有成功.
因此,假设有一天谷歌将通过支持库支持旧版Android的GIF和WEBP动画(他们在这里写了),我决定尝试使用ImageDecoder来完成任务.
事实上,在ImageDecoder的整个API中,我们应该如何使用它.我不知道如何克服其局限性.
这就是ImageDecoder如何用于在ImageView上显示动画WebP(当然,这里只有一个示例):
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()
}
}
Run Code Online (Sandbox Code Playgroud)
我试图阅读ImageDecoder和AnimatedImageDrawable的所有文档,并查看其代码,但我不知道如何手动遍历每个帧,并有时间需要在它们之间等待.
有没有办法使用ImageDecoder API手动遍历每个帧,获取一个位图来绘制并知道在帧之间需要等待多长时间?有可用的解决方法吗?也许甚至使用AnimatedImageDrawable?
我想在较旧的Android版本上做同样的事情.可能吗?如果是这样的话?也许在不同的API /库上?谷歌写道,它的工作方式是在较旧的Android版本上使用ImageDecoder,但我没有看到它被提到任何地方(除了我提供的链接).可能尚未准备好...... Android P甚至没有达到0.1%的用户......也许Fresco能做到吗?我也试过在那里检查它,但我也没有看到它能够做到这一点,并且它只是一个巨大的库,只用于这个任务,所以我更喜欢使用不同的库而不是..我也知道libwebp是可用的,但它是用C/C++而不确定它是否适合Android,以及它是否适用于Android/Java/Kotlin上的端口.
编辑:
因为我认为我得到了我想要的东西,对于第三方库和ImageDecoder,能够从动画WebP中获取位图,我仍然想知道如何使用ImageDecoder获取帧数和当前帧,如果这是可能的.我尝试过使用ImageDecoder.decodeDrawable(source, object : ImageDecoder.OnHeaderDecodedListener...
,但是它没有提供帧数信息,并且我无法在API中看到我可以转到特定的帧索引并从那里开始,或者知道特定的帧有多长需要进入下一帧.所以我对这里的那些人做了一些了解.
可悲的是,我也发现谷歌的ImageDecoder也适用于较旧的Android版本.
如果有一种方法可以像我对HEIC相对较新的动画文件那样做,那也很有趣.目前仅支持Android P.
好的,使用Glide库和GlideWebpDecoder库,我得到了一个可能的解决方案。
我不确定这是否是最好的方法,但是我认为它应该可以正常工作。接下来的代码显示了如何针对动画需要显示的每个帧,将可绘制的绘制放入我创建的Bitmap实例中。这不完全是我的要求,但可能会帮助其他人。
这是代码(可在此处找到项目):
CallbackEx.kt
abstract class CallbackEx : Drawable.Callback {
override fun unscheduleDrawable(who: Drawable, what: Runnable) {}
override fun invalidateDrawable(who: Drawable) {}
override fun scheduleDrawable(who: Drawable, what: Runnable, `when`: Long) {}
}
Run Code Online (Sandbox Code Playgroud)
MyAppGlideModule.kt
@GlideModule
class MyAppGlideModule : AppGlideModule()
Run Code Online (Sandbox Code Playgroud)
MainActivity.kt
class MainActivity : AppCompatActivity() {
var webpDrawable: WebpDrawable? = null
var gifDrawable: GifDrawable? = null
var callback: Drawable.Callback? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
useFrameByFrameDecoding()
// useNormalDecoding()
}
fun useNormalDecoding() {
//webp url : https://res.cloudinary.com/demo/image/upload/fl_awebp/bored_animation.webp
Glide.with(this)
// .load(R.raw.test)
// .load(R.raw.fast)
.load(R.raw.example2)
// .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>?) {
imageView.setImageDrawable(drawable)
when (drawable) {
is GifDrawable -> {
drawable.start()
}
is WebpDrawable -> {
drawable.start()
}
}
}
})
}
fun useFrameByFrameDecoding() {
//webp url : https://res.cloudinary.com/demo/image/upload/fl_awebp/bored_animation.webp
Glide.with(this)
.load(R.raw.test)
// .load(R.raw.fast)
// .load(R.raw.example2)
// .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>?) {
// val callback
when (drawable) {
is GifDrawable -> {
gifDrawable = 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.setLoopCount(GifDrawable.LOOP_FOREVER)
callback = object : CallbackEx() {
override fun invalidateDrawable(who: Drawable) {
who.draw(canvas)
imageView.setImageBitmap(bitmap)
Log.d("AppLog", "invalidateDrawable ${drawable.toString().substringAfter('@')} ${drawable.frameIndex}/${drawable.frameCount}")
}
}
drawable.callback = callback
drawable.start()
}
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)
drawable.setLoopCount(WebpDrawable.LOOP_FOREVER)
callback = object : CallbackEx() {
override fun invalidateDrawable(who: Drawable) {
who.draw(canvas)
imageView.setImageBitmap(bitmap)
Log.d("AppLog", "invalidateDrawable ${drawable.toString().substringAfter('@')} ${drawable.frameIndex}/${drawable.frameCount}")
}
}
drawable.callback = callback
drawable.start()
}
}
}
})
}
override fun onStart() {
super.onStart()
gifDrawable?.start()
gifDrawable?.start()
}
override fun onStop() {
super.onStop()
Log.d("AppLog", "onStop")
webpDrawable?.stop()
gifDrawable?.stop()
}
}
Run Code Online (Sandbox Code Playgroud)
不知道为什么SimpleTarget
将其标记为已弃用,但是我应该使用什么代替。
使用类似的技术,我还发现了如何使用ImageDecoder进行操作,但是由于某种原因,它们却没有相同的功能。这里有一个示例项目。
这是代码:
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()
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1325 次 |
最近记录: |