Python >> Tutoriel Python >  >> Python

La vignette PIL fait pivoter mon image ?

Je suis d'accord avec presque tout comme répondu par "unutbu" et Ignacio Vazquez-Abrams, cependant...

L'indicateur d'orientation EXIF ​​peut avoir une valeur comprise entre 1 et 8 selon la façon dont l'appareil photo a été tenu.

La photo de portrait peut être prise avec le haut de l'appareil photo à gauche ou à droite, la photo de paysage peut être prise à l'envers.

Voici un code qui en tient compte (Testé avec un reflex numérique Nikon D80)

    import Image, ExifTags

    try :
        image=Image.open(os.path.join(path, fileName))
        for orientation in ExifTags.TAGS.keys() : 
            if ExifTags.TAGS[orientation]=='Orientation' : break 
        exif=dict(image._getexif().items())

        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.thumbnail((THUMB_WIDTH , THUMB_HIGHT), Image.ANTIALIAS)
        image.save(os.path.join(path,fileName))

    except:
        traceback.print_exc()

Se sentir obligé de partager ma version, qui est fonctionnellement identique à celles suggérées dans d'autres réponses, mais qui est, à mon avis, plus propre :

import functools

from PIL import Image

def image_transpose_exif(im):
    """
    Apply Image.transpose to ensure 0th row of pixels is at the visual
    top of the image, and 0th column is the visual left-hand side.
    Return the original image if unable to determine the orientation.

    As per CIPA DC-008-2012, the orientation field contains an integer,
    1 through 8. Other values are reserved.

    Parameters
    ----------
    im: PIL.Image
       The image to be rotated.
    """

    exif_orientation_tag = 0x0112
    exif_transpose_sequences = [                   # Val  0th row  0th col
        [],                                        #  0    (reserved)
        [],                                        #  1   top      left
        [Image.FLIP_LEFT_RIGHT],                   #  2   top      right
        [Image.ROTATE_180],                        #  3   bottom   right
        [Image.FLIP_TOP_BOTTOM],                   #  4   bottom   left
        [Image.FLIP_LEFT_RIGHT, Image.ROTATE_90],  #  5   left     top
        [Image.ROTATE_270],                        #  6   right    top
        [Image.FLIP_TOP_BOTTOM, Image.ROTATE_90],  #  7   right    bottom
        [Image.ROTATE_90],                         #  8   left     bottom
    ]

    try:
        seq = exif_transpose_sequences[im._getexif()[exif_orientation_tag]]
    except Exception:
        return im
    else:
        return functools.reduce(type(im).transpose, seq, im)

La réponse de xilvar est très agréable, mais avait deux lacunes mineures que je voulais corriger dans une modification rejetée, donc je la publierai comme réponse.

D'une part, la solution de xilvar échoue si le fichier n'est pas un JPEG ou s'il n'y a pas de données exif présentes. Et pour l'autre, il tournait toujours de 180 degrés au lieu du montant approprié.

import Image, ExifTags

try:
    image=Image.open(os.path.join(path, fileName))
    if hasattr(image, '_getexif'): # only present in JPEGs
        for orientation in ExifTags.TAGS.keys(): 
            if ExifTags.TAGS[orientation]=='Orientation':
                break 
        e = image._getexif()       # returns None if no EXIF data
        if e is not None:
            exif=dict(e.items())
            orientation = exif[orientation] 

            if orientation == 3:   image = image.transpose(Image.ROTATE_180)
            elif orientation == 6: image = image.transpose(Image.ROTATE_270)
            elif orientation == 8: image = image.transpose(Image.ROTATE_90)

    image.thumbnail((THUMB_WIDTH , THUMB_HIGHT), Image.ANTIALIAS)
    image.save(os.path.join(path,fileName))

except:
    traceback.print_exc()