📄 psd_handler.cpp
字号:
// Set up everything for the legacy import, but don't do it yet. This lets us do a forced legacy // import if the XMP packet gets parsing errors. // Parse the IPTC and Exif, determine the last-legacy priority. For PSD files the relevant // legacy priorities (ignoring Mac pnot and ANPA resources) are: // kLegacyJTP_PSIR_OldCaption - highest // kLegacyJTP_PSIR_IPTC // kLegacyJTP_None - lowest // ! Yes, TIFF tags 270 (Image Description, dc:description), 315 (Artist, dc:creator), and // ! 33432 (Copyright, dc:rights) are ignored in Photoshop files. The only imported legacy forms // ! of these are IPTC DataSets 2:120 (Caption), 2:80 (By-line), and 2:116 ( Copyright Notice). bool found; RecJTP_LegacyPriority lastLegacy = kLegacyJTP_None; bool readOnly = ((this->parent->openFlags & kXMPFiles_OpenForUpdate) == 0); if ( readOnly ) { this->iptcMgr = new IPTC_Reader(); this->exifMgr = new TIFF_MemoryReader(); } else { this->iptcMgr = new IPTC_Writer(); this->exifMgr = new TIFF_FileWriter(); } PSIR_Manager & psir = this->psirMgr; // Give the compiler help in recognizing non-aliases. IPTC_Manager & iptc = *this->iptcMgr; TIFF_Manager & exif = *this->exifMgr; PSIR_Manager::ImgRsrcInfo iptcInfo, exifInfo; bool haveIPTC = psir.GetImgRsrc ( kPSIR_IPTC, &iptcInfo ); bool haveExif = psir.GetImgRsrc ( kPSIR_Exif, &exifInfo ); found = psir.GetImgRsrc ( kPSIR_OldCaption, 0 ); if ( ! found ) found = psir.GetImgRsrc ( kPSIR_OldCaptionPStr, 0 ); if ( found ) lastLegacy = kLegacyJTP_PSIR_OldCaption; if ( haveIPTC ) { iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen ); if ( lastLegacy < kLegacyJTP_PSIR_IPTC ) lastLegacy = kLegacyJTP_PSIR_IPTC; } if ( haveExif ) { exif.ParseMemoryStream ( exifInfo.dataPtr, exifInfo.dataLen ); } XMP_OptionBits options = 0; if ( this->containsXMP ) options |= k2XMP_FileHadXMP; if ( haveIPTC ) options |= k2XMP_FileHadIPTC; if ( haveExif ) options |= k2XMP_FileHadExif; // Process the XMP packet. If it fails to parse, do a forced legacy import but still throw an // exception. This tells the caller that an error happened, but gives them recovered legacy // should they want to proceed with that. if ( ! this->xmpPacket.empty() ) { XMP_Assert ( this->containsXMP ); // Common code takes care of packetInfo.charForm, .padSize, and .writeable. XMP_StringPtr packetStr = this->xmpPacket.c_str(); XMP_StringLen packetLen = this->xmpPacket.size(); try { this->xmpObj.ParseFromBuffer ( packetStr, packetLen ); } catch ( ... ) { XMP_ClearOption ( options, k2XMP_FileHadXMP ); ImportJTPtoXMP ( kXMP_JPEGFile, lastLegacy, &exif, psir, &iptc, &this->xmpObj, options ); throw; // ! Rethrow the exception, don't absorb it. } } // Process the legacy metadata. ImportJTPtoXMP ( kXMP_PhotoshopFile, lastLegacy, &exif, psir, &iptc, &this->xmpObj, options ); this->containsXMP = true; // Assume we now have something in the XMP. } // PSD_MetaHandler::ProcessXMP// =================================================================================================// PSD_MetaHandler::UpdateFile// ===========================void PSD_MetaHandler::UpdateFile ( bool doSafeUpdate ){ XMP_Assert ( ! doSafeUpdate ); // This should only be called for "unsafe" updates. // Decide whether to do an in-place update. This can only happen if all of the following are true: // - There is an XMP packet in the file. // - The are no changes to the legacy image resources. (The IPTC and EXIF are in the PSIR.) // - The new XMP can fit in the old space. ExportXMPtoJTP ( kXMP_PhotoshopFile, &this->xmpObj, this->exifMgr, &this->psirMgr, this->iptcMgr ); XMP_Int64 oldPacketOffset = this->packetInfo.offset; XMP_Int32 oldPacketLength = this->packetInfo.length; // printf ( "PSD_MetaHandler::UpdateFile - XMP old packet offset %lld (0x%llX), size %d\n", // oldPacketOffset, oldPacketOffset, oldPacketLength ); if ( oldPacketOffset == kXMPFiles_UnknownOffset ) oldPacketOffset = 0; // ! Simplify checks. if ( oldPacketLength == kXMPFiles_UnknownLength ) oldPacketLength = 0; bool doInPlace = (oldPacketOffset != 0) && (oldPacketLength != 0); // ! Has old packet and new packet fits. if ( doInPlace && (this->psirMgr.IsLegacyChanged()) ) doInPlace = false; if ( doInPlace ) { #if GatherPerformanceData sAPIPerf->back().extraInfo += ", PSD in-place update"; #endif LFA_FileRef liveFile = this->parent->fileRef; XMP_Assert ( this->xmpPacket.size() == (size_t)oldPacketLength ); // ! Done by common PutXMP logic. // printf ( "PSD_MetaHandler::UpdateFile - XMP in-place packet offset %lld (0x%llX), size %d\n", // oldPacketOffset, oldPacketOffset, this->xmpPacket.size() ); LFA_Seek ( liveFile, oldPacketOffset, SEEK_SET ); LFA_Write ( liveFile, this->xmpPacket.c_str(), this->xmpPacket.size() ); } else { #if GatherPerformanceData sAPIPerf->back().extraInfo += ", PSD copy update"; #endif std::string origPath = this->parent->filePath; LFA_FileRef origRef = this->parent->fileRef; std::string updatePath; LFA_FileRef updateRef = 0; CreateTempFile ( origPath, &updatePath, kCopyMacRsrc ); updateRef = LFA_Open ( updatePath.c_str(), 'w' ); this->parent->filePath = updatePath; this->parent->fileRef = updateRef; try { XMP_Assert ( ! this->skipReconcile ); this->skipReconcile = true; this->WriteFile ( origRef, origPath ); this->skipReconcile = false; } catch ( ... ) { this->skipReconcile = false; LFA_Close ( updateRef ); this->parent->filePath = origPath; this->parent->fileRef = origRef; throw; } LFA_Close ( origRef ); LFA_Delete ( origPath.c_str() ); LFA_Close ( updateRef ); LFA_Rename ( updatePath.c_str(), origPath.c_str() ); this->parent->filePath = origPath; this->parent->fileRef = 0; } this->needsUpdate = false;} // PSD_MetaHandler::UpdateFile// =================================================================================================// PSD_MetaHandler::WriteFile// ==========================// The metadata parts of a Photoshop file are all in the image resources. The PSIR_Manager's// UpdateFileResources method will take care of the image resource portion of the file, updating// those resources that have changed and preserving those that have not.void PSD_MetaHandler::WriteFile ( LFA_FileRef sourceRef, const std::string & sourcePath ){ LFA_FileRef destRef = this->parent->fileRef; XMP_AbortProc abortProc = this->parent->abortProc; void * abortArg = this->parent->abortArg; const bool checkAbort = (abortProc != 0); XMP_Uns32 sourceLen = (XMP_Uns32) LFA_Measure ( sourceRef ); if ( sourceLen == 0 ) return; // Tolerate empty files. // Reconcile the legacy metadata, unless this is called from UpdateFile. Reserialize the XMP to // get standard padding, PutXMP has probably done an in-place serialize. Set the XMP image resource. if ( ! skipReconcile ) { ExportXMPtoJTP ( kXMP_PhotoshopFile, &this->xmpObj, this->exifMgr, &this->psirMgr, this->iptcMgr ); } this->xmpObj.SerializeToBuffer ( &this->xmpPacket, kXMP_UseCompactFormat ); this->packetInfo.offset = kXMPFiles_UnknownOffset; this->packetInfo.length = this->xmpPacket.size(); this->packetInfo.padSize = GetPacketPadSize ( this->xmpPacket.c_str(), this->xmpPacket.size() ); this->psirMgr.SetImgRsrc ( kPSIR_XMP, this->xmpPacket.c_str(), this->xmpPacket.size() ); // Copy the file header and color mode section, then write the updated image resource section, // and copy the tail of the source file (layer and mask section to EOF). LFA_Seek ( sourceRef, 0, SEEK_SET ); LFA_Truncate (destRef, 0 ); LFA_Copy ( sourceRef, destRef, 26 ); // Copy the file header. XMP_Uns32 cmLen; LFA_Read ( sourceRef, &cmLen, 4 ); LFA_Write ( destRef, &cmLen, 4 ); // Copy the color mode section length. cmLen = GetUns32BE ( &cmLen ); LFA_Copy ( sourceRef, destRef, cmLen ); // Copy the color mode section contents. XMP_Uns32 irLen; LFA_Read ( sourceRef, &irLen, 4 ); // Get the source image resource section length. irLen = GetUns32BE ( &irLen ); this->psirMgr.UpdateFileResources ( sourceRef, destRef, 0, abortProc, abortArg ); XMP_Uns32 tailOffset = 26 + 4 + cmLen + 4 + irLen; XMP_Uns32 tailLength = sourceLen - tailOffset; LFA_Seek ( sourceRef, tailOffset, SEEK_SET ); LFA_Seek ( destRef, 0, SEEK_END ); LFA_Copy ( sourceRef, destRef, tailLength ); // Copy the tail of the file. this->needsUpdate = false;} // PSD_MetaHandler::WriteFile// =================================================================================================
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -