python-3.xexifheic

How to extract GPS location from HEIC files?


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?


Solution

  • UPDATED POST 06-12-2022

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

    ORIGINAL POST 06-11-2022

    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.