Fix broken animations for some sticker packs.

Makes a few tweaks to the APNG handling to make sure images of that type are properly identified and decoded by the StreamFactoryApngDecoder.
This commit is contained in:
jeffrey-signal
2025-08-19 20:12:25 -04:00
committed by GitHub
parent 50ed455717
commit d983538122
3 changed files with 15 additions and 9 deletions

View File

@@ -45,9 +45,11 @@ class StreamBitmapDecoder(
}
return when (imageType) {
ImageHeaderParser.ImageType.GIF, ImageHeaderParser.ImageType.PNG_A -> false
ImageHeaderParser.ImageType.WEBP_A -> true
ImageHeaderParser.ImageType.ANIMATED_WEBP -> true
ImageHeaderParser.ImageType.GIF,
ImageHeaderParser.ImageType.PNG_A,
ImageHeaderParser.ImageType.WEBP_A,
ImageHeaderParser.ImageType.ANIMATED_WEBP -> false
else -> true
}
}

View File

@@ -5,14 +5,15 @@
package org.thoughtcrime.securesms.glide.cache
import com.bumptech.glide.Glide
import com.bumptech.glide.Registry
import com.bumptech.glide.load.ImageHeaderParser
import com.bumptech.glide.load.Options
import com.bumptech.glide.load.ResourceDecoder
import com.bumptech.glide.load.engine.Resource
import org.signal.core.util.StreamUtil
import org.signal.glide.apng.decode.APNGDecoder
import org.signal.glide.apng.decode.APNGParser
import org.signal.glide.common.io.StreamReader
import org.thoughtcrime.securesms.glide.GlideStreamConfig
import org.thoughtcrime.securesms.glide.ImageHeaderParserUtils
import org.thoughtcrime.securesms.mms.InputStreamFactory
import java.nio.ByteBuffer
@@ -20,12 +21,15 @@ import java.nio.ByteBuffer
* A variant of [StreamApngDecoder] that decodes animated PNGs from [InputStreamFactory] sources.
*/
class StreamFactoryApngDecoder(
private val byteBufferDecoder: ResourceDecoder<ByteBuffer, APNGDecoder>
private val byteBufferDecoder: ResourceDecoder<ByteBuffer, APNGDecoder>,
private val glide: Glide,
private val registry: Registry
) : ResourceDecoder<InputStreamFactory, APNGDecoder> {
override fun handles(source: InputStreamFactory, options: Options): Boolean {
return if (options.get(ApngOptions.ANIMATE) == true) {
APNGParser.isAPNG(LimitedReader(StreamReader(source.create()), GlideStreamConfig.markReadLimitBytes))
val imageType = ImageHeaderParserUtils.getType(registry.imageHeaderParsers, source.create(), glide.arrayPool)
imageType == ImageHeaderParser.ImageType.PNG_A
} else {
false
}

View File

@@ -88,7 +88,7 @@ public class SignalGlideComponents implements RegisterGlideComponents {
ByteBufferApngDecoder byteBufferApngDecoder = new ByteBufferApngDecoder();
StreamApngDecoder streamApngDecoder = new StreamApngDecoder(byteBufferApngDecoder);
StreamFactoryApngDecoder streamFactoryApngDecoder = new StreamFactoryApngDecoder(byteBufferApngDecoder);
StreamFactoryApngDecoder streamFactoryApngDecoder = new StreamFactoryApngDecoder(byteBufferApngDecoder, glide, registry);
registry.prepend(InputStream.class, APNGDecoder.class, streamApngDecoder);
registry.prepend(InputStreamFactory.class, APNGDecoder.class, streamFactoryApngDecoder);