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


    需要读取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 0x20cf9  鳿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

  • 相关阅读:
    python操作MySQL数据库
    fs 小计
    yii xss模型安全
    freeswitch 音 视频 支持的编码
    MYSQL手工注入某日本网站
    Linux 系统 pptpd+radius+mysql 安装攻略
    mysql主从复制之mysql-proxy实现读写分离
    nginx-1.2.7+tcp_proxy_module负载均衡配置
    nginx-1.2.7 + tcp_proxy_module手动编译安装
    关于弹框的那些事~
  • 原文地址:https://www.cnblogs.com/eustoma/p/2415846.html
Copyright © 2020-2023  润新知