APNG identification
This commit is contained in:
parent
01e1058f1a
commit
33841788f7
5 changed files with 50 additions and 5 deletions
|
@ -7,7 +7,7 @@ All notable changes to this project will be documented in this file.
|
|||
### Added
|
||||
|
||||
- option to set the Tags page as home
|
||||
- support for animated PNG
|
||||
- support for animated PNG (requires rescan)
|
||||
- Info: added day filter with item date
|
||||
- Widget: option to update image on tap
|
||||
- Slideshow / Screen saver: option for random transition
|
||||
|
|
|
@ -301,7 +301,7 @@ This change eventually prevents building the app with Flutter v3.7.11.
|
|||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
<!-- as of Flutter v3.7.7, background blur yields black screen with Impeller -->
|
||||
<!-- as of Flutter v3.10.1, Impeller badly renders text, fails to render videos, and crashes with Google Maps -->
|
||||
<meta-data
|
||||
android:name="io.flutter.embedding.android.EnableImpeller"
|
||||
android:value="false" />
|
||||
|
|
|
@ -75,6 +75,7 @@ import deckers.thibault.aves.metadata.metadataextractor.Helper.getSafeInt
|
|||
import deckers.thibault.aves.metadata.metadataextractor.Helper.getSafeRational
|
||||
import deckers.thibault.aves.metadata.metadataextractor.Helper.getSafeString
|
||||
import deckers.thibault.aves.metadata.metadataextractor.Helper.isPngTextDir
|
||||
import deckers.thibault.aves.metadata.metadataextractor.PngActlDirectory
|
||||
import deckers.thibault.aves.model.FieldMap
|
||||
import deckers.thibault.aves.utils.ContextUtils.queryContentPropValue
|
||||
import deckers.thibault.aves.utils.LogUtils
|
||||
|
@ -657,6 +658,11 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// identification of animated PNG
|
||||
if (metadata.containsDirectoryOfType(PngActlDirectory::class.java)) {
|
||||
flags = flags or MASK_IS_ANIMATED
|
||||
}
|
||||
}
|
||||
|
||||
MimeTypes.GIF -> {
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package deckers.thibault.aves.metadata.metadataextractor
|
||||
import com.drew.imaging.png.PngChunkType
|
||||
import com.drew.metadata.png.PngDirectory
|
||||
|
||||
class PngActlDirectory : PngDirectory(chunkType) {
|
||||
override fun getTagNameMap(): HashMap<Int, String> {
|
||||
return tagNames
|
||||
}
|
||||
|
||||
companion object {
|
||||
val chunkType = PngChunkType("acTL")
|
||||
|
||||
// tags should be distinct from those already defined in `PngDirectory`
|
||||
const val TAG_NUM_FRAMES = 101
|
||||
const val TAG_NUM_PLAYS = 102
|
||||
|
||||
private val tagNames = hashMapOf(
|
||||
TAG_NUM_FRAMES to "Number Of Frames",
|
||||
TAG_NUM_PLAYS to "Number Of Plays",
|
||||
)
|
||||
}
|
||||
}
|
|
@ -34,9 +34,10 @@ import java.io.InputStream
|
|||
import java.util.zip.InflaterInputStream
|
||||
import java.util.zip.ZipException
|
||||
|
||||
// adapted from `PngMetadataReader` to prevent OOM from reading large chunks
|
||||
// as of `metadata-extractor` v2.18.0, there is no way to customize the reader
|
||||
// without copying `desiredChunkTypes` and the whole `processChunk` function
|
||||
// adapted from `PngMetadataReader` to:
|
||||
// - prevent OOM from reading large chunks. As of `metadata-extractor` v2.18.0, there is no way to customize the reader
|
||||
// without copying `desiredChunkTypes` and the whole `processChunk` function.
|
||||
// - parse `acTL` chunk to identify animated PNGs.
|
||||
object SafePngMetadataReader {
|
||||
private val LOG_TAG = LogUtils.createTag<SafePngMetadataReader>()
|
||||
|
||||
|
@ -60,6 +61,7 @@ object SafePngMetadataReader {
|
|||
PngChunkType.pHYs,
|
||||
PngChunkType.sBIT,
|
||||
PngChunkType.eXIf,
|
||||
PngActlDirectory.chunkType,
|
||||
)
|
||||
|
||||
@Throws(IOException::class, PngProcessingException::class)
|
||||
|
@ -99,6 +101,21 @@ object SafePngMetadataReader {
|
|||
directory.setInt(PngDirectory.TAG_FILTER_METHOD, header.filterMethod.toInt())
|
||||
directory.setInt(PngDirectory.TAG_INTERLACE_METHOD, header.interlaceMethod.toInt())
|
||||
metadata.addDirectory(directory)
|
||||
// TLAD insert start
|
||||
} else if (chunkType == PngActlDirectory.chunkType) {
|
||||
if (bytes.size != 8) {
|
||||
throw PngProcessingException("Invalid number of bytes")
|
||||
}
|
||||
val reader = SequentialByteArrayReader(bytes)
|
||||
try {
|
||||
metadata.addDirectory(PngActlDirectory().apply {
|
||||
setInt(PngActlDirectory.TAG_NUM_FRAMES, reader.int32)
|
||||
setInt(PngActlDirectory.TAG_NUM_PLAYS, reader.int32)
|
||||
})
|
||||
} catch (ex: IOException) {
|
||||
throw PngProcessingException(ex)
|
||||
}
|
||||
// TLAD insert end
|
||||
} else if (chunkType == PngChunkType.PLTE) {
|
||||
val directory = PngDirectory(PngChunkType.PLTE)
|
||||
directory.setInt(PngDirectory.TAG_PALETTE_SIZE, bytes.size / 3)
|
||||
|
|
Loading…
Reference in a new issue