读取图像中的 EXIF 信息(不全,能够读取部分)

python读取图像的exif信息 python读取图像的exif信息import exifread功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 ###... 阅读详情

需要读取EXIF信息,自己阅读了一些资料,现在共享一下
需要注意的是,由于EXIF是一种可交换的文件格式,所以可以用在Intel系列和Motorola系列的CPU上(至于两者CPU的区别,大家可以到网上找找,这里不做说明)。在文件中有一个标志,如果是“MM”表示Motorola的CPU,否则为“II”表示Intel的CPU。
  这个代码是使用C写的,读取文件用的API。本来我想写成一个VC使用的类的,但是自己还是太懒了。需要的自己去转换吧。

  贴在这里主要就是这方面的资料国内太少了,希望本文能够帮助某部分人 :)
  同样,下面贴出 .h 文件与 .c 文件,需要的人拷贝下来

////////////////////////////////////////////////////////////////////////////////
//      .h 文件

/********************************************************************

         Copyright@  版权所有@ 1998-2005hengai 。保留所有权利。

********************************************************************/

 

 

/********************************************************************

   文件说明:  能够读取  JPG  图像文件中的  EXIF  信息

   文件名称: exif.h

   版本号   :  1.0.0

   作     者: hengai

   修改纪录:

   使用方法:  包含此头文件,然后调用函数

               int EXIF_Read(LPCTSTR pszJpgFileName, EXIFINFO* pExifInfo)

               即可获取  EXIF  信息。EXIF 信息包含在参数  pExifInfo  中

             在定义了  #define EXIF_OUTPUT_ERRMSG ( 默认下已经定义) 后可以使用

               LPCTSTR EXIF_GetErrorString();  获取出错信息

*********************************************************************

 

//////////////////////////////////////////////////////////////////////////

#ifndef  STATIC

#define  STATIC      static

#endif

#define  EXIF_OUTPUT_ERRMSG        // 定义是否输出出错信息

//////////////////////////////////////////////////////////////////////////

//               定义常量

#define  MAX_COMMENT     1000        // 最大的注释字符串长度

 

//////////////////////////////////////////////////////////////////////////

// 写入注释时,表明注释的类型,如  ASCII, UNICODE  等

typedef   enum   ECT {

   CT_ASCII   =  0 ,

   CT_UNICODE ,

   CT_JIS ,

   CT_UNDEFINE

} COMMENT_TYPE ;

//////////////////////////////////////////////////////////////////////////

//               定义需要的结构体

#define  ET_NOT_CLOSE_FILE         0x00000001    // 最后不关闭打开的文件句柄

#define  ET_MALLOC_THUMBNAIL       0x00000002    // 拷贝缩略图的数据,调用者需要使用  free()

#define  ET_MALLOC_USERCOM         0x00000004    // 是否拷贝用户注释,调用者需要使用  free()

#define  ET_MALLOC_MAKERCOM        0x00000008    // 是否拷贝厂商注释,调用者需要使用  free()

//JPG  文件中的读入后的  EXIFF  信息保存到这个结构体中

typedef   struct   tag_ExifInfo   {

   DWORD   dwExifType ;              // 取值为  ET_NOT_CLOSE_FILE|ET_MALLOC_THUMBNAIL, ....

   DWORD   dwExifType2 ;

   char    Version        [ 5 ];        //EXIF  信息版本

   char    CameraMake     [ 32 ];       //DC  制造商

   char    CameraModel    [ 40 ];       //DC  型号

   char    DateTime       [ 20 ];       //JPG  文件日期

   char    DateTimeDigitized [ 20 ];   //JPG  文件被其它软件修改日期

   int     Height ,  Width ;           // 图像高度、宽度

   int     Orientation ;             // 拍摄方向,例如相机向左手方向旋转后拍摄的

   int     IsColor ;                 //

   int     Process ;                 // 被处理

   int     FlashUsed ;               // 是否使用闪光灯

   float   FocalLength ;             // 焦距

   float   ExposureTime ;            // 曝光时间( 快门速度)

   float   ApertureFNumber ;         // 光圈数

   float   Distance ;                // 拍摄物体距离

   float   CCDWidth ;                 //CCD  大小

   float   ExposureBias ;            // 曝光补偿

   int     Whitebalance ;            // 白平衡

   int     MeteringMode ;            // 测光模式

   int     ExposureProgram ;         // 曝光

   int     ISOequivalent ;           //ISO

   int     CompressionLevel ;        // 压缩

   float   FocalplaneXRes ;          // 焦平面X 轴分辨率

   float   FocalplaneYRes ;          // 焦平面Y 轴分辨率

   float   FocalplaneUnits ;         // 焦平面分辨率单位

   float   Xresolution ;             //X  轴分辨率

   float   Yresolution ;             //Y  轴分辨率

   float   ResolutionUnit ;          // 分辨率单位

   float   Brightness ;               // 亮度

   char    Comments [ MAX_COMMENT ];   // 注释

   DWORD   UserCOMLength ;           // 用户注释长度。如果==0 表示没有用户注释

   char    * UserCOM ;                // 用户注释

                                 //if(dwExifType&ET_MALLOC_USERCOM == TRUE)  这个数值保存了用户注释数据,调用者需要使用  free()

                                  // 否则为用户注释的偏移量( 相对于文件起始0 处)

   DWORD   MakerCOMLength ;          // 厂商注释长度。如果==0 表示没有厂商注释

   char    * MakerCOM ;               // 厂商注释

                                 //if(dwExifType&ET_MALLOC_MAKERCOM == TRUE)  这个数值保存了厂商注释数据,调用者需要使用  free()

                                  // 否则为厂商注释的偏移量( 注意:是在当前SECTION 中的偏移量,不是相对整个文件的)

 

 

   UCHAR   *  ThumbnailPointer ;      // 缩略图数据。

                                 //if(dwExifType&ET_MALLOC_THUMBNAIL == TRUE)  这个数值保存了缩略图的数据

                                 // 否则为一个  DWORD( 需要强制转换)  表示缩略图在JPG 文件中的偏移值( 相对于文件起始0 处)

   DWORD   ThumbnailSize ;           // 缩略图的大小( 字节流  ThumbnailPointer  的长度)

                                 // 如果<=0 表示该  JPG  文件没有缩略图

   HFILE   hJpgFileHandle ;          // 返回打开的  JPG  文件句柄。必须  dwExifType&ET_NOT_CLOSE_FILE == TRUE  才是有效句柄

                                 // 用户需要使用  CloseHandle(hJpgFileHandle) 来关闭这个句柄

   BOOL    IsExif ;                  // 是否存在  EXIF  信息

}  EXIFINFO ;

//////////////////////////////////////////////////////////////////////////

//               接口函数

int   EXIF_Read ( LPCTSTR   pszJpgFileName ,  EXIFINFO *  pExifInfo );

LPCTSTR   EXIF_GetErrorString ();

int   EXIF_AddUserComments ( LPCTSTR   pszJpgFileName ,  LPCTSTR   pszUserComments ,  DWORD   dwCommentLength ,  COMMENT_TYPE   nCommentType );


////////////////////////////////////////////////////////////////////////
//   .c 文件

/********************************************************************

         Copyright@  版权所有@ 1998-2005 HENGAI 。保留所有权利。

********************************************************************/

 

 

/********************************************************************

   文件说明:

   文件名称: exif.c

   版本号   : 1.0.0

   作     者: hengai

   修改纪录:

*********************************************************************/

#include  "exif.h"

//////////////////////////////////////////////////////////////////////////

// 读取  EXIF  过程中需要的结构体

typedef   struct   tag_Section_t {

     UCHAR       * Data ;

     int         Type ;

     unsigned    Size ;

}  Section_t ;

//////////////////////////////////////////////////////////////////////////

#ifdef    EXIF_OUTPUT_ERRMSG

STATIC   TCHAR   m_szLastError [ 256 ];   // 这里保存了出错的信息

#define  EXIF_ERR_OUT ( str_err )  strcpy ( m_szLastError , str_err );

 

LPCTSTR   EXIF_GetErrorString ()

{

   return   ( LPCTSTR ) m_szLastError ;

}

#else

#define  EXIF_ERR_OUT

LPCTSTR   EXIF_GetErrrorString ()

{

   return   "Plese #define EXIT_ERR_OUT in exif.h" ;

}

#endif

 

STATIC   EXIFINFO *  m_pExifInfo   =  0 ;    //

STATIC        int   m_MotorolaOrder     =  0 ;   //

STATIC    int   m_ExifImageWidth    =  0 ;   //

 

//////////////////////////////////////////////////////////////////////////

 

/* Describes format descriptor */

static   const   int   m_BytesPerFormat [] = { 0 , 1 , 1 , 2 , 4 , 8 , 1 , 1 , 2 , 4 , 8 , 4 , 8 };

#define  NUM_FORMATS       12

 

#define  FMT_BYTE          1             //Format Byte

#define  FMT_STRING        2

#define  FMT_USHORT        3

#define  FMT_ULONG         4

#define  FMT_URATIONAL     5

#define  FMT_SBYTE         6

#define  FMT_UNDEFINED     7

#define  FMT_SSHORT        8

#define  FMT_SLONG         9

#define  FMT_SRATIONAL    10

#define  FMT_SINGLE       11

#define  FMT_DOUBLE       12

//////////////////////////////////////////////////////////////////////////

#define  MAX_SECTIONS     20         //JPG  文件中能够允许的最多  SECTION  个数

 

#ifndef  M_SOI

#define  M_SOF0    0xC0              // Start Of Frame N

#define  M_SOF1    0xC1              // N indicates which compression process

#define  M_SOF2    0xC2               // Only SOF0-SOF2 are now in common use

#define  M_SOF3    0xC3

#define  M_SOF5    0xC5              // NB: codes C4 and CC are NOT SOF markers

#define  M_SOF6    0xC6

#define  M_SOF7    0xC7

#define  M_SOF9    0xC9

#define  M_SOF10   0xCA

#define  M_SOF11   0xCB

#define  M_SOF13   0xCD

#define  M_SOF14   0xCE

#define  M_SOF15   0xCF

#define  M_SOI     0xD8              // Start Of Image (beginning of datastream)

#define  M_EOI     0xD9              // End Of Image (end of datastream)

#define  M_SOS     0xDA              // Start Of Scan (begins compressed data)

#define  M_JFIF    0xE0              // Jfif marker

#define  M_EXIF    0xE1              // Exif marker

#define  M_COM     0xFE              // COMment

 

// 定义  APP  标识(SECTION)

#define  M_APP0    0xE0

#define  M_APP1    0xE1

#define  M_APP2    0xE2

#define  M_APP3    0xE3

#define  M_APP4    0xE4

#define  M_APP5    0xE5

#define  M_APP6    0xE6

//...

#endif

 

// Describes tag values

// 注意:  下面的定义是按照  Intel CPU  来定义的,也就是说所有的都是高位在后,

// 这样的定义可能与  EXIF  白皮书上的定义不一致。例如白皮书上把  TAG_MAKE  定义为  0F01

// 下面是主要信息

#define  TAG_MAKE                 0x010F      // 相机DC  制造商

#define  TAG_MODEL               0x0110      //DC  型号

#define  TAG_ORIENTATION         0x0112      // 拍摄时方向,例如向左手旋转DC 90 度拍摄照片

#define  TAG_XRESOLUTION         0x011A      //X  轴分辨率

#define  TAG_YRESOLUTION         0x011B      //Y  轴分辨率

#define  TAG_RESOLUTIONUNIT      0x0128      // 分辨率单位,例如  inch, cm

#define  TAG_DATATIME            0x0132      // 日期时间

#define  TAG_YBCR_POSITION       0x0213      //YCbCr  位置控制,例如 居中

#define  TAG_COPYRIGHT           0x8298      // 版权

#define  TAG_EXIF_OFFSET         0x8769      //EXIF  偏移,这时候相当于处理一个新的  EXIF  信息

 

//

#define  TAG_IMAGEWIDTH          0x0001      // 图像宽度

#define  TAG_IMAGEHEIGHT         0x0101      // 图像高度

//BOOKMARK

// 辅助信息

#define  TAG_EXPOSURETIME        0x829A      // 曝光时间,例如  1/30  秒

#define  TAG_FNUMBER             0x829D      // 光圈,例如  F2.8

#define  TAG_EXIF_VERSION        0x9000      //EXIF  信息版本

#define  TAG_DATETIME_ORIGINAL   0x9003      // 照片拍摄时间,例如  2005-10-13 11:09:35

#define  TAG_DATATIME_DIGITIZED    0x9004    // 相片被其它图像修改软件修改后的时间,例如   2005-10-13 11:36:35

#define  TAG_COMPONCONFIG        0x9101      //ComponentsConfiguration  色彩空间配置

#define  TAG_COMPRESS_BIT        0x9202      // 每像素压缩位数

#define  TAG_SHUTTERSPEED        0x9201      // 快门速度,例如  1/30  秒

#define  TAG_APERTURE            0x9202      // 光圈值,例如  F2.8

#define  TAG_BRIGHTNESS          0x9203      // 亮度

#define  TAG_EXPOSURE_BIAS       0x9204      // 曝光补偿,例如  EV0.0

#define  TAG_MAXAPERTURE         0x9205      // 最大光圈值,例如  F2.8

#define  TAG_SUBJECT_DISTANCE    0x9206      // 拍摄物距离,例如  3.11  米

#define  TAG_METERING_MODE       0x9207      // 测光模式,例如矩阵

#define  TAG_WHITEBALANCE        0x9208      //LightSource  白平衡

#define  TAG_FLASH               0x9209      // 是否使用闪光灯

#define  TAG_FOCALLENGTH         0x920A      // 焦距,例如  7.09mm

#define  TAG_USERCOMMENT         0x9286      // 用户注释

#define  TAG_MAKE_COMMENT        0x927C      // 厂商注释。这个版本不提供(2005-10-13)

#define  TAG_SUBSECTIME          0x9290      //SubSecTime

#define  TAG_SUBTIME_ORIGINAL    0x9291      //SubSecTimeOriginal

#define  TAG_SUBTIME_DIGITIZED   0x9292      //SubSecTimeDigitized

#define  TAG_FLASHPIXVERSION     0x00A0      //Flash Pix  版本

#define  TAG_COLORSPACE          0x01A0      // 色彩空间,例如  sRGB

 

#define  TAG_PIXEL_XDIMENSION    0x02A0      //

#define  TAG_PIXEL_YDIMENSION    0x03A0      //

#define  TAG_

//EXIFR98

 

// 缩略图

#define  TAG_INTEROP_OFFSET      0xa005      // 偏移

 

#define  TAG_FOCALPLANEXRES      0xA20E      // 焦平面X 轴分辨率,例如  1024000/278

#define  TAG_FOCALPLANEYRES      0xA20F      // 焦平面X 轴分辨率,例如  768000/209

#define  TAG_FOCALPLANEUNITS     0xA210      // 焦平面分辨率单位

#define  TAG_EXIF_IMAGEWIDTH     0xA002      //EXIF  图像宽度( 就是这张  JPG  图像)

#define  TAG_EXIF_IMAGELENGTH    0xA003      //EXIF  图像高度

 

#define  TAG_EXPOSURE_PROGRAM    0x8822      //

#define  TAG_ISO_EQUIVALENT      0x8827      //

#define  TAG_COMPRESSION_LEVEL   0x9102      //

 

#define  TAG_THUMBNAIL_OFFSET    0x0201      // 缩略图偏移

#define  TAG_THUMBNAIL_LENGTH    0x0202      // 缩略图大小

 

 

#define  TAG_GPS_VERSIONID         0x0000    //GPS  版本

#define  TAG_GPS_LATITUDEREF       0x0001    // 纬度参考,例如南纬

#define  TAG_GPS_LATITUDE          0x0002    // 纬度值

#define  TAG_GPS_LONGITUDEREF      0x0003    // 经度参考,例如东经

#define  TAG_GPS_LONGITUDE         0x0004    // 经度值

#define  TAG_GPS_ALTITUDEREF       0x0005    // 海拔高度参考

#define  TAG_GPS_ALTITUDE          0x0006    // 海拔

#define  TAG_GPS_TIMESTAMP         0x0007    // 时间戳

#define  TAG_GPS_SATELLITES        0x0008    // 卫星

#define  TAG_GPS_STATUS            0x0009    // 状态

#define  TAG_GPS_MEASUREMODE       0x000A    //

#define  TAG_GPS_DOP               0x000B    //

#define  TAG_GPS_SPEEDREF          0x000C    //

#define  TAG_GPS_SPEED             0x000D    //

#define  TAG_GPS_TRACKREF          0x000E    //

#define  TAG_GPS_TRACK             0x000F    //

#define  TAG_GPS_IMGDIRECTIONREF   0x0010    //

#define  TAG_GPS_IMGDIRECTION      0x0011    //

#define  TAG_GPS_MAPDATUM          0x0012    //

#define  TAG_GPS_DESTLATITUDEREF   0x0013    //

#define  TAG_GPS_DESTLATITUDE      0x0014    //

#define  TAG_GPS_DESTLONGITUDEREF    0x0015 //

#define  TAG_GPS_DESTLONGITUDE     0x0016    //

#define  TAG_GPS_DESTBEARINGREF    0x0017    //

#define  TAG_GPS_DESTBEARING       0x0018    //

#define  TAG_GPS_DESTDISTANCEREF   0x0019    //

#define  TAG_GPS_DESTDISTANCE      0x001A    //

//////////////////////////////////////////////////////////////////////////

/*--------------------------------------------------------------------------

Get 16 bits motorola order (always) for jpeg header stuff.

--------------------------------------------------------------------------*/

STATIC   int   EXIF_Get16m ( void   *  Short )

{

   return   ((( unsigned   char   *) Short )[ 0 ] <<  8 ) | (( unsigned   char   *) Short )[ 1 ];

}

 

/*--------------------------------------------------------------------------

Convert a 16 bit unsigned value from file's native unsigned char order

--------------------------------------------------------------------------*/

STATIC   int   EXIF_Get16u ( void   *  Short )

{

   if   ( m_MotorolaOrder )

   {

     return   ((( unsigned   char   *) Short )[ 0 ] <<  8 ) | (( unsigned   char   *) Short )[ 1 ];

   }

   else

   {

     return   ((( unsigned   char   *) Short )[ 1 ] <<  8 ) | (( unsigned   char   *) Short )[ 0 ];

   }

}

 

/*--------------------------------------------------------------------------

Convert a 32 bit signed value from file's native unsigned char order

--------------------------------------------------------------------------*/

STATIC   long   EXIF_Get32s ( void   *  Long )

{

   if   ( m_MotorolaOrder )

   {

     return    (((  char   *) Long )[ 0 ] <<  24 ) | ((( unsigned   char   *) Long )[ 1 ] <<  16 )

       | ((( unsigned   char   *) Long )[ 2 ] <<  8   ) | ((( unsigned   char   *) Long )[ 3 ] <<  0   );

   }

   else

   {

     return    (((  char   *) Long )[ 3 ] <<  24 ) | ((( unsigned   char   *) Long )[ 2 ] <<  16 )

       | ((( unsigned   char   *) Long )[ 1 ] <<  8   ) | ((( unsigned   char   *) Long )[ 0 ] <<  0   );

   }

}

 

/*--------------------------------------------------------------------------

Convert a 32 bit unsigned value from file's native unsigned char order

--------------------------------------------------------------------------*/

STATIC   ULONG   EXIF_Get32u ( void   *  Long )

{

   return   ( unsigned   long ) EXIF_Get32s ( Long ) &  0XFFFFFFFF ;

}

 

/*--------------------------------------------------------------------------

Evaluate number, be it int, rational, or float from directory.

--------------------------------------------------------------------------*/

STATIC   double   EXIF_ConvertAnyFormat ( void   *  ValuePtr ,  int   Format )

{

   double   Value ;

   Value   =  0 ;

 

   switch ( Format )

   {

   case   FMT_SBYTE :      Value   = *( signed   char   *) ValuePtr ;    break ;

   case   FMT_BYTE :       Value   = *( unsigned   char   *) ValuePtr ;  break ;

   

   case   FMT_USHORT :     Value   =  EXIF_Get16u ( ValuePtr );       break ;

   case   FMT_ULONG :      Value   =  EXIF_Get32u ( ValuePtr );       break ;

   

   case   FMT_URATIONAL :

   case   FMT_SRATIONAL :

     {

       int   Num , Den ;

       Num   =  EXIF_Get32s ( ValuePtr );

       Den   =  EXIF_Get32s ( 4 +( char   *) ValuePtr );

        if   ( Den   ==  0 )

       {

         Value   =  0 ;

       }

       else

       {

         Value   = ( double ) Num/Den ;

       }

       break ;

     }

   

   case   FMT_SSHORT :     Value   = ( signed   short ) EXIF_Get16u ( ValuePtr );  break ;

   case   FMT_SLONG :      Value   =  EXIF_Get32s ( ValuePtr );                break ;

   

   /* Not sure if this is correct (never seen float used in Exif format)

     */

   case   FMT_SINGLE :     Value   = ( double )*( float   *) ValuePtr ;      break ;

   case   FMT_DOUBLE :     Value   = *( double   *) ValuePtr ;             break ;

   }

   return   Value ;

}

////////////////////////////////////////////////////////////////////////////////

 

//////////////////////////////////////////////////////////////////////////

 

/*********************************************************************

   函数声明:

   参     数:

           IN:

          OUT:

          I/O:

     返回值:

   功能描述:  处理  JPG  文件中的注释信息

   引     用:

*********************************************************************/

STATIC   void   EXIF_Process_COM   ( CONST   UCHAR   *  Data ,  int   length )

{

   int   ch ;

   char   Comment [ MAX_COMMENT + 1 ];

   int   nch ;

   int   a ;

 

   nch   =  0 ;

 

   if   ( length   >  MAX_COMMENT )  length   =  MAX_COMMENT ;  // Truncate if it won't fit in our structure.

 

   for   ( a = 2 ; a < length ; a ++)

   {

     ch   =  Data [ a ];

   

     if   ( ch   ==  '/r'   &&  Data [ a + 1 ] ==  '/n' )  continue ;  // Remove cr followed by lf.

   

     if   (( ch >= 0x20 ) ||  ch   ==  '/n'   ||  ch   ==  '/t' )

     {

       Comment [ nch ++] = ( char ) ch ;

     }

     else

     {

       Comment [ nch ++] =  '?' ;

     }

   }

 

   Comment [ nch ] =  '/0' ;  // Null terminate

 

   //if (ShowTags) printf("COM marker comment: %s/n",Comment);

 

   strcpy ( m_pExifInfo -> Comments , Comment );

}

 

/*********************************************************************

   函数声明: STATIC BOOL EXIF_ProcessExifDir(...)

   参     数:

           IN: CONST UCHAR* DataStart:  数据流的起始位置。这个数值仅仅在函数  EXIF_Decode  中能够改变

               CONST DWORD dwFilePointerBeforeReadData:  在读取数据流之前的文件指针位置

               UCHAR *DirStart: SECTION  中数据流,去除了前面的  EXIF/0/0(6)+II(2)+2A00(2)+08000000(6)=14

               UCHAR *OffsetBase:  仅仅去除了  EXIFF/0/0(6)=6 字节

               UINT ExifLength:  整个  SECTION  数据流的长度去除  EXIF/0/0 后的长度==All Length - 6

               EXIFINFO * const m_exifinfo: 

          OUT:

          I/O:

               UCHAR **const LastExifRefdP:  偏移过后的位置

     返回值:

   功能描述:

   引     用:

*********************************************************************/

STATIC   BOOL   EXIF_ProcessExifDir ( CONST   UCHAR *  DataStart ,  CONST   DWORD   dwFilePointerBeforeReadData ,

                                 UCHAR   * DirStart ,  UCHAR   * OffsetBase ,  CONST   UINT   ExifLength ,

                                 EXIFINFO   *  const   m_exifinfo ,  UCHAR   ** const   LastExifRefdP   )

{

   int   de   =  0 ;                  //

   int   a   =  0 ;                   //

   int   NumTagEntries   =  0 ;       // 包含的  TAG  的个数

   UINT   ThumbnailOffset   =  0 ;    // 缩略图偏移量

   UINT   ThumbnailSize   =  0 ;      // 缩略图的大小

   int    BytesCount   =  0 ;         //

   UCHAR   *  TagEntry   =  0 ;        // 每个  TAG  的入口

   int   Tag ,  Format ,  Components ;

   UCHAR   *  ValuePtr   =  0 ;        // 偏移后的位置。因为  TAG  与内容很多时候都不是连续的,而是中间有个偏移量

   DWORD   OffsetVal   =  0 ;         // 偏移量

 

   // 读取文件中存在  TAG  个数

   NumTagEntries   =  EXIF_Get16u ( DirStart );

 

   // 判断  EXIF  信息的长度是否正确

   // 下面  DirStart+2  指再去除了  NumTagEntries  所占的  2  个字节

   if   (( DirStart + 2 + NumTagEntries * 12 ) > ( OffsetBase + ExifLength ))

   {

     EXIF_ERR_OUT ( "Illegally sized directory" );

     return   0 ;

   }

   for   ( de = 0 ; de < NumTagEntries ; de ++)

   {

     // 在下面的操作中,所有的数据通通使用  UCHAR*  来表示

     TagEntry   =  DirStart + 2 + 12 * de ;     //TagEntry  的入口点

     Tag   =  EXIF_Get16u ( TagEntry );

     Format   =  EXIF_Get16u ( TagEntry + 2 );

     Components   =  EXIF_Get32u ( TagEntry + 4 );

   

     if   (( Format - 1 ) >=  NUM_FORMATS )

     {

       //(-1) catches illegal zero case as unsigned underflows to positive large

       EXIF_ERR_OUT ( "Illegal format code in EXIF dir" );

       return   0 ;

     }   

     BytesCount   =  Components   *  m_BytesPerFormat [ Format ];

     if   ( BytesCount   >  4 )

     {

       OffsetVal   =  EXIF_Get32u ( TagEntry + 8 );

       //If its bigger than 4 unsigned chars, the dir entry contains an offset.

       if   ( OffsetVal + BytesCount   >  ExifLength )

       {

         //JPG  文件内容遭到破坏

         EXIF_ERR_OUT ( "Illegal pointer offset value in EXIF." );

         return   0 ;

       }

       ValuePtr   =  OffsetBase + OffsetVal ;

     }

     else

     {

       //4 unsigned chars or less and value is in the dir entry itself

       ValuePtr   =  TagEntry + 8 ;

     }

     if   (* LastExifRefdP   <  ValuePtr + BytesCount )

     {

       // 当前已经处理的进度

       // 这样可以再次的检测  JPG  文件的合法性

       * LastExifRefdP   =  ValuePtr + BytesCount ;

     }

 

     // Extract useful components of tag

     switch ( Tag )

     {

     case   TAG_MAKE :

       strncpy ( m_exifinfo -> CameraMake , ( char *) ValuePtr ,  31 );

       break ;

     case   TAG_MODEL :

       strncpy ( m_exifinfo -> CameraModel , ( char *) ValuePtr ,  39 );

       break ;

     

     case   TAG_EXIF_VERSION :

       strncpy ( m_exifinfo -> Version ,( char *) ValuePtr ,  4 );

       break ;

     // 日期和时间 

     case   TAG_DATETIME_ORIGINAL :

       strncpy ( m_exifinfo -> DateTime , ( char *) ValuePtr ,  19 );

       break ;

     case   TAG_DATATIME_DIGITIZED :

       strncpy ( m_exifinfo -> DateTimeDigitized , ( char *) ValuePtr ,  19 );

       break ;

     // 用户注释

     case   TAG_USERCOMMENT :

        m_exifinfo -> UserCOMLength   =  BytesCount ;

       if ( m_exifinfo -> dwExifType   &  ET_MALLOC_USERCOM )

       {

         m_exifinfo -> UserCOM   =  malloc ( BytesCount );

         memcpy ( m_exifinfo -> UserCOM ,  ValuePtr ,  BytesCount );

         /*/ /Olympus   誠cf9  誠cf9  蟎cf9  郳cf9  籠cf9  鶿cf9  籠cf9  醆cf9  診cf9  赲cf9  譢cf9  cf9  蔦cf9  蚛cf9  礬cf9  腬cf9  譢cf9  頫cf9  篭cf9  骪cf9  肻cf9  鎈cf9  蘚cf9  頫cf9  砛cf9  鋅cf9  縗cf9  誠cf9  竆cf9  馶cf8 0x20 禱cf9  鳿cf9  瞈cf9  籠cf9  蔦cf9  荺cf7 '/0',

         // 下面先将后面的空格替换成  '/0'  然后再拷贝注释Comment

         for   ( a = BytesCount ; a > 0 ;)

         {

           a --;

           if   ((( char *) ValuePtr )[ a ] ==  ' ' )

           {

             (( char *) ValuePtr )[ a ] =  '/0' ;

           }

           else

           {

             break ;

           }

         }

         // 将用户注释拷贝到  exifinfo.Comments  中

          // 首先判断是否是  ASCII  模式( 就是注释的前面  5  个字符是  ASCII)

         // 如果是,则取消拷贝最前面的   ASCII  五个字符

         if   ( memcmp ( ValuePtr ,  "ASCII" , 5 ) ==  0 )

         {

           for   ( a = 5 ; a < 10 ; a ++)

           {

             char   c ;

             c   = (( char *) ValuePtr )[ a ];

             if   ( c   !=  '/0'   &&  c   !=  ' ' )

             {

               strncpy ( m_exifinfo -> Comments , ( char *) ValuePtr + a ,  MAX_COMMENT - 1 );

               break ;

             }

           }       

         }

         else

         {

           strncpy ( m_exifinfo -> Comments , ( char *) ValuePtr ,  MAX_COMMENT - 1 );

         }*/

       }

       else

       {

         // 记录用户注释相对于整个文件起始处的偏移量

         m_exifinfo -> UserCOM   = ( CHAR *)( OffsetBase + OffsetVal - DataStart + dwFilePointerBeforeReadData );

         //m_exifinfo->UserCOM = (char*)OffsetVal;   // 偏移

       }

       break ;

     // 厂商注释

     case   TAG_MAKE_COMMENT :

       m_exifinfo -> MakerCOMLength   =  BytesCount ;

       if ( m_exifinfo -> dwExifType   &  ET_MALLOC_MAKERCOM )

       {

         m_exifinfo -> MakerCOM   =  malloc ( BytesCount );

         memcpy ( m_exifinfo -> MakerCOM ,  ValuePtr ,  BytesCount );

       }

       else

       {

         m_exifinfo -> MakerCOM   = ( char *) OffsetVal ;  // 偏移

       }

       break ;

     // 光圈

     case   TAG_FNUMBER :

       m_exifinfo -> ApertureFNumber   = ( float ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       break ;

 

     case   TAG_APERTURE :     // 光圈值

     case   TAG_MAXAPERTURE :  // 最大光圈值

     //More relevant info always comes earlier, so only

     //use this field if we don't have appropriate aperture

     //information yet.

     /*-   if (m_exifinfo->ApertureFNumber == 0)

       {

         m_exifinfo->ApertureFNumber = (float)exp(EXIF_ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5);//ATTENTION

         m_exifinfo->ApertureFNumber = (float)(EXIF_ConvertAnyFormat(ValuePtr, Format)*log(2)*0.5);

       }-*/

       break ;

 

     //Brightness

      case   TAG_BRIGHTNESS :

       m_exifinfo -> Brightness   = ( float ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       break ;

 

     // 焦距信息( 例如  7.09mm)     

     case   TAG_FOCALLENGTH :

     //Nice digital cameras actually save the focal length

     //as a function of how farthey are zoomed in.

     

       m_exifinfo -> FocalLength   = ( float ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       break ;

 

     // 目标距离( 例如  1.11 米)

     case   TAG_SUBJECT_DISTANCE :

     //Inidcates the distacne the autofocus camera is focused to.

     //Tends to be less accurate as distance increases.

       m_exifinfo -> Distance   = ( float ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       break ;

 

     // 曝光时间( 例如  1/30  秒)

     case   TAG_EXPOSURETIME :

     //Simplest way of expressing exposure time, so I

     //trust it most.   (overwrite previously computd value

     //if there is one)

       m_exifinfo -> ExposureTime   =

         ( float ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       break ;

 

     //SHUTTERSPEED  快门速度不需要   

     case   TAG_SHUTTERSPEED :

     //More complicated way of expressing exposure time,

     //so only use this value if we don't already have it

     //from somewhere else. 

     /*-   if (m_exifinfo->ExposureTime == 0)

       {

         m_exifinfo->ExposureTime = (float)

           (1/exp(EXIF_ConvertAnyFormat(ValuePtr, Format)*log(2)));

       }-*/

       break ;

 

   //FLASH  闪光灯信息不需要     

     case   TAG_FLASH :

       if   (( int ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format ) &  7 )

       {

         m_exifinfo -> FlashUsed   =  1 ;

       }

       else

       {

         m_exifinfo -> FlashUsed   =  0 ;

       }

       break ;

     

     case   TAG_ORIENTATION :

       m_exifinfo -> Orientation   = ( int ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       if   ( m_exifinfo -> Orientation   <  1   ||  m_exifinfo -> Orientation   >  8 )

       {

         EXIF_ERR_OUT ( "Undefined rotation value" );

         m_exifinfo -> Orientation   =  0 ;

       }

       break ;

     //EXIF  图像高度与宽度( 例如  1024*768)

     case   TAG_EXIF_IMAGELENGTH :

     case   TAG_EXIF_IMAGEWIDTH :

       a   = ( int ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       if   ( m_ExifImageWidth   <  a )  m_ExifImageWidth   =  a ;

       break ;

   // 焦平面  X  轴分辨率( 例如  1024000/278) ,理论上与  Y  一致

     case   TAG_FOCALPLANEXRES :

       m_exifinfo -> FocalplaneXRes   = ( float ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       break ;

   // 焦平面  Y  轴分辨率( 例如  768000/209) ,理论上与  X  一致

     case   TAG_FOCALPLANEYRES :

       m_exifinfo -> FocalplaneYRes   = ( float ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       break ;

     case   TAG_RESOLUTIONUNIT :

       switch (( int ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format ))

       {

       case   1 :  m_exifinfo -> ResolutionUnit   =  1 . 0f ;              break ;    // 1 inch

       case   2 :  m_exifinfo -> ResolutionUnit   =  1 . 0f ;              break ;    //

       case   3 :  m_exifinfo -> ResolutionUnit   =  0 . 3937007874f ;     break ;    // 1 centimeter

       case   4 :  m_exifinfo -> ResolutionUnit   =  0 . 03937007874f ;    break ;    // 1 millimeter

       case   5 :  m_exifinfo -> ResolutionUnit   =  0 . 00003937007874f ;          // 1 micrometer

       }

       break ;

     // 焦平面分辨率单位( 例如米)

     case   TAG_FOCALPLANEUNITS :

       switch (( int ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format ))

       {

       case   1 :  m_exifinfo -> FocalplaneUnits   =  1 . 0f ;              break ;   // 1 inch

       case   2 :  m_exifinfo -> FocalplaneUnits   =  1 . 0f ;              break ;   //

       case   3 :  m_exifinfo -> FocalplaneUnits   =  0 . 3937007874f ;     break ;   // 1 centimeter

       case   4 :  m_exifinfo -> FocalplaneUnits   =  0 . 03937007874f ;    break ;   // 1 millimeter

       case   5 :  m_exifinfo -> FocalplaneUnits   =  0 . 00003937007874f ; break ;   // 1 micrometer//

       }

       break ;

 

     // 曝光补偿信息

     case   TAG_EXPOSURE_BIAS :

       m_exifinfo -> ExposureBias   = ( float )  EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       break ;

     // 白平衡

     case   TAG_WHITEBALANCE :

       m_exifinfo -> Whitebalance   = ( int ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       break ;

     case   TAG_METERING_MODE :

       m_exifinfo -> MeteringMode   = ( int ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       break ;

     case   TAG_EXPOSURE_PROGRAM :

       m_exifinfo -> ExposureProgram   = ( int ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       break ;

     case   TAG_ISO_EQUIVALENT :

       m_exifinfo -> ISOequivalent   = ( int ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       if   (  m_exifinfo -> ISOequivalent   <  50   )  m_exifinfo -> ISOequivalent   *=  200 ;

       break ;

     case   TAG_COMPRESSION_LEVEL :

       m_exifinfo -> CompressionLevel   = ( int ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       break ;

     //X  轴分辨率

     case   TAG_XRESOLUTION :

       m_exifinfo -> Xresolution   = ( float ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       break ;

     //Y  轴分辨率

     case   TAG_YRESOLUTION :

       m_exifinfo -> Yresolution   = ( float ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       break ;

     // 缩略图 偏移量 

     case   TAG_THUMBNAIL_OFFSET :

       ThumbnailOffset   = ( unsigned ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

       break ;

     // 缩略图的大小

     case   TAG_THUMBNAIL_LENGTH :

         ThumbnailSize   = ( unsigned ) EXIF_ConvertAnyFormat ( ValuePtr ,  Format );

         break ;

     }  //end switch(Tag)

     //EXIF  信息偏移

     //

     if   ( Tag   ==  TAG_EXIF_OFFSET   ||  Tag   ==  TAG_INTEROP_OFFSET )

     {

       UCHAR   *  SubdirStart ;

       SubdirStart   =  OffsetBase   +  EXIF_Get32u ( ValuePtr );

        if   ( SubdirStart   <  OffsetBase   ||

         SubdirStart   >  OffsetBase + ExifLength )

       {

         EXIF_ERR_OUT ( "Illegal subdirectory link" );

         return   0 ;

       }

       EXIF_ProcessExifDir ( DataStart ,  dwFilePointerBeforeReadData ,  SubdirStart ,  OffsetBase ,  ExifLength ,  m_exifinfo ,  LastExifRefdP );

       continue ;

     } 

   }  //end for {for (de=0;de<NumTagEntries;de++)}

   {

     //In addition to linking to subdirectories via exif tags,

     //there's also a potential link to another directory at the end

     //of each directory.   This has got to be the result of a

     //committee! 

   

     UCHAR   *  SubdirStart ;

     unsigned   Offset ;

     Offset   =  EXIF_Get16u ( DirStart + 2 + 12 * NumTagEntries );

     if   ( Offset )

     {

       SubdirStart   =  OffsetBase   +  Offset ;

       if   ( SubdirStart   <  OffsetBase

         ||  SubdirStart   >  OffsetBase + ExifLength )

       {

         EXIF_ERR_OUT ( "Illegal subdirectory link" );

         return   0 ;

       }

       EXIF_ProcessExifDir ( DataStart ,  dwFilePointerBeforeReadData ,  SubdirStart ,  OffsetBase ,  ExifLength ,  m_exifinfo ,  LastExifRefdP );

     }

   }

 

   if   ( ThumbnailSize   &&  ThumbnailOffset )

   {

     // 如果文件中存在缩略图,那么将缩略图的数据保存

     // 注意:这里仅仅负责  malloc ,调用者需要自己  free

     if   ( ThumbnailSize   +  ThumbnailOffset   <=  ExifLength )

     {

       // 将缩略图的数据全部拷贝到一块新开辟的内存

       if ( m_exifinfo -> dwExifType & ET_MALLOC_THUMBNAIL )

       {

         UCHAR   * pThumbnailData   =  OffsetBase   +  ThumbnailOffset ;

         DWORD   dw   =  pThumbnailData - DataStart + dwFilePointerBeforeReadData ;

         m_exifinfo -> ThumbnailPointer   = ( UCHAR *) malloc ( ThumbnailSize );

         memcpy ( m_exifinfo -> ThumbnailPointer ,  pThumbnailData ,  ThumbnailSize );

       }

       else

       {

         m_exifinfo -> ThumbnailPointer   = ( UCHAR *)( OffsetBase + ThumbnailOffset - DataStart + dwFilePointerBeforeReadData );

       }

       m_exifinfo -> ThumbnailSize   =  ThumbnailSize ;

     }

   }

 

   return   TRUE ;

}

 

/*********************************************************************

   函数声明: STATIC BOOL EXIF_process_EXIF(UCHAR * CharBuf, UINT length)

   参     数:

           IN: CONST UCHAR* DataStart:  数据流的起始位置。这个数值仅仅在函数  EXIF_Decode  中能够改变

               CONST DWORD dwFilePointerBeforeReadData:  在读取数据流之前的文件指针位置

               UCHAR * CharBuf:  这个  SECTION  数据内容。注意:前面已经去掉了包含长度的2 个字符

               CONST UINT length:  这个  SECTION  数据流的长度

     返回值:

   功能描述:  处理某个  SECTION  中的  EXIF  信息。

             成功返回TRUE 表示EXIF 信息存在且正确,失败返回FALSE

   引     用:

*********************************************************************/

STATIC   BOOL   EXIF_process_EXIF ( CONST   UCHAR   * DataStart ,   CONST   DWORD   dwFilePointerBeforeReadData ,

                               UCHAR   * CharBuf ,  CONST   UINT   length )

{

   int   FirstOffset   =  0 ;

   UCHAR   * LastExifRefd   =  0 ;

   m_pExifInfo -> FlashUsed   =  0 ;

   m_pExifInfo -> Comments [ 0 ] =  '/0' ;

 

   m_ExifImageWidth   =  0 ;

 

   // 检查  EXIF  头是否正确

   {

     static   const   unsigned   char   ExifHeader [] =  "Exif/0/0" ;

     if   ( memcmp ( CharBuf + 0 ,  ExifHeader , 6 ))

     {

       EXIF_ERR_OUT ( "Incorrect Exif header" );

       return   0 ;

     }

   }

   // 判断内存中数据的排列是按照  Intel  还是按照  Motorola CPU  排列的

   if   ( memcmp ( CharBuf + 6 , "II" , 2 ) ==  0 )

   {

     m_MotorolaOrder   =  0 ;     //

   }

   else   if   ( memcmp ( CharBuf + 6 , "MM" , 2 ) ==  0 )

   {

     m_MotorolaOrder   =  1 ;   //

   }

   else

   {

     EXIF_ERR_OUT ( "Invalid Exif alignment marker." );

     return   0 ;

   }

 

   // 检查下面  2  个字节是否是  0x2A00

   if   ( EXIF_Get16u ( CharBuf + 8 ) !=  0x2A )

   {

     EXIF_ERR_OUT ( "Invalid Exif start (1)" );

     return   0 ;

   }

 

   // 判断下面的  0th IFD Offset  是否是  0x08000000

   FirstOffset   =  EXIF_Get32u ( CharBuf + 10 );

   if   ( FirstOffset   <  8   ||  FirstOffset   >  16 )

   {

     EXIF_ERR_OUT ( "Suspicious offset of first IFD value" );

     return   0 ;

   }

 

   LastExifRefd   =  CharBuf ;

 

   // 开始处理  EXIF  信息

   if   (! EXIF_ProcessExifDir ( DataStart ,  dwFilePointerBeforeReadData ,

     CharBuf + 14 ,  CharBuf + 6 ,  length - 6 ,  m_pExifInfo , & LastExifRefd ))

   {

     return   0 ;

   }

 

   // This is how far the interesting (non thumbnail) part of the exif went.

   // int ExifSettingsLength = LastExifRefd - CharBuf; 

   //  计算  CCD  宽度( 单位: 毫米)

   if   ( m_pExifInfo -> FocalplaneXRes   !=  0 )

   {

     m_pExifInfo -> CCDWidth   = ( float )( m_ExifImageWidth   *  m_pExifInfo -> FocalplaneUnits   /  m_pExifInfo -> FocalplaneXRes );

   }

 

   return   1 ;

}

 

STATIC   VOID   EXIF_process_SOFn   ( CONST   UCHAR   *  Data ,  int   marker )

{

   int   data_precision ,  num_components ;

 

   data_precision   =  Data [ 2 ];

   m_pExifInfo -> Height   =  EXIF_Get16m (( void *)( Data + 3 ));

   m_pExifInfo -> Width   =  EXIF_Get16m (( void *)( Data + 5 ));

   num_components   =  Data [ 7 ];

 

   if   ( num_components   ==  3 )

   {

     m_pExifInfo -> IsColor   =  1 ;

   }

   else

   {

     m_pExifInfo -> IsColor   =  0 ;

   }

 

   m_pExifInfo -> Process   =  marker ;

 

   //if (ShowTags) printf("JPEG image is %uw * %uh, %d color components, %d bits per sample/n",

   //                ImageInfo.Width, ImageInfo.Height, num_components, data_precision);

}

 

STATIC   int   EXIF_Decode ( HANDLE   hFile )

{

   int   a = 0 ,  b = 0 ;

   int   nHaveCom   =  0 ;              // 是否存在注释,并且保存注释字符串的长度

   int   nSectionsRead   =  0 ;         // 已经读取  SECTION  的个数

   DWORD   dwFileRead   =  0 ;          // 使用  ReadFile  读取文件时,读取的字节数

   DWORD   dwFilePointerBeforeReadData   =  0 ;   // 在读取数据流之前,文件指针的位置

   Section_t   Sections [ MAX_SECTIONS ];        //JPG  文件中  SECTIONS

 

     int     nSectionLength = 0 ;      //SECTION(APP)  长度

     int     marker   =  0 ;            //

     int     ll = 0 , lh = 0 ,  got = 0 ;      //

     UCHAR   * Data   =  0 ;             //

 

   // 读入  JPG  第1, 2 个字节,判断是否是  0xFF,M_SOI

   ReadFile ( hFile , & a ,  1 , & dwFileRead ,  NULL );

   if ( dwFileRead   !=  1 )

   {

     EXIF_ERR_OUT ( "Unexpect File End" );

     return   - 1 ;

   }

   ReadFile ( hFile , & b ,  1 , & dwFileRead ,  NULL );

   if ( dwFileRead   !=  1 )

   {

     EXIF_ERR_OUT ( "Unexpect File End" );

     return   - 1 ;

   }

   // 判断该文件是否是  EXIF  文件

   //EXIF  文件的起始  2  字节必定是  FF D8

   if   ( a   !=  0xFF   ||  b   !=  M_SOI )

   {

     EXIF_ERR_OUT ( "File Format Error" );

     return   - 1 ;

   }

   // 使用一个循环,读取  JPG  文件中的  SECTION

   // 第一个  SECTION  肯定是  APP1 ,而APP1 起始的Marker 肯定为  FFE1

   for (;;)

   {

     if   ( nSectionsRead   >=  MAX_SECTIONS )

      {

       EXIF_ERR_OUT ( "Too many sections in this jpg file" );

       return   - 1 ;

     }

     // 查找  JPG  文件填充字符,接下来的7 个字符必须有一个不是  0xFF

     for   ( a = 0 ; a < 7 ; a ++)

     {

       ReadFile ( hFile , & marker ,  1 , & dwFileRead ,  NULL );

       if ( dwFileRead   !=  1 )

       {

         EXIF_ERR_OUT ( "Unexpect File End" );

         return   - 1 ;

       }

       if   ( marker   !=  0xFF )  break ;

     

       if   ( a   >=  6 )

       {

         EXIF_ERR_OUT ( "Too many padding unsigned chars" );

         return   - 1 ;

       }

     }

#ifdef _DEBUG

     if ( nSectionsRead == 0 )   // 是  APP 1

     {

       ASSERT ( marker   ==  M_APP1 );

     }

#endif

     Sections [ nSectionsRead ]. Type   =  marker ;

     // 记录读取流数据之前的文件指针位置

     dwFilePointerBeforeReadData   =  SetFilePointer ( hFile ,  0 ,  NULL ,  FILE_CURRENT );

     // 读取这个  SECTION  的长度

     ReadFile ( hFile , & lh ,  1 , & dwFileRead ,  NULL );

     ReadFile ( hFile , & ll ,  1 , & dwFileRead ,  NULL );

     nSectionLength   = ( lh   <<  8 ) |  ll ;     //EXIF  文件高字节在前,低字节在后,不能读取一个WORD 类型

   

     if   ( nSectionLength   <  2 )

     {

       EXIF_ERR_OUT ( "Invalid Marker" );

       return   - 1 ;

     }

     Data   = ( UCHAR   *) malloc ( nSectionLength );

     if   ( Data   ==  NULL )

     {

       EXIF_ERR_OUT ( "Could not allocate memory!" );

       return   - 1 ;

     }

     Sections [ nSectionsRead ]. Data   =  Data ;

   

     // Store first two pre-read unsigned chars.

     Data [ 0 ] = ( UCHAR ) lh ;

      Data [ 1 ] = ( UCHAR ) ll ;

     ReadFile ( hFile ,  Data + 2 ,  nSectionLength - 2 , & dwFileRead ,  NULL );

     if ( dwFileRead   !=( DWORD )( nSectionLength - 2 ))

     {

       EXIF_ERR_OUT ( "Premature end of file?" );

       return   - 1 ;

     }

     dwFileRead   =  SetFilePointer ( hFile ,  0 ,  NULL ,  FILE_CURRENT );

     // 得到当前文件的指针位置

     nSectionsRead   +=  1 ;

     switch ( marker )

     {

     case   M_SOS :    // 到了数据区

       return   1 ;

     case   M_EOI :    //End Of Image

       EXIF_ERR_OUT ( "No image in this jpeg file" );

       return   - 1 ;

     case   M_COM :    // 注释区

        if   ( nHaveCom )

       {

         // Discard this section.

         free ( Sections [-- nSectionsRead ]. Data );

         Sections [ nSectionsRead ]. Data = 0 ;

       }

       else

       {

         EXIF_Process_COM ( Data ,  nSectionLength );

         nHaveCom   =  1 ;

       }

     case   M_JFIF :

       // 标准的  JPG  文件通常都有  TAG ,并且处于  M_APP0  中

       //EXIF  图像使用  exif  标记( 在  M_APP1  中) 来取代这个

       // 但是有些软件( 例如  ACDSee) 在修改  JPG  文件后会同时保留这  2  个TAG

       // 我们在这里不需要  M_JFIF  信息,直接跳过去即可

       // 如果是重写文件,仅仅需要把  JFIF  信息复制到新的JPG 文件头

       free ( Sections [-- nSectionsRead ]. Data );

       Sections [ nSectionsRead ]. Data = 0 ;

       break ;

     case   M_EXIF :

       //EXIF  信息  TAG

       if   ( memcmp ( Data + 2 ,  "Exif" ,  4 ) ==  0 )

       {

         m_pExifInfo -> IsExif   =  EXIF_process_EXIF ( Data ,  dwFilePointerBeforeReadData , ( unsigned   char   *) Data + 2 ,  nSectionLength );

       }

       else

       {

         // Discard this section.

         free ( Sections [-- nSectionsRead ]. Data );

         Sections [ nSectionsRead ]. Data = 0 ;

       }

       break ;

     case   M_SOF0 :

     case   M_SOF1 :

     case   M_SOF2 :

     case   M_SOF3 :

     case   M_SOF5 :

     case   M_SOF6 :

     case   M_SOF7 :

     case   M_SOF9 :

     case   M_SOF10 :

     case   M_SOF11 :

     case   M_SOF13 :

     case   M_SOF14 :

     case   M_SOF15 :

       EXIF_process_SOFn ( Data ,  marker );

       break ;

     default :

       // Skip any other sections.

       //if (ShowTags) printf("Jpeg section marker 0x%02x size %d/n",marker, nSectionLength);

       break ;

     }

   }

   return   1 ;

}

/*********************************************************************

   函数声明:

   参     数:

            IN: LPCTSTR pszJpgFileName: JPG  文件全路径名

          OUT:

          I/O: EXIFINFO* pExifInfo:  保存了  EXIF  信息的结构体

     返回值: >=0 表示成功,<0 读取失败

   功能描述:  读取并返回  JPG  文件中的  EXIF  信息

   引     用:  外部调用者

   注     意:

*********************************************************************/

int   EXIF_Read ( LPCTSTR   pszJpgFileName ,  EXIFINFO *  pExifInfo )

{

   int   nReturn   = - 1 ;

   HANDLE   hFile   =  INVALID_HANDLE_VALUE ;

   if ( pExifInfo   ==  0 )

   {

     EXIF_ERR_OUT ( "Parameter incorreted! pExifInfo must not be NULL!" );

     return   - 1 ;

   }

   hFile   =  CreateFile ( pszJpgFileName ,   //LPCTSTR lpcszFileName

     GENERIC_READ ,                      //DWORD dwAccess

     FILE_SHARE_READ ,                   //DWORD dwShareMode

     NULL ,                              //LPSECURITY_ATTRIBUTES lpSecurityAttributes

     OPEN_EXISTING ,                     //DWORD dwCreate. 打开文件,如果不存在则失败

     FILE_ATTRIBUTE_NORMAL ,             //DWORD dwFlagsAndAttributes

     NULL                                //HANDLE hTemplateFile

     );

   // 打开  JPG  文件失败

   if ( hFile   ==  INVALID_HANDLE_VALUE )

   {

     EXIF_ERR_OUT ( "JPG File Not Found!" );

     return   - 1 ;

   }

   // 将文件指针移到最前

   SetFilePointer ( hFile ,  0 ,  NULL ,  FILE_BEGIN );

   // 开始处理  JPG  文件

   pExifInfo -> ThumbnailPointer   =  NULL ;

   pExifInfo -> ThumbnailSize   =  0 ;

   pExifInfo -> IsExif   =  FALSE ;

 

   m_pExifInfo   =  pExifInfo ;

   nReturn   =  EXIF_Decode ( hFile );

   if ( nReturn >= 0   && ( m_pExifInfo -> dwExifType & ET_NOT_CLOSE_FILE ) )

   {

     m_pExifInfo -> hJpgFileHandle   =  hFile ;

   }

   else

   {

     CloseHandle ( hFile );

   }

   return   nReturn ;

}

 

/*********************************************************************

   函数声明: int EXIF_AddUserComments(LPCTSTR pszJpgFileName, LPCTSTR pszUserComments, DWORD dwCommentLength, COMMENT_TYPE nCommentType)

   参     数:

           IN: LPCTSTR pszJpgFileName: JPG  文件全路径名

               LPCTSTR pszUserComments:  需要写入的注释

               DWORD dwCommentLength:  需要写入的注释的长度

               COMMENT_TYPE nCommentType:  注释写入时的类型,例如  ASCII, UNICODE, JIS  等

          OUT:

          I/O:

     返回值:  成功返回一个>0 的数值表示写入的注释长度,失败返回<0

   功能描述:  将指定的用户注释写入到  JPG  文件中

   引     用:

*********************************************************************/

int   EXIF_AddUserComments ( LPCTSTR   pszJpgFileName ,  LPCTSTR   pszUserComments ,  DWORD   dwCommentLength ,  COMMENT_TYPE   ctCommentType )

{

   int   nReturn   = - 1 ;

   EXIFINFO   exifinfo   = { 0 };

   HANDLE   hFile   =  INVALID_HANDLE_VALUE ;

   DWORD   dwWriteBytes   =  0 ;

   TCHAR   pszCommentType [ 8 ] = { 0 };

   switch ( ctCommentType )

   {

   case   CT_ASCII :

     strcpy ( pszCommentType ,  "ASCII" );

     break ;

   case   CT_UNDEFINE :

     strcpy ( pszCommentType ,  "UNICODE" );

     break ;

   case   CT_JIS :

     strcpy ( pszCommentType ,  "JIS" );

     break ;

   }

 

   if ( pszUserComments   ==  0 )

   {

     EXIF_ERR_OUT ( "Parameter incorreted! pszUserComments must not be NULL!" );

     return   - 1 ;

   }

   if ( dwWriteBytes   >  strlen ( pszUserComments ))

   {

     EXIF_ERR_OUT ( "dwWriteBytes must be bigger or equal than the length of user comments!" );

     return   - 1 ;

   }

   hFile   =  CreateFile ( pszJpgFileName ,   //LPCTSTR lpcszFileName

     GENERIC_WRITE | GENERIC_READ ,        //DWORD dwAccess

     FILE_SHARE_WRITE | FILE_SHARE_READ ,  //DWORD dwShareMode

     NULL ,                              //LPSECURITY_ATTRIBUTES lpSecurityAttributes

     OPEN_ALWAYS ,                       //DWORD dwCreate. 打开文件,如果不存在则创建

     FILE_ATTRIBUTE_NORMAL ,             //DWORD dwFlagsAndAttributes

     NULL                                //HANDLE hTemplateFile

     );

   // 打开  JPG  文件失败

   if ( hFile   ==  INVALID_HANDLE_VALUE )

   {

     EXIF_ERR_OUT ( "JPG File Not Found!" );

     return   - 1 ;

   }

   // 将文件指针移到最前

   SetFilePointer ( hFile ,  0 ,  NULL ,  FILE_BEGIN );

   // 开始处理  JPG  文件

   exifinfo . dwExifType   |=  ET_NOT_CLOSE_FILE ;

   exifinfo . ThumbnailPointer   =  NULL ;

   exifinfo . ThumbnailSize   =  0 ;

   exifinfo . UserCOM   =  0 ;

   exifinfo . UserCOMLength   =  0 ;

   m_pExifInfo   = & exifinfo ;

   nReturn   =  EXIF_Decode ( hFile );

   if ( nReturn >= 0   && ( m_pExifInfo -> dwExifType & ET_NOT_CLOSE_FILE ) )

   {

     m_pExifInfo -> hJpgFileHandle   =  hFile ;

   }

   else

   {

     CloseHandle ( hFile );

   }

   if ( nReturn < 0 )

   {

     return   nReturn ;

   }

   // 如果这个  JPG  文件中没有内存缓冲区

   if ( m_pExifInfo -> UserCOMLength <= 8 )

   {

     EXIF_ERR_OUT ( "This JPG file not include user comments buffer area!" );

     CloseHandle ( hFile );

     return   - 1 ;

   }

   SetFilePointer ( hFile ,  0 ,  0 ,  FILE_BEGIN );

   SetFilePointer ( hFile , ( DWORD ) m_pExifInfo -> UserCOM ,  0 ,  FILE_BEGIN );

   // 下面写入用户的注释

   // 写入编码方式

   WriteFile ( hFile ,  pszCommentType ,  8 , & dwWriteBytes ,  NULL );

   m_pExifInfo -> UserCOMLength   -=  8 ;   // 前面有  8  个字节的编码方式

   if ( m_pExifInfo -> UserCOMLength > dwWriteBytes )

   {

     WriteFile ( hFile ,  pszUserComments ,  dwCommentLength + 1 , & dwWriteBytes ,  NULL );

     nReturn   = ( int ) dwWriteBytes ;

   }

   else

   {

     WriteFile ( hFile ,  pszUserComments ,  m_pExifInfo -> UserCOMLength + 1 , & dwWriteBytes ,  NULL );

     nReturn   = ( int ) dwWriteBytes ;

   }

   // 再写入  /0

   //WriteFile(hFile, '/0', 1, &dwWriteBytes, NULL);

   return   nReturn ;

}

 

http://blog.vckbase.com/hengai/archive/2005/11/08/14612.html

图像元数据(Metadata) ——Exif信息分析 文章目录1、元数据1. 图片元数据2. 如何查看元数据2、图像Exif信息2.1 简介2.1 JPG文件结构2.2 Exif与TIFF的关系2.3 Exif元数据2.4 总结3、Exif工具3.1 Pillow库3.2 exiv23.3 exifread库3.4 piexif库4、Exif记录的信息(标签)参考文献 1、元数据 元数据(Matedata),又称中介数据、中继数据,为描述数据的数据(... 阅读详情

相关推荐

修改图像Exif数据: 5种使用 Python 读取和修改图像 EXIF 元数据的方法

5种使用 Python 读取和修改图像 EXIF 元数据的方法,包含完整示例代码

寻木2016的专栏 3660

Python pyecharts Boxplot图

现在能在网上找到很多很多的学习资源,有免费的也有收费的,当我拿到1套比较全的学习资源之前,我并没着急去看第1节,我而是去审视这套资源是否值得学习,有时候也会去问一些学长的意见,如果可以之后,我会对这套学习资源做1个学习计划,我的学习计划主要包括规划图和学习进度表。分享给大家这份我薅到的免费视频资料,质量还不错,大家可以跟着学习。

m0_57472099的博客 1332

jpg读取exif属性值

项目在开发过程中,需要读取JPG影像中的exif的GPS,相机参数,影像大小等参数,根据exif属性的格式定义,解析所需要信息的字段,成功提取内容。 Exif 编辑 Exif是一种图像文件格式,它的数据存储与JPEG格式是完全相同的。实际上Exif格式就是在JPEG格式头部插入了数码照片的信息,包括拍摄时的光圈、快门、白平衡、ISO、焦距、日期时间等各种和拍摄条件以及相机品牌、型号、色彩编码、拍

星星之火燃亮码空 3864

图像中的Exif信息及其处理

1.Exif 可交换图像文件格式(英语:Exchangeable image file format,官方简称Exif),是专门为数码相机的照片设定的文件格式,可以记录数码照片的属性信息和拍摄数据。EXIF可以附加于JPEG、TIFF、RIFF等文件之中,为其增加有关数码相机拍摄信息的内容和索引图或图像处理软件的版本信息[1]。 xif标准最初由日本电子工业发展协会(JEIDA - Japan Electronic Industry Development Association)制订,目前的最新版本是发布

机器人视觉感知 8971

修改图像Exif数据: 5种使用 Python 读取和修改图像 EXIF 元数据的方法_python读取exif信息(2)

EXIF 数据或可交换图像文件格式数据是存储在图像文件中的一组元数据。它提供了拍摄图像时所用相机设置的详细信息,如 GPS 坐标、快门速度、光圈、ISO 和焦距。此外,它还包括照片拍摄的日期和时间、地点以及其他技术细节。如果您想了解有关 EXIF 的更多信息,请参阅EXIF或文章保护您的照片:Exif 数据查看器和 Exif 数据移除器。只需几行代码,Python 就能从图像中提取并显示 EXIF 数据。这有助于轻松查看和分析图像元数据,而无需专业软件。

2401_84972870的博客 1668

JPG图像exif和XPM信息中GPS数据姿态数据航向角数据的提取

JPG图像的编码相关内容太多不在多说了大家随手能查很多资料。 今天重点说说图像数据中的GPS信息以及飞机、相机姿态角度数据提取。 JPG作为复杂的图像数据很多人都知道存在一个叫做EXIF的数据规范,在这个数据规范中,包含了相机数据、拍摄数据、厂家信息以及GPS信息这样很多个数据信息,其中已经有GPS信息,当然,这是按照EXIF信息元的标准来写入的,查相关资料还是比较充分,整个这个部分总体的概念就是...

laoleizi的博客 4368

【zz】缩略图的相关知识

所谓所缩略图(THUMBNAIL),是同存与JPEG图片文件夹下的THUMBNAIL图片{注:此数据为Windows系统文件,可通过/文件选项/查看/选择[显示所有文件和文件夹]、取消[隐藏受保护的操作系统文件]察看此数据}  Windows XP因为为了加快读写速度, XP默认对于JPG, BMP等常规图片格式不进行内容读写, 只读取图片文件内置的预览内容{THUMBNAIL}.  由于JPEG

百里鹤的专栏 1889

Java从照片中提取EXIF信息指南

本文还有配套的精品资源,点击获取 简介:在Java中读取照片的Exif信息是图像处理的一个重要方面,它包含了关于拍摄日期、时间、位置和相机设置等关键数据。本文介绍如何利用metadata-extractor库来提取JPEG、TIFF、HEIC等格式照片的Exif元数据。引入库后,通过几个简单步骤即可实现:创建Metadata对象,使用MetadataReader读取元数据,...

weixin_36364707的博客 2627

python通过pil模块获得图片exif信息的方法

本文实例讲述了python通过pil模块获得图片exif信息的方法。分享给大家供大家参考。python的pil模块功能超级强大,不但可以用来处理图片也可以用来获取图片的exif数据。python通过pil模块获得图片exif信息的方法。希望本文所述对大家的Python程序设计有所帮助。

csdn_manong1的博客 1263

.NET 3.0 中的图像EXIF信息检索指南

在C#中处理图像时,了解常见的图像文件格式是基础中的基础。图像文件格式众多,每种格式都有其特定的用途和优势。一些常见的格式如JPEG、PNG、BMP、GIF和TIFF等,各有各的特点。JPEG(联合摄影专家组)是一种广泛使用的有损压缩格式,适用于照片等连续色调图像。它通过舍弃一些图像细节来减小文件大小,导致在放大查看时会出现“马赛克”现象。PNG(便携式网络图形)格式支持无损压缩,是网页图像的理想选择,它没有版权问题,并能支持透明背景。

weixin_30995917的博客 1012

【IPAM】Netbox docker模式版本升级

NETBOX 是一个开源的网络资源管理系统,主要用于管理 IP 地址、机架、设备、接口等网络资源信息。下面是 NETBOX 的功能、优点和缺点的详细介绍。

u012153104的博客 1329

python读取与保存图片的exif信息

图片的exif文件格式中保存了很多信息,比如GPS经纬度,高度,焦距等信息。 在图片的属性中可以看到这些信息: 我们可以使用python来进行exif数据的读取和保存。 1. 首先安装piexif pip3 install piexif 2.exif数据读取代码 import piexif from PIL import Image # Read Image fname = './1.JPG' img = Image.open(fname) exif_dict = piexif.loa

Jeff_zjf的博客 1万+

Python+OpenCV实战:5分钟搞定机械臂手眼标定(眼在手上模式)

本文详细介绍了使用Python和OpenCV在5分钟内完成机械臂手眼标定(眼在手上模式)的实战教程。通过解析相机坐标系与机械臂基坐标系的转换关系,提供从数据采集到标定矩阵计算的全流程代码实现,帮助开发者快速解决AX=XB问题,提升机械臂视觉引导精度。

weixin_33670786的博客 497

图像的EXIF信息简介及获取!

一、什么是EXIF? EXIF信息,是可交换图像文件的缩写,是专门为数码相机的照片设定的,可以记录数码照片的属性信息和拍摄数据。EXIF最初由日本电子工业发展协会在1996年制定,版本为1.0。1998年,升级到2.1,增加了对音频文件的支持。2002年3月,发表了2.2版。EXIF可以附加于JPEG、TIFF、RIFF等文件之中,为其增加有关数码相机拍摄信息的内容和索引图或图像...

dulingwen的博客 5646

标准化降水指数介绍

Mckee et al.(1993)认为降水量的减少是导致干旱的主要因素,其他气候因子一般变化较小,对干旱产生的影响不大,因此SPI使用降水量作为唯一参数。SPI能较好表达因降水量的大小反映干旱状况,操作简单,所需资料仅为降水量,同时该干旱指数在各个地区和各个时段都具有良好的计算稳定性,是继PDSI之后另一种被广泛应用的干旱指数。𝐻(𝑥)是Γ分布求得的概率,并当𝐻(𝑥)>0.5时,S=1;式中,𝛼是形状参数,𝛽是尺度参数,𝑥是当月降水量,𝛤(𝛼)是Gamma函数,用极大似然估计法计算最佳的𝛼和𝛽,即。

weixin_44259522的博客 2857

用C++手把手教你连接SimNow期货模拟盘:从CTP API封装到第一个订单(附完整代码)

本文详细介绍了如何使用C++连接SimNow期货模拟盘,从CTP API的基础架构解析到实现第一个订单的完整流程。内容涵盖CTP API的封装、SimNow环境配置、交易通道实现、行情接收与处理等核心环节,并提供完整代码示例,帮助开发者快速掌握量化交易中的期货模拟盘连接技术。

weixin_27215337的博客 328

iOS 读取图片 exif 信息

1.Exif简介 可交换图像文件格式常被简称为Exif(Exchangeable image file format),是专门为数码相机的照片设定的,可以记录数码照片的属性信息和拍摄数据。 Exif可以附加于JPEG、TIFF、RIFF、EXIF、GPS等文件之中,为其增加有关数码相机拍摄信息的内容和索引图或图像处理软件的版本信息。 Exif信息以0xFFE1作为开头标记,后两个字节表示Ex

wenhaiwang的专栏 5618

博士申请-考核制经验分享(2)——个人简历

申博过程中一般在联系导师时就将个人简历作为邮件附件,有些学校也会在提交材料或者复试阶段提交个人简历。

weixin_49282401的博客 5523

python读取和写入EXIF信息

什么是EXIF信息呢? 百度百科:Exif是一种图象文件格式,它的数据存储与JPEG格式是完全相同的。实际上Exif格式就是在JPEG格式头部插入了数码照片的信息,包括拍摄时的光圈、快门、白平衡、ISO、焦距、日期时间等各种和拍摄条件以及相机品牌、型号、色彩编码、拍摄时录制的声音以及全球定位系统(GPS)、缩略图等。所有的JPEG文件以字符串“0xFFD8”开头,并以字符串“0xFFD9”结...

mmdev 4359

YOLOv11改进 - 卷积Conv | PConv(Pinwheel-shaped Conv): 风车状卷积用于红外小目标检测 | AAAI 2025

本文介绍了风车状卷积(PConv)和基于尺度的动态(SD)损失在YOLOv11中的结合应用。PConv采用不对称填充,通过特殊结构设计、卷积运算和分组卷积技术,能更好地适应红外小目标的像素高斯空间分布,在少量增加参数的情况下极大扩展感受野。SD损失可根据目标大小动态调整尺度和位置损失的影响。我们将PConv集成到YOLOv11的主干网络低层,并在相关配置文件中进行设置。实验证明,YOLOv11 - PConv在IRSTD - 1K和SIRST - UAVB数据集上取得显著性能提升,验证了方法的有效性和泛化能

魔改工程师的博客 1334

机器人中的数值优化(十五)——PHR增广拉格朗日乘子法

本系列文章主要是我在学习《数值优化》过程中的一些笔记和相关思考,主要的学习资料是深蓝学院的课程《机器人中的数值优化》和高立编著的《数值最优化方法》等,本系列文章篇数较多,不定期更新,上半部分介绍无约束优化,下半部分介绍带约束的优化,中间会穿插一些路径规划方面的应用实例

慕羽★的博客 2002

python读取图片的exif信息

python读取图片的exif信息图片的exif信息exifread第三方库相机的内参矩阵读取图片exif信息的代码 图片的exif信息 图片信息也是存在元数据的,网上官方称之为exif(exchange image file format),中文意思是交换图像文件格式。 每张图片都包含EXIF信息,它是可交换图像文件的缩写,是专门为数码相机的照片设定的,可以记录数码照片的属性信息和拍摄数据。 要注意的是有些图片是没有元数据的,比如压缩过的图片,元数据被破坏,无法探测,所以图片一定要是原图。 EXIF可以附

SiuooooBoom的博客 3003

PowerDesigner 数据库建模使用详解

PowerDesigner 数据库建模使用详解

congge 7081

EXIF.Js:读取图片的EXIF信息

首先,EXIF是什么? EXIF(Exchangeable Image File)是“可交换图像文件”的缩写,当中包含了专门为数码相机的照片而定制的元数据,可以记录数码照片的拍摄参数、缩略图及其他属性信息,简单来说,Exif信息是镶嵌在 JPEG/TIFF 图像文件格式内的一组拍摄参数,需要注意的是EXIF信息是不支持png,webp等图片格式的。(建议自己试的时候,现拍一张,把地理位...

aozhou9334的博客 1584

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

上一篇: android键盘映射
下一篇: 欺骗编译器取得ISurface对象的方法
eustoma
博客等级 码龄18年 79粉丝 54原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值