PIL缩略图旋转我的图片?
我正在尝试把从数码相机拍摄的大图片转换成可以在网上显示的格式。这看起来应该很简单,但实际上并不是这样。当我用PIL来创建缩略图时,如果我的原始图片是竖着的(高比宽),生成的图片就会旋转90度,导致原始图片的顶部在生成图片的左边。如果原始图片是横着的(宽比高),生成的图片就会保持正确的方向。这个问题可能和我传入的尺寸有关吗?我使用缩略图功能是因为它似乎是为了保持图片的长宽比。还是说我完全看不清楚,做了什么傻事?我设置的尺寸是1000,1000,因为我想把最长的一边缩小到1000像素,同时保持长宽比不变。
代码看起来很简单
img = Image.open(filename)
img.thumbnail((1000,1000), Image.ANTIALIAS)
img.save(output_fname, "JPEG")
提前感谢任何帮助。
14 个回答
直接使用 PIL.ImageOps.exif_transpose 这个功能,来自Pillow库。
跟其他回答中提到的每一个函数不一样,包括我最开始提到的那个,这个功能会处理掉图片的EXIF信息中的方向字段(因为图片已经不再以奇怪的方式显示了),而且它返回的是一个全新的图片对象,这样对这个新对象的修改不会影响到原来的图片。
我几乎同意“unutbu”和Ignacio Vazquez-Abrams的所有回答,不过...
EXIF方向标志的值可以在1到8之间,这取决于相机的持握方式。
比如,拍摄人像照片时,相机的顶部可以在左边或右边,而拍摄风景照片时,甚至可以是倒过来的。
下面是考虑到这些情况的代码(在单反相机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()
请注意,下面有更好的答案。
当一张图片的高度大于宽度时,这意味着相机被旋转了。有些相机可以检测到这一点,并把这个信息写入图片的EXIF元数据中。有些图片查看器会注意到这些元数据,并相应地显示图片。
PIL可以读取图片的元数据,但在你保存图片时,它不会写入或复制这些元数据。因此,你的智能图片查看器就不会像之前那样自动旋转图片了。
根据@Ignacio Vazquez-Abrams的评论,你可以用PIL这样读取元数据,并在必要时进行旋转:
import ExifTags
import Image
img = Image.open(filename)
print(img._getexif().items())
exif=dict((ExifTags.TAGS[k], v) for k, v in img._getexif().items() if k in ExifTags.TAGS)
if not exif['Orientation']:
img=img.rotate(90, expand=True)
img.thumbnail((1000,1000), Image.ANTIALIAS)
img.save(output_fname, "JPEG")
但要注意,上面的代码可能并不适用于所有相机。
最简单的解决办法可能是使用其他程序来制作缩略图。
phatch是一个用Python编写的批量照片编辑器,可以处理和保留EXIF元数据。你可以使用这个程序来制作缩略图,或者查看它的源代码,看看如何在Python中实现这个功能。我相信它使用了pyexiv2来处理EXIF元数据。pyexiv2可能比PIL的ExifTags模块更好地处理EXIF。
imagemagick也是一个制作批量缩略图的好选择。