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

前端 未结 3 1021
轮回少年
轮回少年 2020-12-07 19:36

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 rot

相关标签:
3条回答
  • 2020-12-07 19:42

    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 <natim@users.sf.net> - 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.

    0 讨论(0)
  • 2020-12-07 19:43

    First you have to make sure that your camera actually has a rotation sensor. Most camera models without sensor simply set the Orientation Tag to 1 (Horizontal) for ALL pictures.

    Then I recommend to use pyexiv2 and pyjpegtran in your case. PIL doesn't support lossless rotation, which is the domain of pyjpegtran. pyexiv2 is a library that allows you to copy metadata from one image to another (i think the method name is copyMetadata).

    Are you sure that you don't want to resize your photos before displaying them in the browser? A 8 Megapixel JPEG is much too big for the browser window and will cause endless loading times.

    0 讨论(0)
  • 2020-12-07 19:48

    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".

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