Chinaunix首页 | 论坛 | 博客
  • 博客访问: 987879
  • 博文数量: 158
  • 博客积分: 4380
  • 博客等级: 上校
  • 技术积分: 2367
  • 用 户 组: 普通用户
  • 注册时间: 2006-09-21 10:45
文章分类

全部博文(158)

文章存档

2012年(158)

我的朋友

分类: C/C++

2012-11-26 16:09:27

第一段程序用纯C读取TIFF文件的EXIF,好处是不需要第三方的库,缺点是需要对各种图像格式进行解析
第二段程序用Gdi+读取图像文件的EXIF,好处是通用于其支持的所有图像格式,缺点是需要Gdi+
第三段程序用Gdi+读取图像文件的指定EXIF条目
需要说明的是,代码只是演示,所以去除了一些仅在演示时不需要的代码,比如 fclose

第一段程序用纯C读取TIFF文件的EXIF,好处是不需要第三方的库,缺点是需要对各种图像格式进行解析
#define _CRT_SECURE_NO_WARNINGS
#include
#include
//#include
typedef signed char int8_t;
typedef unsigned char   uint8_t;
typedef short  int16_t;
typedef unsigned short  uint16_t;
typedef int  int32_t;
typedef unsigned   uint32_t;
typedef long long  int64_t;
typedef unsigned long long   uint64_t;

int main2()
{
    FILE* img = fopen( "E:\\sources\\T007\\images\\1-5s-gain-10.bin", "rb" );
    if( !img ) return -1;

    uint8_t buf[4];
    if( 1 != fread(buf,4,1,img) ) return -1; // 退出时需要fclose(img),自己加,下同
    if( buf[0]==0x4D && buf[1]==0x4D ) return +1; // big-endian byte order tiff, 可以处理,但此事例就不处理了,因为方法是一样的
    if( buf[0]!=0x49 || buf[1]!=0x49 ) return -2; // little-endian byte order tiff
    uint16_t ver = *(uint16_t*)(buf+2); // 永远的版本号42

    uint32_t idf_next;
    if( 1 != fread(&idf_next,sizeof(idf_next),1,img) ) return -1;
    for( ; idf_next!=0; )
    {
        if( 0 != fseek(img,idf_next,SEEK_SET) ) return -3;
        uint16_t de_num;
        if( 1 != fread(&de_num,sizeof(de_num),1,img) ) return -1;
        for( uint16_t i=0; i        {
            uint8_t de[12];
            if( 1 != fread(&de,sizeof(de),1,img) ) return -1;

            uint16_t id   = *(uint16_t*)(de+0);
            uint16_t type = *(uint16_t*)(de+2);
            uint32_t num  = *(uint32_t*)(de+4);
            uint32_t addr = *(uint32_t*)(de+8);

            // 每种类型所占字节数
            static unsigned int type_bytenums[12] = { 1, 1, 2, 4, 8, 1, 1, 2, 4, 8, 4, 8 };
            if( type-1 >= 12 ) return -4;

            long x = ftell( img );
            // 内容不多于4字节的话,自己用addr本身保存内容
            if( type_bytenums[type-1]*num <= 4 )
                addr = idf_next + 2 + i*12 + 8;

            long ff = ftell( img );
            int ShowDirectoryEntry( uint16_t id, uint16_t type, uint32_t bytenum, FILE* img, uint32_t addr );
            int r = ShowDirectoryEntry(id,type,type_bytenums[type-1]*num,img,addr);
            if( r!=0 ) return r;
            if( 0 != fseek(img,ff,SEEK_SET) ) return -3;
        }
        if( 1 != fread(&idf_next,sizeof(idf_next),1,img) ) return -1;
    }

    fclose( img );
    return 0;
}

int ShowDirectoryEntry( uint16_t id, uint16_t type, uint32_t bytenum, FILE* img, uint32_t addr )
{
    assert( bytenum<4096 ); // 只是一个测试,不追求完美
    uint8_t buf[4096];
    if( 0 != fseek(img,addr,SEEK_SET) ) return -3;
    if( 1 != fread(buf,bytenum,1,img) ) return -1;

    printf( "%hu = ", id );
    switch( type )
    {
    case 1: // byte
    case 6: // sbyte
        printf( "..." );
        break;
    case 2: // ascii
        printf( "%s", (char*)buf );
        break;
    case 3: // short
        for( uint32_t i=0; i            printf( "%hu ", ((uint16_t*)buf)[i] );
        break;
    case 8: // sshort
        for( uint32_t i=0; i            printf( "%hd ", ((int16_t*)buf)[i] );
        break;
    case 4: // long
        for( uint32_t i=0; i            printf( "%I32u ", ((uint32_t*)buf)[i] );
        break;
    case 9: // slong
        for( uint32_t i=0; i            printf( "%I32d ", ((int32_t*)buf)[i] );
        break;
    case 5: // rational
        for( uint32_t i=0; i            printf( "%I32u+%I32u ", ((uint32_t*)buf)[2*i+0], ((uint32_t*)buf)[2*i+1] );
        break;
    case 10: // srational
        for( uint32_t i=0; i            printf( "%I32d+%I32d ", ((int32_t*)buf)[2*i+0], ((int32_t*)buf)[2*i+1] );
        break;
    case 7: // undefined
    default:
        printf( "???" );
        break;
    case 11: // float
        for( uint32_t i=0; i            printf( "%f ", ((float*)buf)[i] );
        break;
    case 12: // double
        for( uint32_t i=0; i            printf( "%lf ", ((double*)buf)[i] );
        break;
    }
    printf( "\n" );

    return 0;
}

第二段程序用Gdi+读取图像文件的EXIF,好处是通用于其支持的所有图像格式,缺点是需要Gdi+
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib")

int main()
{
    // 将 PropertyTag 对应的 名称 取出来
    map IdName_map;
    {
        ifstream is( "C:\\Program Files\\Microsoft SDKs\\Windows\\v6.0A\\Include\\GdiPlusImaging.h" );
        for( string line; getline(is,line); )
        {
            if( line == "// Image property ID tags" )
            {
                for( string line; getline(is,line); )
                {
                    string a, b, c;
                    istringstream iss( line );
                    if( iss>>a>>b>>c && a=="#define" && c.size()==6 && c[0]=='0' && c[1]=='x' )
                    {
                        istringstream iss( &c[2] );
                        PROPID id;
                        if( iss>>hex>>id )
                        {
                            IdName_map.insert( make_pair(id,b) );
                        }
                    }
                }

                break;
            }
        }
    }

    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup( &gdiplusToken, &gdiplusStartupInput, NULL );
    {
        Image image( L"E:\\sources\\T007\\images\\1-5s-gain-10.bin");

        UINT totalBufferSize;
        UINT numProperties;
        image.GetPropertySize( &totalBufferSize, &numProperties );

        PropertyItem* pAllItems = (PropertyItem*)operator new( totalBufferSize );

        image.GetAllPropertyItems( totalBufferSize, numProperties, pAllItems );

        for( UINT i=0; i        {
            const PropertyItem& the = pAllItems[i];

            map::const_iterator itor = IdName_map.find( the.id );
            if( itor != IdName_map.end() )
                cout << itor->second << " = ";
            else
                cout << the.id << " = ";

            switch( the.type )
            {
            case PropertyTagTypeByte:
                cout << "...";
                break;
            case PropertyTagTypeASCII:
                cout << (const char*)the.value;
                break;
            case PropertyTagTypeShort:
                for( ULONG i=0; i                    cout << ((unsigned short*)the.value)[i] << ' ';
                break;
            case PropertyTagTypeLong:
                for( ULONG i=0; i                    cout << ((unsigned long*)the.value)[i] << ' ';
                break;
            case PropertyTagTypeRational:
                for( ULONG i=0; i                    cout << ((unsigned long*)the.value)[2*i+0] << '+' << ((unsigned long*)the.value)[2*i+1] << ' ';
                break;
            case 6:
                cout << "...";
                break;
            case PropertyTagTypeUndefined:
                cout << "???";
                break;
            case 8:
                for( ULONG i=0; i                    cout << ((short*)the.value)[i] << ' ';
                break;
            case PropertyTagTypeSLONG:
                for( ULONG i=0; i                    cout << ((signed long*)the.value)[i] << ' ';
                break;
            case PropertyTagTypeSRational:
                for( ULONG i=0; i                    cout << ((signed long*)the.value)[2*i+0] << '+' << ((signed long*)the.value)[2*i+1] << ' ';
                break;
            case 11:
                for( ULONG i=0; i                    cout << ((float*)the.value)[i] << ' ';
                break;
            case 12:
                for( ULONG i=0; i                    cout << ((double*)the.value)[i] << ' ';
                break;
            default:
                cout << "???";
            }

            cout << '\n';
        }

        operator delete( pAllItems );
    }
    GdiplusShutdown(gdiplusToken);

    return 0;
}

第三段程序用Gdi+读取图像文件的制造商信息
#include
#include
#include
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib")

int main()
{
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup( &gdiplusToken, &gdiplusStartupInput, NULL );
    {
        Image image( L"E:\\sources\\T007\\images\\1-5s-gain-10.bin" );

        UINT itemsize = image.GetPropertyItemSize(PropertyTagSoftwareUsed);

        PropertyItem* item = (PropertyItem*)operator new(itemsize);
        if( Ok == image.GetPropertyItem(PropertyTagSoftwareUsed,itemsize,item) )
            std::cout << (char*)item->value << std::endl;
        operator delete(item);
    }
    GdiplusShutdown(gdiplusToken);
    return 0;
}

阅读(4702) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~