取相片的拍摄日期

Option Explicit
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
Private Type JpgHeadInfo
    iJpgSOI As Integer
    iJpgAPP1 As Integer
    iJpgAPP1Size As Integer '使用时要转换成long型
    sJpgExif As String * 4
    bJpgReserve(1) As Byte
    sJpgBigEndian As String * 2 '数据大小描述符(2个字节) 是 "Motorola" 的字节顺序, 数据的低位被存放在高地址,也就是 BigEndian. II:BigEndian;MM:Motorola
    iJpg2AFlag As Integer
    lJpgIFDOffset As Long 'IFD : 图像文件目录
    lJpgIFDCount As Integer
End Type
Private Type JpgIFD 'IFD : 图像文件目录
    iLableName As Integer
    iLabelType As Integer
    lLableSize As Long
    lLableData As Long
End Type

'取照相机的照片日期
Public Function JpgInfoDate(Optional sFileName As String) As String
    Dim bData() As Byte, aJpgIFD() As JpgIFD
    Dim JpgHI As JpgHeadInfo
    
    Dim iI As Long, bStr() As Byte
    
    ReDim bData(2048) As Byte
    If Dir(sFileName) = "" Then
        Exit Function
    End If
    Open sFileName For Binary Access Read As #1
    Get #1, , bData
    Close #1
    
    CopyMemory JpgHI, bData(0), Len(JpgHI) '能看懂就是高手了,不解释
    
    If Not Hex(JpgHI.iJpgSOI) = "D8FF" Then
        '非JPG文件
        Exit Function
    End If
    If Not Hex(JpgHI.iJpgAPP1) = "E1FF" Then
        'Exif也使用应用标记来插入数据, 但是Exif 使用 APP1(0xFFE1)标记来避免与JFIF格式的 冲突.
        Exit Function
    End If
    If Not JpgHI.sJpgExif = "Exif" Then
        'MM格式不处理
        Exit Function
    End If
    
    If Not JpgHI.sJpgBigEndian = "II" Then
        'MM格式不处理
        Exit Function
    End If
    If JpgHI.lJpgIFDCount <= 0 Then
        'IFD个数不对
        Exit Function
    End If
    
    ReDim aJpgIFD(JpgHI.lJpgIFDCount)
    
    CopyMemory aJpgIFD(0), bData(14 + JpgHI.lJpgIFDOffset), Len(aJpgIFD(0)) * (1 + JpgHI.lJpgIFDCount)
    
    For iI = LBound(aJpgIFD) To UBound(aJpgIFD)
'        Debug.Print Hex(aJpgIFD(iI).iLableName), Hex(aJpgIFD(iI).iLabelType), Hex(aJpgIFD(iI).lLableSize), Hex(aJpgIFD(iI).lLableData)
        If aJpgIFD(iI).iLabelType = 2 And aJpgIFD(iI).iLableName = &H132 Then '日文字
            ReDim bStr(aJpgIFD(iI).lLableSize)
            CopyMemory bStr(0), bData(aJpgIFD(iI).lLableData + 12), aJpgIFD(iI).lLableSize
            JpgInfoDate = Replace(StrConv(bStr, vbUnicode), vbNullChar, "")
            Exit Function
        End If
    Next
    
End Function
 

参考文献:


什么是 Exif?

基本上, Exif文件格式与JPEG 文件格式相同. Exif按照JPEG的规格在JPEG中插入一些 图像/数字相机 的信息数据以及缩略图像. 于是你能通过与JPEG兼容的互联网浏览器/图片浏览器/图像处理等一些软件 来查看Exif格式的图像文件. 就跟浏览通常的JPEG图像文件一样.
 

JPEG格式和标记

每一个JPEG文件的内容都开始于一个二进制的值 '0xFFD8', 并结束与二进制值'0xFFD9'. 在JPEG的数据 中有好几种类似于二进制 0xFFXX 的数据, 它们都统称作 "标记", 并且它们代表了一段JPEG的 信息数据. 0xFFD8 的意思是 SOI图像起始(Start of image), 0xFFD9 则表示 EOI图像结束 (End of image). 这两个特殊的标记的后面都不跟随数据, 而其他的标记在后面则会附带数据. 标记的基本 格式如下.

0xFF+标记号(1个字节)+数据大小描述符(2个字节)+数据内容(n个字节)

数据大小描述符(2个字节) 是 "Motorola" 的字节顺序, 数据的低位被存放在高地址,也就是 BigEndian. 请注意上面中的 "数据内容" 中包含他前面的数据大小描述符, 如果下面的是一个标记的话;

FF C1 00 0C

它就表示这个标记(0xFFC1) 的数据占 0x000C(等于12)个字节. 但是这个数据大小'12' 包含了 "数据大小" 描述符, 也就是在0x000C后面它只允许带有10 个字节大小的数据.

在JPEG 格式中, 最开始先是用一些标记来描述数据, 然后是放置 SOS数据流的起始(Start of stream) 标记. 在SOS标记的后面才是, 存放JPEG图像的数据流并终结于EOI标记.
 

SOI 标记 标记 XX 的大小=SSSS 标记 YY 的大小=TTTT SOS 标记 的大小=UUUU 图像数据流 EOI 标记
FFD8 FFXX SSSS DDDD...... FFYY TTTT DDDD...... FFDA UUUU DDDD.... I I I I.... FFD9

Exif使用的标记

0xFFE0~0xFFEF之间的标记被叫做 "应用标记", 它们在JPEG图像解码中不是必须存在的. 它们被使用于用户的应用程序之中. 例如, 老款的olympus/canon/casio/agfa 数字相机使用 JFIF(JPEG文件交换格式/JPEG File Interchange Format)来存储图像. JFIF 使用 APP0(0xFFE0) 标记来插入数字相机的配置信息数据和缩略图.

Exif也使用应用标记来插入数据, 但是Exif 使用 APP1(0xFFE1)标记来避免与JFIF格式的 冲突. 且每一个 Exif 文件格式都开始于它, 如;
 

SOI 标记 APP1 标记 APP1 数据 Other 标记
FFD8 FFE1 SSSS 457869660000 TTTT...... FFXX SSSS DDDD......


该图像文件从SOI(0xFFD8) 标记开始, 因此它是一个 JPEG 文件. 后面马上跟着 APP1 标记. 而它的所有 Exif数据都被存储在 APP1 数据域中. 上面的 "SSSS" 这部分表示 APP1 数据域 (Exif data area)的大小. 请注意这里的大小 "SSSS" 包含描述符本身的大小.

在 "SSSS"后面, 是 APP1 的数据. 其中第一个部分是一个特殊的数据,它用来标识是否是 Exif, 其值是ASCII 字符 "Exif" 和 两个0x00字节 的组合字符串.

在 APP1 标记域的后面是, 跟随着其他的 JPEG 标记.
 

Exif数据结构

Exif的数据结构 (APP1)大致如下面那样. 这是"Intel"字节序的情况, 并且它包含了JPEG 格式的 缩略图. 就像上面描述的那样, Exif 数据开始于ASCII字符 "Exif" 和2个字节的0x00, 后面才是 Exif的数据. Exif 使用 TIFF 格式来存储数据. 想获取TIFF的更多的细节的话, 请参考 "TIFF6.0规格说明(TIFF6.0 specification)".

 

FFE1 APP1 标记
SSSS APP1 数据 APP1 数据大小
45786966 0000 Exif 头
49492A00 08000000 TIFF 头
XXXX. . . . IFD0 (主图像) 目录
LLLLLLLL 连接到 IFD1
XXXX. . . . IFD0的数据域
XXXX. . . .    Exif 子IFD 目录
00000000 连接结束
XXXX. . . . Exif 子IFD的数据域
XXXX. . . .    Interoperability IFD Directory
00000000 连接结束
XXXX. . . . Interoperability IFD的数据域
XXXX. . . . Makernote IFD Directory
00000000 连接结束
XXXX. . . . Makernote IFD的数据域
XXXX. . . . IFD1(缩略图像) 目录
00000000 连接结束
XXXX. . . . IFD1的数据域
FFD8XXXX. . . XXXXFFD9 缩略图像

TIFF 头的结构

TIFF格式中前8个字节是 TIFF 头. 其中最开始的前2个字节定义了 TIFF 数据的字节序. 如果这个值是 0x4949="I I"的话, 就表示按照 "Intel" 的字节序(Little Endian) 来排列数据. 如果是 0x4d4d="MM", 则说明按照 "Motorola" 的字节序(Big Endian)来排列数据. 例如, 这个值是'305,419,896' (注意:16进制值为0x12345678). 在 Motorola 的 字节序中, 数据存储时的排列顺序为 0x12,0x34,0x56,0x78. 而用 Intel 的字节序的话, 它就是按照 0x78,0x56,0x34,0x12 来排序数据. 几乎所有的数字相机都是使用 Intel 的字节序. 不过 Ricoh 使用的是 Motorola 的. Sony 使用的是 Intel 字节序(除了 D700). Kodak 的DC200/210/240 使用的是 Motorola 字节序, 但是 DC220/260 使用的是 Intel的, 尽管它们都是使用在 PowerPC的平台上! 因此当我们需要使用 Exif 数据的值的时候, 我们必须每次都要检查它的字节序. 尽管 JPEG 数据仅仅是使用 Motorola 字节序, 但 Exif 却是允许这两种字节序存在的. 我不明白 Exif 为什么不把字节序修订成 Motorola的.

随后的两个字节是一个2字节长度的固定值 0x002A. 如果数据使用 Intel 字节序, 则这两个 字节的数据排列为 "0x2a,0x00". 如果是 Motorola 的, 则是 "0x00,0x2a". TIFF头的最后的 4个字节是到第一个 IFD(图像文件目录/Image File Directory, 将在下一节中描述)的偏移量. 这个偏移量是指从TIFF头("II" 或者 "MM")开始, 包含自己偏移量值的本身, 到下一个IFD为止的 长度的字节数. 通常地第一个 IFD 是紧挨着 TIFF 头出现的, 因此这个偏移量的值是 '0x00000008'.
 

字节序 标签标注 到第一个IFD的偏移量
"I I" or "MM" 0x002a 0x00000008

IFD : 图像文件目录

紧挨着 TIFF 头, 就是第一个 IFD:图像文件目录(Image File Directory). 它包含了图像 信息的数据. 在下面的表格中, 前两个字节('EEEE') 表示在IFD中有多少个目录项(directory entry) . 它后面存放就是目录项(每个项目大小为12字节) . 在最后一个目录项之后, 有 一个4个字节大小的数据(表格中'LLLLLLLL' ), 它意味着到下一个IFD的偏移量. 如果这个 值是'0x00000000', 则表示它是最后一个IFD 并且不在跟任何的 IFD 相连接.
 

EEEE 目录项的号码
TTTT ffff NNNNNNNN DDDDDDDD 项目 0
TTTT ffff NNNNNNNN DDDDDDDD 项目 1
. . . . . . . . . . . . . . .
TTTT ffff NNNNNNNN DDDDDDDD 项目 EEEE-1
LLLLLLLL 到下一个IFD的偏移量


上表中的'TTTT'(2个字节) 是一个标签的号码, 代表数据的种类. 'ffff'(2个字节)表示 数据的格式, 'NNNNNNNN'(4个字节)表示组件的数目. 'DDDDDDDD'(4个字节) 则是数据的 值或者到数据值的偏移量.
 

数据格式

数据格式 (上面表格中的'ffff') 的定义如下表示. "rational" 的意思是说明数据的 内容是一个分数, 它含有2个有符号/无符号的长整形(signed/unsigned long integer)值, 并且第一个值表示的是分子, 第二个值则是, 分母.

数据的值 1 2 3 4 5 6
格式 unsigned byte ascii strings unsigned short unsigned long unsigned rational signed byte
组件的大小(字节数) 1 1 2 4 8 1
数据的值 7 8 9 10 11 12
格式 undefined signed short signed long signed rational single float double float
组件的大小(字节数) 1 2 4 8 4 8


通过多个存储在'NNNNNNNN'数据区的'组件的大小(字节数)'你能得到所有数据的字节长度. 如果数据的长度小于4个字节, 则'DDDDDDDD' 就表示的是标签的值. 如果长度超过4字节, 则'DDDDDDDD' 里存放的就是所要存储数据的偏移量地址.

IFD数据结构

在Exif格式中, 第一个IFD 是IFD0(主图像IFD), 然后它连接到IFD1(缩略图IFD) 并且IFD 连接在此结束. 但是 IFD0/IFD1 不包含任何的数字相机的信息例如快门速度, 焦距等. IFD0 总是包含一个特殊的标签 Exif偏移量(0x8769), 它表示到 Exif子IFD 的偏移量. Exif子IFD 也是一个IFD 格式化的数据, 它包含了数字相机的信息.

在扩展Exif格式(Exif2.1/DCF)中, Exif子IFD还包含了特殊的标签 Exif Interoperability Offset (0xa005). 这个偏移量也指向Interoperability IFD. 根据 DCF 规格, 这个标签是必须的并且子IFD (主图像 IFD) 和 IFD1 (缩略图 IFD) 中可能也会包含Interoperability IFD. 通常, 仅仅主图像仅仅有这个标签.

另外一些数字相机也为Makernote(制造商注释)使用 IFD 数据格式; 这是生产商特定的 魔数(magic number)区域. 判断makernote 是否是IFD 格式是非常困难的, 必须仔细的 编程. 关于Makernote的信息请参考附录.

0000: 49 49 2A 00 08 00 00 00-02 00 1A 01 05 00 01 00
0010: 00 00 26 00 00 00 69 87-04 00 01 00 00 00 11 02
0020: 00 00 40 00 00 00 48 00-00 00 01 00 00 00

上面的是TIFF数据的开头部分, 对它的解读如下;

  • 前两个字节是 "I I", 所以字节序是 'Intel'.
  • 在地址0x0004~0x0007处存放的值是 0x08000000, 因此IFD0 从地址 '0x0008'开始
  • 在地址0x0008~0x0009处存放的值是 0x0200, 则表示IFD0有 '2' 个目录项.
  • 在地址0x000a~0x000b处存放的值是 0x1A01, 它意味着这是一个 XResolution(0x011A) 标签, 表示这是图像的水平分辨率.
  • 地址0x000c~0x000d处存放的值为 0x0500, 说明数据的格式是一个 unsigned rational(0x0005).
  • 地址0x000e~0x0011处存放的值是 0x01000000, 说明组件的数据只有 '1'个. Unsigned rational的数据大小是8字节(组件的大小), 因此数据的总长度是 1x8=8字节.
  • 总数居长度比4字节大了, 因此它后面的4个字节里面存放的是一个指向实际数据的偏移量地址.
  • 地址0x0012~0x0015处存放的是 0x26000000, 表示XResolution(水平分辨率) 数据的存储地址是0x0026
  • 地址0x0026~0x0029处存放的数据是 0x48000000, 说明分子的值为 72, 而地址0x002a~0x002d 处存放的是0x0100000000, 说明分母为 '1'. 因此XResoultion 的值是 72/1.
  • 地址0x0016~0x0017处存放的数据为0x6987, 表示下一个标签是 ExifOffset(0x8769). 这就是 指向 Exif子IFD的偏移量
  • 而它的数据格式是 0x0004, 即是一个无符号的长整形(unsigned long integer).
  • 这个标签只有一个组件. 无符号长整形的数据大小是4字节, 因此总数据长度为4字节.
  • 总数据长度是 4字节, 则说明下一个4字节的数据中存放的是Exif子IFD的偏移量.
  • 地址0x001e~0x0021处存放的是 0x11020000, 则说明Exif子IFD的开始地址是 '0x0211'.
  • 这是最后一个目录项, 接下来的4个字节存放的是下一个IFD的偏移地址.
  • 地址0x0022~0x0025处存放的是 0x40000000, 就可以知道下一个IFD的开始地址为 '0x0040'

缩略图

Exif格式中包含缩略图像(除了Ricoh RDC-300Z). 通常它被放到IFD1的后面. 缩略图有 3 种格式; JPEG 格式(JPEG 使用YCbCr), RGB TIFF 格式, YCbCr TIFF 格式. 在Exif2.1之后推荐使用JPEG 格式和160x120像素的尺寸. 根据 DCF 规格, 缩略图像必须 使用JPEG 格式以及图像的尺寸 固定为160x120 像素.
 

JPEG格式的缩略图

IFD1中的标签Compression(0x0103)如果是 '6', 则缩略图就是JPEG格式. 几乎所有的 Exif图像中缩略图都使用JPEG 格式. 在这种情况下, 你能从IFD1的JpegIFOffset(0x0201) 标签中得到缩略图的偏移量, 从标签JpegIFByteCount(0x0202)中得到缩略图的大小. 数据格式则是普通的 JPEG 格式, 也就是从0xFFD8处开始在0xFFD9处结束.
 

TIFF格式的缩略图

IFD1的标签Compression(0x0103)如果是 '1', 则缩略图的格式就没有经过压缩的 (就是TIFF 图像). 缩略图数据的开始点是标签 StripOffset(0x0111) , 缩略图的尺寸 就是标签 StripByteCounts(0x0117) 之和.

如果缩略图使用非压缩格式并且IFD1中的标签 PhotometricInterpretation(0x0106) 是 '2', 则缩略图使用了 RGB 格式. 在这种情况下, 你只要简单的把数据拷贝到计算机的RGB格式 中就能看到缩略图了(如 BMP 格式, 或者拷贝到 VRAM 目录下). Kodak DC-210/220/260 就使用 这个格式. 注意TIFF中存储的像素数据是'RGB' 顺序的, 而 BMP 里的存储顺序则是 'BGR' .
如果这个标签的值是 '6', 缩略图使用 YCbCr 格式. 如果你想要看到缩略图的话, 你必须把它 转换成 RGB 格式的. Ricoh RDC4200/4300, Fuji DS-7/300 和 DX-5/7/9 使用的是这种格式 (较新的 RDC5000/MX-X00 系列使用的是 JPEG). 在下一节中主要描述的就是Fuji DS相机的缩略图 的图像转换. 想要了解更多的信息, 请参考 TIFF6.0 规格说明.

在DX-5/7/9的场合, YCbCrSubsampling(0x0212) 的值是 '2,1', PlanarConfiguration(0x011c) 的 值是 '1'. 因此这种图像的数据排列是下面的那样.

Y(0,0),Y(1,0),Cb(0,0),Cr(0,0), Y(2,0),Y(3,0),Cb(2,0),Cr(3.0), Y(4,0),Y(5,0),Cb(4,0),Cr(4,0). . . .

括号中的数字代表的是像素坐标. DX 系列中000YCbCrCoefficients(0x0211) 的值是 '0.299/0.587/0.114', ReferenceBlackWhite(0x0214) 的值是 '0,255,128,255,128,255'. 于是把 Y/Cb/Cr 转换成 RGB 就是;

B(0,0)=(Cb-128)*(2-0.114*2)+Y(0,0)
R(0,0)=(Cr-128)*(2-0.299*2)+Y(0,0)
G(0,0)=(Y(0,0)-0.114*B(0,0)-0.299*R(0,0))/0.587

水平 subsampling 的值是 '2', 因此你能使用 Y(1,0)和 Cr(0,0)/Cb(0,0)计算出B(1,0)/R(1,0)/G(1,0). 根据ImageWidth(0x0100) 和 ImageLength(0x0101)的值可以重复这些转换.
 

Exif/TIFF使用的标签数

下面显示了 Exif/TIFF 使用的标签数. 如果这个标签组件数目的上限, CompoNo 一栏就代表这一数值. 如果这个数值没有, 则说明这儿没有上限值.

IFD0 (主图像)使用的标签

标签号 标签名 格式 组件数 描述
0x010e ImageDescription ascii string 用来描述图像. 双字节的字符码不能使用, 如 中文/韩文/日文.
0x010f Make ascii string 表示数字相机的制造商. 在 Exif 标准中, 这个标签是可选的, 但是在DCF中它是必需的.
0x0110 Model ascii string 表示数字相机的模块代码. 在 Exif 标准中, 这个标签是可选的, 但在DCF中它也是必需的.
0x0112 Orientation unsigned short 1
Value 0th Row 0th Column
1 top left side
2 top right side
3 bottom right side
4 bottom left side
5 left side top
6 right side top
7 right side bottom
8 left side bottom
当拍照时, 相机相对于场景的方向. 在右边表示的是'0th row' 以及 '0th column' 在视觉位置上的关系.
0x011a XResolution unsigned rational 1 图像的 显示/打印 分辨率. 缺省值是 1/72英寸, 但是它没有意义因为个人PC在 显示/打印 图像的时候不使用这个值.
0x011b YResolution unsigned rational 1
0x0128 ResolutionUnit unsigned short 1 XResolution(0x011a)/YResolution(0x011b)的单位. '1' 表示没有单位, '2' 意味着英寸, '3' 表示厘米. 缺省值是 '2'(英寸).
0x0131 Software ascii string 显示固件的版本号(数字相机的内部控制软件).
0x0132 DateTime ascii string 20 图像最后一次被修改时的日期/时间. 日期的格式是 "YYYY:MM:DD HH:MM:SS"+0x00, 一共 20个字节. 如果没有设置时钟或者数字相机没有时钟, 则这个域是用空格来填充. 通常, 它和DateTimeOriginal(0x9003)具有相同的值
0x013e WhitePoint unsigned rational 2 定义图像白点(white point/白点:在彩色分色、照相或摄影时作为色彩平衡测量用途的参考点) 的色度(chromaticity). 如果图像是用CIE标准照度 D65(著名的是 '光线/daylight'的国际标准), 这个值是 '3127/10000,3290/10000'.
0x013f PrimaryChromaticities unsigned rational 6 定义图像的原始色度. 如果图像使用 CCIR 推荐 709原始色度, 则这个值是 '640/1000,330/1000,300/1000,600/1000,150/1000,0/1000'.
0x0211 YCbCrCoefficients unsigned rational 3 当图像的格式是 YCbCr(JPEG的格式), 这个值表示转换成 RGB格式的一个常量. 通常, 这个值是'0.299/0.587/0.114'.
0x0213 YCbCrPositioning unsigned short 1 当图像的格式是 YCbCr 并且使用 '子采样/Subsampling'(色度数据的剪切值, 所有的数字相机都使用), 定义了subsampling 像素阵列的色度采样点. '1'表示像素阵列的中心, '2' 表示基准点.
0x0214 ReferenceBlackWhite unsigned rational 6 表示黑点(black point)/白点 的参考值. 在YCbCr 格式中,前两个值是 Y的黑点/白点, 下两个值是 Cb, 最后两个值是 Cr. 而在 RGB 格式中, 前两个表示R的黑点/白点, 下两个是 G, 最后两个是 B.
0x8298 Copyright ascii string 表示版权信息
0x8769 ExifOffset unsigned long 1 Exif 子IFD的偏移量


Exif 子IFD使用的标签

标签号 标签名 格式 组件数 描述
0x829a ExposureTime unsigned rational 1 曝光时间 (快门速度的倒数). 单位是秒.
0x829d FNumber unsigned rational 1 拍照时的光圈F-number(F-stop).
0x8822 ExposureProgram unsigned short 1 拍照时相机使用的曝光程序. '1' 表示手动曝光, '2' 表示正常程序曝光, '3' 表示光圈优先曝光, '4' 表示快门优先曝光, '5' 表示创意程序(慢速程序), '6' 表示动作程序(高速程序), '7'表示 肖像模式, '8' 表示风景模式.
0x8827 ISOSpeedRatings unsigned short 2 CCD 的感光度, 等效于 Ag-Hr 胶片的速率.
0x9000 ExifVersion undefined 4 Exif 的版本号. 用4个ASCII字符来存储. 如果图片是基于Exif V2.1的, 这个值是 "0210". 因为它不是一个用NULL(0x00)来终结的字符串,所以这里的类型是 'undefined'.
0x9003 DateTimeOriginal ascii string 20 照片在被拍下来的日期/时间. 使用用户的软件是不能被修改这个值的. 日期的格式是 "YYYY:MM:DD HH:MM:SS"+0x00, 一共占用20个字节. 如果数字相机没有设置时钟或者 数字相机没有时钟, 这个域使用空格来填充. 在Exif标准中, 这个标签是可选的, 但是在 DCF中是必需的.
0x9004 DateTimeDigitized ascii string 20 照片被数字化时的日期/时间. 通常, 它与DateTimeOriginal(0x9003)具有相同的值. 数据格式是 "YYYY:MM:DD HH:MM:SS"+0x00, 一共占用20个字节. 如果数字相机没有设置时钟或者 数字相机没有时钟, 这个域使用空格来填充. 在Exif标准中, 这个标签是可选的, 但是在 DCF中是必需的.
0x9101 ComponentsConfiguration undefined 表示的是像素数据的顺序. 大多数情况下RGB格式使用 '0x04,0x05,0x06,0x00' 而YCbCr 格式使用 '0x01,0x02,0x03,0x00'. 0x00:并不存在, 其他的对应关系为 0x01:Y, 0x02:Cb, 0x03:Cr, 0x04:Red, 0x05:Green, 0x06:Bllue.
0x9102 CompressedBitsPerPixel unsigned rational 1 JPEG (粗略的估计)的平均压缩率.
0x9201 ShutterSpeedValue signed rational 1 用APEX表示出的快门速度. 为了转换成原始的 'Shutter Speed'; 则先要计算2的ShutterSpeedValue次幂, 然后求倒数. 例如, 如果 ShutterSpeedValue 是 '4', 快门速度则是1/(24)=1/16秒.
0x9202 ApertureValue unsigned rational 1 拍照时镜头的光圈. 单位是 APEX. 为了转换成普通的 F-number(F-stop), 则要先计算出根号2 2 (=1.4142)的ApertureValue次幂. 例如, 如果ApertureValue 是 '5', F-number 就等于1.41425 = F5.6.
0x9203 BrightnessValue signed rational 1 被拍摄对象的明度, 单位是 APEX. 为了从BrigtnessValue(Bv)计算出曝光量(Ev), 你必须加上 SensitivityValue(Sv).
Ev=Bv+Sv   Sv=log2(ISOSpeedRating/3.125)
ISO100:Sv=5, ISO200:Sv=6, ISO400:Sv=7, ISO125:Sv=5.32.
0x9204 ExposureBiasValue signed rational 1 照片拍摄时的曝光补偿. 单位是APEX(EV).
0x9205 MaxApertureValue unsigned rational 1 镜头的最大光圈值. 你可以通过计算根号2的MaxApertureValue次幂来转换成普通的光圈 F-number (跟ApertureValue:0x9202的处理过程一样).
0x9206 SubjectDistance signed rational 1 到焦点的距离, 单位是米.
0x9207 MeteringMode unsigned short 1 曝光的测光方法. '0' 表示未知, '1' 为平均测光, '2' 为中央重点测光, '3' 是点测光, '4' 是多点测光, '5' 是多区域测光, '6' 部分测光, '255' 则是其他.
0x9208 LightSource unsigned short 1 光源, 实际上是表示白平衡设置. '0' 意味着未知, '1'是日光, '2'是荧光灯, '3' 白炽灯(钨丝), '10' 闪光灯, '17' 标准光A, '18' 标准光B, '19' 标准光C, '20' D55, '21' D65, '22' D75, '255' 为其他.
0x9209 Flash unsigned short 1 '0' 表示闪光灯没有闪光, '1' 表示闪光灯闪光, '5' 表示闪光但没有检测反射光, '7' 表示闪光且检测了反射光.
0x920a FocalLength unsigned rational 1 拍摄照片时的镜头的焦距长度. 单位是毫米.
0x927c MakerNote undefined 制造商的内部数据. 一些制造商如 Olympus/Nikon/Sanyo 等在这个区域中使用IFD 格式的数据.
0x9286 UserComment undefined 存储用户的注释. 这个标签允许使用两字节的德字符或者 unicode. 前8 个字节描述的是字符集. 'JIS' 是日文 (著名的有 Kanji).
'0x41,0x53,0x43,0x49,0x49,0x00,0x00,0x00':ASCII
'0x4a,0x49,0x53,0x00,0x00,0x00,0x00,0x00':JIS
'0x55,0x4e,0x49,0x43,0x4f,0x44,0x45,0x00':Unicode
'0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00':Undefined
0x9290 SubsecTime ascii string 一些数字相机每秒能拍摄 2~30 张照片, 但是DateTime/DateTimeOriginal/DateTimeDigitized 标签只能记录到秒单位的时间. SubsecTime 标签就是用来记录秒后面的数据(微秒).
例如, DateTimeOriginal = "1996:09:01 09:15:30", SubSecTimeOriginal = "130", 合并起来的原始的拍摄 时间就是 "1996:09:01 09:15:30.130"
0x9291 SubsecTimeOriginal ascii string
0x9292 SubsecTimeDigitized ascii string
0xa000 FlashPixVersion undefined 4 存储FlashPix 的版本信息. 如果图像数据是基于 FlashPix formar Ver.1.0, 则这个值为 "0100". 因为它不是一个用NULL(0x00)来终结的字符串,所以这里的类型是 'undefined'.
0xa001
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值