Modify or Delete Exif tag 'Orientation' in Python

Depado picture Depado · Feb 26, 2014 · Viewed 8.9k times · Source

I need some of my pictures to be displayed with the same orientation whether the software reads the exif data or not. One solution (the only one that could fit actually) would be to rotate the image according to the exif tag if it exists and then delete or modify this tag to '1'.

Example
Let's say an image has the Orientation exif tag set to 3. What I want to do is rotate this image according to this tag and save it this way. So that a software that doesn't interpret exif will still display it in the good orientation. Though if the exif tag Orientation is still set to 3, then a software that interprets Exif will rotate my already-rotated image. So that's why I want to set this tag to 1 (which means : no orientation) or delete it.

My final goal is that the image will always be displayed the same, whichever software I use to open it.

There are a lot of questions about that, Exif and Python, blah blah blah. Here is a list of libs that I heard about :

  • Pyexiv2 : Not suitable, I'm currently using Python 3.3 with Pillow
  • Gexiv2 : Looks like a bit platform specific
  • EXIF.py
  • Pexif : Looks like the most recent one ?

What are the best practices ? Is there a pure python solution ? (Which I could install with pip and put it in my requirements.txt) Is there some kind of new lib I could use which is specific to Python3 ?

My only problem right now is to modify and write those exif data to the image file. I have no problem to read exif data, and rotate the image according to the orientation tag. Any tips or advice on that ?

Answer

Wesley picture Wesley · Apr 3, 2014

note:

This answer works for Python2.7 - you can probably just swap Pillow for PIL in Python3, but I can't speak to that from experience. Note that unlike pyexiv2 and most of the other packages that allow you to modify EXIF metadata, the pexif library is standalone and pure python, so it does not need to bind to any C libraries that may not be present on your machine.

overview:

You need to use two separate tools for the two steps:

  • pexif to modify the metadata (EXIF tag)
  • PIL to rotate the image

pexif part:

Four steps:

  • open the image
  • check orientation (needed later for rotation)
  • change orientation to 1
  • save the image

If the orientation tag isn't found, an AttributeError results, hence the try:. Also note that pexif needs the orientation tag to be a list (with one element).

import pexif
img = pexif.JpegFile.fromFile(temp_dir + filename)

try:
  #Get the orientation if it exists
  orientation = img.exif.primary.Orientation[0]
  img.exif.primary.Orientation = [1]
  img.writeFile(temp_dir + filename)

PIL part:

Now to rotate the image. A source for the meaning of the possible orientations (used to generate the lookup table for rotations) is here.

  • open the image
  • apply the necessary rotation/reflection
  • save the image
from PIL import Image

img = Image.open(temp_dir + filename)
if orientation is 6: img = img.rotate(-90)
elif orientation is 8: img = img.rotate(90)
elif orientation is 3: img = img.rotate(180)
elif orientation is 2: img = img.transpose(Image.FLIP_LEFT_RIGHT)
elif orientation is 5: img = img.rotate(-90).transpose(Image.FLIP_LEFT_RIGHT)
elif orientation is 7: img = img.rotate(90).transpose(Image.FLIP_LEFT_RIGHT)
elif orientation is 4: img = img.rotate(180).transpose(Image.FLIP_LEFT_RIGHT)

#save the result
img.save(temp_dir + filename)

put it all together:

if ctype == 'image/jpeg':
  from PIL import Image
  import pexif

  img = pexif.JpegFile.fromFile(temp_dir + filename)

  try:
    #Get the orientation if it exists
    orientation = img.exif.primary.Orientation[0]
    img.exif.primary.Orientation = [1]
    img.writeFile(temp_dir + filename)

    #now rotate the image using the Python Image Library (PIL)
    img = Image.open(temp_dir + filename)
    if orientation is 6: img = img.rotate(-90)
    elif orientation is 8: img = img.rotate(90)
    elif orientation is 3: img = img.rotate(180)
    elif orientation is 2: img = img.transpose(Image.FLIP_LEFT_RIGHT)
    elif orientation is 5: img = img.rotate(-90).transpose(Image.FLIP_LEFT_RIGHT)
    elif orientation is 7: img = img.rotate(90).transpose(Image.FLIP_LEFT_RIGHT)
    elif orientation is 4: img = img.rotate(180).transpose(Image.FLIP_LEFT_RIGHT)

    #save the result
    img.save(temp_dir + filename)
  except: pass