2009-10-22 13 views
20

私は画像のサイズを変更するためにPythonを使用しようとしています。 私のカメラでは、ファイルはすべて横書きです。PILを使用して回転EXIF情報のサイズを変更してファイルに適用するにはどうすればよいですか?

exif情報は、画像ビューアに別の方法で回転するように要求するタグを処理します。 ブラウザのほとんどがこの情報を理解していないので、このEXIF情報を使用してイメージを回転し、他のすべてのEXIF情報を保持したいと考えています。

私はそれをPythonを使ってどうやって行うことができますか?

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を使用することができます。

はEXIF.pyのソースコードを読んで、私はそのような何かを発見しましたか?

+0

詳細情報:http://www.abc-view.com/articles/article5.htmlこの値に関しては、特定のプロセスで関数を使用すべきだと思いますか? – Natim

+2

良い質問! PILは(jpegtranのように)JPEGを無損失で回転できますか?無損失の変換なしで、私はこれを行うことを検討しませんでした。 – u0b34a0f6ae

答えて

15

私はついにpyexiv2を使用しましたが、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 

(Python 2.5の場合を除いて)改善できる点がある場合は、教えてください。

+1

ファイルパスを取得するためにglobモジュールを使用した場合、listJPEG関数が少し短くなる可能性があります。また、_mkdir()を廃止する標準ライブラリにos.makedirsがあります。サイズ変更されたJPEGを書き込むためのコードブロックメタデータのコピーは、重複したコードを避けるために関数にリファクタリングする必要があります。ファイル形式などを調整するために追加のコマンドラインパラメータが必要なのかもしれません。 – fbuchinger

+0

良い音がします。ありがとうございました:) – Natim

+0

私はここでパーティーに遅れていますが、StackOverflowの回答はcc-wikiの下でライセンスされています。これはGPLされているこの回答の内容と矛盾しています。 –

2

まず、カメラに実際に回転センサーが付いていることを確認する必要があります。センサなしのほとんどのカメラモデルでは、すべての画像でオリエンテーションタグを1(水平)に設定するだけです。

次に、あなたのケースではpyexiv2とpyjpegtranを使用することをお勧めします。 PILはpyjpegtranのドメインであるロスレスローテーションをサポートしていません。 pyexiv2は、ある画像から別の画像にメタデータをコピーできるライブラリです(メソッド名はcopyMetadataです)。

写真をブラウザに表示する前に、写真のサイズを変更したくないのですか? 8メガピクセルのJPEGは、ブラウザウィンドウには大きすぎるので、無限の読み込み時間が発生します。

+0

私が言ったように、私は画像のサイズを変更し、それらを回転させ、いくつかの有用なEXIF情報を保持したい。 – Natim

6

PILはEXIFメタデータを読み取ることはできますが、PILは変更してイメージファイルに書き戻すことはできません。

より良い選択は、pyexiv2ライブラリです。このライブラリを使用すると、写真の向きを変えることができます。ここに例があります:

これは、 "Rotated 90 CW"に対応する方向を6に設定します。

+0

実際、Exif.Image.Orientationタグが設定されていますので、EXIF情報が分からなくてもブラウザーで表示できるように、右の向きで画像を書きたいと思います。とにかく、pyexiv2は必要なライブラリです。あなたは私のコードの背後にあるように見えます。 – Natim

関連する問題