info: improved DNG tags display

This commit is contained in:
Thibault Deckers 2022-03-21 15:42:27 +09:00
parent 2cbeff39c4
commit fa862c041e
7 changed files with 175 additions and 163 deletions

View file

@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file.
- Theme: light/dark/black and poly/monochrome settings - Theme: light/dark/black and poly/monochrome settings
- Video: speed and muted state indicators - Video: speed and muted state indicators
- Info: option to set date from other item - Info: option to set date from other item
- Info: improved DNG tags display
- warn and optionally set metadata date before moving undated items - warn and optionally set metadata date before moving undated items
### Changed ### Changed

View file

@ -74,7 +74,10 @@ import deckers.thibault.aves.utils.UriUtils.tryParseId
import io.flutter.plugin.common.MethodCall import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import kotlinx.coroutines.* import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import java.nio.charset.Charset import java.nio.charset.Charset
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import java.text.ParseException import java.text.ParseException
@ -163,15 +166,24 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
// tags // tags
val tags = dir.tags val tags = dir.tags
if (dir is ExifDirectoryBase) { if (dir is ExifDirectoryBase) {
if (dir.isGeoTiff()) { when {
dir.isGeoTiff() -> {
// split GeoTIFF tags in their own directory // split GeoTIFF tags in their own directory
val geoTiffDirMap = metadataMap["GeoTIFF"] ?: HashMap()
metadataMap["GeoTIFF"] = geoTiffDirMap
val byGeoTiff = tags.groupBy { ExifTags.isGeoTiffTag(it.tagType) } val byGeoTiff = tags.groupBy { ExifTags.isGeoTiffTag(it.tagType) }
metadataMap["GeoTIFF"] = HashMap<String, String>().apply { byGeoTiff[true]?.map { exifTagMapper(it) }?.let { geoTiffDirMap.putAll(it) }
byGeoTiff[true]?.map { exifTagMapper(it) }?.let { putAll(it) }
}
byGeoTiff[false]?.map { exifTagMapper(it) }?.let { dirMap.putAll(it) } byGeoTiff[false]?.map { exifTagMapper(it) }?.let { dirMap.putAll(it) }
} else { }
dirMap.putAll(tags.map { exifTagMapper(it) }) mimeType == MimeTypes.DNG -> {
// split DNG tags in their own directory
val dngDirMap = metadataMap["DNG"] ?: HashMap()
metadataMap["DNG"] = dngDirMap
val byDng = tags.groupBy { ExifTags.isDngTag(it.tagType) }
byDng[true]?.map { exifTagMapper(it) }?.let { dngDirMap.putAll(it) }
byDng[false]?.map { exifTagMapper(it) }?.let { dirMap.putAll(it) }
}
else -> dirMap.putAll(tags.map { exifTagMapper(it) })
} }
} else if (dir.isPngTextDir()) { } else if (dir.isPngTextDir()) {
metadataMap.remove(thisDirName) metadataMap.remove(thisDirName)

View file

@ -224,4 +224,6 @@ object DngTags {
REDUCTION_MATRIX_3 to "Reduction Matrix 3", REDUCTION_MATRIX_3 to "Reduction Matrix 3",
RGB_TABLES to "RGB Tables", RGB_TABLES to "RGB Tables",
) )
val tags = tagNameMap.keys
} }

View file

@ -49,46 +49,6 @@ object ExifTags {
// obsoleted by the 6.0 ExtraSamples (338) // obsoleted by the 6.0 ExtraSamples (338)
private const val TAG_MATTEING = 0x80e3 private const val TAG_MATTEING = 0x80e3
/*
GeoTIFF
*/
// ModelPixelScaleTag (optional)
// Tag = 33550 (830E.H)
// Type = DOUBLE
// Count = 3
const val TAG_MODEL_PIXEL_SCALE = 0x830e
// ModelTiepointTag (conditional)
// Tag = 33922 (8482.H)
// Type = DOUBLE
// Count = 6*K, K = number of tiepoints
const val TAG_MODEL_TIEPOINT = 0x8482
// ModelTransformationTag (conditional)
// Tag = 34264 (85D8.H)
// Type = DOUBLE
// Count = 16
const val TAG_MODEL_TRANSFORMATION = 0x85d8
// GeoKeyDirectoryTag (mandatory)
// Tag = 34735 (87AF.H)
// Type = UNSIGNED SHORT
// Count = variable, >= 4
const val TAG_GEO_KEY_DIRECTORY = 0x87af
// GeoDoubleParamsTag (optional)
// Tag = 34736 (87BO.H)
// Type = DOUBLE
// Count = variable
private const val TAG_GEO_DOUBLE_PARAMS = 0x87b0
// GeoAsciiParamsTag (optional)
// Tag = 34737 (87B1.H)
// Type = ASCII
// Count = variable
private const val TAG_GEO_ASCII_PARAMS = 0x87b1
/* /*
Photoshop Photoshop
https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/ https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/
@ -100,15 +60,6 @@ object ExifTags {
// Type = UNDEFINED // Type = UNDEFINED
private const val TAG_IMAGE_SOURCE_DATA = 0x935c private const val TAG_IMAGE_SOURCE_DATA = 0x935c
private val geotiffTags = listOf(
TAG_GEO_ASCII_PARAMS,
TAG_GEO_DOUBLE_PARAMS,
TAG_GEO_KEY_DIRECTORY,
TAG_MODEL_PIXEL_SCALE,
TAG_MODEL_TIEPOINT,
TAG_MODEL_TRANSFORMATION,
)
private val tagNameMap = hashMapOf( private val tagNameMap = hashMapOf(
TAG_X_POSITION to "X Position", TAG_X_POSITION to "X Position",
TAG_Y_POSITION to "Y Position", TAG_Y_POSITION to "Y Position",
@ -118,20 +69,16 @@ object ExifTags {
TAG_RATING_PERCENT to "Rating Percent", TAG_RATING_PERCENT to "Rating Percent",
// SGI // SGI
TAG_MATTEING to "Matteing", TAG_MATTEING to "Matteing",
// GeoTIFF
TAG_GEO_ASCII_PARAMS to "Geo Ascii Params",
TAG_GEO_DOUBLE_PARAMS to "Geo Double Params",
TAG_GEO_KEY_DIRECTORY to "Geo Key Directory",
TAG_MODEL_PIXEL_SCALE to "Model Pixel Scale",
TAG_MODEL_TIEPOINT to "Model Tiepoint",
TAG_MODEL_TRANSFORMATION to "Model Transformation",
// Photoshop // Photoshop
TAG_IMAGE_SOURCE_DATA to "Image Source Data", TAG_IMAGE_SOURCE_DATA to "Image Source Data",
).apply { ).apply {
putAll(DngTags.tagNameMap) putAll(DngTags.tagNameMap)
putAll(GeoTiffTags.tagNameMap)
} }
fun isGeoTiffTag(tag: Int) = geotiffTags.contains(tag) fun isDngTag(tag: Int) = DngTags.tags.contains(tag)
fun isGeoTiffTag(tag: Int) = GeoTiffTags.tags.contains(tag)
fun getTagName(tag: Int): String? { fun getTagName(tag: Int): String? {
return tagNameMap[tag] return tagNameMap[tag]

View file

@ -0,0 +1,50 @@
package deckers.thibault.aves.metadata
object GeoTiffTags {
// ModelPixelScaleTag (optional)
// Tag = 33550 (830E.H)
// Type = DOUBLE
// Count = 3
const val TAG_MODEL_PIXEL_SCALE = 0x830e
// ModelTiepointTag (conditional)
// Tag = 33922 (8482.H)
// Type = DOUBLE
// Count = 6*K, K = number of tiepoints
const val TAG_MODEL_TIEPOINT = 0x8482
// ModelTransformationTag (conditional)
// Tag = 34264 (85D8.H)
// Type = DOUBLE
// Count = 16
const val TAG_MODEL_TRANSFORMATION = 0x85d8
// GeoKeyDirectoryTag (mandatory)
// Tag = 34735 (87AF.H)
// Type = UNSIGNED SHORT
// Count = variable, >= 4
const val TAG_GEO_KEY_DIRECTORY = 0x87af
// GeoDoubleParamsTag (optional)
// Tag = 34736 (87BO.H)
// Type = DOUBLE
// Count = variable
private const val TAG_GEO_DOUBLE_PARAMS = 0x87b0
// GeoAsciiParamsTag (optional)
// Tag = 34737 (87B1.H)
// Type = ASCII
// Count = variable
private const val TAG_GEO_ASCII_PARAMS = 0x87b1
val tagNameMap = hashMapOf(
TAG_GEO_ASCII_PARAMS to "Geo Ascii Params",
TAG_GEO_DOUBLE_PARAMS to "Geo Double Params",
TAG_GEO_KEY_DIRECTORY to "Geo Key Directory",
TAG_MODEL_PIXEL_SCALE to "Model Pixel Scale",
TAG_MODEL_TIEPOINT to "Model Tiepoint",
TAG_MODEL_TRANSFORMATION to "Model Transformation",
)
val tags = tagNameMap.keys
}

View file

@ -69,13 +69,13 @@ object MetadataExtractorHelper {
- If the ModelPixelScaleTag is included in an IFD, then a ModelTiepointTag SHALL also be included. - If the ModelPixelScaleTag is included in an IFD, then a ModelTiepointTag SHALL also be included.
*/ */
fun ExifDirectoryBase.isGeoTiff(): Boolean { fun ExifDirectoryBase.isGeoTiff(): Boolean {
if (!this.containsTag(ExifTags.TAG_GEO_KEY_DIRECTORY)) return false if (!this.containsTag(GeoTiffTags.TAG_GEO_KEY_DIRECTORY)) return false
val modelTiepoint = this.containsTag(ExifTags.TAG_MODEL_TIEPOINT) val modelTiepoint = this.containsTag(GeoTiffTags.TAG_MODEL_TIEPOINT)
val modelTransformation = this.containsTag(ExifTags.TAG_MODEL_TRANSFORMATION) val modelTransformation = this.containsTag(GeoTiffTags.TAG_MODEL_TRANSFORMATION)
if (!modelTiepoint && !modelTransformation) return false if (!modelTiepoint && !modelTransformation) return false
val modelPixelScale = this.containsTag(ExifTags.TAG_MODEL_PIXEL_SCALE) val modelPixelScale = this.containsTag(GeoTiffTags.TAG_MODEL_PIXEL_SCALE)
if ((modelTransformation && modelPixelScale) || (modelPixelScale && !modelTiepoint)) return false if ((modelTransformation && modelPixelScale) || (modelPixelScale && !modelTiepoint)) return false
return true return true

View file

@ -26,7 +26,7 @@ object MimeTypes {
private const val CR2 = "image/x-canon-cr2" private const val CR2 = "image/x-canon-cr2"
private const val CRW = "image/x-canon-crw" private const val CRW = "image/x-canon-crw"
private const val DCR = "image/x-kodak-dcr" private const val DCR = "image/x-kodak-dcr"
private const val DNG = "image/x-adobe-dng" const val DNG = "image/x-adobe-dng"
private const val ERF = "image/x-epson-erf" private const val ERF = "image/x-epson-erf"
private const val K25 = "image/x-kodak-k25" private const val K25 = "image/x-kodak-k25"
private const val KDC = "image/x-kodak-kdc" private const val KDC = "image/x-kodak-kdc"