前两天python群中一位女神发了一张照片,虽然只是个风景照。但是我突然想起之前在读 <
时书中有讲到在图片中包含exif(exchange image file format)
,exif标准定义了如何存储图片和音频文件的标准,包含文档的作者,修改时间甚至有可能包含照片的GPS位置信息。(事实上不止图片,文档,表格,音频,视频都有类似exif的元数据)。
from PIL import Image
from PIL.ExifTags import TAGS
img = Image.open(r"1.jpg")
for tag,value in img._getexif().items():
print(TAGS.get(tag,tag),value)
程序运行结果如下:
('ImageWidth', 5312)
('ImageLength', 2988)
('JpegIFByteCount', 0)
('WhiteBalance', 0)
('UserComment', u'\n')
('MeteringMode', 65535)
('LightSource', 0)
('Flash', 0)
('FocalLength', (480, 100))
('Orientation', 0)
('Make', u'samsung')
('Model', u'SM-N9100\x00')
('DateTime', u'2016:05:07 15:32:37')
('JpegIFOffset', 258)
('ExifOffset', 228)
但是经过我各种百度和谷歌之后,并没有找到PIL修改exif信息的操作,希望知道如何用PIL操作exif的各位看官在下面留个言。为此我不得不寻求与其他库,比如piexif(https://pypi.python.org/pypi/piexif)。
根据官方文档显示,piexif只有五个函数,使用起来确实很简单。本文就不充当文档解释的工作了,直接给一个完整的自己写的class。
import piexif
from piexif import ImageIFD # 0th
from piexif import ExifIFD # Exif
from piexif import GPSIFD # GPS
from piexif import InteropIFD #interop
class Exif(dict):
Group_0th = "0th"
Group_1st = "1st"
Group_Exif = "Exif"
Group_GPS = "GPS"
Group_Interop = "Interop"
Group_Thumbnail = "thumbnail"
_unkown_tag = {"name":"unkown","type":"unkown"}
def __init__(self,path):
dict.__init__(self)
self.__name = path
self.update(piexif.load(self.__name))
def pretty_dict(self):
"""print exif info"""
ret_dict = {}
for group,group_value in self.items():
ret_dict.setdefault(group,{})
if group_value is not None and group_value:
for tag,value in group_value.items():
name = piexif.TAGS[group].get(tag,self._unkown_tag)["name"]
ret_dict[group][name] = value
return ret_dict
def as_byte(self):
"""for raw write exif to image"""
return piexif.dump(self)
def write(self,path=None):
piexif.insert(self.as_byte(),path or self.__name)
def insert_exif(self,group,tags):
"""group is one of Group_0th,Group_1st,Group_Exif,
Group_GPS,Group_Interop,Group_Thumbnail
tags reference class ImageIFD,ExifIFD,GPSIFD,InteropIFD
"""
if isinstance(tags,dict):
for tag,value in tags.items():
self[group][tag] = value
elif isinstance(tags,list) or isinstance(tags,tuple):
for tag,value in tags:
self[group][tag] = value
def remove_exif(self,group,tag=None):
"""group is one of Group_0th,Group_1st,Group_Exif,
Group_GPS,Group_Interop,Group_Thumbnail
tags reference class ImageIFD,ExifIFD,GPSIFD,InteropIFD
"""
if tag is None:
self[group] = {}
elif tag in self[group]:
del self[group][tag]
下图是一个添加了exif信息的图片头:
FF D8 是jpg文件的标识头
FF E1 Exif头部开始标志
00 29 根据jpeg标准,29(注意,这是十六进制)是段内容和段长度本身但不包括段标识和段类型的长度
45 79 69 66 00 00 Exif内容的前缀(这是固定的)
4D 4D 00 2A …… 45 49 00 FF Exif内容
可以看出,exif信息只是填充在jpg文件中的一个FF E1打头的注释段,填充在文件头部。