📄 reconciletiff.cpp
字号:
// =================================================================================================// ADOBE SYSTEMS INCORPORATED// Copyright 2006-2007 Adobe Systems Incorporated// All Rights Reserved//// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms// of the Adobe license agreement accompanying it.// =================================================================================================#include "XMP_Environment.h" // ! This must be the first include.#include "Reconcile_Impl.hpp"#include "UnicodeConversions.hpp"#include <stdio.h>#if XMP_WinBuild #define snprintf _snprintf#endif#if XMP_WinBuild #pragma warning ( disable : 4996 ) // '...' was declared deprecated#endif// =================================================================================================/// \file ReconcileTIFF.cpp/// \brief Utilities to reconcile between XMP and legacy TIFF/Exif metadata.///// =================================================================================================// =================================================================================================// =================================================================================================// Tables of the TIFF/Exif tags that are mapped into XMP. For the most part, the tags have obvious// mappings based on their IFD, tag number, type and count. These tables do not list tags that are// mapped as subsidiary parts of others, e.g. TIFF SubSecTime or GPS Info GPSDateStamp. Tags that// have special mappings are marked by having an empty string for the XMP property name.// ! These tables have the tags listed in the order of tables 3, 4, 5, and 12 of Exif 2.2, with the// ! exception of ImageUniqueID (which is listed at the end of the Exif mappings). This order is// ! very important to consistent checking of the legacy status. The NativeDigest properties list// ! all possible mapped tags in this order. The NativeDigest strings are compared as a whole, so// ! the same tags listed in a different order would compare as different.// ! The sentinel tag value can't be 0, that is a valid GPS Info tag, 0xFFFF is unused so far.struct TIFF_MappingToXMP { XMP_Uns16 id; XMP_Uns16 type; XMP_Uns32 count; // Zero means any. const char * name; // The name of the mapped XMP property. The namespace is implicit.};enum { kAnyCount = 0 };static const TIFF_MappingToXMP sPrimaryIFDMappings[] = { { /* 256 */ kTIFF_ImageWidth, kTIFF_ShortOrLongType, 1, "ImageWidth" }, { /* 257 */ kTIFF_ImageLength, kTIFF_ShortOrLongType, 1, "ImageLength" }, { /* 258 */ kTIFF_BitsPerSample, kTIFF_ShortType, 3, "BitsPerSample" }, { /* 259 */ kTIFF_Compression, kTIFF_ShortType, 1, "Compression" }, { /* 262 */ kTIFF_PhotometricInterpretation, kTIFF_ShortType, 1, "PhotometricInterpretation" }, { /* 274 */ kTIFF_Orientation, kTIFF_ShortType, 1, "Orientation" }, { /* 277 */ kTIFF_SamplesPerPixel, kTIFF_ShortType, 1, "SamplesPerPixel" }, { /* 284 */ kTIFF_PlanarConfiguration, kTIFF_ShortType, 1, "PlanarConfiguration" }, { /* 530 */ kTIFF_YCbCrSubSampling, kTIFF_ShortType, 2, "YCbCrSubSampling" }, { /* 531 */ kTIFF_YCbCrPositioning, kTIFF_ShortType, 1, "YCbCrPositioning" }, { /* 282 */ kTIFF_XResolution, kTIFF_RationalType, 1, "XResolution" }, { /* 283 */ kTIFF_YResolution, kTIFF_RationalType, 1, "YResolution" }, { /* 296 */ kTIFF_ResolutionUnit, kTIFF_ShortType, 1, "ResolutionUnit" }, { /* 301 */ kTIFF_TransferFunction, kTIFF_ShortType, 3*256, "TransferFunction" }, { /* 318 */ kTIFF_WhitePoint, kTIFF_RationalType, 2, "WhitePoint" }, { /* 319 */ kTIFF_PrimaryChromaticities, kTIFF_RationalType, 6, "PrimaryChromaticities" }, { /* 529 */ kTIFF_YCbCrCoefficients, kTIFF_RationalType, 3, "YCbCrCoefficients" }, { /* 532 */ kTIFF_ReferenceBlackWhite, kTIFF_RationalType, 6, "ReferenceBlackWhite" }, { /* 306 */ kTIFF_DateTime, kTIFF_ASCIIType, 20, "" }, // ! Has a special mapping. { /* 270 */ kTIFF_ImageDescription, kTIFF_ASCIIType, kAnyCount, "" }, // ! Has a special mapping. { /* 271 */ kTIFF_Make, kTIFF_ASCIIType, kAnyCount, "Make" }, { /* 272 */ kTIFF_Model, kTIFF_ASCIIType, kAnyCount, "Model" }, { /* 305 */ kTIFF_Software, kTIFF_ASCIIType, kAnyCount, "Software" }, // Has alias to xmp:CreatorTool. { /* 315 */ kTIFF_Artist, kTIFF_ASCIIType, kAnyCount, "" }, // ! Has a special mapping. { /* 33432 */ kTIFF_Copyright, kTIFF_ASCIIType, kAnyCount, "" }, { 0xFFFF, 0, 0, 0 } // ! Must end with sentinel.};static const TIFF_MappingToXMP sExifIFDMappings[] = { { /* 36864 */ kTIFF_ExifVersion, kTIFF_UndefinedType, 4, "" }, // ! Has a special mapping. { /* 40960 */ kTIFF_FlashpixVersion, kTIFF_UndefinedType, 4, "" }, // ! Has a special mapping. { /* 40961 */ kTIFF_ColorSpace, kTIFF_ShortType, 1, "ColorSpace" }, { /* 37121 */ kTIFF_ComponentsConfiguration, kTIFF_UndefinedType, 4, "" }, // ! Has a special mapping. { /* 37122 */ kTIFF_CompressedBitsPerPixel, kTIFF_RationalType, 1, "CompressedBitsPerPixel" }, { /* 40962 */ kTIFF_PixelXDimension, kTIFF_ShortOrLongType, 1, "PixelXDimension" }, { /* 40963 */ kTIFF_PixelYDimension, kTIFF_ShortOrLongType, 1, "PixelYDimension" }, { /* 37510 */ kTIFF_UserComment, kTIFF_UndefinedType, kAnyCount, "" }, // ! Has a special mapping. { /* 40964 */ kTIFF_RelatedSoundFile, kTIFF_ASCIIType, 13, "RelatedSoundFile" }, { /* 36867 */ kTIFF_DateTimeOriginal, kTIFF_ASCIIType, 20, "" }, // ! Has a special mapping. { /* 36868 */ kTIFF_DateTimeDigitized, kTIFF_ASCIIType, 20, "" }, // ! Has a special mapping. { /* 33434 */ kTIFF_ExposureTime, kTIFF_RationalType, 1, "ExposureTime" }, { /* 33437 */ kTIFF_FNumber, kTIFF_RationalType, 1, "FNumber" }, { /* 34850 */ kTIFF_ExposureProgram, kTIFF_ShortType, 1, "ExposureProgram" }, { /* 34852 */ kTIFF_SpectralSensitivity, kTIFF_ASCIIType, kAnyCount, "SpectralSensitivity" }, { /* 34855 */ kTIFF_ISOSpeedRatings, kTIFF_ShortType, kAnyCount, "ISOSpeedRatings" }, { /* 34856 */ kTIFF_OECF, kTIFF_UndefinedType, kAnyCount, "" }, // ! Has a special mapping. { /* 37377 */ kTIFF_ShutterSpeedValue, kTIFF_SRationalType, 1, "ShutterSpeedValue" }, { /* 37378 */ kTIFF_ApertureValue, kTIFF_RationalType, 1, "ApertureValue" }, { /* 37379 */ kTIFF_BrightnessValue, kTIFF_SRationalType, 1, "BrightnessValue" }, { /* 37380 */ kTIFF_ExposureBiasValue, kTIFF_SRationalType, 1, "ExposureBiasValue" }, { /* 37381 */ kTIFF_MaxApertureValue, kTIFF_RationalType, 1, "MaxApertureValue" }, { /* 37382 */ kTIFF_SubjectDistance, kTIFF_RationalType, 1, "SubjectDistance" }, { /* 37383 */ kTIFF_MeteringMode, kTIFF_ShortType, 1, "MeteringMode" }, { /* 37384 */ kTIFF_LightSource, kTIFF_ShortType, 1, "LightSource" }, { /* 37385 */ kTIFF_Flash, kTIFF_ShortType, 1, "" }, // ! Has a special mapping. { /* 37386 */ kTIFF_FocalLength, kTIFF_RationalType, 1, "FocalLength" }, { /* 37396 */ kTIFF_SubjectArea, kTIFF_ShortType, kAnyCount, "SubjectArea" }, // ! Actually 2..4. { /* 41483 */ kTIFF_FlashEnergy, kTIFF_RationalType, 1, "FlashEnergy" }, { /* 41484 */ kTIFF_SpatialFrequencyResponse, kTIFF_UndefinedType, kAnyCount, "" }, // ! Has a special mapping. { /* 41486 */ kTIFF_FocalPlaneXResolution, kTIFF_RationalType, 1, "FocalPlaneXResolution" }, { /* 41487 */ kTIFF_FocalPlaneYResolution, kTIFF_RationalType, 1, "FocalPlaneYResolution" }, { /* 41488 */ kTIFF_FocalPlaneResolutionUnit, kTIFF_ShortType, 1, "FocalPlaneResolutionUnit" }, { /* 41492 */ kTIFF_SubjectLocation, kTIFF_ShortType, 2, "SubjectLocation" }, { /* 41493 */ kTIFF_ExposureIndex, kTIFF_RationalType, 1, "ExposureIndex" }, { /* 41495 */ kTIFF_SensingMethod, kTIFF_ShortType, 1, "SensingMethod" }, { /* 41728 */ kTIFF_FileSource, kTIFF_UndefinedType, 1, "" }, // ! Has a special mapping. { /* 41729 */ kTIFF_SceneType, kTIFF_UndefinedType, 1, "" }, // ! Has a special mapping. { /* 41730 */ kTIFF_CFAPattern, kTIFF_UndefinedType, kAnyCount, "" }, // ! Has a special mapping. { /* 41985 */ kTIFF_CustomRendered, kTIFF_ShortType, 1, "CustomRendered" }, { /* 41986 */ kTIFF_ExposureMode, kTIFF_ShortType, 1, "ExposureMode" }, { /* 41987 */ kTIFF_WhiteBalance, kTIFF_ShortType, 1, "WhiteBalance" }, { /* 41988 */ kTIFF_DigitalZoomRatio, kTIFF_RationalType, 1, "DigitalZoomRatio" }, { /* 41989 */ kTIFF_FocalLengthIn35mmFilm, kTIFF_ShortType, 1, "FocalLengthIn35mmFilm" }, { /* 41990 */ kTIFF_SceneCaptureType, kTIFF_ShortType, 1, "SceneCaptureType" }, { /* 41991 */ kTIFF_GainControl, kTIFF_ShortType, 1, "GainControl" }, { /* 41992 */ kTIFF_Contrast, kTIFF_ShortType, 1, "Contrast" }, { /* 41993 */ kTIFF_Saturation, kTIFF_ShortType, 1, "Saturation" }, { /* 41994 */ kTIFF_Sharpness, kTIFF_ShortType, 1, "Sharpness" }, { /* 41995 */ kTIFF_DeviceSettingDescription, kTIFF_UndefinedType, kAnyCount, "" }, // ! Has a special mapping. { /* 41996 */ kTIFF_SubjectDistanceRange, kTIFF_ShortType, 1, "SubjectDistanceRange" }, { /* 42016 */ kTIFF_ImageUniqueID, kTIFF_ASCIIType, 33, "ImageUniqueID" }, { 0xFFFF, 0, 0, 0 } // ! Must end with sentinel.};static const TIFF_MappingToXMP sGPSInfoIFDMappings[] = { { /* 0 */ kTIFF_GPSVersionID, kTIFF_ByteType, 4, "" }, // ! Has a special mapping. { /* 2 */ kTIFF_GPSLatitude, kTIFF_RationalType, 3, "" }, // ! Has a special mapping. { /* 4 */ kTIFF_GPSLongitude, kTIFF_RationalType, 3, "" }, // ! Has a special mapping. { /* 5 */ kTIFF_GPSAltitudeRef, kTIFF_ByteType, 1, "GPSAltitudeRef" }, { /* 6 */ kTIFF_GPSAltitude, kTIFF_RationalType, 1, "GPSAltitude" }, { /* 7 */ kTIFF_GPSTimeStamp, kTIFF_RationalType, 3, "" }, // ! Has a special mapping. { /* 8 */ kTIFF_GPSSatellites, kTIFF_ASCIIType, kAnyCount, "GPSSatellites" }, { /* 9 */ kTIFF_GPSStatus, kTIFF_ASCIIType, 2, "GPSStatus" }, { /* 10 */ kTIFF_GPSMeasureMode, kTIFF_ASCIIType, 2, "GPSMeasureMode" }, { /* 11 */ kTIFF_GPSDOP, kTIFF_RationalType, 1, "GPSDOP" }, { /* 12 */ kTIFF_GPSSpeedRef, kTIFF_ASCIIType, 2, "GPSSpeedRef" }, { /* 13 */ kTIFF_GPSSpeed, kTIFF_RationalType, 1, "GPSSpeed" }, { /* 14 */ kTIFF_GPSTrackRef, kTIFF_ASCIIType, 2, "GPSTrackRef" }, { /* 15 */ kTIFF_GPSTrack, kTIFF_RationalType, 1, "GPSTrack" }, { /* 16 */ kTIFF_GPSImgDirectionRef, kTIFF_ASCIIType, 2, "GPSImgDirectionRef" }, { /* 17 */ kTIFF_GPSImgDirection, kTIFF_RationalType, 1, "GPSImgDirection" }, { /* 18 */ kTIFF_GPSMapDatum, kTIFF_ASCIIType, kAnyCount, "GPSMapDatum" }, { /* 20 */ kTIFF_GPSDestLatitude, kTIFF_RationalType, 3, "" }, // ! Has a special mapping. { /* 22 */ kTIFF_GPSDestLongitude, kTIFF_RationalType, 3, "" }, // ! Has a special mapping. { /* 23 */ kTIFF_GPSDestBearingRef, kTIFF_ASCIIType, 2, "GPSDestBearingRef" }, { /* 24 */ kTIFF_GPSDestBearing, kTIFF_RationalType, 1, "GPSDestBearing" }, { /* 25 */ kTIFF_GPSDestDistanceRef, kTIFF_ASCIIType, 2, "GPSDestDistanceRef" }, { /* 26 */ kTIFF_GPSDestDistance, kTIFF_RationalType, 1, "GPSDestDistance" }, { /* 27 */ kTIFF_GPSProcessingMethod, kTIFF_UndefinedType, kAnyCount, "" }, // ! Has a special mapping. { /* 28 */ kTIFF_GPSAreaInformation, kTIFF_UndefinedType, kAnyCount, "" }, // ! Has a special mapping. { /* 30 */ kTIFF_GPSDifferential, kTIFF_ShortType, 1, "GPSDifferential" }, { 0xFFFF, 0, 0, 0 } // ! Must end with sentinel.};// =================================================================================================static XMP_Uns32 GatherInt ( const char * strPtr, size_t count ){ XMP_Uns32 value = 0; const char * strEnd = strPtr + count; while ( strPtr < strEnd ) { char ch = *strPtr; if ( (ch < '0') || (ch > '9') ) break; value = value*10 + (ch - '0'); ++strPtr; } return value;}// =================================================================================================// =================================================================================================// =================================================================================================// ComputeTIFFDigest// =================//// Compute a 128 bit (16 byte) MD5 digest of the mapped TIFF tags and format it as a string like:// 256,257,...;A0FCE844924381619820B6F7117C8B83// The first portion is a decimal list of the tags from sPrimaryIFDMappings, the last part is the// MD5 digest as 32 hex digits using capital A-F.// ! The order of listing for the tags is crucial for the change comparisons to work!static voidComputeTIFFDigest ( const TIFF_Manager & tiff, std::string * digestStr ){ MD5_CTX context; MD5_Digest digest; char buffer[40]; size_t in, out; TIFF_Manager::TagInfo tagInfo; MD5Init ( &context ); digestStr->clear(); digestStr->reserve ( 160 ); // The current length is 134. for ( size_t i = 0; sPrimaryIFDMappings[i].id != 0xFFFF; ++i ) { snprintf ( buffer, sizeof(buffer), "%d,", sPrimaryIFDMappings[i].id ); // AUDIT: Use of sizeof(buffer) is safe. digestStr->append ( buffer ); bool found = tiff.GetTag ( kTIFF_PrimaryIFD, sPrimaryIFDMappings[i].id, &tagInfo ); if ( found ) MD5Update ( &context, (XMP_Uns8*)tagInfo.dataPtr, tagInfo.dataLen ); } size_t endPos = digestStr->size() - 1; (*digestStr)[endPos] = ';'; MD5Final ( digest, &context ); for ( in = 0, out = 0; in < 16; in += 1, out += 2 ) { XMP_Uns8 byte = digest[in]; buffer[out] = ReconcileUtils::kHexDigits [ byte >> 4 ]; buffer[out+1] = ReconcileUtils::kHexDigits [ byte & 0xF ]; } buffer[32] = 0; digestStr->append ( buffer );} // ComputeTIFFDigest;// =================================================================================================// ComputeExifDigest// =================//// Compute a 128 bit (16 byte) MD5 digest of the mapped Exif andf GPS tags and format it as a string like:// 36864,40960,...;A0FCE844924381619820B6F7117C8B83// The first portion is a decimal list of the tags, the last part is the MD5 digest as 32 hex// digits using capital A-F. The listed tags are those from sExifIFDMappings followed by those from// sGPSInfoIFDMappings.// ! The order of listing for the tags is crucial for the change comparisons to work!static voidComputeExifDigest ( const TIFF_Manager & exif, std::string * digestStr ){ MD5_CTX context; MD5_Digest digest; char buffer[40]; size_t in, out; TIFF_Manager::TagInfo tagInfo; MD5Init ( &context ); digestStr->clear(); digestStr->reserve ( 440 ); // The current length is 414. for ( size_t i = 0; sExifIFDMappings[i].id != 0xFFFF; ++i ) { snprintf ( buffer, sizeof(buffer), "%d,", sExifIFDMappings[i].id ); // AUDIT: Use of sizeof(buffer) is safe. digestStr->append ( buffer ); bool found = exif.GetTag ( kTIFF_ExifIFD, sExifIFDMappings[i].id, &tagInfo ); if ( found ) MD5Update ( &context, (XMP_Uns8*)tagInfo.dataPtr, tagInfo.dataLen ); } for ( size_t i = 0; sGPSInfoIFDMappings[i].id != 0xFFFF; ++i ) { snprintf ( buffer, sizeof(buffer), "%d,", sGPSInfoIFDMappings[i].id ); // AUDIT: Use of sizeof(buffer) is safe. digestStr->append ( buffer ); bool found = exif.GetTag ( kTIFF_GPSInfoIFD, sGPSInfoIFDMappings[i].id, &tagInfo ); if ( found ) MD5Update ( &context, (XMP_Uns8*)tagInfo.dataPtr, tagInfo.dataLen ); } size_t endPos = digestStr->size() - 1; (*digestStr)[endPos] = ';'; MD5Final ( digest, &context ); for ( in = 0, out = 0; in < 16; in += 1, out += 2 ) { XMP_Uns8 byte = digest[in]; buffer[out] = ReconcileUtils::kHexDigits [ byte >> 4 ]; buffer[out+1] = ReconcileUtils::kHexDigits [ byte & 0xF ]; } buffer[32] = 0; digestStr->append ( buffer );} // ComputeExifDigest;// =================================================================================================// ReconcileUtils::CheckTIFFDigest// ===============================intReconcileUtils::CheckTIFFDigest ( const TIFF_Manager & tiff, const SXMPMeta & xmp ){ std::string newDigest, oldDigest; ComputeTIFFDigest ( tiff, &newDigest ); bool found = xmp.GetProperty ( kXMP_NS_TIFF, "NativeDigest", &oldDigest, 0 ); if ( ! found ) return kDigestMissing; if ( newDigest == oldDigest ) return kDigestMatches; return kDigestDiffers;} // ReconcileUtils::CheckTIFFDigest;// =================================================================================================// ReconcileUtils::CheckExifDigest// ===============================intReconcileUtils::CheckExifDigest ( const TIFF_Manager & tiff, const SXMPMeta & xmp ){ std::string newDigest, oldDigest; ComputeExifDigest ( tiff, &newDigest ); bool found = xmp.GetProperty ( kXMP_NS_EXIF, "NativeDigest", &oldDigest, 0 ); if ( ! found ) return kDigestMissing; if ( newDigest == oldDigest ) return kDigestMatches; return kDigestDiffers;} // ReconcileUtils::CheckExifDigest;// =================================================================================================// ReconcileUtils::SetTIFFDigest// =============================voidReconcileUtils::SetTIFFDigest ( const TIFF_Manager & tiff, SXMPMeta * xmp ){ std::string newDigest; ComputeTIFFDigest ( tiff, &newDigest ); xmp->SetProperty ( kXMP_NS_TIFF, "NativeDigest", newDigest.c_str() );} // ReconcileUtils::SetTIFFDigest;// =================================================================================================// ReconcileUtils::SetExifDigest// =============================voidReconcileUtils::SetExifDigest ( const TIFF_Manager & tiff, SXMPMeta * xmp ){ std::string newDigest; ComputeExifDigest ( tiff, &newDigest );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -