Fix PNG animations.

Adds an `InputStreamFactory` APNG decoder so images animate correctly when loaded via the new `DecryptableUriStreamLoader`.
This commit is contained in:
jeffrey-signal
2025-08-12 09:56:46 -04:00
committed by GitHub
parent ee657cb075
commit 709ff90d35
2 changed files with 49 additions and 2 deletions

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2025 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.thoughtcrime.securesms.glide.cache
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.mms.InputStreamFactory
import java.nio.ByteBuffer
/**
* A variant of [ApngStreamCacheDecoder] that decodes animated PNGs from [org.thoughtcrime.securesms.mms.InputStreamFactory] sources.
*/
class ApngStreamFactoryDecoder(
private val byteBufferDecoder: ResourceDecoder<ByteBuffer, APNGDecoder>
) : ResourceDecoder<InputStreamFactory, APNGDecoder> {
override fun handles(source: InputStreamFactory, options: Options): Boolean {
return if (options.get(ApngOptions.ANIMATE) == true) {
return APNGParser.isAPNG(LimitedReader(StreamReader(source.create()), GlideStreamConfig.markReadLimitBytes))
} else {
false
}
}
override fun decode(
source: InputStreamFactory,
width: Int,
height: Int,
options: Options
): Resource<APNGDecoder>? {
val data = StreamUtil.readFully(source.create())
val byteBuffer = ByteBuffer.wrap(data)
return byteBufferDecoder.decode(byteBuffer, width, height, options)
}
}