标签

2015年11月9日星期一

小谈Jpeg格式图片中的Exif信息

我们在使用数码照相机拍摄照片的时候,会发现拍出来的图片文件往往会带有一些额外信息,诸如拍摄日期,相机型号等等。实际上如果我们使用智能手机或带GPS功能的照相机,图片还会附加有其地理信息。了解图片存储机制的应该知道,Jpeg格式通过一定的压缩算法来保存其图片的图像信息,然而一个Jpeg文件(或其他格式图片文件)的内容远不只有图像本身。
可交换图像文件格式(EXIF,Exchangable Image File Format)是专门为数码照片设定的一套信息存储标准。其最初由日本电子工业发展协会在1996年制定。在摄影工业电子化的过程中已经完全普及。通过日本照相与成像产品协会(CIPA,Camera & Imaging Products Association)官方提供的EXIF 2.3的文档,我们可以了解图片额外信息在图片文件中的存储方式。
Jpeg图片文件通过0xFFXX(XX表示任意字节)的双字节来表示一个标记器(Marker),例如0xFFD8表示图片的开始(SOI,Start of Image),0xFFD9表示图片的结束(EOI,End of Image)。大部分Marker及其附属信息格式如下:
0xFF+Marker Number(1 byte)+Data size(2 bytes)+Data(n bytes)
FF后紧跟的1字节标记号,表示附加的Marker的类型,接后是两字节大小的数据表示数据区的大小N,然后便是大小为N字节的附加数据。0xFFE0-0xFFEF范围内的Marker表示Application Marker。EXIF对应的Marker标号是0xFFE1。其后两个字节的数据大小(需要注意的是所有的数字均以小端格式存储)。接下来是六个字节的特殊验证信息用于检验是否真正的EXIF数据,即“Exif”的ASCII码以及两字节的0x00。
通过UltraEdit工具打开一个jpg文件可以见到EXIF Marker和其后的校验信息
校验信息之后的第一个字节即为这段头部信息的结束位置,这个位置将用于接下来Offset(偏移值)的计算。图片信息通过IFD(Image File Directory,图片文件目录)的形式组织起来,TIFF头部后便是IFD 0。

上图截与EXIF的官方文档。在0号IFD块中,先有八字节大小的File Header,然后紧接着两字节的数据表示紧跟着的IFD的块数N。
这两个字节后面接着12N个字节的其他IFD块信息,也就是说在IFD 0中,其他IFD块的信息每一块由12字节来表示。其组织格式为:
Tag ID(2 bytes) + Data Type(2 bytes) + Data Count(4 bytes) + Value Offset(4 bytes)
Tag ID表示这一个IFD所表示的是这一个IFD块所表示的信息指的是什么,根据EXIF标准定义。例如,拍摄者的姓名(Artist)对应的Tag ID是315,x轴分辨率的Tag ID为282。
Data Type表示这一段数据的数据类型,举例列举部分对应关系:

  • 1 BYTE,表示一字节大小的无符号整数
  • 2 ASCII 一字节大小的ASCII码
  • 3 SHORT,两字节大小的无符号整数
  • 4 LONG,四字节大小的无符号整数
  • 5 RATIONAL,有理数,共八字节的大小,分别为两个LONG型整数p,q,表示有理数p/q
Data Count则表示数据的数目K,因此假如是Data Type为5,即RATIONAL有理数,而数据数目为3,则表示这段IFD块表示的数据大小一共为8×3=24个字节。也即数据大小为S×K,其中S为数据类型的大小。
Value Offset为4字节的数据,当S×K小于等于四字节的时候,说明数据刚好能够由这一块空间表示,这时候这四个字节即为数据本身,否则这四个字节表示一个指针,指向真正的数据位置(实际是一个偏移值,以TIFF头部信息结束位置为起始点的偏移值)。

举例:GPS信息的存储
在IFD 0中,大部分的附加信息仍然是通过偏移值的形式指引到其他的IFD块,例如GPS信息。GPS信息的Tag ID为34853(0x8825,小端),类型为Long,个数为1,其Value Offset表示一个指向GPS详细信息的位置的指针。
GPS的详细信息也是通过IFD形式组织起来的,因此在其起始位置为两个字节的数据(没有IFD 0的File Header),表示数据数目N,后面紧跟12N字节大小的详细数据。
在GPS IFD中,也有一个标准的Tag ID对应表,例如0表示GPS版本号,1表示南/北纬,2表示纬度。对应表如下:
LatitudeRef和LongitudeRef分别为一个字母的ASCII码,表示南北纬和东西经(通过字母N,S,E,W)。经纬度均由三个有理数表示,也即度/分/秒。海拔信息通过AltitudeRef和Altitude表示,AltitudeRef为0表示海平面以上,为1表示海平面以下。此外还有很多其他详细的信息,诸如接收器的速度等等。

为了验证我自己对文档的理解是否正确,我写了一个简单的Java程序,可以通过命令行修改一个jpg文件的GPS信息。源码地址在Github上。测试结果是成功的。(诸如Instagram,微信或微博等手机应用在发送带图片的动态时,如果用户选择添加位置,应用会读取图片EXIF信息中的地理信息)
以上为阅读EXIF文档后的有限总结。

没有评论 :

发表评论