python 如何使用 PIL 调整大小并将旋转 EXIF 信息应用于文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1606587/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use PIL to resize and apply rotation EXIF information to the file?
提问by Natim
I am trying to use Python to resize picture. With my camera, files are all written is landscape way.
我正在尝试使用 Python 调整图片大小。用我的相机,所有文件都是横向写入的。
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.
exif 信息处理一个标签,要求图像查看器以某种方式旋转。由于大多数浏览器不理解此信息,因此我想使用此 EXIF 信息旋转图像并保留所有其他 EXIF 信息。
Do you know how I can do that using Python ?
你知道我如何使用 Python 做到这一点吗?
Reading the EXIF.py source code, I found something like that :
阅读 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'})
How can I use this information and PIL to apply it ?
我如何使用这些信息和 PIL 来应用它?
采纳答案by Natim
I finally used pyexiv2, but it is a bit tricky to install on other platforms than GNU.
我最终使用了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
If you see something that could be improved (except the fact that it is still for Python 2.5) then please let me know.
如果你看到一些可以改进的东西(除了它仍然适用于 Python 2.5),请告诉我。
回答by ataylor
Although PIL can read EXIF metadata, it doesn't have the ability to change it and write it back to an image file.
尽管 PIL 可以读取 EXIF 元数据,但它无法更改它并将其写回图像文件。
A better choice is the pyexiv2library. With this library it's quite simple flip the photo's orientation. Here's an example:
更好的选择是pyexiv2库。使用这个库,翻转照片的方向非常简单。下面是一个例子:
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".
这会将方向设置为 6,对应于“旋转 90 CW”。
回答by fbuchinger
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.
首先,您必须确保您的相机实际上有一个旋转传感器。大多数没有传感器的相机型号只需将所有图片的方向标签设置为 1(水平)。
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).
然后我建议在你的情况下使用 pyexiv2 和 pyjpegtran 。PIL 不支持无损旋转,这是 pyjpegtran 的领域。pyexiv2 是一个库,它允许您将元数据从一个图像复制到另一个图像(我认为方法名称是 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.
您确定不想在浏览器中显示照片之前调整它们的大小吗?一个 8 兆像素的 JPEG 对于浏览器窗口来说太大了,会导致无限的加载时间。