用 Pillow 在上传前清除图片 EXIF 的 GPS 与设备信息

举报
yd_246123679 发表于 2026/11/04 07:22:06 2026/11/04
【摘要】 上传图片前,EXIF 中的 GPS、相机型号和 MakerNote 可能泄露位置与设备信息。本文用 Pillow 读取像素、处理方向并重建无元数据副本,再给出 exiftool 验证命令与边界说明。

用 Pillow 在上传前清除图片 EXIF 的 GPS 与设备信息

问题场景

很多手机照片在 JPEG 的 EXIF 中记录 GPS 坐标、机身序列号、镜头型号、拍摄时间,以及厂商私有的 MakerNote。业务把原图直接上传到对象存储后,这些字段会跟着进入 CDN、日志或第三方处理链路。即使页面不展示,下载原图仍可能读到。常见需求是:用户选择图片后,在上传前生成一份干净副本,只保留像素和必要色彩信息。

EXIF 可以理解为若干 IFD(Image File Directory)。GPS 信息由 IFD0 的 GPSInfo 指针(tag 0x8825)指向 GPS IFD;厂商私有的 MakerNote(tag 0x927C)通常位于 Exif SubIFD(指针 0x8769)中。删除指针即可让对应 IFD 不再被写出,但更稳妥的隐私做法是重建像素副本,让新文件根本不携带旧 EXIF。

最小实现:像素重建,不继承元数据

依赖 Pillow:

python -m pip install Pillow

strip_exif.py:

from PIL import Image, ImageOps

def strip_metadata(src: str, dst: str, quality: int = 90) -> None:
    with Image.open(src) as im:
        # 先按 EXIF Orientation 旋转像素,再把 EXIF 丢掉,避免方向错误
        im = ImageOps.exif_transpose(im)
        im.load()

        # 如业务需要色彩一致性,可保留 ICC;它不是 GPS/设备信息
        icc = im.info.get('icc_profile')

        # 调色板/CMYK 先转为常规模式,避免重建后保存失败
        if im.mode == 'P':
            im = im.convert('RGBA')
        elif im.mode == 'CMYK':
            im = im.convert('RGB')

        # 新建图像并只复制像素,不复制 info/exif/xmp
        clean = Image.new(im.mode, im.size)
        clean.paste(im)

        lower = dst.lower()
        if lower.endswith(('.jpg', '.jpeg')):
            if clean.mode not in ('RGB', 'L'):
                clean = clean.convert('RGB')
            clean.save(
                dst,
                format='JPEG',
                quality=quality,
                optimize=True,
                **({'icc_profile': icc} if icc else {}),
            )
        elif lower.endswith('.png'):
            clean.save(dst, format='PNG', optimize=True)
        else:
            clean.save(dst)

if __name__ == '__main__':
    import sys
    strip_metadata(sys.argv[1], sys.argv[2])

运行:

python strip_exif.py input.jpg output.jpg

这段代码的关键点:

  • ImageOps.exif_transpose 先把方向应用到像素,否则删除 Orientation 后图片可能横竖颠倒。
  • Image.new 加 paste 只复制像素,不继承原图的 info、EXIF、XMP;保存时也不传 exif=。
  • 保留 ICC 是可选项,目的是减少广色域图片的颜色偏差;ICC 不含 GPS。若要求零附加元数据,可以去掉 ICC。
  • JPEG 保存会重新编码,属于有损流程;quality 只是占位参数,按业务画质要求调整,不能声称无损。

如果必须保留部分 EXIF:定向删除

有些业务需要保留曝光参数,只想删除 GPS 与 MakerNote。可以在读取 EXIF 后删指针:

from PIL import Image, ImageOps

with Image.open('input.jpg') as im:
    im = ImageOps.exif_transpose(im)
    exif = im.getexif()

    exif.pop(0x8825, None)  # GPSInfo IFD
    exif.pop(0x8769, None)  # Exif SubIFD,MakerNote 常在其中
    exif.pop(0x927C, None)  # 顶层 MakerNote(如有)
    exif.pop(0x010F, None)  # Make
    exif.pop(0x0110, None)  # Model
    exif.pop(0x0131, None)  # Software

    im.save('output.jpg', exif=exif, quality=90)

注意:0x8769 一旦删除,Exif SubIFD 里的 MakerNote、镜头、曝光等会一起消失;这不是只删一个字段。不同厂商还可能把设备信息放在 IFD0 的其他标签里,逐项删除容易漏。隐私优先时,仍建议使用前面的像素重建方案。

用 exiftool 验证

先检查原图,确认确实存在 GPS 与设备标签:

exiftool -json -GPS:all -MakerNote:all -Make -Model -SerialNumber -Software input.jpg

再检查输出副本:

exiftool -json -GPS:all -MakerNote:all -Make -Model -SerialNumber -Software output.jpg

如果输出对象里只剩 SourceFile,没有 GPSLatitude、GPSLongitude、Make、Model、MakerNote* 等键,说明目标标签没有被写出。还可以看剩余 EXIF:

exiftool -EXIF:all output.jpg

保留 ICC 时,exiftool output.jpg 可能仍显示 ICC_Profile,这属于色彩配置,不是 GPS 或设备信息。若要验证完全无 EXIF,以 -EXIF:all 无输出为准。

边界与限制

  • 本文示例以 JPEG 为主。PNG、WebP 也可能带 EXIF/XMP;思路相同,但保存参数和验证标签要按格式调整。HEIC 需要额外插件,不在示例范围内。
  • 重新保存 JPEG 会重新编码,可能损失画质;对原图归档场景,可考虑用 exiftool 做无损元数据删除,再上传副本。
  • 动图(如 GIF/WebP 动画)用 Image.open 默认只处理当前帧,不能直接套用上述流程。
  • 超大图片会占用较多内存;生产环境应限制上传尺寸,并处理 Pillow 的解压炸弹警告。
  • 删除元数据不等于内容安全:图片像素中仍可能有屏幕、证件、人脸等敏感信息,需要配合业务审核。
  • 上传链路还应使用服务端校验,不能只依赖前端处理;客户端生成的副本仍可能被绕过。
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。