0%

用 python 删除照片中的 exif 信息 & 一些常用 tips

前言

Python 快速实现去除照片中的 Exif 信息。

很多 App 会请求地理位置信息,即便你没有授权,但是只要你上传过照片(这里特指自己用手机拍的图片),大概率还是会通过 Exif 信息暴露地理位置,然后会收到非常流氓的周边推广及广告。

因此,决定用 Python 脚本删掉照片中的 Exif 信息。

实现

在 Python 中关于图片的操作,一般都会基于 PIL ,不再赘述。

读取 Exif

1
pip install exifread

exifread api

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def parse_image(path):
"""解析单张图片的信息"""
file = open(path, "rb")
tags = exifread.process_file(file)
info = Info()
for tag in tags.keys():
if tag not in ('JPEGThumbnail', 'TIFFThumbnail', 'Filename', 'EXIF MakerNote'):
print("Key: %s, value %s" % (tag, tags[tag]))

info.ImageWidth = tags["Image ImageWidth"]
info.ImageLength = tags["Image ImageLength"]
info.Make = tags["Image Make"]
info.Model = tags["Image Model"]

info.GPSLatitudeRef = tags["GPS GPSLatitudeRef"]
info.GPSLatitude = tags["GPS GPSLatitude"]
info.GPSLongitudeRef = tags["GPS GPSLongitudeRef"]
info.GPSLongitude = tags["GPS GPSLongitude"]

info.DateTimeOriginal = tags["EXIF DateTimeOriginal"]

return info

修改 Exif

1
pip install piexif

piexif api

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def modify_gps(path, copy=True):
# 读取图片
img = Image.open(path)

try:
exif_dict = piexif.load(img.info['exif'])
except IOError:
print('加载文件地理位置异常!')
return
exif_dict['GPS'][2] = ((0, 0), (0, 0), (0, 0))
exif_dict['GPS'][4] = ((0, 0), (0, 0), (0, 0))

print(exif_dict['GPS'])

exif_bytes = piexif.dump(exif_dict)

if copy:
modify_path = path.replace(".jpg", "_hack.jpg")
modify = img.copy()
modify.save(modify_path, "jpeg", exif=exif_bytes)
else:
img.save(path, "jpeg", exif=exif_bytes)

这里简单粗暴,直接修改成了 0,当然如果有兴趣做位置伪装,也可以写入特定地址的经纬度信息。

删除 Exif

1
2
3
4
5
6
7
def earse_exif(dir):
for root, dirs, files in os.walk(dir):
for name in files:
file = os.path.join(root, name)
if file.endswith("jpg") or file.endswith("jpeg"):
piexif.remove(file)
parse_image(file).to_string()

这里主要是 piexif.remove(src) 。非常方便,支持 jpeg 类型和 webp 类型的图片。内部完成了信息去除及二次写操作,直接调用即可。

拓展

Python toString()

实现类似 Java 中打印所有属性值的 toString() 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Info:
ImageWidth = ""
ImageLength = ""
Make = ""
Model = ""

GPSLatitudeRef = ""
GPSLatitude = ""

GPSLongitudeRef = ""
GPSLongitude = ""

DateTimeOriginal = ""

def to_string(self):
print('\n'.join(['%s:%s' % item for item in self.__dict__.items()]))

文件夹遍历

  • 单层

    1
    2
    3
    4
    def list_dir(path):
    files = os.listdir(path)
    for file in files:
    print(file)
  • 多层嵌套

    1
    2
    3
    4
    5
    6
    7
    8
    def list_dir(path):
    result = os.walk(path)
    for root, dirs, files in result:
    for name in files:
    file = os.path.join(root, name)
    print(file)
    for name in dirs:
    print(os.path.join(root, name))

接收命令行参数

1
2
3
4
5
if __name__ == '__main__':

print(sys.argv)
print(len(sys.argv))
print(str(sys.argv))
1
2
3
4
5
6
 > python ImageExif.py 1 2 3 4

['ImageExif.py', '1', '2', '3', '4']
5
['ImageExif.py', '1', '2', '3', '4']

之前写了一些脚本,比如用来抓图或者爬虫的,但是目标经常会发生变化,因此每次不得不打开代码重新编辑。其实可以用命令行参数的方式把要变更的信息直接传传递过去。用过 sys.argv 接口就可以了。

总结

Python 🐂 🍺。

加个鸡腿呗.