catalog: use PNG last modification time as fallback

This commit is contained in:
Thibault Deckers 2021-02-04 12:10:17 +09:00
parent 4661cdecbe
commit 1b6febe034
3 changed files with 30 additions and 2 deletions

View file

@ -23,6 +23,7 @@ import com.drew.metadata.file.FileTypeDirectory
import com.drew.metadata.gif.GifAnimationDirectory
import com.drew.metadata.iptc.IptcDirectory
import com.drew.metadata.mp4.media.Mp4UuidBoxDirectory
import com.drew.metadata.png.PngDirectory
import com.drew.metadata.webp.WebpDirectory
import com.drew.metadata.xmp.XmpDirectory
import deckers.thibault.aves.channel.calls.Coresult.Companion.safe
@ -37,6 +38,8 @@ import deckers.thibault.aves.metadata.MediaMetadataRetrieverHelper.getSafeDescri
import deckers.thibault.aves.metadata.MediaMetadataRetrieverHelper.getSafeInt
import deckers.thibault.aves.metadata.Metadata.getRotationDegreesForExifCode
import deckers.thibault.aves.metadata.Metadata.isFlippedForExifCode
import deckers.thibault.aves.metadata.MetadataExtractorHelper.PNG_LAST_MODIFICATION_TIME_FORMAT
import deckers.thibault.aves.metadata.MetadataExtractorHelper.PNG_TIME_DIR_NAME
import deckers.thibault.aves.metadata.MetadataExtractorHelper.getSafeBoolean
import deckers.thibault.aves.metadata.MetadataExtractorHelper.getSafeDateMillis
import deckers.thibault.aves.metadata.MetadataExtractorHelper.getSafeInt
@ -70,6 +73,7 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.beyka.tiffbitmapfactory.TiffBitmapFactory
import java.io.File
import java.text.ParseException
import java.util.*
import kotlin.math.roundToLong
@ -217,6 +221,7 @@ class MetadataHandler(private val context: Context) : MethodCallHandler {
return dirMap
}
// legend: ME=MetadataExtractor, EI=ExifInterface, MMR=MediaMetadataRetriever
// set `KEY_DATE_MILLIS` from these fields (by precedence):
// - ME / Exif / DATETIME_ORIGINAL
// - ME / Exif / DATETIME
@ -224,6 +229,7 @@ class MetadataHandler(private val context: Context) : MethodCallHandler {
// - EI / Exif / DATETIME
// - ME / XMP / xmp:CreateDate
// - ME / XMP / photoshop:DateCreated
// - ME / PNG / TIME / LAST_MODIFICATION_TIME
// - MMR / METADATA_KEY_DATE
// set `KEY_XMP_TITLE_DESCRIPTION` from these fields (by precedence):
// - ME / XMP / dc:title
@ -348,12 +354,29 @@ class MetadataHandler(private val context: Context) : MethodCallHandler {
}
}
// identification of animated GIF & WEBP, GeoTIFF
when (mimeType) {
MimeTypes.PNG -> {
// date fallback to PNG time chunk
if (!metadataMap.containsKey(KEY_DATE_MILLIS)) {
for (dir in metadata.getDirectoriesOfType(PngDirectory::class.java).filter { it.name == PNG_TIME_DIR_NAME }) {
dir.getSafeString(PngDirectory.TAG_LAST_MODIFICATION_TIME) {
try {
PNG_LAST_MODIFICATION_TIME_FORMAT.parse(it)?.let { date ->
metadataMap[KEY_DATE_MILLIS] = date.time
}
} catch (e: ParseException) {
Log.w(LOG_TAG, "failed to parse PNG date=$it for uri=$uri", e)
}
}
}
}
}
MimeTypes.GIF -> {
// identification of animated GIF
if (metadata.containsDirectoryOfType(GifAnimationDirectory::class.java)) flags = flags or MASK_IS_ANIMATED
}
MimeTypes.WEBP -> {
// identification of animated WEBP
for (dir in metadata.getDirectoriesOfType(WebpDirectory::class.java)) {
dir.getSafeBoolean(WebpDirectory.TAG_IS_ANIMATION) {
if (it) flags = flags or MASK_IS_ANIMATED
@ -361,6 +384,7 @@ class MetadataHandler(private val context: Context) : MethodCallHandler {
}
}
MimeTypes.TIFF -> {
// identification of GeoTIFF
for (dir in metadata.getDirectoriesOfType(ExifIFD0Directory::class.java)) {
if (dir.isGeoTiff()) flags = flags or MASK_IS_GEOTIFF
}

View file

@ -3,9 +3,13 @@ package deckers.thibault.aves.metadata
import com.drew.lang.Rational
import com.drew.metadata.Directory
import com.drew.metadata.exif.ExifIFD0Directory
import java.text.SimpleDateFormat
import java.util.*
object MetadataExtractorHelper {
const val PNG_TIME_DIR_NAME = "PNG-tIME"
val PNG_LAST_MODIFICATION_TIME_FORMAT = SimpleDateFormat("yyyy:MM:dd hh:mm:ss", Locale.ROOT)
// extensions
fun Directory.getSafeDescription(tag: Int, save: (value: String) -> Unit) {

View file

@ -17,7 +17,7 @@ class InfoSearchDelegate extends SearchDelegate {
static const suggestions = {
'Date & time': 'date or time or when -timer -uptime -exposure -timeline',
'Description': 'abstract or description or comment',
'Description': 'abstract or description or comment or textual',
'Dimensions': 'width or height or dimension or framesize or imagelength',
'Resolution': 'resolution',
'Rights': 'rights or copyright or artist or creator or by-line or credit -tool',