diff options
Diffstat (limited to 'source/XMPFiles/FormatSupport/ReconcileTIFF.cpp')
-rw-r--r-- | source/XMPFiles/FormatSupport/ReconcileTIFF.cpp | 177 |
1 files changed, 149 insertions, 28 deletions
diff --git a/source/XMPFiles/FormatSupport/ReconcileTIFF.cpp b/source/XMPFiles/FormatSupport/ReconcileTIFF.cpp index 5dbca57..4ae7564 100644 --- a/source/XMPFiles/FormatSupport/ReconcileTIFF.cpp +++ b/source/XMPFiles/FormatSupport/ReconcileTIFF.cpp @@ -1,6 +1,6 @@ // ================================================================================================= // ADOBE SYSTEMS INCORPORATED -// Copyright 2006-2007 Adobe Systems Incorporated +// Copyright 2006-2008 Adobe Systems Incorporated // All Rights Reserved // // NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms @@ -491,7 +491,11 @@ ImportSingleTIFF_ASCII ( const TIFF_Manager::TagInfo & tagInfo, if ( isUTF8 ) { strValue.assign ( chPtr, tagInfo.dataLen ); } else { - ReconcileUtils::LocalToUTF8 ( chPtr, tagInfo.dataLen, &strValue ); + #if ! XMP_UNIXBuild + ReconcileUtils::LocalToUTF8 ( chPtr, tagInfo.dataLen, &strValue ); + #else + return; // ! Hack until legacy-as-local issues are resolved for generic UNIX. + #endif } xmp->SetProperty ( xmpNS, xmpProp, strValue.c_str() ); } @@ -865,7 +869,11 @@ ImportArrayTIFF_ASCII ( const TIFF_Manager::TagInfo & tagInfo, if ( isUTF8 ) { strValue.assign ( chPtr, tagInfo.dataLen ); } else { - ReconcileUtils::LocalToUTF8 ( chPtr, tagInfo.dataLen, &strValue ); + #if ! XMP_UNIXBuild + ReconcileUtils::LocalToUTF8 ( chPtr, tagInfo.dataLen, &strValue ); + #else + return; // ! Hack until legacy-as-local issues are resolved for generic UNIX. + #endif } chPtr = strValue.c_str(); chEnd = chPtr + strValue.size(); @@ -1333,7 +1341,11 @@ ImportTIFF_LocTextASCII ( const TIFF_Manager & tiff, XMP_Uns8 ifd, XMP_Uns16 tag if ( isUTF8 ) { strValue.assign ( chPtr, tagInfo.dataLen ); } else { - ReconcileUtils::LocalToUTF8 ( chPtr, tagInfo.dataLen, &strValue ); + #if ! XMP_UNIXBuild + ReconcileUtils::LocalToUTF8 ( chPtr, tagInfo.dataLen, &strValue ); + #else + return; // ! Hack until legacy-as-local issues are resolved for generic UNIX. + #endif } xmp->SetLocalizedText ( xmpNS, xmpProp, "", "x-default", strValue.c_str() ); } @@ -1351,14 +1363,20 @@ ImportTIFF_LocTextASCII ( const TIFF_Manager & tiff, XMP_Uns8 ifd, XMP_Uns16 tag static void ImportTIFF_EncodedString ( const TIFF_Manager & tiff, const TIFF_Manager::TagInfo & tagInfo, - SXMPMeta * xmp, const char * xmpNS, const char * xmpProp ) + SXMPMeta * xmp, const char * xmpNS, const char * xmpProp, bool isLangAlt = false ) { try { // Don't let errors with one stop the others. std::string strValue; bool ok = tiff.DecodeString ( tagInfo.dataPtr, tagInfo.dataLen, &strValue ); - if ( ok ) xmp->SetProperty ( xmpNS, xmpProp, strValue.c_str() ); + if ( ! ok ) return; + + if ( ! isLangAlt ) { + xmp->SetProperty ( xmpNS, xmpProp, strValue.c_str() ); + } else { + xmp->SetLocalizedText ( xmpNS, xmpProp, "", "x-default", strValue.c_str() ); + } } catch ( ... ) { // Do nothing, let other imports proceed. @@ -1438,12 +1456,12 @@ ImportTIFF_OECFTable ( const TIFF_Manager::TagInfo & tagInfo, bool nativeEndian, bytePtr += 4; // Move to the list of names. for ( size_t i = columns; i > 0; --i ) { size_t nameLen = strlen((XMP_StringPtr)bytePtr) + 1; // ! Include the terminating nul. - if ( (bytePtr + nameLen) > byteEnd ) goto BadExif; + if ( (bytePtr + nameLen) > byteEnd ) { xmp->DeleteProperty ( xmpNS, xmpProp ); return; }; xmp->AppendArrayItem ( xmpNS, arrayPath.c_str(), kXMP_PropArrayIsOrdered, (XMP_StringPtr)bytePtr ); bytePtr += nameLen; } - if ( (byteEnd - bytePtr) != (8 * columns * rows) ) goto BadExif; // Make sure the values are present. + if ( (byteEnd - bytePtr) != (8 * columns * rows) ) { xmp->DeleteProperty ( xmpNS, xmpProp ); return; }; // Make sure the values are present. SXMPUtils::ComposeStructFieldPath ( xmpNS, xmpProp, kXMP_NS_EXIF, "Values", &arrayPath ); XMP_Int32 * binPtr = (XMP_Int32*)bytePtr; @@ -1463,10 +1481,6 @@ ImportTIFF_OECFTable ( const TIFF_Manager::TagInfo & tagInfo, bool nativeEndian, } return; - - BadExif: // Ignore the tag if the table is ill-formed. - xmp->DeleteProperty ( xmpNS, xmpProp ); - return; } catch ( ... ) { // Do nothing, let other imports proceed. @@ -1512,12 +1526,12 @@ ImportTIFF_SFRTable ( const TIFF_Manager::TagInfo & tagInfo, bool nativeEndian, bytePtr += 4; // Move to the list of names. for ( size_t i = columns; i > 0; --i ) { size_t nameLen = strlen((XMP_StringPtr)bytePtr) + 1; // ! Include the terminating nul. - if ( (bytePtr + nameLen) > byteEnd ) goto BadExif; + if ( (bytePtr + nameLen) > byteEnd ) { xmp->DeleteProperty ( xmpNS, xmpProp ); return; }; xmp->AppendArrayItem ( xmpNS, arrayPath.c_str(), kXMP_PropArrayIsOrdered, (XMP_StringPtr)bytePtr ); bytePtr += nameLen; } - if ( (byteEnd - bytePtr) != (8 * columns * rows) ) goto BadExif; // Make sure the values are present. + if ( (byteEnd - bytePtr) != (8 * columns * rows) ) { xmp->DeleteProperty ( xmpNS, xmpProp ); return; }; // Make sure the values are present. SXMPUtils::ComposeStructFieldPath ( xmpNS, xmpProp, kXMP_NS_EXIF, "Values", &arrayPath ); XMP_Uns32 * binPtr = (XMP_Uns32*)bytePtr; @@ -1537,10 +1551,6 @@ ImportTIFF_SFRTable ( const TIFF_Manager::TagInfo & tagInfo, bool nativeEndian, } return; - - BadExif: // Ignore the tag if the table is ill-formed. - xmp->DeleteProperty ( xmpNS, xmpProp ); - return; } catch ( ... ) { // Do nothing, let other imports proceed. @@ -1912,7 +1922,7 @@ ReconcileUtils::ImportExif ( const TIFF_Manager & tiff, SXMPMeta * xmp, int dige ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_ExifIFD, kTIFF_UserComment, kXMP_NS_EXIF, "UserComment", &tagInfo ); if ( ok ) { - ImportTIFF_EncodedString ( tiff, tagInfo, xmp, kXMP_NS_EXIF, "UserComment" ); + ImportTIFF_EncodedString ( tiff, tagInfo, xmp, kXMP_NS_EXIF, "UserComment", true /* isLangAlt */ ); } // 36867 DateTimeOriginal is a date master with 37521 SubSecTimeOriginal. @@ -1921,6 +1931,11 @@ ReconcileUtils::ImportExif ( const TIFF_Manager & tiff, SXMPMeta * xmp, int dige if ( ok && (tagInfo.type == kTIFF_ASCIIType) && (tagInfo.count == 20) ) { ImportTIFF_Date ( tiff, tagInfo, kTIFF_SubSecTimeOriginal, xmp, kXMP_NS_EXIF, "DateTimeOriginal" ); } + if ( ! xmp->DoesPropertyExist ( kXMP_NS_XMP, "CreateDate" ) ) { + std::string exifDate; + ok = xmp->GetProperty ( kXMP_NS_EXIF, "DateTimeOriginal", &exifDate, 0 ); + if ( ok ) xmp->SetProperty ( kXMP_NS_XMP, "CreateDate", exifDate.c_str() ); + } // 36868 DateTimeDigitized is a date master with 37522 SubSecTimeDigitized. ok = ImportTIFF_VerifyImport ( tiff, xmp, digestState, kTIFF_ExifIFD, kTIFF_DateTimeDigitized, @@ -2156,7 +2171,7 @@ ExportSingleTIFF_ASCII ( const SXMPMeta & xmp, const char * xmpNS, const char * if ( ! XMP_PropIsSimple ( xmpFlags ) ) return; // ? Complain? Delete the tag? - tiff->SetTag ( ifd, id, kTIFF_ASCIIType, xmpValue.size()+1, xmpValue.c_str() ); + tiff->SetTag ( ifd, id, kTIFF_ASCIIType, (XMP_Uns32)( xmpValue.size()+1 ), xmpValue.c_str() ); } catch ( ... ) { // Do nothing, let other exports proceed. @@ -2190,13 +2205,13 @@ ExportArrayTIFF_ASCII ( const SXMPMeta & xmp, const char * xmpNS, const char * x size_t count = xmp.CountArrayItems ( xmpNS, xmpProp ); for ( size_t i = 1; i <= count; ++i ) { // ! XMP arrays are indexed from 1. - (void) xmp.GetArrayItem ( xmpNS, xmpProp, i, &itemValue, &xmpFlags ); + (void) xmp.GetArrayItem ( xmpNS, xmpProp, (XMP_Index)i, &itemValue, &xmpFlags ); if ( ! XMP_PropIsSimple ( xmpFlags ) ) continue; // ? Complain? fullValue.append ( itemValue ); fullValue.append ( 1, '\x0' ); } - tiff->SetTag ( ifd, id, kTIFF_ASCIIType, fullValue.size(), fullValue.c_str() ); // ! Already have trailing nul. + tiff->SetTag ( ifd, id, kTIFF_ASCIIType, (XMP_Uns32)fullValue.size(), fullValue.c_str() ); // ! Already have trailing nul. } catch ( ... ) { // Do nothing, let other exports proceed. @@ -2273,7 +2288,7 @@ ExportTIFF_LocTextASCII ( const SXMPMeta & xmp, const char * xmpNS, const char * return; } - tiff->SetTag ( ifd, id, kTIFF_ASCIIType, xmpValue.size()+1, xmpValue.c_str() ); + tiff->SetTag ( ifd, id, kTIFF_ASCIIType, (XMP_Uns32)( xmpValue.size()+1 ), xmpValue.c_str() ); } catch ( ... ) { // Do nothing, let other exports proceed. @@ -2288,7 +2303,7 @@ ExportTIFF_LocTextASCII ( const SXMPMeta & xmp, const char * xmpNS, const char * static void ExportTIFF_EncodedString ( const SXMPMeta & xmp, const char * xmpNS, const char * xmpProp, - TIFF_Manager * tiff, XMP_Uns8 ifd, XMP_Uns16 id ) + TIFF_Manager * tiff, XMP_Uns8 ifd, XMP_Uns16 id, bool isLangAlt = false ) { try { // Don't let errors with one stop the others. @@ -2301,7 +2316,13 @@ ExportTIFF_EncodedString ( const SXMPMeta & xmp, const char * xmpNS, const char return; } - if ( ! XMP_PropIsSimple ( xmpFlags ) ) return; // ? Complain? Delete the tag? + if ( ! isLangAlt ) { + if ( ! XMP_PropIsSimple ( xmpFlags ) ) return; // ? Complain? Delete the tag? + } else { + if ( ! XMP_ArrayIsAltText ( xmpFlags ) ) return; // ? Complain? Delete the tag? + bool ok = xmp.GetLocalizedText ( xmpNS, xmpProp, "", "x-default", 0, &xmpValue, 0 ); + if ( ! ok ) return; // ? Complain? Delete the tag? + } XMP_Uns8 encoding = kTIFF_EncodeASCII; for ( size_t i = 0; i < xmpValue.size(); ++i ) { @@ -2321,6 +2342,93 @@ ExportTIFF_EncodedString ( const SXMPMeta & xmp, const char * xmpNS, const char } // ExportTIFF_EncodedString // ================================================================================================= +// ExportTIFF_GPSCoordinate +// ======================== +// +// The XMP format is either "deg,min,secR" or "deg,min.fracR", where 'R' is the reference direction, +// 'N', 'S', 'E', or 'W'. The location gets output as ( deg/1, min/1, sec/1 ) for the first form, +// and ( deg/1, minFrac/denom, 0/1 ) for the second form. + +// ! We arbitrarily limit the number of fractional minute digits to 6 to avoid overflow in the +// ! combined numerator. But we don't otherwise check for overflow or range errors. + +static void +ExportTIFF_GPSCoordinate ( const SXMPMeta & xmp, const char * xmpNS, const char * xmpProp, + TIFF_Manager * tiff, XMP_Uns8 ifd, XMP_Uns16 _id ) +{ + XMP_Uns16 refID = _id-1; // ! The GPS refs and locations are all tag N-1 and N pairs. + XMP_Uns16 locID = _id; + + XMP_Assert ( (locID & 1) == 0 ); + + try { // Don't let errors with one stop the others. + + std::string xmpValue; + XMP_OptionBits xmpFlags; + + bool foundXMP = xmp.GetProperty ( xmpNS, xmpProp, &xmpValue, &xmpFlags ); + if ( ! foundXMP ) { + tiff->DeleteTag ( ifd, refID ); + tiff->DeleteTag ( ifd, locID ); + return; + } + + if ( ! XMP_PropIsSimple ( xmpFlags ) ) return; + + const char * chPtr = xmpValue.c_str(); + + XMP_Uns32 deg=0, minNum=0, minDenom=1, sec=0; + + for ( ; ('0' <= *chPtr) && (*chPtr <= '9'); ++chPtr ) deg = deg*10 + (*chPtr - '0'); + if ( *chPtr != ',' ) return; // Bad XMP string. + ++chPtr; // Skip the comma. + + for ( ; ('0' <= *chPtr) && (*chPtr <= '9'); ++chPtr ) minNum = minNum*10 + (*chPtr - '0'); + if ( (*chPtr != ',') && (*chPtr != '.') ) return; // Bad XMP string. + + if ( *chPtr == ',' ) { + + ++chPtr; // Skip the comma. + for ( ; ('0' <= *chPtr) && (*chPtr <= '9'); ++chPtr ) sec = sec*10 + (*chPtr - '0'); + + } else { + + XMP_Assert ( *chPtr == '.' ); + ++chPtr; // Skip the period. + for ( ; ('0' <= *chPtr) && (*chPtr <= '9'); ++chPtr ) { + if ( minDenom > 100*1000 ) continue; // Don't accumulate any more digits. + minDenom *= 10; + minNum = minNum*10 + (*chPtr - '0'); + } + + } + + if ( *(chPtr+1) != 0 ) return; // Bad XMP string. + + char ref[2]; + ref[0] = *chPtr; + ref[1] = 0; + + tiff->SetTag ( ifd, refID, kTIFF_ASCIIType, 2, &ref[0] ); + + XMP_Uns32 loc[6]; + tiff->PutUns32 ( deg, &loc[0] ); + tiff->PutUns32 ( 1, &loc[1] ); + tiff->PutUns32 ( minNum, &loc[2] ); + tiff->PutUns32 ( minDenom, &loc[3] ); + tiff->PutUns32 ( sec, &loc[4] ); + tiff->PutUns32 ( 1, &loc[5] ); + + tiff->SetTag ( ifd, locID, kTIFF_RationalType, 3, &loc[0] ); + + } catch ( ... ) { + // Do nothing, let other exports proceed. + // ? Notify client? + } + +} // ExportTIFF_GPSCoordinate + +// ================================================================================================= // ================================================================================================= // ================================================================================================= @@ -2378,12 +2486,17 @@ ReconcileUtils::ExportTIFF ( const SXMPMeta & xmp, TIFF_Manager * tiff ) // ReconcileUtils::ExportExif // ========================== // -// Only a few tags are written back from XMP to the Exif IFD, they are each handled explicitly. -// The writeback tags are: +// Only a few tags are written back from XMP to the Exif and GPS IFDs, they are each handled +// explicitly. The Exif writeback tags are: // 36867 - DateTimeOriginal (plus 37521 SubSecTimeOriginal) // 36868 - DateTimeDigitized (plus 37522 SubSecTimeDigitized) // 37510 - UserComment // 40964 - RelatedSoundFile +// The GPS writeback tags are: +// 1 - GPSLatitudeRef +// 2 - GPSLatitude +// 3 - GPSLongitudeRef +// 4 - GPSLongitude // ! Older versions of Photoshop did not import the UserComment or RelatedSoundFile tags. Don't // ! export the current XMP unless the original XMP had the tag or the current XMP has the tag. @@ -2405,7 +2518,7 @@ ReconcileUtils::ExportExif ( const SXMPMeta & xmp, TIFF_Manager * tiff ) if ( tiff->xmpHadUserComment || xmp.DoesPropertyExist ( kXMP_NS_EXIF, "UserComment" ) ) { ExportTIFF_EncodedString ( xmp, kXMP_NS_EXIF, "UserComment", - tiff, kTIFF_ExifIFD, kTIFF_UserComment ); + tiff, kTIFF_ExifIFD, kTIFF_UserComment, true /* isLangAlt */ ); } if ( tiff->xmpHadRelatedSoundFile || xmp.DoesPropertyExist ( kXMP_NS_EXIF, "RelatedSoundFile" ) ) { @@ -2413,4 +2526,12 @@ ReconcileUtils::ExportExif ( const SXMPMeta & xmp, TIFF_Manager * tiff ) tiff, kTIFF_ExifIFD, kTIFF_RelatedSoundFile ); } + if ( xmp.DoesPropertyExist ( kXMP_NS_EXIF, "GPSLatitude" ) ) { + ExportTIFF_GPSCoordinate ( xmp, kXMP_NS_EXIF, "GPSLatitude", tiff, kTIFF_GPSInfoIFD, kTIFF_GPSLatitude ); + } + + if ( xmp.DoesPropertyExist ( kXMP_NS_EXIF, "GPSLongitude" ) ) { + ExportTIFF_GPSCoordinate ( xmp, kXMP_NS_EXIF, "GPSLongitude", tiff, kTIFF_GPSInfoIFD, kTIFF_GPSLongitude ); + } + } // ReconcileUtils::ExportExif; |