Reading and writing IPTC metadata in Python using pyexiftool
The tool that we recommend the most for command-line use is Phil Harvey’s exiftool (exiftool.org).
Pyexiftool is a simple wrapper around the tool.
Note that pyexiftool requires the Perl exiftool to be installed on the host machine and simply uses Python exec() to run the command-line exiftool and process the results.
This may cause problems if you don’t have enough control over your environment to install exiftool.
Installing pyexiftool for Python is simple if your system already has exiftool installed:
python -m pip install -U pyexiftool
As the docs say, “Since exiftool
is run in batch mode, only a single instance needs to be launched and can be reused for many queries. This is much more efficient than launching a separate process for every single query.”
On this page:
- 1 Examples of reading IPTC metadata in Python using pyexiftool
- 1.1 View all embedded metadata for an image file
- 1.2 View a single-valued metadata property in an image file
- 1.3 View multi-valued properties in image files
- 1.4 View a structured property for an image file
- 1.5 View all properties read by Google Image Search for the Licensable badge feature
- 1.6 View all properties read by Google Image Search for Licensable badge and Synthetic Media features
- 2 Examples of writing IPTC metadata in Python using pyexiftool
- 3 Would you like more examples? Just ask!
Examples of reading IPTC metadata in Python using pyexiftool
To get you started quickly, here are some examples of things that can be done with it regarding IPTC metadata (we cover writing these fields below)
View all embedded metadata for an image file
Simply run exiftool with the file name / path to the image file that you wish to investigate:
% python
>>> import exiftool
... with exiftool.ExifTool() as et:
... print(et.execute("-XMP:all", "test-image.jpg"))
...
which will extract all XMP-encoded metadata including IPTC.
Another approach is to use the ExiftoolHelper feature of pyexiftool, which improves error handling:
% python
>>> from exiftool import ExifToolHelper
... with ExifToolHelper() as et:
... for d in et.get_metadata("test-image.jpg"):
... for k, v in d.items():
... print(f"{k} = {v}")
...
This will simply display all metadata (IPTC, Exif and other formats) that can be extracted from the file.
View a single-valued metadata property in an image file
Exiftool can extract any single property from a media file. To find out which tag to use, first consult the IPTC Photo Metadata Standard Specification to get the XMP tag used, then consult the exiftool XMP tags page to determine how to specify that tag for exiftool.
Show only the Digital Source Type value
% python
>>> import exiftool
... with exiftool.ExifTool() as et:
... print(et.execute("-XMP-iptcExt:digitalsourcetype", "test-image.jpg"))
...
[XMP] Digital Source Type : https://cv.iptc.org/newscodes/digitalsourcetype/digitalCapture
Show only the Credit Line value
% python
>>> import exiftool
... with exiftool.ExifTool() as et:
... print(et.execute("-XMP-photoshop:Credit", "test-image.jpg"))
...
[XMP] Credit : Jane Smith, Smith Photography Ltd
View multi-valued properties in image files
Here’s an example of viewing a non-structured but multi-valued property:
Show the creator value(s)
By default, exiftool shows multi-valued properties as comma-separated values on the same line:
% python
>>> import exiftool
... with exiftool.ExifTool() as et:
... print(et.execute("-XMP-dc:creator", "test-image.jpg"))
...
[XMP] Creator : Creator1 (ref2021.1), New Creator
To make it clear that this is in fact a repeatable value, you can ask for JSON-encoded output using execute_json()
:
% python
>>> import exiftool
... with exiftool.ExifTool() as et:
... print(et.execute_json("-XMP-dc:creator", "test-image.jpg"))
...
[{'SourceFile': 'test-image.jpg', 'XMP:Creator': ['Creator1 (ref2021.1)', 'New Creator']}]
View a structured property for an image file
Some properties (such as Licensor which is used for Google’s Licensable feature) are structured, which means they contain sub-properties. In this case, running the simple et.execute_json("-XMP-plus:Licensor", "test-image.jpg"))
returns no results.
The secret is to pass the -struct
option to the exiftool constructor:
% python
>>> from exiftool import ExifToolHelper
... with ExifToolHelper(common_args=["-struct", "-G1"]) as et:
... print(et.execute_json("-XMP-plus:Licensor", "test-image.jpg"))
...
[{'SourceFile': 'test-image.jpg', 'XMP-plus:Licensor': [{'LicensorCity': 'Licensor City 1 (ref2021.1)', 'LicensorCountry': 'Licensor Country 1 (ref2021.1)', 'LicensorEmail': 'Licensor Email 1 (ref2021.1)', 'LicensorExtendedAddress': 'Licensor Ext Addr 1 (ref2021.1)', 'LicensorID': 'Licensor ID 1 (ref2021.1)', 'LicensorName': 'Licensor Name 1 (ref2021.1)', 'LicensorPostalCode': 'Licensor Postcode 1 (ref2021.1)', 'LicensorRegion': 'Licensor Region 1 (ref2021.1)', 'LicensorStreetAddress': 'Licensor Street Addr 1 (ref2021.1)', 'LicensorTelephone1': 'Licensor Phone1 1 (ref2021.1)', 'LicensorTelephone2': 'Licensor Phone2 1 (ref2021.1)', 'LicensorTelephoneType1': 'Work', 'LicensorTelephoneType2': 'Cell', 'LicensorURL': 'Licensor URL 1 (ref2021.1)'}, {'LicensorCity': 'Licensor City 2 (ref2021.1)', 'LicensorCountry': 'Licensor Country 2 (ref2021.1)', 'LicensorEmail': 'Licensor Email 2 (ref2021.1)', 'LicensorExtendedAddress': 'Licensor Ext Addr 2 (ref2021.1)', 'LicensorID': 'Licensor ID 2 (ref2021.1)', 'LicensorName': 'Licensor Name 2 (ref2021.1)', 'LicensorPostalCode': 'Licensor Postcode 2 (ref2021.1)', 'LicensorRegion': 'Licensor Region 2 (ref2021.1)', 'LicensorStreetAddress': 'Licensor Street Addr 2 (ref2021.1)', 'LicensorTelephone1': 'Licensor Phone1 2 (ref2021.1)', 'LicensorTelephone2': 'Licensor Phone2 2 (ref2021.1)', 'LicensorTelephoneType1': 'Work', 'LicensorTelephoneType2': 'Cell', 'LicensorURL': 'Licensor URL 2 (ref2021.1)'}]}]
View all properties read by Google Image Search for the Licensable badge feature
To read more than one property from a file, simply specify multiple Exiftool tags, each prefixed with a dash/hyphen character.
% python
>>> from exiftool import ExifToolHelper
... with ExifToolHelper(common_args=["-struct", "-G1"]) as et:
... print(et.execute_json("-XMP-dc:creator","-XMP-photoshop:Credit","-XMP-dc:rights","-XMP-xmpRights:WebStatement","-XMP-plus:LicensorURL", "test-image.jpg"))
...
[{'SourceFile': 'test-image.jpg', 'XMP-dc:Creator': ['Creator1 (ref2021.1)', 'New Creator'], 'XMP-photoshop:Credit': 'Credit Line (ref2021.1)', 'XMP-dc:Rights': 'Copyright (Notice) 2021.1 IPTC - www.iptc.org (ref2021.1)', 'XMP-xmpRights:WebStatement': 'http://www.WebStatementOfRights.org/2021.1'}]
View all properties read by Google Image Search for Licensable badge and Synthetic Media features
% python
>>> from exiftool import ExifToolHelper
... with ExifToolHelper(common_args=["-struct", "-G1"]) as et:
... print(et.execute_json("-XMP-dc:creator","-XMP-photoshop:Credit","-XMP-dc:rights","-XMP-xmpRights:WebStatement","-XMP-plus:LicensorURL", "-XMP-iptcExt:DigitalSourceType", "test-image.jpg"))
...
[{'SourceFile': 'test-image.jpg', 'XMP-dc:Creator': ['Creator1 (ref2021.1)', 'New Creator'], 'XMP-photoshop:Credit': 'Credit Line (ref2021.1)', 'XMP-dc:Rights': 'Copyright (Notice) 2021.1 IPTC - www.iptc.org (ref2021.1)', 'XMP-xmpRights:WebStatement': 'http://www.WebStatementOfRights.org/2021.1', 'XMP-iptcExt:DigitalSourceType': 'http://cv.iptc.org/newscodes/digitalsourcetype/softwareImage'}]
Examples of writing IPTC metadata in Python using pyexiftool
The same exiftool XMP tags can be used to write metadata to image files on the command line.
Writing Digital Source Type for synthetic media
Note that the value can be any text string, but we recommend using a full URI from the IPTC Digital Source Type vocabulary:
% python
>>> from exiftool import ExifToolHelper
... with ExifToolHelper() as et:
... et.execute("-XMP-iptcExt:digitalsourcetype=https://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia", "test-image.jpg")
...
'1 image files updated\n'
% exiftool -XMP-iptcExt:digitalsourcetype test-image.jpg
Digital Source Type : https://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia
(Note that Google’s documentation on Digital Source Type for synthetic media specifies using only the ID, not the full URI. So if you are writing software to read these values, we recommend that you support both the fully-expanded URI and the short ID.)
Writing Creator and Credit Line metadata
The contents of these fields will be displayed in the Google Images search results details panel.
% python
>>> from exiftool import ExifToolHelper
... with ExifToolHelper() as et:
... et.execute("-XMP-dc:creator=Jane Smith","-XMP-photoshop:Credit=Jane Smith, Smith Photography Ltd","-XMP-dc:rights=Copyright Smith Photography Ltd 2023","-XMP-xmpRights:WebStatement=http://smithphotography.com/licensing/","-XMP-plus:LicensorURL=http://www.mypictureagency.com/obtain-licence/","test-image.jpg")
...
'1 image files updated\n'
% exiftool -XMP-dc:creator -XMP-photoshop:Credit -XMP-dc:rights -XMP-xmpRights:WebStatement -XMP-plus:LicensorURL -XMP-iptcExt:DigitalSourceType test-image.jpg
Creator : Jane Smith
Credit : Jane Smith, Smith Photography Ltd
Rights : Copyright Smith Photography Ltd 2023
Web Statement : http://smithphotography.com/licensing/
Licensor URL : http://www.mypictureagency.com/obtain-licence/
Writing Licensor URL metadata
This triggers the “Get this image on…” text in Google Images search results.
% python
>>> from exiftool import ExifToolHelper
... with ExifToolHelper() as et:
... et.execute("-XMP-plus:LicensorURL=http://www.mypictureagency.com/obtain-licence/","test-image.jpg")
...
'1 image files updated\n'
% exiftool -XMP-plus:LicensorURL test-image.jpg
Licensor URL : http://www.mypictureagency.com/obtain-licence/
Writing Web Statement of Rights metadata
This triggers the “Licensable” badge in Google image search results.
% python
>>> from exiftool import ExifToolHelper
... with ExifToolHelper() as et:
... et.execute("-XMP-xmpRights:WebStatement=http://smithphotography.com/licensing/","test-image.jpg")
...
'1 image files updated\n'
% exiftool -XMP-xmpRights:WebStatement test-image.jpg
Web Statement : http://smithphotography.com/licensing/
Writing all metadata that can be read by Google Search
% python
>>> from exiftool import ExifToolHelper
... with ExifToolHelper() as et:
... et.execute("-XMP-dc:creator=Jane Smith","-XMP-photoshop:Credit=Jane Smith, Smith Photography Ltd","-XMP-dc:rights=Copyright Smith Photography Ltd 2023","-XMP-xmpRights:WebStatement=http://smithphotography.com/licensing/","-XMP-plus:LicensorURL=http://www.mypictureagency.com/obtain-licence/","-XMP-iptcExt:DigitalSourceType=https://cv.iptc.org/newscodes/digitalsourcetype/digitalCapture","test-image.jpg")
...
'1 image files updated\n'
% exiftool -XMP-dc:creator -XMP-photoshop:Credit -XMP-dc:rights -XMP-xmpRights:WebStatement -XMP-plus:LicensorURL -XMP-iptcExt:DigitalSourceType test-image.jpg
Creator : Jane Smith
Credit : Jane Smith, Smith Photography Ltd
Rights : Copyright Smith Photography Ltd 2023
Web Statement : http://smithphotography.com/licensing/
Licensor URL : http://www.mypictureagency.com/obtain-licence/
Digital Source Type : https://cv.iptc.org/newscodes/digitalsourcetype/digitalCapture
Appending to an existing set of repeatable tags
exiftool allows appending to a repeatable list of tags, for example Image Creator (dc:creator). This functionality also works through pyexiftool:
% python
>>> from exiftool import ExifToolHelper
>>> with ExifToolHelper() as et:
... et.execute("-XMP-dc:creator+=Jane Smith","test-image.jpg")
...
'1 image files updated\n'
% exiftool -XMP-dc:creator test-image.jpg
Creator : John Smith, Jane Smith
Would you like more examples? Just ask!
If you would like to see other exiftool examples, or if you have suggestions of exiftool incantations that you find useful and you would like to share them with others, please let us know!