EXIF格式分析及通过XML处理(4)

EXIF格式分析及通过XML处理<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

猛禽[Mental Studio](个人专栏)(BLOG)

http://mental.mentsu.com

下面的代码片断

(Borland C++ Builder) 实现了从 EXIF 数据到 XML 的转换:

//---------------------------------------------------------------------------

#include <pshpack1.h>

typedef struct {

WORD EntryTag;

WORD EntryType;

DWORD EntrySize;

DWORD EntryValue;

} TIFDEntry;

#include <poppack.h>

//---------------------------------------------------------------------------

BYTE * __fastcall TExifXML::GetIFD(_di_IXMLNode aNode, BYTE * aTIFFHeader, int aPosition, AnsiString aName)

{

_di_IXMLNode pIFD = aNode->AddChild( "IFD" );

if ( aName != "" )

pIFD->Attributes["name"] = aName;

BYTE * p = aTIFFHeader + aPosition;

WORD nWord;

memcpy( &nWord, p, sizeof ( nWord ) );

p += sizeof ( nWord );

_di_IXMLNode pChild = pIFD->AddChild( "Count" );

pChild->Text = Format( "0x%X", ARRAYOFCONST( ( ( int )nWord ) ) );

TIFDEntry ent;

_di_IXMLNode pEntry;

BYTE * pTemp;

for ( int i = nWord; i > 0; --i )

{

memcpy( &ent, p, sizeof ( ent ) );

p += sizeof ( ent );

pEntry = pIFD->AddChild( "Entry" );

pChild = pEntry->AddChild( "Tag" );

pChild->Text = Format( "0x%X", ARRAYOFCONST( ( ( int )ent.EntryTag ) ) );

pChild = pEntry->AddChild( "Type" );

pChild->Text = IntToStr( ent.EntryType );

pChild = pEntry->AddChild( "Size" );

pChild->Text = Format( "0x%X", ARRAYOFCONST( ( ( int )ent.EntrySize ) ) );

pChild = pEntry->AddChild( "Value" );

switch ( ent.EntryType ) {

case 1 : // BYTE

if ( ent.EntrySize == 1 )

pChild->Text = Format( "0x%.02X", ARRAYOFCONST( ( ( int )( BYTE )ent.EntryValue ) ) );

else

throw Exception( "Unsupported!" );

break;

case 2 : // ASCII

if ( ent.EntrySize <= 4 )

pChild->Text = reinterpret_cast<LPSTR>( &ent.EntryValue );

else

pChild->Text = reinterpret_cast<LPSTR>( aTIFFHeader + ent.EntryValue );

break;

case 3 : // SHORT

if ( ent.EntrySize == 1 )

pChild->Text = Format( "0x%.04X", ARRAYOFCONST( ( ( int )( WORD )ent.EntryValue ) ) );

else

throw Exception( "Unsupported!" );

break;

case 5 : // RATIONAL

pChild->Text = FloatToStr( *reinterpret_cast<DWORD *>( aTIFFHeader + ent.EntryValue )

/ ( double )( *reinterpret_cast<DWORD *>( aTIFFHeader + ent.EntryValue + sizeof ( DWORD ) ) ) );

break;

case 7 : // UNDEFINED

if ( ent.EntrySize <= 4 )

pTemp = reinterpret_cast<BYTE *>( &ent.EntryValue );

else

pTemp = aTIFFHeader + ent.EntryValue;

pChild->Text = "";

for ( int j = 0; j < ( int )ent.EntrySize; ++j )

{

pChild->Text = pChild->Text

+ Format( " 0x%.02X", ARRAYOFCONST( ( ( int )( BYTE )( *pTemp ) ) ) );

pTemp++;

if ( j % 16 == 15 )

pChild->Text = pChild->Text + "/r/n";

}

break;

case 9 : // SLONG

if ( ent.EntrySize == 1 )

pChild->Text = IntToStr( ent.EntryValue );

else

throw Exception( "Unsupported!" );

break;

case 10: // SRATIONAL

pChild->Text = FloatToStr( *reinterpret_cast<int *>( aTIFFHeader + ent.EntryValue )

/ ( double )( *reinterpret_cast<int *>( aTIFFHeader + ent.EntryValue + sizeof ( int ) ) ) );

break;

default: // LONG & other unknown type

pChild->Text = Format( "0x%.08X", ARRAYOFCONST( ( ( int )ent.EntryValue ) ) );

break;

}

switch ( ent.EntryTag ) {

case 0x8769 : // Exif IFD

GetIFD( aNode, aTIFFHeader, ent.EntryValue, "EXIF" );

break;

case 0x8805 : // GPS IFD

GetIFD( aNode, aTIFFHeader, ent.EntryValue, "GPS" );

break;

case 0xA005 : // Interoperability IFD

GetIFD( aNode, aTIFFHeader, ent.EntryValue, "InterOp" );

break;

}

}

return p;

}

//---------------------------------------------------------------------------

void __fastcall TExifXML::GetTIFFHeader(_di_IXMLNode aNode, BYTE * aTIFFHeader)

{

BYTE * p = aTIFFHeader;

char sByteOrder[3];

memcpy( sByteOrder, p, 2 );

p += 2;

sByteOrder[2] = 0;

_di_IXMLNode pChild = aNode->AddChild( "ByteOrder" );

pChild->Text = sByteOrder;

WORD nFlag;

memcpy( &nFlag, p, sizeof ( nFlag ) );

p += sizeof ( nFlag );

pChild = aNode->AddChild( "Flag" );

pChild->Text = Format( "0x%.04X", ARRAYOFCONST( ( ( int )nFlag ) ) );

DWORD nPointer;

memcpy( &nPointer, p, sizeof ( nPointer ) );

int i = 0;

while ( nPointer > 0 )

{

p = GetIFD( aNode, aTIFFHeader, nPointer, AnsiString( "IFD" ) + IntToStr( i++ ) );

if ( !p )

break;

memcpy( &nPointer, p, sizeof ( nPointer ) );

}

}

//---------------------------------------------------------------------------

int __fastcall TExifXML::LoadFromStream(TStream * aStream)

{

if ( !FXMLDoc )

throw Exception( "XMLDoc property is null!" );

TMauto_ptr<TMemoryStream> ms( new TMemoryStream( ) );

ms->CopyFrom( aStream, aStream->Size );

ms->Seek( 0, soFromBeginning );

FXMLDoc->FileName = "";

FXMLDoc->Active = true;

FXMLDoc->Version = "1.0";

FXMLDoc->Encoding = "GB2312";

_di_IXMLNode pNode = FXMLDoc->AddChild( "ExifAPP1" );

_di_IXMLNode pChild = pNode->AddChild( "ExifID" );

char sExifID[6];

ms->Read( sExifID, 6 );

pChild->Text = sExifID;

pChild = pNode->AddChild( "TIFFHeader" );

BYTE * pHeader = static_cast<BYTE *>( ms->Memory ) + ( int )ms->Position;

GetTIFFHeader( pChild, pHeader );

return ms->Size;

}

其中FXMLDoc是一个TXMLDocument控件,用于生成XMLLoadFromStream方法读入的内容为JPEG APP1这个Marker Segment的内容(注意,不是JPEG文件)。GetTIFFHeader方法用于读出TIFFHeader的内容,包括Image File HeaderIFD链表。GetIFD则是用于解读IFD的具体内容,其中包括对EXIF的三个扩充IFD的递归解读,并且其中包含了将各种数据类型转换为字符串的部分,特别是对不定长的UNDEFINED类型的处理(其结果见下面转换后的XML)。

(待续)

你可能感兴趣的:(Exif)