Fix AnimatedImage component (#2174)

* Fix and optimize image animation for 0 and 1 frames

* Change default frame duration to 10fps to match those of a browser

* Fix zero-size image with ImageBitmap.Blank
This commit is contained in:
Ilya Ryzhenkov
2022-07-07 19:53:33 +03:00
committed by GitHub
parent 3129fa1d53
commit 7fbbdd8eca

View File

@@ -10,7 +10,7 @@ import org.jetbrains.skia.Codec
import java.net.MalformedURLException
import java.net.URL
private const val DEFAULT_FRAME_DURATION = 50
private const val DEFAULT_FRAME_DURATION = 100
actual class AnimatedImage(val codec: Codec)
@@ -26,42 +26,50 @@ actual suspend fun loadResourceAnimatedImage(path: String): AnimatedImage {
@Composable
actual fun AnimatedImage.animate(): ImageBitmap {
val transition = rememberInfiniteTransition()
val frameIndex by transition.animateValue(
initialValue = 0,
targetValue = codec.frameCount - 1,
Int.VectorConverter,
animationSpec = infiniteRepeatable(
animation = keyframes {
durationMillis = 0
for ((index, frame) in codec.framesInfo.withIndex()) {
index at durationMillis
val frameDuration = calcFrameDuration(frame)
durationMillis += frameDuration
}
when (codec.frameCount) {
0 -> return ImageBitmap.Blank // No frames at all
1 -> {
// Just one frame, no animation
val bitmap = remember(codec) { Bitmap().apply { allocPixels(codec.imageInfo) } }
remember(bitmap) {
codec.readPixels(bitmap, 0)
}
)
)
return bitmap.asComposeImageBitmap()
}
else -> {
val transition = rememberInfiniteTransition()
val frameIndex by transition.animateValue(
initialValue = 0,
targetValue = codec.frameCount - 1,
Int.VectorConverter,
animationSpec = infiniteRepeatable(
animation = keyframes {
durationMillis = 0
for ((index, frame) in codec.framesInfo.withIndex()) {
index at durationMillis
val frameDuration = calcFrameDuration(frame)
val bitmap = remember(codec) { Bitmap().apply { allocPixels(codec.imageInfo) } }
durationMillis += frameDuration
}
}
)
)
remember(bitmap, frameIndex) {
codec.readPixels(bitmap, frameIndex)
val bitmap = remember(codec) { Bitmap().apply { allocPixels(codec.imageInfo) } }
remember(bitmap, frameIndex) {
codec.readPixels(bitmap, frameIndex)
}
return bitmap.asComposeImageBitmap()
}
}
return bitmap.asComposeImageBitmap()
}
private fun calcFrameDuration(frame: AnimationFrameInfo): Int {
var frameDuration = frame.duration
// If the frame does not contain information about a duration, set a reasonable constant duration
if (frameDuration == 0) {
frameDuration = DEFAULT_FRAME_DURATION
}
return frameDuration
val frameDuration = frame.duration
return if (frameDuration == 0) DEFAULT_FRAME_DURATION else frameDuration
}
/**