In Python, how do I read the exif data for an image?

I'm using PIL. How do I turn the EXIF data of a picture into a dictionary?

2

9 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 } 
12

For 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 an Exif instance. Values can be retrieved and set like a dictionary. When saving JPEG, PNG or WEBP, the instance can be passed as an exif argument 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.

1

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

I 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') 
3
import 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

2

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

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like