catalog: get date from XMP as fallback from Exif
This commit is contained in:
parent
93af6b0d1b
commit
8c5a600151
5 changed files with 40 additions and 8 deletions
|
@ -44,6 +44,7 @@ import deckers.thibault.aves.metadata.MetadataExtractorHelper.getSafeInt
|
|||
import deckers.thibault.aves.metadata.MetadataExtractorHelper.getSafeRational
|
||||
import deckers.thibault.aves.metadata.MetadataExtractorHelper.getSafeString
|
||||
import deckers.thibault.aves.metadata.XMP
|
||||
import deckers.thibault.aves.metadata.XMP.getSafeDateMillis
|
||||
import deckers.thibault.aves.metadata.XMP.getSafeLocalizedText
|
||||
import deckers.thibault.aves.utils.BitmapUtils
|
||||
import deckers.thibault.aves.utils.BitmapUtils.getBytes
|
||||
|
@ -205,6 +206,13 @@ class MetadataHandler(private val context: Context) : MethodCallHandler {
|
|||
result.success(metadataMap)
|
||||
}
|
||||
|
||||
// set `KEY_DATE_MILLIS` from these fields (by precedence):
|
||||
// - Exif / DATETIME_ORIGINAL
|
||||
// - Exif / DATETIME
|
||||
// - XMP / xmp:CreateDate
|
||||
// set `KEY_XMP_TITLE_DESCRIPTION` from these fields (by precedence):
|
||||
// - XMP / dc:title
|
||||
// - XMP / dc:description
|
||||
private fun getCatalogMetadataByMetadataExtractor(uri: Uri, mimeType: String, path: String?): Map<String, Any> {
|
||||
val metadataMap = HashMap<String, Any>()
|
||||
|
||||
|
@ -270,9 +278,12 @@ class MetadataHandler(private val context: Context) : MethodCallHandler {
|
|||
val values = (1 until count + 1).map { xmpMeta.getArrayItem(XMP.DC_SCHEMA_NS, XMP.SUBJECT_PROP_NAME, it).value }
|
||||
metadataMap[KEY_XMP_SUBJECTS] = values.joinToString(separator = ";")
|
||||
}
|
||||
xmpMeta.getSafeLocalizedText(XMP.TITLE_PROP_NAME) { metadataMap[KEY_XMP_TITLE_DESCRIPTION] = it }
|
||||
xmpMeta.getSafeLocalizedText(XMP.DC_SCHEMA_NS, XMP.TITLE_PROP_NAME) { metadataMap[KEY_XMP_TITLE_DESCRIPTION] = it }
|
||||
if (!metadataMap.containsKey(KEY_XMP_TITLE_DESCRIPTION)) {
|
||||
xmpMeta.getSafeLocalizedText(XMP.DESCRIPTION_PROP_NAME) { metadataMap[KEY_XMP_TITLE_DESCRIPTION] = it }
|
||||
xmpMeta.getSafeLocalizedText(XMP.DC_SCHEMA_NS, XMP.DESCRIPTION_PROP_NAME) { metadataMap[KEY_XMP_TITLE_DESCRIPTION] = it }
|
||||
}
|
||||
if (!metadataMap.containsKey(KEY_DATE_MILLIS)) {
|
||||
xmpMeta.getSafeDateMillis(XMP.XMP_SCHEMA_NS, XMP.CREATE_DATE_PROP_NAME) { metadataMap[KEY_DATE_MILLIS] = it }
|
||||
}
|
||||
} catch (e: XMPException) {
|
||||
Log.w(LOG_TAG, "failed to read XMP directory for uri=$uri", e)
|
||||
|
|
|
@ -41,6 +41,8 @@ object Metadata {
|
|||
}
|
||||
}
|
||||
|
||||
// not sure which standards are used for the different video formats,
|
||||
// but looks like some form of ISO 8601 `basic format`:
|
||||
// yyyyMMddTHHmmss(.sss)?(Z|+/-hhmm)?
|
||||
fun parseVideoMetadataDate(metadataDate: String?): Long {
|
||||
var dateString = metadataDate ?: return 0
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.util.Log
|
|||
import com.adobe.internal.xmp.XMPException
|
||||
import com.adobe.internal.xmp.XMPMeta
|
||||
import deckers.thibault.aves.utils.LogUtils
|
||||
import java.util.*
|
||||
|
||||
object XMP {
|
||||
private val LOG_TAG = LogUtils.createTag(XMP::class.java)
|
||||
|
@ -14,20 +15,38 @@ object XMP {
|
|||
const val SUBJECT_PROP_NAME = "dc:subject"
|
||||
const val TITLE_PROP_NAME = "dc:title"
|
||||
const val DESCRIPTION_PROP_NAME = "dc:description"
|
||||
const val CREATE_DATE_PROP_NAME = "xmp:CreateDate"
|
||||
const val THUMBNAIL_PROP_NAME = "xmp:Thumbnails"
|
||||
const val THUMBNAIL_IMAGE_PROP_NAME = "xmpGImg:image"
|
||||
private const val GENERIC_LANG = ""
|
||||
private const val SPECIFIC_LANG = "en-US"
|
||||
|
||||
fun XMPMeta.getSafeLocalizedText(propName: String, save: (value: String) -> Unit) {
|
||||
fun XMPMeta.getSafeLocalizedText(schema: String, propName: String, save: (value: String) -> Unit) {
|
||||
try {
|
||||
if (this.doesPropertyExist(DC_SCHEMA_NS, propName)) {
|
||||
val item = this.getLocalizedText(DC_SCHEMA_NS, propName, GENERIC_LANG, SPECIFIC_LANG)
|
||||
if (this.doesPropertyExist(schema, propName)) {
|
||||
val item = this.getLocalizedText(schema, propName, GENERIC_LANG, SPECIFIC_LANG)
|
||||
// double check retrieved items as the property sometimes is reported to exist but it is actually null
|
||||
if (item != null) save(item.value)
|
||||
}
|
||||
} catch (e: XMPException) {
|
||||
Log.w(LOG_TAG, "failed to get text for XMP propName=$propName", e)
|
||||
Log.w(LOG_TAG, "failed to get text for XMP schema=$schema, propName=$propName", e)
|
||||
}
|
||||
}
|
||||
|
||||
fun XMPMeta.getSafeDateMillis(schema: String, propName: String, save: (value: Long) -> Unit) {
|
||||
try {
|
||||
if (this.doesPropertyExist(schema, propName)) {
|
||||
val item = this.getPropertyDate(schema, propName)
|
||||
// double check retrieved items as the property sometimes is reported to exist but it is actually null
|
||||
if (item != null) {
|
||||
// strip time zone from XMP dates so that we show date/times as local ones
|
||||
// this aligns with Exif date/times, which are specified without time zones
|
||||
item.timeZone = TimeZone.getDefault()
|
||||
save(item.calendar.timeInMillis)
|
||||
}
|
||||
}
|
||||
} catch (e: XMPException) {
|
||||
Log.w(LOG_TAG, "failed to get text for XMP schema=$schema, propName=$propName", e)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.4.10'
|
||||
ext.kotlin_version = '1.4.20'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
|
|
@ -299,7 +299,7 @@ class ImageEntry {
|
|||
|
||||
bool get isLocated => _addressDetails != null;
|
||||
|
||||
LatLng get latLng => isCatalogued ? LatLng(_catalogMetadata.latitude, _catalogMetadata.longitude) : null;
|
||||
LatLng get latLng => hasGps ? LatLng(_catalogMetadata.latitude, _catalogMetadata.longitude) : null;
|
||||
|
||||
String get geoUri {
|
||||
if (!hasGps) return null;
|
||||
|
|
Loading…
Reference in a new issue