使用Python而不使用PIL(包括缩略图)在EXIF中指定方向旋转图像

ATO*_*TOA 19 python exif image ios

我有以下场景:

  • 我正在将iPhone中的图像和EXIF信息发送到我的Pyhon套接字服务器.
  • 我需要根据拍摄图像时的实际方向正确定位图像.我知道IOS总是将图像保存为Landscape Left并将实际方向添加为EXIF字段(EXIF.Image.Orientation).
  • 我正在阅读EXIF字段以查看实际方向.然后我使用wxpython将图像旋转到正确的方向.

我正在使用pyexiv2进行EXIF操作.

问题:EXIF信息包括使用wxpython旋转图像时丢失的缩略图.

我做了什么:我在旋转图像之前正在阅读EXIF.我重置了EXIF中的方向字段.然后我在轮换后把它放回去.

问题:

EXIF内的缩略图不会旋转.因此,图像和缩略图具有不同的方向.

有问题吗?

是否有除PIL之外的任何模块来旋转图像以保留其EXIF信息?

是否有单独的EXIF字段用于缩略图方向?

有没有办法可以单独旋转缩略图?

谢谢你的帮助...

sca*_*aza 63

这个解决方案适合我: 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=dict(image._getexif().items())

    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
Run Code Online (Sandbox Code Playgroud)

之前:

之前

后: 后

  • 它也会旋转缩略图吗? (2认同)
  • PIL 图像 im0 的旋转度作为一个非常不Pythonic的单行: `deg = {3:180,6:270,8:90}.get(im0._getexif().get(274,0),0) if hasattr(im0,'_getexif') else 0` (2认同)
  • 当我这样做时,生成的图像现在已旋转,但 EXIF 旋转信息仍在文件中,因此当我使用 Safari 打开它时,旋转会应用两次(第一次是在转置图像中硬编码,第二次是在转置图像中)时间,因为 Safari 在读取 EXIF 后再次旋转它)。转置图像时是否应该删除 EXIF 旋转?如何?谢谢! (2认同)

小智 7

与@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
Run Code Online (Sandbox Code Playgroud)


Gar*_*Jax 6

如果您使用Pillow> = 6.0.0,则可以使用内置ImageOps.exif_transpose函数根据其exif标签正确旋转图像:

from PIL import ImageOps

image = ImageOps.exif_transpose(image)
Run Code Online (Sandbox Code Playgroud)

  • @DrK,我更新了答案以反映 Pillow 6.0.0+ 需要使用 exif_t​​ranspose 函数。 (3认同)
  • 此功能不适用于 tif 图像。参考[此处](https://github.com/python-pillow/Pillow/issues/4346) (2认同)

ATO*_*TOA 5

我找到了解决方案...请查看... http://www.atoztoa.com/2012/12/rotate-images-along-with-thumbnails-in.html

'''
Rotate Image
'''
import pyexiv2
import wx
import cStringIO
import os

def rotateImage(infile, device):
    try:
        # Read Metadata from the image
        metadata = pyexiv2.metadata.ImageMetadata(infile)
        metadata.read();

        # Let's get the orientation
        orientation = metadata.__getitem__("Exif.Image.Orientation")
        orientation = int(str(orientation).split("=")[1][1:-1])

        # Extract thumbnail
        thumb = metadata.exif_thumbnail

        angle = 0

        # Check the orientation field in EXIF and rotate image accordingly
        if device == "iPhone" or device == "iPad":
            # Landscape Left : Do nothing
            if orientation == ORIENTATION_NORMAL:
                angle = 0
            # Portrait Normal : Rotate Right
            elif orientation == ORIENTATION_LEFT:
                angle = -90
            # Landscape Right : Rotate Right Twice
            elif orientation == ORIENTATION_DOWN:
                angle = 180
            # Portrait Upside Down : Rotate Left
            elif orientation == ORIENTATION_RIGHT:
                angle = 90

            # Resetting Exif field to normal
            print "Resetting exif..."
            orientation = 1
            metadata.__setitem__("Exif.Image.Orientation", orientation)

        # Rotate
        if angle != 0:
            # Just rotating the image based on the angle
            print "Rotating image..."
            angle = math.radians(angle)
            img = wx.Image(infile, wx.BITMAP_TYPE_ANY)
            img_centre = wx.Point( img.GetWidth()/2, img.GetHeight()/2 )
            img = img.Rotate( angle, img_centre, True )
            img.SaveFile(infile, wx.BITMAP_TYPE_JPEG)

            # Create a stream out of the thumbnail and rotate it using wx
            # Save the rotated image to a temporary file
            print "Rotating thumbnail..."
            t = wx.EmptyImage(100, 100)
            thumbStream = cStringIO.StringIO(thumb.data)
            t.LoadStream(thumbStream, wx.BITMAP_TYPE_ANY)
            t_centre = wx.Point( t.GetWidth()/2, t.GetHeight()/2 )
            t = t.Rotate( angle, t_centre, True )
            t.SaveFile(infile + ".jpg", wx.BITMAP_TYPE_JPEG)
            thumbStream.close()

            # Read the rotated thumbnail and put it back in the rotated image
            thumb.data = open(infile + ".jpg", "rb").read();
            # Remove temporary file
            os.remove(infile + ".jpg")

        # Write back metadata
        metadata.write();

    except Exception, e:
        print "Error rotating image... : " + str(e)
Run Code Online (Sandbox Code Playgroud)