Python改变图片EXIF信息(修复图片上传后方向改变的BUG)

简介

EXIF,Exchangeable image file format,可交换图像文件格式,用于记录数码照片的属性信息和拍摄数据

EXIF 中有一个字段 Orientation,存放方向信息,前端上传图片到后端再获取,可能会发生方向改变的 BUG,只要后端接收到图片后按旋转信息旋转并删除该信息便可以解决(这步前端解决也可以

test.jpg




安装

pip install piexif
pip install pillow

该库只有五个函数:




读取 EXIF

随意拍一张照片并命名为 1.jpg

import piexif

exif_dict = piexif.load('1.jpg')
for k, v in exif_dict.items():
    print(k, v)
thumbnail = exif_dict.pop('thumbnail')  # 提取缩略图
if thumbnail:
    with open('thumbnail.jpg', 'wb+') as f:
        f.write(thumbnail)




保存 EXIF

import io
import piexif
from PIL import Image

# 读取图片并创建缩略图
bytesIO = io.BytesIO()
thumb_im = Image.open('test.jpg')
thumb_im.thumbnail((50, 50), Image.ANTIALIAS)
thumb_im.save(bytesIO, 'jpeg')
thumbnail = bytesIO.getvalue()

# 编辑EXIF数据
zeroth_ifd = {
    piexif.ImageIFD.Make: 'Canon',
    piexif.ImageIFD.XResolution: (96, 1),
    piexif.ImageIFD.YResolution: (96, 1),
    piexif.ImageIFD.Software: 'piexif'
}
exif_ifd = {
    piexif.ExifIFD.DateTimeOriginal: '2099:09:29 10:10:10',
    piexif.ExifIFD.LensMake: 'LensMake',
    piexif.ExifIFD.Sharpness: 65535,
    piexif.ExifIFD.LensSpecification: ((1, 1), (1, 1), (1, 1), (1, 1)),
}
gps_ifd = {
    piexif.GPSIFD.GPSVersionID: (2, 0, 0, 0),
    piexif.GPSIFD.GPSAltitudeRef: 1,
    piexif.GPSIFD.GPSDateStamp: '1999:99:99 99:99:99',
}
first_ifd = {
    piexif.ImageIFD.Make: 'Canon',
    piexif.ImageIFD.XResolution: (40, 1),
    piexif.ImageIFD.YResolution: (40, 1),
    piexif.ImageIFD.Software: 'piexif'
}

# 保存
exif_dict = {'0th': zeroth_ifd, 'Exif': exif_ifd, 'GPS': gps_ifd, '1st': first_ifd, 'thumbnail': thumbnail}
exif_bytes = piexif.dump(exif_dict)
im = Image.open('test.jpg')
im.save('result.jpg', exif=exif_bytes)

# 读取EXIF
exif_dict = piexif.load('result.jpg')
for k, v in exif_dict.items():
    print(k, v)
# 0th {271: b'Canon', 282: (96, 1), 283: (96, 1), 305: b'piexif', 34665: 115, 34853: 226}
# Exif {36867: b'2099:09:29 10:10:10', 41994: 65535, 42034: ((1, 1), (1, 1), (1, 1), (1, 1)), 42035: b'LensMake'}
# GPS {0: (2, 0, 0, 0), 5: 1, 29: b'1999:99:99 99:99:99'}
# Interop {}
# 1st {271: b'Canon', 282: (40, 1), 283: (40, 1), 305: b'piexif', 513: 391, 514: 1556}
# thumbnail b'……'

Windows 属性

使用 EXIF Viewer(k8ym) 查看




插入 EXIF

import piexif

exif_dict = piexif.load('test.jpg')
exif_dict['0th'] = {piexif.ImageIFD.Software: 'piexif'}  # 修改来源-程序名称
exif_bytes = piexif.dump(exif_dict)
piexif.insert(exif_bytes, 'test.jpg')
# piexif.insert(exif_bytes, 'test.jpg', 'result.jpg')




删除 EXIF

import piexif

piexif.remove('test.jpg')
for k, v in piexif.load('test.jpg').items():
    print(k, v)
# 0th {}
# Exif {}
# GPS {}
# Interop {}
# 1st {}
# thumbnail None




复制 EXIF

import piexif

piexif.transplant('result.jpg', 'test.jpg')
for k, v in piexif.load('test.jpg').items():
    print(k, v)
# 0th {305: b'piexif', 34665: 45}
# Exif {34850: 0, 36864: b'\x00\x00\x00', 36867: b'', 36868: b'', 37379: (0, 1), 40962: 512, 40963: 512}
# GPS {}
# Interop {}
# 1st {}
# thumbnail None




将 PIL 读取的信息存入 EXIF

import piexif
from PIL import Image

im = Image.open('test.jpg')
exif_dict = piexif.load(im.info['exif'])
width, height = im.size
exif_dict['0th'][piexif.ImageIFD.XResolution] = (width, 1)
exif_dict['0th'][piexif.ImageIFD.YResolution] = (height, 1)
exif_bytes = piexif.dump(exif_dict)
im.save('result.jpg', exif=exif_bytes)




标签内容

如旋转信息 Orientation

import piexif

exif_dict = piexif.load('1.jpg')  # 拍一张照片
if piexif.ImageIFD.Orientation in exif_dict['0th']:
    print(exif_dict['0th'][piexif.ImageIFD.Orientation])
# 6

详细查阅:EXIF 文件格式描述




根据旋转信息旋转图片

用于修复图片上传后方向改变的BUG,按旋转信息 Orientation 旋转并删除该信息

Orientation(274)0th Row0th Column
1topleft side
2topright side
3bottomright side
4bottomleft side
5left sidetop
6right sidetop
7right sidebottom
8left sidebottom

import piexif
from PIL import Image


def rotate_by_orientation(filename):
    img = Image.open(filename)
    if 'exif' in img.info:
        exif_dict = piexif.load(img.info['exif'])
        if piexif.ImageIFD.Orientation in exif_dict['0th']:
            orientation = exif_dict['0th'].pop(piexif.ImageIFD.Orientation)
            exif_bytes = piexif.dump(exif_dict)
            if orientation == 2:
                img = img.transpose(Image.FLIP_LEFT_RIGHT)
            elif orientation == 3:
                img = img.rotate(180)
            elif orientation == 4:
                img = img.rotate(180).transpose(Image.FLIP_LEFT_RIGHT)
            elif orientation == 5:
                img = img.rotate(-90, expand=True).transpose(Image.FLIP_LEFT_RIGHT)
            elif orientation == 6:
                img = img.rotate(-90, expand=True)
            elif orientation == 7:
                img = img.rotate(90, expand=True).transpose(Image.FLIP_LEFT_RIGHT)
            elif orientation == 8:
                img = img.rotate(90, expand=True)
            img.save(filename, exif=exif_bytes)
            print('保存成功')


if __name__ == '__main__':
    rotate_by_orientation('1.jpg')




生成一套方向图片

import piexif
from PIL import Image

img = Image.open('test.jpg')  # 打开一张没有方向信息且方向正确的图片
exif_dict = piexif.load(img.info['exif'])

exif_dict['0th'][piexif.ImageIFD.Orientation] = 1
exif_bytes = piexif.dump(exif_dict)
img.copy().save('1.jpg', exif=exif_bytes)

exif_dict['0th'][piexif.ImageIFD.Orientation] = 2
exif_bytes = piexif.dump(exif_dict)
img.copy().transpose(Image.FLIP_LEFT_RIGHT).save('2.jpg', exif=exif_bytes)

exif_dict['0th'][piexif.ImageIFD.Orientation] = 3
exif_bytes = piexif.dump(exif_dict)
img.copy().rotate(180).save('3.jpg', exif=exif_bytes)

exif_dict['0th'][piexif.ImageIFD.Orientation] = 4
exif_bytes = piexif.dump(exif_dict)
img.copy().rotate(180).transpose(Image.FLIP_LEFT_RIGHT).save('4.jpg', exif=exif_bytes)

exif_dict['0th'][piexif.ImageIFD.Orientation] = 5
exif_bytes = piexif.dump(exif_dict)
img.copy().rotate(-90, expand=True).transpose(Image.FLIP_LEFT_RIGHT).save('5.jpg', exif=exif_bytes)

exif_dict['0th'][piexif.ImageIFD.Orientation] = 6
exif_bytes = piexif.dump(exif_dict)
img.copy().rotate(90, expand=True).save('6.jpg', exif=exif_bytes)

exif_dict['0th'][piexif.ImageIFD.Orientation] = 7
exif_bytes = piexif.dump(exif_dict)
img.copy().rotate(90, expand=True).transpose(Image.FLIP_LEFT_RIGHT).save('7.jpg', exif=exif_bytes)

exif_dict['0th'][piexif.ImageIFD.Orientation] = 8
exif_bytes = piexif.dump(exif_dict)
img.copy().rotate(-90, expand=True).save('8.jpg', exif=exif_bytes)


Orientation(274)0th Row0th Column效果(保存后就能看到正常方向)
1topleft side
2topright side
3bottomright side
4bottomleft side
5left sidetop
6right sidetop
7right sidebottom
8left sidebottom




ExifToolGUI

还可以使用 ExifToolGUI(9qo8)(该链接已封装好):

  1. 下载 Windows Executable 后解压并改名为 exiftool
  2. 下载 ExifToolGUI 后解压
  3. exiftool 放入 GUI 同一文件夹




前端处理





参考文献

  1. Piexif Documentation
  2. 如何解决上传图片倒转的问题?
  3. Exif文件格式描述
  4. Python图像库Pillow (PIL) 入门
  5. JS Client-Side Exif Orientation: Rotate and Mirror JPEG Images
  6. FileReader:读取本地图片文件并显示
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XerCis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值