📄 jpeg_handler.cpp
字号:
XMP_Assert ( sizeof(g32.data) == 32 ); memcpy ( g32.data, extGUID.c_str(), sizeof(g32.data) ); // AUDIT: Use of sizeof(g32.data) is safe. guidPos = this->extendedXMP.find ( g32 ); this->xmpObj.DeleteProperty ( kXMP_NS_XMP_Note, "HasExtendedXMP" ); // ! Must only be in the file. #if Trace_UnlimitedJPEG printf ( "%s extended XMP for GUID %s\n", ((guidPos != this->extendedXMP.end()) ? "Found" : "Missing"), extGUID.c_str() ); #endif } if ( guidPos != this->extendedXMP.end() ) { try { XMP_StringPtr extStr = guidPos->second.c_str(); XMP_StringLen extLen = guidPos->second.size(); SXMPMeta extXMP ( extStr, extLen ); SXMPUtils::MergeFromJPEG ( &this->xmpObj, extXMP ); } catch ( ... ) { // Ignore failures, let the rest of the XMP and legacy be kept. } } } // Process the legacy metadata. ImportJTPtoXMP ( kXMP_JPEGFile, lastLegacy, &exif, psir, &iptc, &this->xmpObj, options ); if ( haveExif | haveIPTC ) this->containsXMP = true; // Assume we had something for the XMP. } // JPEG_MetaHandler::ProcessXMP// =================================================================================================// JPEG_MetaHandler::UpdateFile// ============================void JPEG_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 a standard packet in the file. // - There is no extended XMP in the file. // - The are no changes to the legacy Exif or PSIR portions. (The IPTC is in the PSIR.) // - The new XMP can fit in the old space, without extensions. ExportXMPtoJTP ( kXMP_JPEGFile, &this->xmpObj, this->exifMgr, this->psirMgr, this->iptcMgr ); XMP_Int64 oldPacketOffset = this->packetInfo.offset; XMP_Int32 oldPacketLength = this->packetInfo.length; 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->extendedXMP.empty()) ) doInPlace = false; if ( doInPlace && (this->exifMgr != 0) && (this->exifMgr->IsLegacyChanged()) ) doInPlace = false; if ( doInPlace && (this->psirMgr != 0) && (this->psirMgr->IsLegacyChanged()) ) doInPlace = false; if ( doInPlace ) { #if GatherPerformanceData sAPIPerf->back().extraInfo += ", JPEG in-place update"; #endif LFA_FileRef liveFile = this->parent->fileRef; std::string & newPacket = this->xmpPacket; XMP_Assert ( newPacket.size() == (size_t)oldPacketLength ); // ! Done by common PutXMP logic. LFA_Seek ( liveFile, oldPacketOffset, SEEK_SET ); LFA_Write ( liveFile, newPacket.c_str(), newPacket.size() ); } else { #if GatherPerformanceData sAPIPerf->back().extraInfo += ", JPEG 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;} // JPEG_MetaHandler::UpdateFile// =================================================================================================// JPEG_MetaHandler::WriteFile// ===========================//// The metadata parts of a JPEG file are APP1 marker segments for Exif and XMP, and an APP13 marker// segment for Photoshop image resources which contain the IPTC. Corresponding marker segments in// the source file are ignored, other parts of the source file are copied. Any initial APP0 marker// segments are copied first. Then the new Exif, XMP, and PSIR marker segments are written. Then the// rest of the file is copied, skipping the old Exif, XMP, and PSIR. The checking for old metadata// stops at the first SOFn marker.// *** What about Mac resources?void JPEG_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_Uns16 marker; size_t segLen; // ! Must be a size to hold at least 64k+2. IOBuffer ioBuf; XMP_Uns32 first4; XMP_Assert ( kIOBufferSize >= (2 + 64*1024) ); // Enough for a marker plus maximum contents. if ( LFA_Measure ( sourceRef ) == 0 ) return; // Tolerate empty files. LFA_Seek ( sourceRef, 0, SEEK_SET ); LFA_Truncate (destRef, 0 ); if ( ! skipReconcile ) { ExportXMPtoJTP ( kXMP_JPEGFile, &this->xmpObj, this->exifMgr, this->psirMgr, this->iptcMgr ); } RefillBuffer ( sourceRef, &ioBuf ); if ( ! CheckFileSpace ( sourceRef, &ioBuf, 4 ) ) { XMP_Throw ( "JPEG must have at least SOI and EOI markers", kXMPErr_BadJPEG ); } marker = GetUns16BE ( ioBuf.ptr ); if ( marker != 0xFFD8 ) XMP_Throw ( "Missing SOI marker", kXMPErr_BadJPEG ); LFA_Write ( destRef, ioBuf.ptr, 2 ); ioBuf.ptr += 2; // Copy the leading APP0 marker segments. while ( true ) { if ( checkAbort && abortProc(abortArg) ) { XMP_Throw ( "JPEG_MetaHandler::WriteFile - User abort", kXMPErr_UserAbort ); } if ( ! CheckFileSpace ( sourceRef, &ioBuf, 2 ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG ); marker = GetUns16BE ( ioBuf.ptr ); if ( marker == 0xFFFF ) { LFA_Write ( destRef, ioBuf.ptr, 1 ); // Copy the 0xFF pad byte. ++ioBuf.ptr; continue; } if ( marker != 0xFFE0 ) break; if ( ! CheckFileSpace ( sourceRef, &ioBuf, 4 ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG ); segLen = GetUns16BE ( ioBuf.ptr+2 ); segLen += 2; // ! Don't do above in case machine does 16 bit "+". if ( ! CheckFileSpace ( sourceRef, &ioBuf, segLen ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG ); LFA_Write ( destRef, ioBuf.ptr, segLen ); ioBuf.ptr += segLen; } // Write the new Exif APP1 marker segment. if ( this->exifMgr != 0 ) { void* exifPtr; XMP_Uns32 exifLen = this->exifMgr->UpdateMemoryStream ( &exifPtr ); if ( exifLen > kExifMaxDataLength ) exifLen = this->exifMgr->UpdateMemoryStream ( &exifPtr, true ); if ( exifLen > kExifMaxDataLength ) XMP_Throw ( "Overflow of Exif APP1 data", kXMPErr_BadJPEG ); if ( exifLen > 0 ) { first4 = MakeUns32BE ( 0xFFE10000 + 2 + kExifSignatureLength + exifLen ); LFA_Write ( destRef, &first4, 4 ); LFA_Write ( destRef, kExifSignatureString, kExifSignatureLength ); LFA_Write ( destRef, exifPtr, exifLen ); } } // Write the new XMP APP1 marker segment, with possible extension marker segments. std::string mainXMP, extXMP, extDigest; SXMPUtils::PackageForJPEG ( this->xmpObj, &mainXMP, &extXMP, &extDigest ); XMP_Assert ( (extXMP.size() == 0) || (extDigest.size() == 32) ); first4 = MakeUns32BE ( 0xFFE10000 + 2 + kMainXMPSignatureLength + mainXMP.size() ); LFA_Write ( destRef, &first4, 4 ); LFA_Write ( destRef, kMainXMPSignatureString, kMainXMPSignatureLength ); LFA_Write ( destRef, mainXMP.c_str(), mainXMP.size() ); size_t extPos = 0; size_t extLen = extXMP.size(); while ( extLen > 0 ) { size_t partLen = extLen; if ( partLen > 65000 ) partLen = 65000; first4 = MakeUns32BE ( 0xFFE10000 + 2 + kExtXMPPrefixLength + partLen ); LFA_Write ( destRef, &first4, 4 ); LFA_Write ( destRef, kExtXMPSignatureString, kExtXMPSignatureLength ); LFA_Write ( destRef, extDigest.c_str(), extDigest.size() ); first4 = MakeUns32BE ( extXMP.size() ); LFA_Write ( destRef, &first4, 4 ); first4 = MakeUns32BE ( extPos ); LFA_Write ( destRef, &first4, 4 ); LFA_Write ( destRef, &extXMP[extPos], partLen ); extPos += partLen; extLen -= partLen; } // Write the new PSIR APP13 marker segment. if ( this->psirMgr != 0 ) { void* psirPtr; XMP_Uns32 psirLen = this->psirMgr->UpdateMemoryResources ( &psirPtr ); if ( psirLen > kPSIRMaxDataLength ) XMP_Throw ( "Overflow of PSIR APP13 data", kXMPErr_BadJPEG ); if ( psirLen > 0 ) { first4 = MakeUns32BE ( 0xFFED0000 + 2 + kPSIRSignatureLength + psirLen ); LFA_Write ( destRef, &first4, 4 ); LFA_Write ( destRef, kPSIRSignatureString, kPSIRSignatureLength ); LFA_Write ( destRef, psirPtr, psirLen ); } } // Copy remaining marker segments, skipping old metadata, to the first SOFn marker. while ( true ) { if ( checkAbort && abortProc(abortArg) ) { XMP_Throw ( "JPEG_MetaHandler::WriteFile - User abort", kXMPErr_UserAbort ); } if ( ! CheckFileSpace ( sourceRef, &ioBuf, 2 ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG ); marker = GetUns16BE ( ioBuf.ptr ); if ( marker == 0xFFFF ) { LFA_Write ( destRef, ioBuf.ptr, 1 ); // Copy the 0xFF pad byte. ++ioBuf.ptr; continue; } if ( ! TableOrDataMarker ( marker ) ) break; if ( ! CheckFileSpace ( sourceRef, &ioBuf, 4 ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG ); segLen = GetUns16BE ( ioBuf.ptr+2 ); if ( ! CheckFileSpace ( sourceRef, &ioBuf, 2+segLen ) ) XMP_Throw ( "Unexpected end to JPEG", kXMPErr_BadJPEG ); bool copySegment = true; XMP_Uns8* signaturePtr = ioBuf.ptr + 4; if ( marker == 0xFFED ) { if ( (segLen >= kPSIRSignatureLength) && CheckBytes ( signaturePtr, kPSIRSignatureString, kPSIRSignatureLength ) ) { copySegment = false; } } else if ( marker == 0xFFE1 ) { if ( (segLen >= kExifSignatureLength) && (CheckBytes ( signaturePtr, kExifSignatureString, kExifSignatureLength ) || CheckBytes ( signaturePtr, kExifSignatureAltStr, kExifSignatureLength )) ) { copySegment = false; } else if ( (segLen >= kMainXMPSignatureLength) && CheckBytes ( signaturePtr, kMainXMPSignatureString, kMainXMPSignatureLength ) ) { copySegment = false; } else if ( (segLen >= kExtXMPPrefixLength) && CheckBytes ( signaturePtr, kExtXMPSignatureString, kExtXMPSignatureLength ) ) { copySegment = false; } } if ( copySegment ) LFA_Write ( destRef, ioBuf.ptr, 2+segLen ); ioBuf.ptr += 2+segLen; } // Copy the remainder of the source file. size_t bufTail = ioBuf.len - (ioBuf.ptr - &ioBuf.data[0]); LFA_Write ( destRef, ioBuf.ptr, bufTail ); ioBuf.ptr += bufTail; while ( true ) { RefillBuffer ( sourceRef, &ioBuf ); if ( ioBuf.len == 0 ) break; LFA_Write ( destRef, ioBuf.ptr, ioBuf.len ); ioBuf.ptr += ioBuf.len; } this->needsUpdate = false;} // JPEG_MetaHandler::WriteFile
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -