⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tiff_handler.cpp

📁 flash xmp sdk,flash官方SDK
💻 CPP
字号:
// =================================================================================================// ADOBE SYSTEMS INCORPORATED// Copyright 2002-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 "TIFF_Handler.hpp"#include "TIFF_Support.hpp"#include "PSIR_Support.hpp"#include "IPTC_Support.hpp"#include "ReconcileLegacy.hpp"#include "MD5.h"using namespace std;// =================================================================================================/// \file TIFF_Handler.cpp/// \brief File format handler for TIFF.////// This handler ...///// =================================================================================================// =================================================================================================// TIFF_CheckFormat// ================// For TIFF we just check for the II/42 or MM/42 in the first 4 bytes and that there are at least// 26 bytes of data (4+4+2+12+4).//// ! The CheckXyzFormat routines don't track the filePos, that is left to ScanXyzFile.bool TIFF_CheckFormat ( XMP_FileFormat format,	                    XMP_StringPtr  filePath,                        LFA_FileRef    fileRef,                        XMPFiles *     parent ){	IgnoreParam(format); IgnoreParam(filePath); IgnoreParam(parent);	XMP_Assert ( format == kXMP_TIFFFile );		enum { kMinimalTIFFSize = 4+4+2+12+4 };	// Header plus IFD with 1 entry.	IOBuffer ioBuf;		LFA_Seek ( fileRef, 0, SEEK_SET );	if ( ! CheckFileSpace ( fileRef, &ioBuf, kMinimalTIFFSize ) ) return false;		bool leTIFF = CheckBytes ( ioBuf.ptr, "\x49\x49\x2A\x00", 4 );	bool beTIFF = CheckBytes ( ioBuf.ptr, "\x4D\x4D\x00\x2A", 4 );		return (leTIFF | beTIFF);	}	// TIFF_CheckFormat// =================================================================================================// TIFF_MetaHandlerCTor// ====================XMPFileHandler * TIFF_MetaHandlerCTor ( XMPFiles * parent ){	return new TIFF_MetaHandler ( parent );}	// TIFF_MetaHandlerCTor// =================================================================================================// TIFF_MetaHandler::TIFF_MetaHandler// ==================================TIFF_MetaHandler::TIFF_MetaHandler ( XMPFiles * _parent ) : psirMgr(0), iptcMgr(0){	this->parent = _parent;	this->handlerFlags = kTIFF_HandlerFlags;	this->stdCharForm  = kXMP_Char8Bit;}	// TIFF_MetaHandler::TIFF_MetaHandler// =================================================================================================// TIFF_MetaHandler::~TIFF_MetaHandler// ===================================TIFF_MetaHandler::~TIFF_MetaHandler(){	if ( this->psirMgr != 0 ) delete ( this->psirMgr );	if ( this->iptcMgr != 0 ) delete ( this->iptcMgr );}	// TIFF_MetaHandler::~TIFF_MetaHandler// =================================================================================================// TIFF_MetaHandler::CacheFileData// ===============================//// The data caching for TIFF is easy to explain and implement, but does more processing than one// might at first expect. This seems unavoidable given the need to close the disk file after calling// CacheFileData. We parse the TIFF stream and cache the values for all tags of interest, and note// whether XMP is present. We do not parse the XMP, Photoshop image resources, or IPTC datasets.// *** This implementation simply returns when invalid TIFF is encountered. Should we throw instead?void TIFF_MetaHandler::CacheFileData(){	LFA_FileRef      fileRef    = this->parent->fileRef;	XMP_PacketInfo & packetInfo = this->packetInfo;		XMP_AbortProc abortProc  = this->parent->abortProc;	void *        abortArg   = this->parent->abortArg;	const bool    checkAbort = (abortProc != 0);		XMP_Assert ( (! this->containsXMP) && (! this->containsTNail) );	// Set containsXMP to true here only if the XMP tag is found.		if ( checkAbort && abortProc(abortArg) ) {		XMP_Throw ( "TIFF_MetaHandler::CacheFileData - User abort", kXMPErr_UserAbort );	}		this->tiffMgr.ParseFileStream ( fileRef );		TIFF_Manager::TagInfo xmpInfo;	bool found = this->tiffMgr.GetTag ( kTIFF_PrimaryIFD, kTIFF_XMP, &xmpInfo );		if ( found ) {		this->packetInfo.offset    = this->tiffMgr.GetValueOffset ( kTIFF_PrimaryIFD, kTIFF_XMP );		this->packetInfo.length    = xmpInfo.dataLen;		this->packetInfo.padSize   = 0;				// Assume for now, set these properly in ProcessXMP.		this->packetInfo.charForm  = kXMP_CharUnknown;		this->packetInfo.writeable = true;		this->xmpPacket.assign ( (XMP_StringPtr)xmpInfo.dataPtr, xmpInfo.dataLen );		this->containsXMP = true;	}	}	// TIFF_MetaHandler::CacheFileData// =================================================================================================// TIFF_MetaHandler::ProcessTNail// ==============================//// Do the same processing as JPEG, even though Exif says that uncompressed images can only have // uncompressed thumbnails. Who know what someone might write?// *** Should extract this code into a utility shared with the JPEG handler.void TIFF_MetaHandler::ProcessTNail(){	this->processedTNail = true;	// Make sure we only come through here once.	this->containsTNail = false;	// Set it to true after all of the info is gathered.	this->containsTNail = this->tiffMgr.GetTNailInfo ( &this->tnailInfo );	if ( this->containsTNail ) this->tnailInfo.fileFormat = this->parent->format;}	// TIFF_MetaHandler::ProcessTNail// =================================================================================================// TIFF_MetaHandler::ProcessXMP// ============================//// Process the raw XMP and legacy metadata that was previously cached. The legacy metadata in TIFF// is messy because there are 2 copies of the IPTC and because of a Photoshop 6 bug/quirk in the way// Exif metadata is saved.void TIFF_MetaHandler::ProcessXMP(){		this->processedXMP = true;	// Make sure we only come through here once.	// 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 PSIR, determine the last-legacy priority. For TIFF files the relevant	// legacy priorities (ignoring Mac pnot and ANPA resources) are:	//	kLegacyJTP_TIFF_IPTC - highest	//	kLegacyJTP_TIFF_TIFF_Tags	//	kLegacyJTP_PSIR_OldCaption	//	kLegacyJTP_PSIR_IPTC - yes, a TIFF file can have the IPTC in 2 places	//	kLegacyJTP_None - lowest		// ! Photoshop 6 wrote annoyingly wacky TIFF files. It buried a lot of the Exif metadata inside	// ! image resource 1058, itself inside of tag 34377 in the 0th IFD. Take care of this before	// ! doing any of the legacy metadata presence or priority analysis. Delete image resource 1058	// ! to get rid of the buried Exif, but don't mark the XMPFiles object as changed. This change	// ! should not trigger an update, but should be included as part of a normal update.		bool found;	RecJTP_LegacyPriority lastLegacy = kLegacyJTP_None;	bool readOnly = ((this->parent->openFlags & kXMPFiles_OpenForUpdate) == 0);	if ( readOnly ) {		this->psirMgr = new PSIR_MemoryReader();		this->iptcMgr = new IPTC_Reader();	} else {		this->psirMgr = new PSIR_FileWriter();		this->iptcMgr = new IPTC_Writer();	}	TIFF_Manager & tiff = this->tiffMgr;	// Give the compiler help in recognizing non-aliases.	PSIR_Manager & psir = *this->psirMgr;	IPTC_Manager & iptc = *this->iptcMgr;		TIFF_Manager::TagInfo psirInfo;	bool havePSIR = tiff.GetTag ( kTIFF_PrimaryIFD, kTIFF_PSIR, &psirInfo );		TIFF_Manager::TagInfo iptcInfo;	bool haveIPTC = tiff.GetTag ( kTIFF_PrimaryIFD, kTIFF_IPTC, &iptcInfo );	// The TIFF IPTC tag.			if ( havePSIR ) {	// ! Do the Photoshop 6 integration before other legacy analysis.		psir.ParseMemoryResources ( psirInfo.dataPtr, psirInfo.dataLen );		PSIR_Manager::ImgRsrcInfo buriedExif;		found = psir.GetImgRsrc ( kPSIR_Exif, &buriedExif );		if ( found ) {			tiff.IntegrateFromPShop6 ( buriedExif.dataPtr, buriedExif.dataLen );			if ( ! readOnly ) psir.DeleteImgRsrc ( kPSIR_Exif );		}	}			if ( haveIPTC ) {	// At this point "haveIPTC" means from TIFF tag 33723.		iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );		lastLegacy = kLegacyJTP_TIFF_IPTC;	}		if ( lastLegacy < kLegacyJTP_TIFF_TIFF_Tags ) {		found = tiff.GetTag ( kTIFF_PrimaryIFD, kTIFF_ImageDescription, 0 );		if ( ! found ) found = tiff.GetTag ( kTIFF_PrimaryIFD, kTIFF_Artist, 0 );		if ( ! found ) found = tiff.GetTag ( kTIFF_PrimaryIFD, kTIFF_Copyright, 0 );		if ( found ) lastLegacy = kLegacyJTP_TIFF_TIFF_Tags;	}		if ( havePSIR ) {		if ( lastLegacy < kLegacyJTP_PSIR_OldCaption ) {			found = psir.GetImgRsrc ( kPSIR_OldCaption, 0 );			if ( ! found ) found = psir.GetImgRsrc ( kPSIR_OldCaptionPStr, 0 );			if ( found ) lastLegacy = kLegacyJTP_PSIR_OldCaption;		}		if ( ! haveIPTC ) {			PSIR_Manager::ImgRsrcInfo iptcInfo;			haveIPTC = psir.GetImgRsrc ( kPSIR_IPTC, &iptcInfo );			if ( haveIPTC ) {				iptc.ParseMemoryDataSets ( iptcInfo.dataPtr, iptcInfo.dataLen );				if ( lastLegacy < kLegacyJTP_PSIR_IPTC ) lastLegacy = kLegacyJTP_PSIR_IPTC;			}		}	}			XMP_OptionBits options = k2XMP_FileHadExif;	// TIFF files are presumed to have Exif legacy.	if ( this->containsXMP ) options |= k2XMP_FileHadXMP;	if ( haveIPTC || (lastLegacy == kLegacyJTP_PSIR_OldCaption) ) options |= k2XMP_FileHadIPTC;	// 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_TIFFFile, lastLegacy, &tiff, psir, &iptc, &this->xmpObj, options );			throw;	// ! Rethrow the exception, don't absorb it.		}	}	// Process the legacy metadata.	ImportJTPtoXMP ( kXMP_TIFFFile, lastLegacy, &tiff, psir, &iptc, &this->xmpObj, options );	this->containsXMP = true;	// Assume we now have something in the XMP.}	// TIFF_MetaHandler::ProcessXMP// =================================================================================================// TIFF_MetaHandler::UpdateFile// ============================//// There is very little to do directly in UpdateFile. ExportXMPtoJTP takes care of setting all of// the necessary TIFF tags, including things like the 2nd copy of the IPTC in the Photoshop image// resources in tag 34377. TIFF_FileWriter::UpdateFileStream does all of the update-by-append I/O.// *** Need to pass the abort proc and arg to TIFF_FileWriter::UpdateFileStream.void TIFF_MetaHandler::UpdateFile ( bool doSafeUpdate ){	XMP_Assert ( ! doSafeUpdate );	// This should only be called for "unsafe" updates.	LFA_FileRef   destRef    = this->parent->fileRef;	XMP_AbortProc abortProc  = this->parent->abortProc;	void *        abortArg   = this->parent->abortArg;	// 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 tags. (The IPTC and PSIR are in the TIFF tags.)	//	- The new XMP can fit in the old space.		ExportXMPtoJTP ( kXMP_TIFFFile, &this->xmpObj, &this->tiffMgr, 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->tiffMgr.IsLegacyChanged()) ) doInPlace = false;	if ( doInPlace ) {		#if GatherPerformanceData			sAPIPerf->back().extraInfo += ", TIFF in-place update";		#endif			LFA_FileRef liveFile = this->parent->fileRef;			XMP_Assert ( this->xmpPacket.size() == (size_t)oldPacketLength );	// ! Done by common PutXMP logic.				LFA_Seek ( liveFile, oldPacketOffset, SEEK_SET );		LFA_Write ( liveFile, this->xmpPacket.c_str(), this->xmpPacket.size() );		} else {		#if GatherPerformanceData			sAPIPerf->back().extraInfo += ", TIFF append update";		#endif			// Reserialize the XMP to get standard padding, PutXMP has probably done an in-place serialize.		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->tiffMgr.SetTag ( kTIFF_PrimaryIFD, kTIFF_XMP, kTIFF_UndefinedType, this->xmpPacket.size(), this->xmpPacket.c_str() );				this->tiffMgr.UpdateFileStream ( destRef );		}	this->needsUpdate = false;}	// TIFF_MetaHandler::UpdateFile// =================================================================================================// TIFF_MetaHandler::WriteFile// ===========================//// The structure of TIFF makes it hard to do a sequential source-to-dest copy with interleaved// updates. So, copy the existing source to the destination and call UpdateFile.void TIFF_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;		XMP_Int64 fileLen = LFA_Measure ( sourceRef );	if ( fileLen > 0xFFFFFFFFLL ) {	// Check before making a copy of the file.		XMP_Throw ( "TIFF fles can't exceed 4GB", kXMPErr_BadTIFF );	}		LFA_Seek ( sourceRef, 0, SEEK_SET );	LFA_Truncate ( destRef, 0 );	LFA_Copy ( sourceRef, destRef, fileLen, abortProc, abortArg );	this->UpdateFile ( false );}	// TIFF_MetaHandler::WriteFile// =================================================================================================

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -