catalog: fallback date from XMP photoshop:DateCreated, fallback HEIF date from MMR
This commit is contained in:
parent
ca670e4ee9
commit
b297fd5fe0
2 changed files with 36 additions and 23 deletions
|
@ -200,6 +200,20 @@ class MetadataHandler(private val context: Context) : MethodCallHandler {
|
||||||
return dirMap
|
return dirMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set `KEY_DATE_MILLIS` from these fields (by precedence):
|
||||||
|
// - ME / Exif / DATETIME_ORIGINAL
|
||||||
|
// - ME / Exif / DATETIME
|
||||||
|
// - EI / Exif / DATETIME_ORIGINAL
|
||||||
|
// - EI / Exif / DATETIME
|
||||||
|
// - ME / XMP / xmp:CreateDate
|
||||||
|
// - ME / XMP / photoshop:DateCreated
|
||||||
|
// - MMR / METADATA_KEY_DATE
|
||||||
|
// set `KEY_XMP_TITLE_DESCRIPTION` from these fields (by precedence):
|
||||||
|
// - ME / XMP / dc:title
|
||||||
|
// - ME / XMP / dc:description
|
||||||
|
// set `KEY_XMP_SUBJECTS` from these fields (by precedence):
|
||||||
|
// - ME / XMP / dc:subject
|
||||||
|
// - ME / IPTC / keywords
|
||||||
private fun getCatalogMetadata(call: MethodCall, result: MethodChannel.Result) {
|
private fun getCatalogMetadata(call: MethodCall, result: MethodChannel.Result) {
|
||||||
val mimeType = call.argument<String>("mimeType")
|
val mimeType = call.argument<String>("mimeType")
|
||||||
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
|
val uri = call.argument<String>("uri")?.let { Uri.parse(it) }
|
||||||
|
@ -211,24 +225,14 @@ class MetadataHandler(private val context: Context) : MethodCallHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
val metadataMap = HashMap(getCatalogMetadataByMetadataExtractor(uri, mimeType, path, sizeBytes))
|
val metadataMap = HashMap(getCatalogMetadataByMetadataExtractor(uri, mimeType, path, sizeBytes))
|
||||||
if (isVideo(mimeType)) {
|
if (isMultimedia(mimeType)) {
|
||||||
metadataMap.putAll(getVideoCatalogMetadataByMediaMetadataRetriever(uri))
|
metadataMap.putAll(getMultimediaCatalogMetadataByMediaMetadataRetriever(uri))
|
||||||
}
|
}
|
||||||
|
|
||||||
// report success even when empty
|
// report success even when empty
|
||||||
result.success(metadataMap)
|
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
|
|
||||||
// set `KEY_XMP_SUBJECTS` from these fields (by precedence):
|
|
||||||
// - XMP / dc:subject
|
|
||||||
// - IPTC / keywords
|
|
||||||
private fun getCatalogMetadataByMetadataExtractor(uri: Uri, mimeType: String, path: String?, sizeBytes: Long?): Map<String, Any> {
|
private fun getCatalogMetadataByMetadataExtractor(uri: Uri, mimeType: String, path: String?, sizeBytes: Long?): Map<String, Any> {
|
||||||
val metadataMap = HashMap<String, Any>()
|
val metadataMap = HashMap<String, Any>()
|
||||||
|
|
||||||
|
@ -301,6 +305,9 @@ class MetadataHandler(private val context: Context) : MethodCallHandler {
|
||||||
}
|
}
|
||||||
if (!metadataMap.containsKey(KEY_DATE_MILLIS)) {
|
if (!metadataMap.containsKey(KEY_DATE_MILLIS)) {
|
||||||
xmpMeta.getSafeDateMillis(XMP.XMP_SCHEMA_NS, XMP.CREATE_DATE_PROP_NAME) { metadataMap[KEY_DATE_MILLIS] = it }
|
xmpMeta.getSafeDateMillis(XMP.XMP_SCHEMA_NS, XMP.CREATE_DATE_PROP_NAME) { metadataMap[KEY_DATE_MILLIS] = it }
|
||||||
|
if (!metadataMap.containsKey(KEY_DATE_MILLIS)) {
|
||||||
|
xmpMeta.getSafeDateMillis(XMP.PHOTOSHOP_SCHEMA_NS, XMP.PS_DATE_CREATED_PROP_NAME) { metadataMap[KEY_DATE_MILLIS] = it }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// identification of panorama (aka photo sphere)
|
// identification of panorama (aka photo sphere)
|
||||||
|
@ -381,22 +388,26 @@ class MetadataHandler(private val context: Context) : MethodCallHandler {
|
||||||
return metadataMap
|
return metadataMap
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getVideoCatalogMetadataByMediaMetadataRetriever(uri: Uri): Map<String, Any> {
|
private fun getMultimediaCatalogMetadataByMediaMetadataRetriever(uri: Uri): Map<String, Any> {
|
||||||
val metadataMap = HashMap<String, Any>()
|
val metadataMap = HashMap<String, Any>()
|
||||||
val retriever = StorageUtils.openMetadataRetriever(context, uri) ?: return metadataMap
|
val retriever = StorageUtils.openMetadataRetriever(context, uri) ?: return metadataMap
|
||||||
try {
|
try {
|
||||||
retriever.getSafeInt(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION) { metadataMap[KEY_ROTATION_DEGREES] = it }
|
retriever.getSafeInt(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION) { metadataMap[KEY_ROTATION_DEGREES] = it }
|
||||||
retriever.getSafeDateMillis(MediaMetadataRetriever.METADATA_KEY_DATE) { metadataMap[KEY_DATE_MILLIS] = it }
|
if (!metadataMap.containsKey(KEY_DATE_MILLIS)) {
|
||||||
|
retriever.getSafeDateMillis(MediaMetadataRetriever.METADATA_KEY_DATE) { metadataMap[KEY_DATE_MILLIS] = it }
|
||||||
|
}
|
||||||
|
|
||||||
val locationString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_LOCATION)
|
if (!metadataMap.containsKey(KEY_LATITUDE)) {
|
||||||
if (locationString != null) {
|
val locationString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_LOCATION)
|
||||||
val matcher = Metadata.VIDEO_LOCATION_PATTERN.matcher(locationString)
|
if (locationString != null) {
|
||||||
if (matcher.find() && matcher.groupCount() >= 2) {
|
val matcher = Metadata.VIDEO_LOCATION_PATTERN.matcher(locationString)
|
||||||
val latitude = matcher.group(1)?.toDoubleOrNull()
|
if (matcher.find() && matcher.groupCount() >= 2) {
|
||||||
val longitude = matcher.group(2)?.toDoubleOrNull()
|
val latitude = matcher.group(1)?.toDoubleOrNull()
|
||||||
if (latitude != null && longitude != null) {
|
val longitude = matcher.group(2)?.toDoubleOrNull()
|
||||||
metadataMap[KEY_LATITUDE] = latitude
|
if (latitude != null && longitude != null) {
|
||||||
metadataMap[KEY_LONGITUDE] = longitude
|
metadataMap[KEY_LATITUDE] = latitude
|
||||||
|
metadataMap[KEY_LONGITUDE] = longitude
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,12 +10,14 @@ object XMP {
|
||||||
private val LOG_TAG = LogUtils.createTag(XMP::class.java)
|
private val LOG_TAG = LogUtils.createTag(XMP::class.java)
|
||||||
|
|
||||||
const val DC_SCHEMA_NS = "http://purl.org/dc/elements/1.1/"
|
const val DC_SCHEMA_NS = "http://purl.org/dc/elements/1.1/"
|
||||||
|
const val PHOTOSHOP_SCHEMA_NS = "http://ns.adobe.com/photoshop/1.0/"
|
||||||
const val XMP_SCHEMA_NS = "http://ns.adobe.com/xap/1.0/"
|
const val XMP_SCHEMA_NS = "http://ns.adobe.com/xap/1.0/"
|
||||||
const val IMG_SCHEMA_NS = "http://ns.adobe.com/xap/1.0/g/img/"
|
const val IMG_SCHEMA_NS = "http://ns.adobe.com/xap/1.0/g/img/"
|
||||||
|
|
||||||
const val SUBJECT_PROP_NAME = "dc:subject"
|
const val SUBJECT_PROP_NAME = "dc:subject"
|
||||||
const val TITLE_PROP_NAME = "dc:title"
|
const val TITLE_PROP_NAME = "dc:title"
|
||||||
const val DESCRIPTION_PROP_NAME = "dc:description"
|
const val DESCRIPTION_PROP_NAME = "dc:description"
|
||||||
|
const val PS_DATE_CREATED_PROP_NAME = "photoshop:DateCreated";
|
||||||
const val CREATE_DATE_PROP_NAME = "xmp:CreateDate"
|
const val CREATE_DATE_PROP_NAME = "xmp:CreateDate"
|
||||||
const val THUMBNAIL_PROP_NAME = "xmp:Thumbnails"
|
const val THUMBNAIL_PROP_NAME = "xmp:Thumbnails"
|
||||||
const val THUMBNAIL_IMAGE_PROP_NAME = "xmpGImg:image"
|
const val THUMBNAIL_IMAGE_PROP_NAME = "xmpGImg:image"
|
||||||
|
|
Loading…
Reference in a new issue