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
- Video: speed and muted state indicators
- Info: option to set date from other item
- Info: improved DNG tags display
- warn and optionally set metadata date before moving undated items
### 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.MethodChannel
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.StandardCharsets
import java.text.ParseException
@ -163,15 +166,24 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
// tags
val tags = dir.tags
if (dir is ExifDirectoryBase) {
if (dir.isGeoTiff()) {
when {
dir.isGeoTiff() -> {
// split GeoTIFF tags in their own directory
val geoTiffDirMap = metadataMap["GeoTIFF"] ?: HashMap()
metadataMap["GeoTIFF"] = geoTiffDirMap
val byGeoTiff = tags.groupBy { ExifTags.isGeoTiffTag(it.tagType) }
metadataMap["GeoTIFF"] = HashMap<String, String>().apply {
byGeoTiff[true]?.map { exifTagMapper(it) }?.let { putAll(it) }
}
byGeoTiff[true]?.map { exifTagMapper(it) }?.let { geoTiffDirMap.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()) {
metadataMap.remove(thisDirName)

View file

@ -128,100 +128,102 @@ object DngTags {
WHITE_LEVEL to "White Level",
DEFAULT_SCALE to "Default Scale",
DEFAULT_CROP_ORIGIN to "Default Crop Origin",
DEFAULT_CROP_SIZE to "DefaultCropSize",
COLOR_MATRIX_1 to "ColorMatrix1",
COLOR_MATRIX_2 to "ColorMatrix2",
CAMERA_CALIBRATION_1 to "CameraCalibration1",
CAMERA_CALIBRATION_2 to "CameraCalibration2",
REDUCTION_MATRIX_1 to "ReductionMatrix1",
REDUCTION_MATRIX_2 to "ReductionMatrix2",
ANALOG_BALANCE to "AnalogBalance",
AS_SHOT_NEUTRAL to "AsShotNeutral",
AS_SHOT_WHITE_XY to "AsShotWhiteXY",
BASELINE_EXPOSURE to "BaselineExposure",
BASELINE_NOISE to "BaselineNoise",
BASELINE_SHARPNESS to "BaselineSharpness",
BAYER_GREEN_SPLIT to "BayerGreenSplit",
LINEAR_RESPONSE_LIMIT to "LinearResponseLimit",
DEFAULT_CROP_SIZE to "Default Crop Size",
COLOR_MATRIX_1 to "Color Matrix 1",
COLOR_MATRIX_2 to "Color Matrix 2",
CAMERA_CALIBRATION_1 to "Camera Calibration 1",
CAMERA_CALIBRATION_2 to "Camera Calibration 2",
REDUCTION_MATRIX_1 to "Reduction Matrix 1",
REDUCTION_MATRIX_2 to "Reduction Matrix 2",
ANALOG_BALANCE to "Analog Balance",
AS_SHOT_NEUTRAL to "As Shot Neutral",
AS_SHOT_WHITE_XY to "As Shot White XY",
BASELINE_EXPOSURE to "Baseline Exposure",
BASELINE_NOISE to "Baseline Noise",
BASELINE_SHARPNESS to "Baseline Sharpness",
BAYER_GREEN_SPLIT to "Bayer Green Split",
LINEAR_RESPONSE_LIMIT to "Linear Response Limit",
CAMERA_SERIAL_NUMBER to "Camera Serial Number",
LENS_INFO to "LensInfo",
CHROMA_BLUR_RADIUS to "ChromaBlurRadius",
ANTI_ALIAS_STRENGTH to "AntiAliasStrength",
SHADOW_SCALE to "ShadowScale",
DNG_PRIVATE_DATA to "DNGPrivateData",
MAKER_NOTE_SAFETY to "MakerNoteSafety",
CALIBRATION_ILLUMINANT_1 to "CalibrationIlluminant1",
CALIBRATION_ILLUMINANT_2 to "CalibrationIlluminant2",
LENS_INFO to "Lens Info",
CHROMA_BLUR_RADIUS to "Chroma Blur Radius",
ANTI_ALIAS_STRENGTH to "Anti Alias Strength",
SHADOW_SCALE to "Shadow Scale",
DNG_PRIVATE_DATA to "DNG Private Data",
MAKER_NOTE_SAFETY to "Maker Note Safety",
CALIBRATION_ILLUMINANT_1 to "Calibration Illuminant 1",
CALIBRATION_ILLUMINANT_2 to "Calibration Illuminant 2",
BEST_QUALITY_SCALE to "Best Quality Scale",
RAW_DATA_UNIQUE_ID to "RawDataUniqueID",
RAW_DATA_UNIQUE_ID to "Raw Data Unique ID",
ORIGINAL_RAW_FILE_NAME to "Original Raw File Name",
ORIGINAL_RAW_FILE_DATA to "OriginalRawFileData",
ACTIVE_AREA to "ActiveArea",
MASKED_AREAS to "MaskedAreas",
AS_SHOT_ICC_PROFILE to "AsShotICCProfile",
AS_SHOT_PRE_PROFILE_MATRIX to "AsShotPreProfileMatrix",
CURRENT_ICC_PROFILE to "CurrentICCProfile",
CURRENT_PRE_PROFILE_MATRIX to "CurrentPreProfileMatrix",
COLORIMETRIC_REFERENCE to "ColorimetricReference",
CAMERA_CALIBRATION_SIGNATURE to "CameraCalibrationSignature",
PROFILE_CALIBRATION_SIGNATURE to "ProfileCalibrationSignature",
EXTRA_CAMERA_PROFILES to "ExtraCameraProfiles",
AS_SHOT_PROFILE_NAME to "AsShotProfileName",
NOISE_REDUCTION_APPLIED to "NoiseReductionApplied",
PROFILE_NAME to "ProfileName",
PROFILE_HUE_SAT_MAP_DIMS to "ProfileHueSatMapDims",
PROFILE_HUE_SAT_MAP_DATA_1 to "ProfileHueSatMapData1",
PROFILE_HUE_SAT_MAP_DATA_2 to "ProfileHueSatMapData2",
PROFILE_TONE_CURVE to "ProfileToneCurve",
PROFILE_EMBED_POLICY to "ProfileEmbedPolicy",
PROFILE_COPYRIGHT to "ProfileCopyright",
FORWARD_MATRIX_1 to "ForwardMatrix1",
FORWARD_MATRIX_2 to "ForwardMatrix2",
PREVIEW_APPLICATION_NAME to "PreviewApplicationName",
PREVIEW_APPLICATION_VERSION to "PreviewApplicationVersion",
PREVIEW_SETTINGS_NAME to "PreviewSettingsName",
PREVIEW_SETTINGS_DIGEST to "PreviewSettingsDigest",
PREVIEW_COLOR_SPACE to "PreviewColorSpace",
PREVIEW_DATE_TIME to "PreviewDateTime",
RAW_IMAGE_DIGEST to "RawImageDigest",
ORIGINAL_RAW_FILE_DIGEST to "OriginalRawFileDigest",
SUB_TILE_BLOCK_SIZE to "SubTileBlockSize",
ROW_INTERLEAVE_FACTOR to "RowInterleaveFactor",
PROFILE_LOOK_TABLE_DIMS to "ProfileLookTableDims",
PROFILE_LOOK_TABLE_DATA to "ProfileLookTableData",
OPCODE_LIST_1 to "OpcodeList1",
OPCODE_LIST_2 to "OpcodeList2",
OPCODE_LIST_3 to "OpcodeList3",
NOISE_PROFILE to "NoiseProfile",
ORIGINAL_DEFAULT_FINAL_SIZE to "OriginalDefaultFinalSize",
ORIGINAL_BEST_QUALITY_FINAL_SIZE to "OriginalBestQualityFinalSize",
ORIGINAL_DEFAULT_CROP_SIZE to "OriginalDefaultCropSize",
PROFILE_HUE_SAT_MAP_ENCODING to "ProfileHueSatMapEncoding",
PROFILE_LOOK_TABLE_ENCODING to "ProfileLookTableEncoding",
BASELINE_EXPOSURE_OFFSET to "BaselineExposureOffset",
DEFAULT_BLACK_RENDER to "DefaultBlackRender",
NEW_RAW_IMAGE_DIGEST to "NewRawImageDigest",
RAW_TO_PREVIEW_GAIN to "RawToPreviewGain",
DEFAULT_USER_CROP to "DefaultUserCrop",
DEPTH_FORMAT to "DepthFormat",
DEPTH_NEAR to "DepthNear",
DEPTH_FAR to "DepthFar",
DEPTH_UNITS to "DepthUnits",
DEPTH_MEASURE_TYPE to "DepthMeasureType",
ENHANCE_PARAMS to "EnhanceParams",
PROFILE_GAIN_TABLE_MAP to "ProfileGainTableMap",
SEMANTIC_NAME to "SemanticName",
SEMANTIC_INSTANCE_ID to "SemanticInstanceID",
CALIBRATION_ILLUMINANT_3 to "CalibrationIlluminant3",
CAMERA_CALIBRATION_3 to "CameraCalibration3",
COLOR_MATRIX_3 to "ColorMatrix3",
FORWARD_MATRIX_3 to "ForwardMatrix3",
ILLUMINANT_DATA_1 to "IlluminantData1",
ILLUMINANT_DATA_2 to "IlluminantData2",
ILLUMINANT_DATA_3 to "IlluminantData3",
MASK_SUB_AREA to "MaskSubArea",
PROFILE_HUE_SAT_MAP_DATA_3 to "ProfileHueSatMapData3",
REDUCTION_MATRIX_3 to "ReductionMatrix3",
RGB_TABLES to "RGBTables",
ORIGINAL_RAW_FILE_DATA to "Original Raw File Data",
ACTIVE_AREA to "Active Area",
MASKED_AREAS to "Masked Areas",
AS_SHOT_ICC_PROFILE to "As Shot ICC Profile",
AS_SHOT_PRE_PROFILE_MATRIX to "As Shot Pre Profile Matrix",
CURRENT_ICC_PROFILE to "Current ICC Profile",
CURRENT_PRE_PROFILE_MATRIX to "Current Pre Profile Matrix",
COLORIMETRIC_REFERENCE to "Colorimetric Reference",
CAMERA_CALIBRATION_SIGNATURE to "Camera Calibration Signature",
PROFILE_CALIBRATION_SIGNATURE to "Profile Calibration Signature",
EXTRA_CAMERA_PROFILES to "Extra Camera Profiles",
AS_SHOT_PROFILE_NAME to "As Shot Profile Name",
NOISE_REDUCTION_APPLIED to "Noise Reduction Applied",
PROFILE_NAME to "Profile Name",
PROFILE_HUE_SAT_MAP_DIMS to "Profile Hue Sat Map Dims",
PROFILE_HUE_SAT_MAP_DATA_1 to "Profile Hue Sat Map Data 1",
PROFILE_HUE_SAT_MAP_DATA_2 to "Profile Hue Sat Map Data 2",
PROFILE_TONE_CURVE to "Profile Tone Curve",
PROFILE_EMBED_POLICY to "Profile Embed Policy",
PROFILE_COPYRIGHT to "Profile Copyright",
FORWARD_MATRIX_1 to "Forward Matrix 1",
FORWARD_MATRIX_2 to "Forward Matrix 2",
PREVIEW_APPLICATION_NAME to "Preview Application Name",
PREVIEW_APPLICATION_VERSION to "Preview Application Version",
PREVIEW_SETTINGS_NAME to "Preview Settings Name",
PREVIEW_SETTINGS_DIGEST to "Preview Settings Digest",
PREVIEW_COLOR_SPACE to "Preview Color Space",
PREVIEW_DATE_TIME to "Preview Date Time",
RAW_IMAGE_DIGEST to "Raw Image Digest",
ORIGINAL_RAW_FILE_DIGEST to "Original Raw File Digest",
SUB_TILE_BLOCK_SIZE to "Sub Tile Block Size",
ROW_INTERLEAVE_FACTOR to "Row Interleave Factor",
PROFILE_LOOK_TABLE_DIMS to "Profile Look Table Dims",
PROFILE_LOOK_TABLE_DATA to "Profile Look Table Data",
OPCODE_LIST_1 to "Opcode List 1",
OPCODE_LIST_2 to "Opcode List 2",
OPCODE_LIST_3 to "Opcode List 3",
NOISE_PROFILE to "Noise Profile",
ORIGINAL_DEFAULT_FINAL_SIZE to "Original Default Final Size",
ORIGINAL_BEST_QUALITY_FINAL_SIZE to "Original Best Quality Final Size",
ORIGINAL_DEFAULT_CROP_SIZE to "Original Default Crop Size",
PROFILE_HUE_SAT_MAP_ENCODING to "Profile Hue Sat Map Encoding",
PROFILE_LOOK_TABLE_ENCODING to "Profile Look Table Encoding",
BASELINE_EXPOSURE_OFFSET to "Baseline Exposure Offset",
DEFAULT_BLACK_RENDER to "Default Black Render",
NEW_RAW_IMAGE_DIGEST to "New Raw Image Digest",
RAW_TO_PREVIEW_GAIN to "Raw To Preview Gain",
DEFAULT_USER_CROP to "Default User Crop",
DEPTH_FORMAT to "Depth Format",
DEPTH_NEAR to "Depth Near",
DEPTH_FAR to "Depth Far",
DEPTH_UNITS to "Depth Units",
DEPTH_MEASURE_TYPE to "Depth Measure Type",
ENHANCE_PARAMS to "Enhance Params",
PROFILE_GAIN_TABLE_MAP to "Profile Gain Table Map",
SEMANTIC_NAME to "Semantic Name",
SEMANTIC_INSTANCE_ID to "Semantic Instance ID",
CALIBRATION_ILLUMINANT_3 to "Calibration Illuminant 3",
CAMERA_CALIBRATION_3 to "Camera Calibration 3",
COLOR_MATRIX_3 to "Color Matrix 3",
FORWARD_MATRIX_3 to "Forward Matrix 3",
ILLUMINANT_DATA_1 to "Illuminant Data 1",
ILLUMINANT_DATA_2 to "Illuminant Data 2",
ILLUMINANT_DATA_3 to "Illuminant Data 3",
MASK_SUB_AREA to "Mask Sub Area",
PROFILE_HUE_SAT_MAP_DATA_3 to "Profile Hue Sat Map Data 3",
REDUCTION_MATRIX_3 to "Reduction Matrix 3",
RGB_TABLES to "RGB Tables",
)
val tags = tagNameMap.keys
}

View file

@ -49,46 +49,6 @@ object ExifTags {
// obsoleted by the 6.0 ExtraSamples (338)
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
https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/
@ -100,15 +60,6 @@ object ExifTags {
// Type = UNDEFINED
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(
TAG_X_POSITION to "X Position",
TAG_Y_POSITION to "Y Position",
@ -118,20 +69,16 @@ object ExifTags {
TAG_RATING_PERCENT to "Rating Percent",
// SGI
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
TAG_IMAGE_SOURCE_DATA to "Image Source Data",
).apply {
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? {
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.
*/
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 modelTransformation = this.containsTag(ExifTags.TAG_MODEL_TRANSFORMATION)
val modelTiepoint = this.containsTag(GeoTiffTags.TAG_MODEL_TIEPOINT)
val modelTransformation = this.containsTag(GeoTiffTags.TAG_MODEL_TRANSFORMATION)
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
return true

View file

@ -26,7 +26,7 @@ object MimeTypes {
private const val CR2 = "image/x-canon-cr2"
private const val CRW = "image/x-canon-crw"
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 K25 = "image/x-kodak-k25"
private const val KDC = "image/x-kodak-kdc"