简体   繁体   中英

Add "Date Taken" Exif/XMP information to TIF file using Python

Using the following Python code on Windows 10, I am trying to edit the EXIF info for "Date Taken" on a tif image file created with Nikon Scan 4.0.3 (software from around 2008).

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)

This works fine in Python 3 for jpeg files, but when I try and use the same code to edit my tif file, I get the following error:

    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

I have thus far been looking for for other packages that might support my file with no avail.

Does anyone know how the edit can be acomlished in Python without deleting existing exif info, and without changing the image format?

To reproduce or obtain a sample of the failing tif files, clone my project (link bellow).

Details:

After scanning thousands of pictures to tif files I would like to specify the EXIF value for "Date Taken". I am writing a Python script to do this in Windows (BitBucket) , that will also to edit "Date Created" and "Date Modified" from a predefined folder naming convention starting with YYYY-MM-DD *. The last two tasks are working for tif files as well as jpeg, but EXIF does not work for tif.

Update:

Running exif tool, I get output without the creation date node, but after setting a date in Windows using file properties, the fields "Create Date" and "Date/Time Original" Appears. Also a raw text printout of XMP meta values gives an added node called xmp:createdate after setting creation date in Windows. Still I cannot figure ot how to create these fields in the file for the first time.

Update 2:

It looks like Exif does not work on the files from Nikon Scan (2005). The only option is to add the xmp:createdate node to the XMP information in the file. If anyone can show me how this is done, either in pure Python or by calling a separate tool from python on Windows, it would deserve the full bounty.

This question was more complicated than I originally thought. I looked at the following Python modules during my research:

  • exif
  • exifread
  • piexif
  • pillow
  • pyexiv2

Some of the modules came close to modifying the date that you wanting to change. But in the end, I could not get any of the modules to work correctly. Correctly means changing the date field without damaging the file. In the end, I'm going to recommended a different approach, which uses subprocess and an external tool that works for Unix and Windows. That tool is exiftool , which I have used for years.

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 allows you to change any setting and all the dates at .netime.

UPDATE NOT USING exiftool:

You can do this with piexif, but you have to create a copy of your TIFF and convert to to JPEG. I noted that when you created this copy some of the metadata is lost, which might be a no-go based on your use case.

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')

I still prefer using exiftool, because it takes less code and doesn't lose some of the details from the original file.

According to Piexif documentation , the piexif.insert method only works for JPEG or WebP files. An alternative would be to save your current exif_bytes into a replacement image file using PIL:

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM