كيفية استخدام PIL لتغيير حجم معلومات EXIF ​​وتطبيقها على الملف؟

StackOverflow https://stackoverflow.com/questions/1606587

سؤال

أحاول استخدام بايثون لتغيير حجم الصورة.باستخدام الكاميرا الخاصة بي، تتم كتابة جميع الملفات بطريقة أفقية.

تتعامل معلومات exif مع علامة لتطلب من عارض الصور التدوير بطريقة أو بأخرى.نظرًا لأن معظم المتصفحات لا تفهم هذه المعلومات، فأنا أرغب في تدوير الصورة باستخدام معلومات EXIF ​​هذه والاحتفاظ بكل معلومات EXIF ​​الأخرى.

هل تعرف كيف يمكنني القيام بذلك باستخدام بايثون؟

عند قراءة كود مصدر EXIF.py، وجدت شيئًا من هذا القبيل:

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'})

كيف يمكنني استخدام هذه المعلومات وPIL لتطبيقها؟

هل كانت مفيدة؟

المحلول

لقد استخدمت أخيرا pyexiv2, ، لكن تثبيته على منصات أخرى غير 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

إذا رأيت شيئًا يمكن تحسينه (باستثناء حقيقة أنه لا يزال مخصصًا لـ Python 2.5)، فيرجى إبلاغي بذلك.

نصائح أخرى

على الرغم من أن PIL يمكنه قراءة بيانات تعريف EXIF، إلا أنه ليس لديه القدرة على تغييرها وكتابتها مرة أخرى في ملف صورة.

الخيار الأفضل هو pyexiv2 مكتبة.باستخدام هذه المكتبة، يكون من السهل جدًا قلب اتجاه الصورة.هنا مثال:

import sys
import pyexiv2

image = pyexiv2.Image(sys.argv[1])
image.readMetadata()

image['Exif.Image.Orientation'] = 6
image.writeMetadata()

يؤدي هذا إلى ضبط الاتجاه على 6، الموافق لـ "Rotated 90 CW".

عليك أولاً التأكد من أن الكاميرا الخاصة بك تحتوي بالفعل على مستشعر دوران.معظم موديلات الكاميرات التي لا تحتوي على مستشعر تقوم ببساطة بتعيين علامة الاتجاه على 1 (أفقي) لجميع الصور.

ثم أوصي باستخدام pyexiv2 وpyjpegtran في حالتك.لا يدعم PIL التدوير بدون فقدان البيانات، وهو مجال pyjpegtran.pyexiv2 هي مكتبة تسمح لك بنسخ البيانات الوصفية من صورة إلى أخرى (أعتقد أن اسم الطريقة هو CopyMetadata).

هل أنت متأكد أنك لا تريد تغيير حجم صورك قبل عرضها في المتصفح؟يعد ملف JPEG بدقة 8 ميجابكسل كبيرًا جدًا بالنسبة لنافذة المتصفح وسيتسبب في أوقات تحميل لا نهاية لها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top