I use the following code to extract GPS location both from JPG and HEIC files:
#coding=utf-8
from PIL import Image
from urllib.request import urlopen
from PIL.ExifTags import TAGS
from PIL.ExifTags import GPSTAGS
from pillow_heif import register_heif_opener
def get_exif(filename):
image = Image.open(filename)
image.verify()
return image._getexif()
def get_geotagging(exif):
if not exif:
raise ValueError("No EXIF metadata found")
geotagging = {}
for (idx, tag) in TAGS.items():
if tag == 'GPSInfo':
if idx not in exif:
raise ValueError("No EXIF geotagging found")
for (key, val) in GPSTAGS.items():
if key in exif[idx]:
geotagging[val] = exif[idx][key]
return geotagging
register_heif_opener()
my_image='IMG_9610.HEIC'
#my_image='IMG_20210116_215317.jpg'
exif = get_exif(my_image)
labeled = get_geotagging(exif)
print(labeled)
This code works well with JPEG files, but returns the following error with HEIC:
AttributeError: _getexif
If I add the following function
def get_labeled_exif(exif):
labeled = {}
for (key, val) in exif.items():
labeled[TAGS.get(key)] = val
return labeled
and replace '_getexif()' with 'getexif()' then it works for both files, but the data is encrypted there - 'GPSInfo': 1234
and get_geotagging()
doesn't work for such exif.
How could I fix it?
The code below is able to extract the GEO tagging information from a HEIC image file on my system.
from PIL import Image
from pillow_heif import register_heif_opener
def get_exif(filename):
image = Image.open(filename)
image.verify()
return image.getexif().get_ifd(0x8825)
def get_geotagging(exif):
geo_tagging_info = {}
if not exif:
raise ValueError("No EXIF metadata found")
else:
gps_keys = ['GPSVersionID', 'GPSLatitudeRef', 'GPSLatitude', 'GPSLongitudeRef', 'GPSLongitude',
'GPSAltitudeRef', 'GPSAltitude', 'GPSTimeStamp', 'GPSSatellites', 'GPSStatus', 'GPSMeasureMode',
'GPSDOP', 'GPSSpeedRef', 'GPSSpeed', 'GPSTrackRef', 'GPSTrack', 'GPSImgDirectionRef',
'GPSImgDirection', 'GPSMapDatum', 'GPSDestLatitudeRef', 'GPSDestLatitude', 'GPSDestLongitudeRef',
'GPSDestLongitude', 'GPSDestBearingRef', 'GPSDestBearing', 'GPSDestDistanceRef', 'GPSDestDistance',
'GPSProcessingMethod', 'GPSAreaInformation', 'GPSDateStamp', 'GPSDifferential']
for k, v in exif.items():
try:
geo_tagging_info[gps_keys[k]] = str(v)
except IndexError:
pass
return geo_tagging_info
register_heif_opener()
my_image = 'IMG_8362.heic'
image_info = get_exif(my_image)
results = get_geotagging(image_info)
print(results)
# x used to mask data
{'GPSLatitudeRef': 'N',
'GPSLatitude': '(3x.0, 5x.0, 1x.0x)',
'GPSLongitudeRef': 'W',
'GPSLongitude': '(8x.0, 2x.0, 5x.2x)',
'GPSAltitudeRef': "b'\\x00'",
'GPSAltitude': '279.63243243243244',
'GPSSpeedRef': 'K',
'GPSSpeed': '0.04649941997239198',
'GPSImgDirectionRef': 'T',
'GPSImgDirection': '274.37165833514456',
'GPSDestBearingRef': 'T',
'GPSDestBearing': '27x.37165833514456',
'GPSDateStamp': '2022:06:12'}
----------------------------------------
My system information
----------------------------------------
Platform: Apple
OS Version: macOS Catalina 10.15.7
Python: 3.9
Pillow: 9.1.1
pillow_heif: 0.3.0
----------------------------------------
The short answer is that Pillow does not currently support the High Efficiency Image Format (HEIF) file format.
Reference:
One of the workarounds for this issue is pyheif. This Python package has the functionality to covert a HEIC image to a JPEG one. After this transformation Pillow
will be able to read the data from the image.
Another workaround for this format reading problem is piexif. Here is an answer that I posted on converting a TIFF
file to a JPEG one for reading with Pillow
.
You could also use ExifTool, which reads HEIC files out of the box. Using it is slightly more complicated, because it requires using subprocess
.