我有以下场景:
我正在使用 pyexiv2 进行 EXIF 操作。
问题:使用 wxpython 旋转图像时丢失的 EXIF 信息(包括缩略图)。
我做了什么:我在旋转图像之前读取 EXIF。我重置了 EXIF 中的方向字段。然后我旋转后把它放回去。
问题:
EXIF 内的缩略图不旋转。因此,图像和缩略图具有不同的方向。
有疑问吗?
除了 PIL 之外还有其他模块可以旋转图像并保留其 EXIF 信息吗?
是否有单独的 EXIF 字段用于缩略图方向?
有没有办法可以单独旋转缩略图?
感谢您的帮助...
这个解决方案对我有用: PIL 缩略图正在旋转我的图像?
无需检查是iPhone还是iPad: 如果照片有方向标签 – 旋转它。
from PIL import Image, ExifTags
try:
image=Image.open(filepath)
for orientation in ExifTags.TAGS.keys():
if ExifTags.TAGS[orientation]=='Orientation':
break
exif = image._getexif()
if exif[orientation] == 3:
image=image.rotate(180, expand=True)
elif exif[orientation] == 6:
image=image.rotate(270, expand=True)
elif exif[orientation] == 8:
image=image.rotate(90, expand=True)
image.save(filepath)
image.close()
except (AttributeError, KeyError, IndexError):
# cases: image don't have getexif
pass
之前:
之后:
如果您使用 Pillow >= 6.0.0,您可以使用内置
ImageOps.exif_transpose
函数根据其 exif 标签正确旋转图像:
from PIL import ImageOps
image = ImageOps.exif_transpose(image)
与@scabbiaza 的答案几乎相同,但使用转置而不是旋转(出于性能目的)。
from PIL import Image, ExifTags
try:
image=Image.open(filepath)
for orientation in ExifTags.TAGS.keys():
if ExifTags.TAGS[orientation]=='Orientation':
break
exif=dict(image._getexif().items())
if exif[orientation] == 3:
image=image.transpose(Image.ROTATE_180)
elif exif[orientation] == 6:
image=image.transpose(Image.ROTATE_270)
elif exif[orientation] == 8:
image=image.transpose(Image.ROTATE_90)
image.save(filepath)
image.close()
except (AttributeError, KeyError, IndexError):
# cases: image don't have getexif
pass
from PIL import Image
def reorient_img(pil_img):
img_exif = pil_img.getexif()
if len(img_exif):
if img_exif[274] == 3:
pil_img = pil_img.transpose(Image.ROTATE_180)
elif img_exif[274] == 6:
pil_img = pil_img.transpose(Image.ROTATE_270)
elif img_exif[274] == 8:
pil_img = pil_img.transpose(Image.ROTATE_90)
return pil_img
因为这是“python exif旋转”的最佳答案,所以我想添加一个附录以防您只需要旋转值而不需要PIL旋转图像 - 在我的例子中我使用QPixmap来旋转图像一个 QGraphicsView,所以我只需要 QPixmap 转换的角度。
上面使用 PIL 获取 exif 的 answer 相当慢。在我的测试中,它花费的时间是 piexif 库的 6 倍(6 毫秒 vs 1 毫秒),因为创建/打开 PIL.Image 需要很多时间。所以我建议在这种情况下使用
piexif
。
import piexif
def get_exif_rotation_angle(picture)
exif_dict = piexif.load(picture)
if piexif.ImageIFD.Orientation in exif_dict["0th"]:
orientation = exif_dict["0th"][piexif.ImageIFD.Orientation]
if orientation == 3:
return 180
elif orientation == 6:
return 90
elif orientation == 8:
return 270
else:
return None
else:
return None
picture
可以是文件路径或字节对象。
参考:https://piexif.readthedocs.io/en/latest/sample.html#rotate-image-by-exif-orientation
https://medium.com/@giovanni_cortes/rotate-image-in-django-when-saved-in-a-model-8fd98aac8f2a
这篇博文解释得很清楚。只要确保您尝试将
@receiver..
代码保留在 forms.py
或 models.py
中,因为我遇到了 cannot import model/view
错误。
保留
rotate_image
中的 models.py
方法 &
@receiver..
代码也在models.py
。
我还遇到了诸如“没有这样的目录”之类的错误。只需确保
full_path
正确设置为媒体文件夹即可。
我用过这条线
fullpath = os.path.join(os.path.dirname(BASE_DIR)) + instance.fimage.url
这是我的看法,支持所有 8 种可能的方向值。
from PIL import Image, ExifTags
for ExifOrientation in ExifTags.TAGS.keys():
if ExifTags.TAGS[ExifOrientation]=='Orientation':
break
def fix_orientation(image: Image) -> Image:
exif = image.getexif()
orientation = exif.get(ExifOrientation, 1)
transposition = {
1: None,
2: Image.FLIP_LEFT_RIGHT,
3: Image.ROTATE_180,
4: Image.FLIP_TOP_BOTTOM,
5: Image.TRANSPOSE,
6: Image.ROTATE_270,
7: Image.TRANSVERSE,
8: Image.ROTATE_90,
}[orientation]
if transposition == None:
return image
ret = image.transpose(transposition)
ret.getexif().pop(ExifOrientation, None)
return ret