PIL has a way to look at a simple set of EXIF tags but cannot read the myriad of file types out there. I needed something to get everything I could out of a NIKON *.jpg file.
The solution I found was running exiftool.exe with the subprocess module.
Exiftool.exe supports many file types. Download at http://www.sno.phy.queensu.ca/~phil/exiftool/
Loading EXIF from a file into Python
To load EXIF data from an image file, use the check_output method in the subprocess module. This method will return the exiftool.exe output as a string. Then splitlines and add each line/tag to a dictionary. I prefer using OrderedDict from the collections module, but I use a regular dictionary in the code below.
import subprocess
# filename is the path to your target image file.
exifdata = subprocess.check_output(['exiftool.exe',
filename], shell=True)
exifdata = exifdata.splitlines()
exif = dict()
for i, each in enumerate(exifdata):
# tags and values are separated by a colon
tag,val = each.split(': ', 1) # '1' only allows one split
exif[tag.strip()] = val.strip()
You can review all the available tags from a file with exif.keys().
Getting a preview image or thumbnail from EXIF into Python
You can get a preview image from a NEF or JPG file also. Not all files will have a preview so you’ll need to handle the error. You can also retrieve the full-size jpeg that is embedded in the file.
import subprocess
import StringIO
from PIL import Image
def get_preview( filename ):
try:
im_binary = subprocess.check_output(['exiftool.exe',
filename,
'-previewimage',
'-b'], shell=True)
image = Image.open( StringIO.StringIO(im_binary) )
return image
except:
return None
def get_thumbnail( filename ):
try:
im_binary = subprocess.check_output(['exiftool.exe',
filename,
'-thumbnailimage',
'-b'], shell=True)
image = Image.open( StringIO.StringIO(im_binary) )
return image
except:
return None
def get_jpeg( filename ):
try:
im_binary = subprocess.check_output(['exiftool.exe',
filename,
'-JpgFromRaw',
'-b'], shell=True)
image = Image.open( StringIO.StringIO(im_binary) )
return image
except:
return None
Preserving the EXIF after PIL manipulation and save
PIL does not automatically save EXIF and PIL’s exif methods do not grab everything, particularly NIKON MakerNote data.
My solution is to save a manipulated image separate from original (do not overwrite original JPG) and copy the EXIF from old to new with exiftool.
# After editing/manipulating image with PIL
savename = filename[:-4]+'_new.jpg'
image.save( savename, quality=95 ) # Default quality is 75
subprocess.call(['exiftool.exe',
savename,
'-tagsFromFile',
filename], shell=True)
After copying the EXIF data, delete the old image or change its name to be a backup. Use os.rename or os.remove.