pythonimageexifxmppiexif

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.


Solution

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

    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.