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
break;
case 8: // sshort
for( uint32_t i=0; i
break;
case 4: // long
for( uint32_t i=0; i
break;
case 9: // slong
for( uint32_t i=0; i
break;
case 5: // rational
for( uint32_t i=0; i
break;
case 10: //
srational
for( uint32_t i=0; i
break;
case 7: // undefined
default:
printf( "???" );
break;
case 11: // float
for(
uint32_t i=0; i
break;
case 12: // double
for(
uint32_t i=0; i
break;
}
printf( "\n" );
return 0;
}
第二段程序用Gdi+读取图像文件的EXIF,好处是通用于其支持的所有图像格式,缺点是需要Gdi+
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
// 将 PropertyTag 对应的 名称 取出来
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
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
break;
case
PropertyTagTypeLong:
for( ULONG i=0; i
break;
case
PropertyTagTypeRational:
for( ULONG i=0; i
break;
case 6:
cout
<< "...";
break;
case
PropertyTagTypeUndefined:
cout <<
"???";
break;
case 8:
for(
ULONG i=0; i
break;
case PropertyTagTypeSLONG:
for( ULONG i=0; i
break;
case
PropertyTagTypeSRational:
for( ULONG i=0; i
break;
case 11:
for(
ULONG i=0; i
break;
case 12:
for( ULONG i=0; 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;
}