From ce27d47342d5e076688ead591b279c9b474f99e4 Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Tue, 16 Apr 2024 22:09:57 +0200 Subject: [PATCH] #976 identify Apple variant of HDR images --- CHANGELOG.md | 4 +++ .../channel/calls/MetadataFetchHandler.kt | 29 +++++++++++++++++++ .../deckers/thibault/aves/metadata/xmp/XMP.kt | 5 ++++ 3 files changed, 38 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bda00713..01ef0cb47 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Added + +- Cataloguing: identify Apple variant of HDR images + ## [v1.10.9] - 2024-04-14 ### Fixed diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataFetchHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataFetchHandler.kt index 0ef28ec13..57a035142 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataFetchHandler.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/MetadataFetchHandler.kt @@ -20,6 +20,7 @@ import com.drew.metadata.exif.ExifDirectoryBase import com.drew.metadata.exif.ExifIFD0Directory import com.drew.metadata.exif.ExifSubIFDDirectory import com.drew.metadata.exif.GpsDirectory +import com.drew.metadata.exif.makernotes.AppleMakernoteDirectory import com.drew.metadata.file.FileTypeDirectory import com.drew.metadata.gif.GifAnimationDirectory import com.drew.metadata.iptc.IptcDirectory @@ -69,6 +70,7 @@ 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.metadata.metadataextractor.mpf.MpEntry import deckers.thibault.aves.metadata.metadataextractor.mpf.MpEntryDirectory import deckers.thibault.aves.metadata.xmp.GoogleXMP import deckers.thibault.aves.metadata.xmp.XMP @@ -639,6 +641,10 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { // JPEG Multi-Picture Format if (metadata.getDirectoriesOfType(MpEntryDirectory::class.java).count { !it.entry.isThumbnail } > 1) { flags = flags or MASK_IS_MULTIPAGE + + if (hasAppleHdrGainMap(uri, sizeBytes, metadata)) { + flags = flags or MASK_IS_HDR + } } // XMP @@ -765,6 +771,29 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler { metadataMap[KEY_FLAGS] = flags } + private fun hasAppleHdrGainMap(uri: Uri, sizeBytes: Long?, primaryMetadata: com.drew.metadata.Metadata): Boolean { + if (!primaryMetadata.containsDirectoryOfType(AppleMakernoteDirectory::class.java)) return false + + val mpEntries = MultiPage.getJpegMpfEntries(context, uri, sizeBytes) ?: return false + mpEntries.filter { it.type == MpEntry.TYPE_UNDEFINED }.forEach { mpEntry -> + var dataOffset = mpEntry.dataOffset + if (dataOffset > 0) { + val baseOffset = MultiPage.getJpegMpfBaseOffset(context, uri, sizeBytes) + if (baseOffset != null) { + dataOffset += baseOffset + } + } + StorageUtils.openInputStream(context, uri)?.let { input -> + input.skip(dataOffset) + val pageMetadata = Helper.safeRead(input) + if (pageMetadata.getDirectoriesOfType(XmpDirectory::class.java).any { it.xmpMeta.hasHdrGainMap() }) { + return true + } + } + } + return false + } + private fun getMultimediaCatalogMetadataByMediaMetadataRetriever( mimeType: String, uri: Uri, diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/xmp/XMP.kt b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/xmp/XMP.kt index 47a26ca7d..b7d49f9f9 100644 --- a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/xmp/XMP.kt +++ b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/xmp/XMP.kt @@ -40,6 +40,7 @@ object XMP { private const val XMP_NS_URI = "http://ns.adobe.com/xap/1.0/" // other namespaces + private const val APPLE_HDRGM_NS_URI = "http://ns.apple.com/HDRGainMap/1.0/" private const val HDRGM_NS_URI = "http://ns.adobe.com/hdr-gain-map/1.0/" private const val PMTM_NS_URI = "http://www.hdrsoft.com/photomatix_settings01" @@ -59,6 +60,7 @@ object XMP { // HDR gain map private val HDRGM_VERSION_PROP_NAME = XMPPropName(HDRGM_NS_URI, "Version") + private val APPLE_HDRGM_VERSION_PROP_NAME = XMPPropName(APPLE_HDRGM_NS_URI, "HDRGainMapVersion") // panorama @@ -137,6 +139,9 @@ object XMP { // `Ultra HDR` if (GoogleXMP.isUltraHdPhoto(this)) return true + // Apple HDR gain map + if (doesPropExist(APPLE_HDRGM_VERSION_PROP_NAME)) return true + return false } catch (e: XMPException) { if (e.errorCode != XMPError.BADSCHEMA) {