您好,欢迎来到99网。
搜索
您的当前位置:首页读Exif格式的代码

读Exif格式的代码

来源:99网
////////////////////////////////////////////////////////////////////////////////

// .h 文件

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

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

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

文件名称: exif.h

版本号 : 1.0.0

作者: hengai

修改纪录:

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

int EXIF_Read(LPCTSTR pszJpgFileName, EXIFINFO* pExifIn fo)

即可获取 EXIF 信息。EXIF信息包含在参数 pExifInfo 中在定义了 #define EXIF_OUTPUT_ERRMSG (默认下已经定义)后可以使用

LPCTSTR EXIF_GetErrorString(); 获取出错信息

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

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

#ifndef STATIC

#define STATIC static

#endif

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

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

// 定义常量

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

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

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

typedef enum ECT{

CT_ASCII = 0,

CT_UNICODE,

CT_JIS,

CT_UNDEFINE

}COMMENT_TYPE;

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

// 定义需要的结构体

#define ET_NOT_CLOSE_File0x00000001//最后不关闭打开的文件句柄

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

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

#define ET_MALLOC_MAKERCOM0x00000008//是否拷贝厂商注释,调用者需要使用 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; //缩略图的大小(字节流 ThumbnailPointe r 的长度)

//如果<=0表示该 JPG 文件没有缩略图HFile hJpgFileHandle; //返回打开的 JPG 文件句柄。必须 dwExi fType&ET_NOT_CLOSE_File == TRUE 才是有效句柄

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

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

} EXIFINFO;

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

// 接口函数

int EXIF_Read(LPCTSTR pszJpgFileName, EXIFINFO* pExifInfo); LPCTSTR EXIF_GetErrorString();

int EXIF_AddUserComments(LPCTSTR pszJpgFileName, LPCTSTR

pszUserComme nts, 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_FORMATS12

#define FMT_BYTE1//Format Byte

#define FMT_STRING2

#define FMT_USHORT3

#define FMT_ULONG4

#define FMT_URATIONAL5

#define FMT_SBYTE6

#define FMT_UNDEFINED7

#define FMT_SSHORT8

#define FMT_SLONG9

#define FMT_SRATIONAL10

#define FMT_SINGLE11

#define FMT_DOUBLE12

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

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

#ifndef M_SOI

#define M_SOF00xC0// Start Of Frame N

#define M_SOF10xC1// N indicates which compression proc ess

#define M_SOF20xC2// Only SOF0-SOF2 are now in common u se

#define M_SOF30xC3

#define M_SOF50xC5// NB: codes C4 and CC are NOT SOF ma rkers

#define M_SOF60xC6

#define M_SOF70xC7

#define M_SOF90xC9

#define M_SOF100xCA

#define M_SOF110xCB

#define M_SOF130xCD

#define M_SOF140xCE

#define M_SOF150xCF

#define M_SOI0xD8// Start Of Image (beginning of datas tream)

#define M_EOI0xD9// End Of Image (end of datastream) #define M_SOS0xDA// Start Of Scan (begins compressed d ata)

#define M_JFIF0xE0// Jfif marker

#define M_EXIF0xE1// Exif marker

#define M_COM0xFE// COMment

//定义 APP 标识(SECTION)

#define M_APP00xE0

#define M_APP10xE1

#define M_APP20xE2

#define M_APP30xE3

#define M_APP40xE4

#define M_APP50xE5

#define M_APP60xE6

//...

#endif

// Describes tag values

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

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

//下面是主要信息

#define TAG_MAKE0x010F//相机DC 制造商

#define TAG_MODEL0x0110//DC 型号

#define TAG_ORIENTATION0x0112//拍摄时方向,例如向左手旋转D C 90度拍摄照片

#define TAG_XRESOLUTION0x011A//X 轴分辨率

#define TAG_YRESOLUTION0x011B//Y 轴分辨率

#define TAG_RESOLUTIONUNIT0x0128//分辨率单位,例如 inch, cm #define TAG_DATATIME0x0132//日期时间

#define TAG_YBCR_POSITION0x0213//YCbCr 位置控制,例如居中#define TAG_COPYRIGHT0x8298//版权

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

//

#define TAG_IMAGEWIDTH0x0001//图像宽度

#define TAG_IMAGEHEIGHT0x0101//图像高度

//BOOKMARK

//辅助信息

#define TAG_EXPOSURETIME0x829A//曝光时间,例如 1/30 秒

#define TAG_FNUMBER0x829D//光圈,例如 F2.8

#define TAG_EXIF_VERSION0x9000//EXIF 信息版本

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

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

#define TAG_COMPONCONFIG0x9101//ComponentsConfiguration 色彩空间配置

#define TAG_COMPRESS_BIT0x9202//每像素压缩位数

#define TAG_SHUTTERSPEED0x9201//快门速度,例如 1/30 秒

#define TAG_APERTURE0x9202//光圈值,例如 F2.8

#define TAG_BRIGHTNESS0x9203//亮度

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

#define TAG_MAXAPERTURE0x9205//最大光圈值,例如 F2.8

#define TAG_SUBJECT_DISTANCE0x9206//拍摄物距离,例如 3.11 米

#define TAG_METERING_MODE0x9207//测光模式,例如矩阵

#define TAG_WHITEBALANCE0x9208//LightSource 白平衡

#define TAG_FLASH0x9209//是否使用闪光灯

#define TAG_FOCALLENGTH0x920A//焦距,例如 7.09mm

#define TAG_USERCOMMENT0x9286//用户注释

#define TAG_MAKE_COMMENT0x927C//厂商注释。这个版本不提供(20 05-10-13)

#define TAG_SUBSECTIME0x9290//SubSecTime

#define TAG_SUBTIME_ORIGINAL0x9291//SubSecTimeOriginal

#define TAG_SUBTIME_DIGITIZED0x9292//SubSecTimeDigitized

#define TAG_FLASHPIXVERSION0x00A0//Flash Pix 版本

#define TAG_COLORSPACE0x01A0//色彩空间,例如 sRGB

#define TAG_PIXEL_XDIMENSION0x02A0//

#define TAG_PIXEL_YDIMENSION0x03A0//

#define TAG_

//EXIFR98

//缩略图

#define TAG_INTEROP_OFFSET0xa005//偏移

#define TAG_FOCALPLANEXRES0xA20E//焦平面X轴分辨率,例如 1024 000/278

#define TAG_FOCALPLANEYRES0xA20F//焦平面X轴分辨率,例如 7680 00/209

#define TAG_FOCALPLANEUNITS0xA210//焦平面分辨率单位

#define TAG_EXIF_IMAGEWIDTH0xA002//EXIF 图像宽度(就是这张 JPG 图像)

#define TAG_EXIF_IMAGELENGTH0xA003//EXIF 图像高度

#define TAG_EXPOSURE_PROGRAM0x8822//

#define TAG_ISO_EQUIVALENT0x8827//

#define TAG_COMPRESSION_LEVEL0x9102//

#define TAG_THUMBNAIL_OFFSET0x0201//缩略图偏移

#define TAG_THUMBNAIL_LENGTH0x0202//缩略图大小

#define TAG_GPS_VERSIONID0x0000//GPS 版本

#define TAG_GPS_LATITUDEREF0x0001//纬度参考,例如南纬

#define TAG_GPS_LATITUDE0x0002//纬度值

#define TAG_GPS_LONGITUDEREF0x0003//经度参考,例如东经

#define TAG_GPS_LONGITUDE0x0004//经度值

#define TAG_GPS_ALTITUDEREF0x0005//海拔高度参考

#define TAG_GPS_ALTITUDE0x0006//海拔

#define TAG_GPS_TIMESTAMP0x0007//时间戳

#define TAG_GPS_SATELLITES0x0008//卫星

#define TAG_GPS_STATUS0x0009//状态

#define TAG_GPS_MEASUREMODE0x000A//

#define TAG_GPS_DOP0x000B//

#define TAG_GPS_SPEEDREF0x000C//

#define TAG_GPS_SPEED0x000D//

#define TAG_GPS_TRACKREF0x000E//

#define TAG_GPS_TRACK0x000F//

#define TAG_GPS_IMGDIRECTIONREF0x0010//

#define TAG_GPS_IMGDIRECTION0x0011//

#define TAG_GPS_MAPDATUM0x0012//

#define TAG_GPS_DESTLATITUDEREF0x0013//

#define TAG_GPS_DESTLATITUDE0x0014//

#define TAG_GPS_DESTLONGITUDEREF0x0015//

#define TAG_GPS_DESTLONGITUDE0x0016//

#define TAG_GPS_DESTBEARINGREF0x0017//

#define TAG_GPS_DESTBEARING0x0018//

#define TAG_GPS_DESTDISTANCEREF0x0019//

#define TAG_GPS_DESTDISTANCE0x001A//

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

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

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 orde r

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

STATIC int EXIF_Get16u(void * Short)

{

if (m_MotorolaOrder)

{

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

}

else

{

return (((unsigned char *)Short)[1] << 8) | ((unsigned char *)Sho rt)[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 orde r

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

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); br eak;

case FMT_SLONG: Value = EXIF_Get32s(ValuePtr); br eak;

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

*/

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 w on't fit in our structure.

for (a=2;a{

ch = Data[a];

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

if ((ch>=0x20) || ch == '\\n' || ch == '\')

{

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

}

else

{

Comment[nch++] = '?';

}

}

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

//if (ShowTags) printf(\"COM marker comment: %s\\n\

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 d wFilePointerBeforeReadData,

UCHAR *DirStart, UCHAR *OffsetBase, C ONST 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\");

return0;

}

for (de=0;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 posi tive large

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

return0;

}

BytesCount = Components * m_BytesPerFormat[Format];

if (BytesCount > 4)

{

OffsetVal = EXIF_Get32u(TagEntry+8);

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

if (OffsetVal+BytesCount > ExifLength)

{

//JPG 文件内容遭到破坏

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

return0;

}

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 醆c f9 診cf9 赲cf9 譢cf9 cf9 蔦cf9 蚛cf9 礬cf9 腬cf9 譢cf9 頫cf9 篭cf9 骪cf9 肻cf9 鎈cf9 蘚cf9 頫cf9 砛cf9 鋅cf9 縗cf9 誠cf9 竆cf 9 馶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\

{

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

{

char c;

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

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

{

strncpy(m_exifinfo->Comments, (char*)ValuePtr+a, MAX_CO MMENT-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(Valu ePtr, 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_ConvertAnyForma t(ValuePtr, Format)*log(2)*0.5);//ATTENTION

m_exifinfo->ApertureFNumber = (float)(EXIF_ConvertAnyFormat(V aluePtr, 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);

//目标距离(例如 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, F ormat);

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))); }-*/

//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(Value Ptr, Format);

break;

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

case TAG_FOCALPLANEYRES:

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

break;

case TAG_RESOLUTIONUNIT:

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

{

case1: m_exifinfo->ResolutionUnit = 1.0f; break; // 1 inch

case2: m_exifinfo->ResolutionUnit = 1.0f; break; //

case3: m_exifinfo->ResolutionUnit = 0.3937007874f; break; // 1 centimeter

case4: m_exifinfo->ResolutionUnit = 0.0393*******f; break; // 1 millimeter

case5: m_exifinfo->ResolutionUnit = 0.00003937007874f; // 1 micrometer

}

break;

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

case TAG_FOCALPLANEUNITS:

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

{

case1: m_exifinfo->FocalplaneUnits = 1.0f; break; // 1 inch

case2: m_exifinfo->FocalplaneUnits = 1.0f; break; //

case3: m_exifinfo->FocalplaneUnits = 0.3937007874f; break; // 1 centimeter

case4: m_exifinfo->FocalplaneUnits = 0.0393*******f; break; // 1 millimeter

case5: m_exifinfo->FocalplaneUnits = 0.00003937007874f;break; // 1 micrometer//

}

break;

//曝光补偿信息

case TAG_EXPOSURE_BIAS:

m_exifinfo->ExposureBias = (float) EXIF_ConvertAnyFormat(ValueP tr, 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(ValueP tr, 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(Value Ptr, 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, For mat);

break;

//缩略图的大小

case TAG_THUMBNAIL_LENGTH:

ThumbnailSize = (unsigned)EXIF_ConvertAnyFormat(ValuePtr, For mat);

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\");

return0;

}

EXIF_ProcessExifDir(DataStart, dwFilePointerBeforeReadData, Sub dirStart, OffsetBase, ExifLength, m_exifinfo, LastExifRefdP);

continue;

}

} //end for {for (de=0;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\");

return0;

}

EXIF_ProcessExifDir(DataStart, dwFilePointerBeforeReadData, Sub dirStart, 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+dwFilePointerBeforeReadDa ta;

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

memcpy(m_exifinfo->ThumbnailPointer, pThumbnailData, Thumbnai lSize);

}

else

{

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

}

m_exifinfo->ThumbnailSize = ThumbnailSize;

}

}

return TRUE;

}

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

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

参数:

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 dw FilePointerBeforeReadData,

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\");

return0;

}

}

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

if (memcmp(CharBuf+6,\"II\

{

m_MotorolaOrder = 0; //

}

else if (memcmp(CharBuf+6,\"MM\

{

m_MotorolaOrder = 1; //

}

else

{

EXIF_ERR_OUT(\"Invalid Exif alignment marker.\");

return0;

}

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

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

{

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

return0;

}

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

FirstOffset = EXIF_Get32u(CharBuf+10);

if (FirstOffset < 8 || FirstOffset > 16)

{

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

return0;

}

LastExifRefd = CharBuf;

//开始处理 EXIF 信息

if (!EXIF_ProcessExifDir(DataStart, dwFilePointerBeforeReadData,

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

{

return0;

}

// 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->F ocalplaneUnits / m_pExifInfo->FocalplaneXRes);

}

return1;

}

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 component s, %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: //到了数据区

return1;

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 个T AG

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

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

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

Sections[nSectionsRead].Data=0;

break;

case M_EXIF:

//EXIF 信息 TAG

if (memcmp(Data+2, \"Exif\

{

m_pExifInfo->IsExif = EXIF_process_EXIF(Data, dwFilePointerBe foreReadData, (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\arker, nSectionLength);

break;

}

}

return1;

}

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

函数声明:

参数:

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 lpSecur ityAttributes

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

pszUserComme nts, 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 N ULL!\");

return -1;

}

if(dwWriteBytes > strlen(pszUserComments))

{

EXIF_ERR_OUT(\"dwWriteBytes must be bigger or equal than the lengt h 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 lpSecur ityAttributes

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, &dwWriteByte s, 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;

}

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- 99spj.com 版权所有 湘ICP备2022005869号-5

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务