Rotating an image with orientation specified in EXIF using Python without PIL including the thumbnail

后端 未结 6 1213
太阳男子
太阳男子 2020-12-02 09:10

I have the following scenario:

  • I am sending an image from iPhone along with the EXIF information to my Pyhon socket server.
  • I need the image to be pro
相关标签:
6条回答
  • 2020-12-02 09:49

    This solution works for me: PIL thumbnail is rotating my image?

    Don't need to check if it's iPhone or iPad: if photo has orientation tag – rotate it.

    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
    

    Before:

    Before

    After: After

    0 讨论(0)
  • 2020-12-02 09:54

    If you're using Pillow >= 6.0.0, you can use the built-in ImageOps.exif_transpose function do correctly rotate an image according to its exif tag:

    from PIL import ImageOps
    
    image = ImageOps.exif_transpose(image)
    
    0 讨论(0)
  • 2020-12-02 09:56

    Since this is the top answer for "python exif rotate" I'd like to add an addendum in case you only need the rotation value and not have PIL rotate the image - in my case I used QPixmap to rotate the image on a QGraphicsView, so I only needed the angle for the QPixmap transformation.
    The answer above using PIL to get exif is rather slow. In my test it took 6x the time as the piexif library did (6 ms vs 1 ms) because creating/opening the PIL.Image takes a lot of time. So I'd recommend using piexif in this case.

    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 can be file path or bytes object.

    Ref: https://piexif.readthedocs.io/en/latest/sample.html#rotate-image-by-exif-orientation

    0 讨论(0)
  • 2020-12-02 10:05

    I have found a solution... check this out... 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)
    
    0 讨论(0)
  • 2020-12-02 10:06

    Pretty much the same answer than @scabbiaza, but using transpose instead of rotate (for performance purposes).

    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
    
    0 讨论(0)
  • 2020-12-02 10:06

    https://medium.com/@giovanni_cortes/rotate-image-in-django-when-saved-in-a-model-8fd98aac8f2a

    This blog post explains it clearly. Just make sure you try keeping the @receiver.. code in forms.py or models.py as I got cannot import model/view errors .

    keep the rotate_image method in models.py & @receiver.. code also in models.py.

    I also got errors like No such directory. Just make sure full_path is set correctly to media folder.

    I used this line

    fullpath = os.path.join(os.path.dirname(BASE_DIR)) + instance.fimage.url

    0 讨论(0)
提交回复
热议问题