CSDN博客

img Raptor
博客专家

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

发表于2004/5/9 11:10:00  2998人阅读

分类: 通用技术

EXIF格式分析及通过XML处理

 

猛禽[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)。

(待续)

0 0

相关博文

我的热门文章

img
取 消
img