3

I use to imports JPG images with "ImportPhotos". It lacks some importants EXIF Tags such : ISO , Shutter Speed, aperture, resolution and Field of view.

There is an answer about how to import XMP Metadata using the layer created by ImportPhoto, using the path (stored in attributes fields).

I need help to complete this script to be able to import as well the EXIF TAG/values listed above.

You can find some sample images there: https://we.tl/t-BjPuzBGMRc

4

It's hard to give a complete solution of your question, because exif tags have different types of data and it should be handled one by one. But as a minimal solution, you can follow next instructions. You should follow instructions after you imported photos using Import Photos plugin

PIL Solution

If you run Image.open("file_path")._getexif(), you'll get an output structured as python dictionary data like below. (I added data type as comment)

{
  256: 5472, # integer
  257: 3648, # integer
  258: (8, 8, 8), # tuple
  270: 'default', #string
  271: 'Hasselblad',
  272: 'L1D-20c',
  274: 1,
  531: 1,
  277: 3,
  282: (72, 1), # tuple, XResolution
  283: (72, 1), # tuple, YResolution
  40092: b '0\x00.\x009..........',
  34853: {  ### GPSInfo part ###
      0: b '\x02\x03\x00\x00',
      1: 'S',
      2: ((21, 1), (19, 1), (556759, 10000)),
      3: 'E',
      4: ((55, 1), (28, 1), (282077, 10000)),
      5: b '\x00',
      6: (395, 10)
  },
  296: 2,
  34665: 332,
  305: '10.00.10.04',
  306: '2019:10:30 10:39:47', # string but it refers date and time. it should be handled. 
  ...
  ...
  ...
}

It means that EXIF metadata is saved by index instead of tag's name. So you need tags name to know what is what, and PIL package provides them via TAGS. Key 34853 includes GPS information. PIL package provides tags' name for GPSInfo via GPSTAGS.

EXIF metadata has different data types, so you should decide which tag you want to use, and handle it by type. Run next script to see which exif metadata your image has. If you don't see a tag you need, it means that the image probably doesn't have it or the tag wasn't saved as EXIF or PIL doesn't give you that information or etc. (I'm not so sure).

from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS

img = Image.open(file_path)
exif = { TAGS[k]: v for k, v in img._getexif().items() if k in TAGS }
print(exif.keys()) # list of exif metadata exists in the image

geoexif = {}
for (tag, value) in GPSTAGS.items():
    if tag in exif["GPSInfo"]:
        geoexif[value] = geotags[tag]

print(geoexif.keys()) # list of GPS information exists in the image

# Output:  exif tags
# dict_keys(['ImageWidth', 'ImageLength', 'BitsPerSample', 'ImageDescription', 'Make', 'Model', 'Orientation', ......}

# Output:  GPSInfo tags your image has in exif
# dict_keys(['GPSVersionID', 'GPSLatitudeRef', 'GPSLatitude', 'GPSLongitudeRef', 'GPSLongitude', 'GPSAltitudeRef', 'GPSAltitude'])

Decide tags, and add fields to attribute table for them. For example, max_apert for MaxApertureValue and iso for ISOSpeedRatings. Select layer and use the following script.

from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS

layer = iface.activeLayer()
dpr = layer.dataProvider()

apr_ind = layer.fields().indexFromName("max_apert")
iso_ind  = layer.fields().indexFromName("iso")
# lat_ind  = layer.fields().indexFromName("lat")

for feature in layer.getFeatures():
    file_path = feature["Path"] 
    print(file_path)

    img = Image.open(file_path)
    exif = { TAGS[k]: v for k, v in img._getexif().items() if k in TAGS }

#    # if you need other GPSInfo
#    geoexif = {}
#    for (tag, value) in GPSTAGS.items():
#        if tag in exif["GPSInfo"]:
#            geoexif[value] = geotags[tag]    

    # "MaxApertureValue": (2971, 1000)  # needs process
    apr = exif["MaxApertureValue"][0] / exif["MaxApertureValue"][1] # process
    iso = exif["ISOSpeedRatings"]
    # lat = geoexif["GPSLatitude"] # ((21,1),(19,1)) needs to be converted 
                                   # into float (real) or into DMS (string)

    dpr.changeAttributeValues({ feature.id():{apr_ind: apr,
                                              iso_ind: iso }})
                                              #, lat_ind: lat }})

enter image description here


pyexiv2 Solution

When you run next script, you'll see all metadata includes EXIF, IPTC, XMP .

from pyexiv2 import Image

image = Image("file_path")
metadata = image.read_all() # returns all metadata (EXIF, IPTC, XMP)
print(metadata.keys()) # prints dict_keys(['EXIF', 'IPTC', 'XMP'])
print(metadata["EXIF"]) # prints EXIF metadata key and values

Then, decide tags you want to add, add new fields for them, customize next script, select layer and run the script.

from pyexiv2 import Image

layer = iface.activeLayer()
dpr = layer.dataProvider()

apr_ind = layer.fields().indexFromName("max_apert")
iso_ind  = layer.fields().indexFromName("iso")

for feature in layer.getFeatures():
    file_path = feature["Path"] 
    print(file_path)

    image = Image(file_path)
    metadata = image.read_all()
    exif = metadata["EXIF"]

    # "MaxApertureValue": '2971/1000'  # string, needs process
    # eval method runs a script as if it is a python code
    apr = eval(exif["Exif.Photo.MaxApertureValue"]) # returns 2971/1000 = 2.971
    iso = int(exif["Exif.Photo.ISOSpeedRatings"])

    dpr.changeAttributeValues({ feature.id():{apr_ind: apr,
                                              iso_ind: iso }})
1
  • awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html This is the list of the TAG - KEY. It helps to match the first step of your code (when we get a list of index / value) with the used TAG Name, and also to get informations about every field (type, eg.) For example, that's how I where able to use KEY 33437 // TAG "FNumber" instead of MaxApertureValue. This solution works like a charm, thanks you so much ! – zlikotp Dec 16 '19 at 15:36

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.