info: improved DNG tags display
This commit is contained in:
parent
2cbeff39c4
commit
fa862c041e
7 changed files with 175 additions and 163 deletions
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in a new issue