I have the following scenario:
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:
After:
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)
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
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)
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
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