在Python中调整图像大小而不丢失EXIF数据

29

我需要使用Python调整jpg图片的大小,同时保留原始图像的EXIF数据(关于拍摄日期、相机型号等的元数据)。所有有关Python和图像的谷歌搜索都指向了PIL库,我目前正在使用它,但似乎无法保留元数据。到目前为止,我使用PIL编写的代码如下:

img = Image.open('foo.jpg')
width,height = 800,600
if img.size[0] < img.size[1]:
    width,height = height,width

resized_img = img.resize((width, height), Image.ANTIALIAS) # best down-sizing filter
resized_img.save('foo-resized.jpg')

有什么想法吗?或者我可以使用其他库吗?


我的回答展示了如何仅使用PIL保留exif数据:https://dev59.com/mmQn5IYBdhLWcg3wLkgd - Gary Kerr
11个回答

17

实际上,使用PIL只需简单的方法即可从一张图片复制EXIF数据到另一张图片。尽管这不能修改EXIF标签。

image = Image.open('test.jpg')
exif = image.info['exif']
# Your picture process here
image = image.rotate(90)
image.save('test_rotated.jpg', 'JPEG', exif=exif)

正如你所看到的,save函数可以接受exif参数,允许在保存时将原始exif数据复制到新图像中。如果您只想做到这一点,实际上不需要任何其他库。我似乎找不到有关保存选项的任何文档,而且我甚至不知道这是否特定于Pillow或与PIL一起使用。(如果有人有某种链接,我会很高兴他们在评论中发表)


谢谢,这正是我想要的。在Pillow文档中并没有明确说明。为了修改exif标签,我使用GExiv2对保存的文件进行操作。 - barsanuphe
1
这实际上是有效的,不确定为什么在简单任务中没有更多讨论,因为其他库可能会增加到不同的操作系统环境中。 - Shane
1
这太棒了。谢谢你。它按照我希望的方式工作。 - Joe Thor

12

2
然而,这将保存错误的信息,特别是关于X和Y分辨率。 - rob
在保存之前,没有任何限制阻止您更新EXIF信息中的相应字段。 - jfs
当exif数据过长时,您会收到此错误:http://stackoverflow.com/questions/1606514/how-to-use-pil-to-resize-and-apply-exif-information-to-the-file - Natim
2
@Jake:你可以尝试http://tilloy.net/dev/pyexiv2/,正如@iny所建议的那样。链接到旧内容(jpeg模块):http://web.archive.org/web/20080425064422/http://www.emilas.com/jpeg/ http://code.google.com/p/pipp/downloads/detail?name=jpeg-0.1.5.win32.zip - jfs
感谢@J.F. Sepastian,pyexiv2看起来是完成此任务的最佳工具,但对于一个看似简单的任务,它有很多依赖项。 - Jake
3
JPEG库(如果您能找到它)似乎只支持Win32操作系统。 - RyanN

10

你可以使用pyexiv2来从源图像复制EXIF数据。在下面的示例中,使用PIL库调整图像大小,使用pyexiv2复制EXIF数据,并将图像大小EXIF字段设置为新大小。

def resize_image(source_path, dest_path, size):
    # resize image
    image = Image.open(source_path)
    image.thumbnail(size, Image.ANTIALIAS)
    image.save(dest_path, "JPEG")

    # copy EXIF data
    source_image = pyexiv2.Image(source_path)
    source_image.readMetadata()
    dest_image = pyexiv2.Image(dest_path)
    dest_image.readMetadata()
    source_image.copyMetadataTo(dest_image)

    # set EXIF image size info to resized size
    dest_image["Exif.Photo.PixelXDimension"] = image.size[0]
    dest_image["Exif.Photo.PixelYDimension"] = image.size[1]
    dest_image.writeMetadata()

# resizing local file
resize_image("41965749.jpg", "resized.jpg", (600,400))

哪个版本的pyexiv2?版本越早,“copyMetadataTo”方法就越不可能存在。我正在使用Ubuntu 8.04,没有这个方法,V0.1.1。 - bootload
对于在 pyexiv2 版本 0.3 下工作的解决方案(作者宣布该项目停止之前的最后一个版本),请参见 https://dev59.com/H1_Va4cB1Zd3GeqPPAa8#18318254。 - Joachim W

4
以下是2018年的最新回答。 piexif是一个纯Python库,可以通过pip轻松安装(pip install piexif),并且工作得非常好(感谢维护者!)。https://pypi.org/project/piexif/ 使用非常简单,只需一行代码即可复制接受的答案,并将所有EXIF标签从原始图像复制到调整大小的图像:
import piexif
piexif.transplant("foo.jpg", "foo-resized.jpg")

我还没有尝试过,但是根据链接文档所述,似乎你也可以通过使用load、dump和insert函数轻松地进行修改。


这绝对是本页上最好的答案。它完美地运行了,而且只需要一行简单的代码。 - autonopy
这真的是最好的答案!!谢谢 @biomiker - Malgo

4
为什么不使用ImageMagick?这是一个非常标准的工具(例如,Gallery 2使用的就是标准工具);虽然我从未使用过它,但它也有python接口(或者,您也可以简单地生成命令),最重要的是,可以在所有转换之间保持EXIF信息。

1
恰巧PIL是Python中的标准工具,因此ImageMagick Python绑定并不那么容易获取。 - iny
在这种情况下,我会生成一个单独的进程。ImageMagick(作为可执行文件)几乎可以在任何配置上使用。 - rob
ImageMagick绑定到Python的问题不在于可用性,而在于缺乏文档。 - Joachim W

3
对于pyexiv2 v0.3.2版本,API文档中提到使用copy方法将一个图像的EXIF数据复制到另一个图像中。在这种情况下,是将原始图像的EXIF数据传递到调整大小后的图像中。

根据@Maksym Kozlenko的建议,更新后的复制EXIF数据的代码如下:
    source_image = pyexiv2.ImageMetadata(source_path)
    source_image.read()

    dest_image = pyexiv2.ImageMetadata(dest_path)
    dest_image.read()

    source_image.copy(dest_image,exif=True)
    dest_image.write()

1

你可以使用pyexiv2在保存文件后修改它。


0

看起来@Depado的解决方案对我不起作用,在我的情况下,图像甚至不包含exif段。

在我的Mac上安装pyexiv2很困难,所以我使用模块pexif https://github.com/bennoleslie/pexif/blob/master/pexif.py。要向不包含exif信息的图像“添加exif段”,我添加了包含exif段的图像中包含的exif信息。

from pexif import JpegFile

#get exif segment from an image
jpeg = JpegFile.fromFile(path_with_exif)
jpeg_exif = jpeg.get_exif()

#import the exif segment above to the image file which does not contain exif segment
jpeg = JpegFile.fromFile(path_without_exif)
exif = jpeg.import_exif(jpeg_exif)
jpeg.writeFile(path_without_exif)

0

更新版本的Maksym Kozlenko Python3和py3exiv2 v0.7

# Resize image and update Exif data
from PIL import Image
import pyexiv2

def resize_image(source_path, dest_path, size):
    # resize image
    image = Image.open(source_path)
    # Using thumbnail, then 'size' is MAX width or weight
    # so will retain aspect ratio
    image.thumbnail(size, Image.ANTIALIAS)
    image.save(dest_path, "JPEG")

    # copy EXIF data
    source_exif = pyexiv2.ImageMetadata(source_path)
    source_exif.read()
    dest_exif = pyexiv2.ImageMetadata(dest_path)
    dest_exif.read()
    source_exif.copy(dest_exif,exif=True)

    # set EXIF image size info to resized size
    dest_exif["Exif.Photo.PixelXDimension"] = image.size[0]
    dest_exif["Exif.Photo.PixelYDimension"] = image.size[1]
    dest_exif.write()

0
from PIL import Image
img_path = "/tmp/img.jpg"
img = Image.open(img_path)
exif = img.info['exif']
img.save("output_"+img_path, exif=exif)

在 Pillow 2.5.3 中测试过


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接