热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

文章目录简介安装读取EXIF保存EXIF插入EXIF删除EXIF复制EXIF将PIL读取的信息存入EXIF标签内容根据旋转信息旋转图片生成一套方向图片ExifToolGUI前端处理

文章目录

  • 简介
  • 安装
  • 读取 EXIF
  • 保存 EXIF
  • 插入 EXIF
  • 删除 EXIF
  • 复制 EXIF
  • 将 PIL 读取的信息存入 EXIF
  • 标签内容
  • 根据旋转信息旋转图片
  • 生成一套方向图片
  • ExifToolGUI
  • 前端处理
  • 参考文献


简介

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

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

test.jpg




安装

pip install piexif
pip install pillow

该库只有五个函数:

  • load(filename_or_bytes):获取 EXIF 数据(字典)
  • dump(exif_dict):以字节形式返回 EXIF 数据
  • insert(exif_bytes, filename):插入 EXIF 数据到图片中
  • remove(filename):删除图片的 EXIF 数据
  • transplant(filename1, filename2):将 EXIF 数据从 filename1 复制到 filename2




读取 EXIF

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

import piexifexif_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 piexifexif_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 piexifpiexif.remove('test.jpg')
for k, v in piexif.load('test.jpg').items():print(k, v)
# 0th {}
# Exif {}
# GPS {}
# Interop {}
# 1st {}
# thumbnail None




复制 EXIF

import piexifpiexif.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 Imageim = 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 piexifexif_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 Imagedef 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 Imageimg = 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:读取本地图片文件并显示

推荐阅读
author-avatar
263企业邮箱温州授权合作伙伴
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有