3

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.

Håkon Seljåsen
  • 589
  • 5
  • 18
  • 1
    Have a read here https://photo.stackexchange.com/a/69193 – Mark Setchell Oct 26 '20 at 10:49
  • The answer provided in your link looks like the only way that works for metadata because I need to update the XMP field "-CreateDate". The following cmd syntax fetched from Documentation gives me correct result: exiftool -overwrite_original -createdate="YYYY:mm:dd HH:MM:SS" a.jpg b.jpg What I then need is to make this call from the python script. – Håkon Seljåsen Oct 31 '20 at 17:04

2 Answers2

5

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 onetime.

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.

LEC
  • 161
  • 9
Life is complex
  • 15,374
  • 5
  • 29
  • 58
  • Thank you for a very thorough response. I plan on making lightweight JPEG copies of my picture archive once the dates are correct. But the first solution where I can edit dates without changing the original files sounds like the way to go for my master archive. Do you have any theory why these Nikon files did not support EXIF? Could the EXIF-standard be too recent? Or the Tiff format too old :'D – Håkon Seljåsen Nov 03 '20 at 12:12
  • 1
    @HåkonSeljåsen You're welcome. Thanks for posting this question, because it required me to think about the problem by exploring the capabilities of various Python modules. – Life is complex Nov 03 '20 at 13:31
  • 1
    @HåkonSeljåsen concerning your Nikon Scan (2005) files. I looked through the Nikon manuals for Nikon Scan and don't see any mentions of setting EXIF information, so I would assume that the vendor didn't provide that support when scanning print photos to digitized ones. And the EXIF-standard started in 1995, so again I assume that Nikon didn't add this ISO standard to their scanner software for some unknown reason. – Life is complex Nov 03 '20 at 13:46
3

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)
General Poxter
  • 554
  • 2
  • 8
  • I tried your code, and it does not give a crash and runs fast enough, but the Nikon tif file does not get its metadata updated. Perhaps it is an entirely XMP based file, that does not support EXIF? Is this possible? When I use windows to set a date the field xmp:createdate is added (extracted using https://stackoverflow.com/a/14637315/3407324). – Håkon Seljåsen Oct 27 '20 at 23:19
  • All right. Maybe try saving as a different file name? – General Poxter Oct 28 '20 at 00:11
  • Yeah I'm out of ideas then for doing this in Python. Sorry : ( – General Poxter Oct 28 '20 at 13:52