I'm using PIL. How do I turn the EXIF data of a picture into a dictionary?
29 Answers
You can use the _getexif() protected method of a PIL Image.
import PIL.Image img = PIL.Image.open('img.jpg') exif_data = img._getexif() This should give you a dictionary indexed by EXIF numeric tags. If you want the dictionary indexed by the actual EXIF tag name strings, try something like:
import PIL.ExifTags exif = { PIL.ExifTags.TAGS[k]: v for k, v in img._getexif().items() if k in PIL.ExifTags.TAGS } 12For Python3.x and starting Pillow==6.0.0, Image objects now provide a "public"/official getexif() method that returns a <class 'PIL.Image.Exif'> instance or None if the image has no EXIF data.
From Pillow 6.0.0 release notes:
getexif()has been added, which returns anExifinstance. Values can be retrieved and set like a dictionary. When saving JPEG, PNG or WEBP, the instance can be passed as anexifargument to include any changes in the output image.
As stated, you can iterate over the key-value pairs of the Exif instance like a regular dictionary. The keys are 16-bit integers that can be mapped to their string names using the ExifTags.TAGS module.
from PIL import Image, ExifTags img = Image.open("sample.jpg") img_exif = img.getexif() print(type(img_exif)) # <class 'PIL.Image.Exif'> if img_exif is None: print('Sorry, image has no exif data.') else: for key, val in img_exif.items(): if key in ExifTags.TAGS: print(f'{ExifTags.TAGS[key]}:{val}') # ExifVersion:b'0230' # ... # FocalLength:(2300, 100) # ColorSpace:1 # ... # Model:'X-T2' # Make:'FUJIFILM' # LensSpecification:(18.0, 55.0, 2.8, 4.0) # ... # DateTime:'2019:12:01 21:30:07' # ... Tested with Python 3.8.8 and Pillow==8.1.0.
You can also use the ExifRead module:
import exifread # Open image file for reading (binary mode) f = open(path_name, 'rb') # Return Exif tags tags = exifread.process_file(f) 6I use this:
import os,sys from PIL import Image from PIL.ExifTags import TAGS for (k,v) in Image.open(sys.argv[1])._getexif().items(): print('%s = %s' % (TAGS.get(k), v)) or to get a specific field:
def get_field (exif,field) : for (k,v) in exif.items(): if TAGS.get(k) == field: return v exif = image._getexif() print get_field(exif,'ExposureTime') 3import sys import PIL import PIL.Image as PILimage from PIL import ImageDraw, ImageFont, ImageEnhance from PIL.ExifTags import TAGS, GPSTAGS class Worker(object): def __init__(self, img): self.img = img self.exif_data = self.get_exif_data() self.lat = self.get_lat() self.lon = self.get_lon() self.date =self.get_date_time() super(Worker, self).__init__() @staticmethod def get_if_exist(data, key): if key in data: return data[key] return None @staticmethod def convert_to_degress(value): """Helper function to convert the GPS coordinates stored in the EXIF to degress in float format""" d0 = value[0][0] d1 = value[0][1] d = float(d0) / float(d1) m0 = value[1][0] m1 = value[1][1] m = float(m0) / float(m1) s0 = value[2][0] s1 = value[2][1] s = float(s0) / float(s1) return d + (m / 60.0) + (s / 3600.0) def get_exif_data(self): """Returns a dictionary from the exif data of an PIL Image item. Also converts the GPS Tags""" exif_data = {} info = self.img._getexif() if info: for tag, value in info.items(): decoded = TAGS.get(tag, tag) if decoded == "GPSInfo": gps_data = {} for t in value: sub_decoded = GPSTAGS.get(t, t) gps_data[sub_decoded] = value[t] exif_data[decoded] = gps_data else: exif_data[decoded] = value return exif_data def get_lat(self): """Returns the latitude and longitude, if available, from the provided exif_data (obtained through get_exif_data above)""" # print(exif_data) if 'GPSInfo' in self.exif_data: gps_info = self.exif_data["GPSInfo"] gps_latitude = self.get_if_exist(gps_info, "GPSLatitude") gps_latitude_ref = self.get_if_exist(gps_info, 'GPSLatitudeRef') if gps_latitude and gps_latitude_ref: lat = self.convert_to_degress(gps_latitude) if gps_latitude_ref != "N": lat = 0 - lat lat = str(f"{lat:.{5}f}") return lat else: return None def get_lon(self): """Returns the latitude and longitude, if available, from the provided exif_data (obtained through get_exif_data above)""" # print(exif_data) if 'GPSInfo' in self.exif_data: gps_info = self.exif_data["GPSInfo"] gps_longitude = self.get_if_exist(gps_info, 'GPSLongitude') gps_longitude_ref = self.get_if_exist(gps_info, 'GPSLongitudeRef') if gps_longitude and gps_longitude_ref: lon = self.convert_to_degress(gps_longitude) if gps_longitude_ref != "E": lon = 0 - lon lon = str(f"{lon:.{5}f}") return lon else: return None def get_date_time(self): if 'DateTime' in self.exif_data: date_and_time = self.exif_data['DateTime'] return date_and_time if __name__ == '__main__': try: img = PILimage.open(sys.argv[1]) image = Worker(img) lat = image.lat lon = image.lon date = image.date print(date, lat, lon) except Exception as e: print(e) I have found that using ._getexif doesn't work in higher python versions, moreover, it is a protected class and one should avoid using it if possible. After digging around the debugger this is what I found to be the best way to get the EXIF data for an image:
from PIL import Image def get_exif(path): return Image.open(path).info['parsed_exif'] This returns a dictionary of all the EXIF data of an image.
Note: For Python3.x use Pillow instead of PIL
2Here's the one that may be little easier to read. Hope this is helpful.
from PIL import Image from PIL import ExifTags exifData = {} img = Image.open(picture.jpg) exifDataRaw = img._getexif() for tag, value in exifDataRaw.items(): decodedTag = ExifTags.TAGS.get(tag, tag) exifData[decodedTag] = value To read image url and get tags
from PIL import Image from urllib.request import urlopen from PIL.ExifTags import TAGS def get_exif(filename): image = Image.open(filename) image.verify() return image._getexif() def get_labeled_exif(exif): labeled = {} for (key, val) in exif.items(): labeled[TAGS.get(key)] = val return labeled my_image= urlopen(url) exif = get_exif(my_image) labeled = get_labeled_exif(exif) print(labeled) and to get GPS coordinate, Jayson DeLancey has excellent blog post.
I usually use pyexiv2 to set exif information in JPG files, but when I import the library in a script QGIS script crash.
I found a solution using the library exif:
It's so easy to use, and with Qgis I don,'t have any problem.
In this code I insert GPS coordinates to a snapshot of screen:
from exif import Image with open(file_name, 'rb') as image_file: my_image = Image(image_file) my_image.make = "Python" my_image.gps_latitude_ref=exif_lat_ref my_image.gps_latitude=exif_lat my_image.gps_longitude_ref= exif_lon_ref my_image.gps_longitude= exif_lon with open(file_name, 'wb') as new_image_file: new_image_file.write(my_image.get_file())