Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use PIL to resize and apply rotation EXIF information to the file?

Tags:

I am trying to use Python to resize picture. With my camera, files are all written is landscape way.

The exif information handle a tag to ask the image viewer to rotate in a way or another. Since most of the browser doesn't understand this information, I want to rotate the image using this EXIF information and keeping every other EXIF information.

Do you know how I can do that using Python ?

Reading the EXIF.py source code, I found something like that :

0x0112: ('Orientation',          {1: 'Horizontal (normal)',           2: 'Mirrored horizontal',           3: 'Rotated 180',           4: 'Mirrored vertical',           5: 'Mirrored horizontal then rotated 90 CCW',           6: 'Rotated 90 CW',           7: 'Mirrored horizontal then rotated 90 CW',           8: 'Rotated 90 CCW'}) 

How can I use this information and PIL to apply it ?

like image 489
Natim Avatar asked Oct 22 '09 11:10

Natim


People also ask

How do I rotate an image in PIL?

PIL.Image.Image.rotate() method – This method is used to rotate a given image to the given number of degrees counter clockwise around its centre. Parameters: image_object: It is the real image which is to be rotated. angle: In degrees counter clockwise.

What is EXIF rotation?

Auto-rotation The EXIF orientation value is used by Photoshop and other photo editing software to automatically rotate photos, saving you a manual task.

How do I view EXIF orientation?

You could check the image orientation in Windows by right clicking an image file, select Properties, and open the Details tab. Not sure if you're using a Mac but I would suspect there will be something similar. The Dimensions property will show the horizontal side (on the left) and the vertical side (on the right).


2 Answers

I finally used pyexiv2, but it is a bit tricky to install on other platforms than GNU.

#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright (C) 2008-2009 Rémy HUBSCHER <[email protected]> - http://www.trunat.fr/portfolio/python.html  # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version.  # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details.  # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.  # Using : #   - Python Imaging Library PIL    http://www.pythonware.com/products/pil/index.htm #   - pyexiv2                       http://tilloy.net/dev/pyexiv2/  ### # What is doing this script ? # #  1. Take a directory of picture from a Reflex Camera (Nikon D90 for example) #  2. Use the EXIF Orientation information to turn the image #  3. Remove the thumbnail from the EXIF Information #  4. Create 2 image one maxi map in 600x600, one mini map in 200x200 #  5. Add a comment with the name of the Author and his Website #  6. Copy the EXIF information to the maxi and mini image #  7. Name the image files with a meanful name (Date of picture)  import os, sys try:     import Image except:     print "To use this program, you need to install Python Imaging Library - http://www.pythonware.com/products/pil/"     sys.exit(1)  try:     import pyexiv2 except:     print "To use this program, you need to install pyexiv2 - http://tilloy.net/dev/pyexiv2/"     sys.exit(1)  ############# Configuration ############## size_mini = 200, 200 size_maxi = 1024, 1024  # Information about the Photograph should be in ASCII COPYRIGHT="Remy Hubscher - http://www.trunat.fr/" ARTIST="Remy Hubscher" ##########################################  def listJPEG(directory):     "Retourn a list of the JPEG files in the directory"     fileList = [os.path.normcase(f) for f in os.listdir(directory)]     fileList = [f for f in fileList if os.path.splitext(f)[1]  in ('.jpg', '.JPG')]     fileList.sort()     return fileList  def _mkdir(newdir):     """     works the way a good mkdir should :)       - already exists, silently complete       - regular file in the way, raise an exception       - parent directory(ies) does not exist, make them as well     """     if os.path.isdir(newdir):         pass     elif os.path.isfile(newdir):         raise OSError("a file with the same name as the desired " \                       "dir, '%s', already exists." % newdir)     else:         head, tail = os.path.split(newdir)         if head and not os.path.isdir(head):             _mkdir(head)         if tail:             os.mkdir(newdir)  if len(sys.argv) < 3:     print "USAGE : python %s indir outdir [comment]" % sys.argv[0]     exit  indir  = sys.argv[1] outdir = sys.argv[2]  if len(sys.argv) == 4:     comment = sys.argv[1] else:     comment = COPYRIGHT  agrandie = os.path.join(outdir, 'agrandie') miniature = os.path.join(outdir, 'miniature')  print agrandie, miniature  _mkdir(agrandie) _mkdir(miniature)  for infile in listJPEG(indir):     mini  = os.path.join(miniature, infile)     grand = os.path.join(agrandie, infile)     file_path = os.path.join(indir, infile)      image = pyexiv2.Image(file_path)     image.readMetadata()      # We clean the file and add some information     image.deleteThumbnail()      image['Exif.Image.Artist'] = ARTIST     image['Exif.Image.Copyright'] = COPYRIGHT      image.setComment(comment)      # I prefer not to modify the input file     # image.writeMetadata()      # We look for a meanful name     if 'Exif.Image.DateTime' in image.exifKeys():         filename = image['Exif.Image.DateTime'].strftime('%Y-%m-%d_%H-%M-%S.jpg')         mini  = os.path.join(miniature, filename)         grand = os.path.join(agrandie, filename)     else:         # If no exif information, leave the old name         mini  = os.path.join(miniature, infile)         grand = os.path.join(agrandie, infile)      # We create the thumbnail     #try:     im = Image.open(file_path)     im.thumbnail(size_maxi, Image.ANTIALIAS)      # We rotate regarding to the EXIF orientation information     if 'Exif.Image.Orientation' in image.exifKeys():         orientation = image['Exif.Image.Orientation']         if orientation == 1:             # Nothing             mirror = im.copy()         elif orientation == 2:             # Vertical Mirror             mirror = im.transpose(Image.FLIP_LEFT_RIGHT)         elif orientation == 3:             # Rotation 180°             mirror = im.transpose(Image.ROTATE_180)         elif orientation == 4:             # Horizontal Mirror             mirror = im.transpose(Image.FLIP_TOP_BOTTOM)         elif orientation == 5:             # Horizontal Mirror + Rotation 90° CCW             mirror = im.transpose(Image.FLIP_TOP_BOTTOM).transpose(Image.ROTATE_90)         elif orientation == 6:             # Rotation 270°             mirror = im.transpose(Image.ROTATE_270)         elif orientation == 7:             # Horizontal Mirror + Rotation 270°             mirror = im.transpose(Image.FLIP_TOP_BOTTOM).transpose(Image.ROTATE_270)         elif orientation == 8:             # Rotation 90°             mirror = im.transpose(Image.ROTATE_90)          # No more Orientation information         image['Exif.Image.Orientation'] = 1     else:         # No EXIF information, the user has to do it         mirror = im.copy()      mirror.save(grand, "JPEG", quality=85)     img_grand = pyexiv2.Image(grand)     img_grand.readMetadata()     image.copyMetadataTo(img_grand)     img_grand.writeMetadata()     print grand      mirror.thumbnail(size_mini, Image.ANTIALIAS)     mirror.save(mini, "JPEG", quality=85)     img_mini = pyexiv2.Image(mini)     img_mini.readMetadata()     image.copyMetadataTo(img_mini)     img_mini.writeMetadata()     print mini      print 

If you see something that could be improved (except the fact that it is still for Python 2.5) then please let me know.

like image 86
Natim Avatar answered Oct 16 '22 04:10

Natim


Although PIL can read EXIF metadata, it doesn't have the ability to change it and write it back to an image file.

A better choice is the pyexiv2 library. With this library it's quite simple flip the photo's orientation. Here's an example:

import sys import pyexiv2  image = pyexiv2.Image(sys.argv[1]) image.readMetadata()  image['Exif.Image.Orientation'] = 6 image.writeMetadata() 

This sets the orientation to 6, corresponding to "Rotated 90 CW".

like image 36
ataylor Avatar answered Oct 16 '22 02:10

ataylor