使用Python将“拍摄日期”Exif/XMP信息添加到TIF文件

3

我正在使用以下Python代码在Windows 10上尝试编辑由Nikon Scan 4.0.3创建的tif图像文件的EXIF信息,其中包括"Date Taken"。

import piexif

def setImageDateTakenAttribute(filename, date_taken):
exif_dict = piexif.load(filename)
exif_dict['Exif'] = { 
    piexif.ExifIFD.DateTimeOriginal: datetime.datetime(*date_taken[:6]).strftime("%Y:%m:%d %H:%M:%S") 
} 
exif_bytes = piexif.dump(exif_dict)
piexif.insert(exif_bytes, filename)

在Python 3中,对于jpeg文件这样做是可以的,但当我尝试使用相同的代码编辑我的tif文件时,就会出现以下错误:

    setImageDateTakenAttribute(full_path, folder_date)
  File "image-and-movie-bulk-creation-dates.py", line 78, in setImageDateTakenAttribute
    piexif.insert(exif_bytes, filename)
  File "C:\Python37\lib\site-packages\piexif\_insert.py", line 39, in insert
    raise InvalidImageDataError
piexif._exceptions.InvalidImageDataError

到目前为止,我一直在寻找其他可能支持我的文件的软件包,但都没有成功。

有人知道如何在Python中完成编辑而不删除现有的exif信息,并且不更改图像格式吗?

要重新创建或获取失败的tif文件样本,请克隆我的项目(下面是链接)。

细节:

将成千上万张图片扫描为tif文件后,我想指定“拍摄日期”的EXIF值。我正在编写一个Python脚本在Windows(BitBucket)中完成此操作,该脚本还将根据以YYYY-MM-DD *开头的预定义文件夹命名约定编辑“创建日期”和“修改日期”。最后两个任务对于tif文件和jpeg文件都起作用,但对于tif则无法使用EXIF。

更新:

运行exif工具后,我得到了输出,但其中缺少creation date节点,但在Windows上设置日期之后,出现了“Create Date”和“Date / Time Original”字段。另外,对XMP元值进行原始文本打印后,在Windows设置创建日期后会添加一个名为xmp:createdate的节点。然而,我仍然无法弄清如何首次在文件中创建这些字段。

更新2:

看起来Exif无法处理来自Nikon Scan(2005)的文件。唯一的选择是在文件中添加xmp:createdate节点的XMP信息。如果有人能向我展示如何完成此操作,无论是通过纯Python还是在Windows上从Python调用单独的工具,都将获得完整的赏金。


1
在这里阅读 https://photo.stackexchange.com/a/69193 - Mark Setchell
你链接中提供的答案似乎是处理元数据的唯一可行方法,因为我需要更新XMP字段“-CreateDate”。从文档中获取的以下cmd语法给出了正确的结果:exiftool -overwrite_original -createdate="YYYY:mm:dd HH:MM:SS" a.jpg b.jpg然后我需要从Python脚本中调用此命令。 - Håkon Seljåsen
2个回答

5

这个问题比我最初想象的要复杂。在我的研究中,我查看了以下Python模块:

  • exif
  • exifread
  • piexif
  • pillow
  • pyexiv2

其中一些模块接近于修改你想要更改的日期字段。但最终,我无法使这些模块正确工作,即更改日期字段而不损坏文件。最终,我推荐采用不同的方法,这种方法使用subprocess 和适用于Unix和Windows的外部工具。该工具是exiftool,我已经使用了多年。

import subprocess
from subprocess import check_output
from datatime import datetime

filename = 'Nikon.NEF'
rtn_data = check_output(['exiftool', filename])
print(rtn_data.decode("utf-8"))
# output 
...
Create Date : 2008:10:24 09:12:12.61
...

today = datetime.today()
new_date = today.strftime("%Y:%m:%d %H:%M:%S")
subprocess.call(['exiftool', f'-CreateDate={new_date}', filename])

changed_data = check_output(['exiftool', filename])
print(changed.decode("utf-8"))
# output 
...
Create Date : 2020:11:02 18:43:13
...

exiftool可以同时更改所有设置和日期。

不使用exiftool进行更新:

您可以使用piexif完成此操作,但必须创建TIFF的副本并将其转换为JPEG。我注意到在创建此副本时,某些元数据会丢失,这可能与您的用例不符。

import piexif
from PIL import Image
from datetime import datetime
from PIL.ExifTags import TAGS

img = Image.open('test.tiff')

# get metadata
meta_dict = {TAGS[key]: img.tag[key] for key in img.tag.keys()}
exif_bytes = piexif.dump(meta_dict)

# get image height and width 
height = img.height
width = img.width

# resize the image and save it to a new file, which is a JPEG
img.resize((width, height), Image.ANTIALIAS).save('test2.jpeg', "JPEG", exif=exif_bytes, quality="web_high", optimize=True)

today = datetime.today()
new_date = today.strftime("%Y:%m:%d %H:%M:%S")

# load the metadata from the original file
exif_dict = piexif.load("test.tiff")

# change various dates
exif_dict['0th'][piexif.ImageIFD.DateTime] = bytes(new_date, 'utf-8')
exif_dict['Exif'][piexif.ExifIFD.DateTimeOriginal] = bytes(new_date, 'utf-8')
exif_dict['Exif'][piexif.ExifIFD.DateTimeDigitized] = bytes(new_date, 'utf-8')

# dump the changes
exif_bytes = piexif.dump(exif_dict)

# write the changes the the JPEG file
piexif.insert(exif_bytes, 'test2.jpeg')

我仍然更喜欢使用ExifTool,因为它代码量更小,而且不会丢失原始文件的某些细节。


非常感谢您提供如此详尽的回复。 我计划在日期正确后制作轻量级JPEG副本以备份图片档案。但第一种解决方案,即可以编辑日期而不更改原始文件的方式,似乎是适用于我的主要档案的最佳选择。您有什么理论可以解释为什么这些尼康文件不支持EXIF吗?EXIF标准可能太新了吗?或者Tiff格式太旧了:D - Håkon Seljåsen
1
@HåkonSeljåsen 不用谢。感谢您发布这个问题,因为它让我通过探索各种Python模块的功能来思考这个问题。 - Life is complex
1
@HåkonSeljåsen 关于您的Nikon Scan(2005)文件。我查看了Nikon Scan的Nikon手册,没有看到任何关于设置EXIF信息的提及,因此我认为在将印刷照片扫描成数字化照片时,供应商没有提供该支持。而且,EXIF标准始于1995年,因此我再次假设Nikon出于某种未知原因没有将此ISO标准添加到其扫描仪软件中。 - Life is complex

3
根据Piexif文档piexif.insert方法仅适用于JPEG或WebP文件。另一种替代方法是使用PIL将当前的exif_bytes保存到替换图像文件中:
import piexif
from PIL import Image

def setImageDateTakenAttribute(filename, date_taken):
    img = Image.open(filename)
    exif_dict = piexif.load(filename)
    exif_dict['Exif'] = { 
        piexif.ExifIFD.DateTimeOriginal: datetime.datetime(*date_taken[:6]).strftime("%Y:%m:%d %H:%M:%S") 
    } 
    exif_bytes = piexif.dump(exif_dict)
    img.save(filename, 'tiff', exif=exif_bytes)

我尝试了你的代码,它没有崩溃并且运行速度足够快,但是尼康tif文件没有更新元数据。也许这是一个完全基于XMP的文件,不支持EXIF?这可能吗?当我使用Windows设置日期时,字段xmp:createdate被添加(使用https://dev59.com/jGw15IYBdhLWcg3wG4AJ#14637315提取)。 - Håkon Seljåsen
好的。也许尝试另存为不同的文件名? - General Poxter
抱歉,我对用Python完成这个任务已经没有更多的想法了。:( - General Poxter

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