Browse Source

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
pull/2183/head
Ilya Ryzhenkov 2 years ago committed by GitHub
parent
commit
7fbbdd8eca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 66
      components/AnimatedImage/library/src/desktopMain/kotlin/org/jetbrains/compose/animatedimage/DesktopAnimatedImage.kt

66
components/AnimatedImage/library/src/desktopMain/kotlin/org/jetbrains/compose/animatedimage/DesktopAnimatedImage.kt

@ -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
}
/**

Loading…
Cancel
Save