According to the specification, EXIF (Exchangeable image file format) is a standard that specifies the formats for images, sound, and tags used by digital still cameras and other systems that handle the image and sound files they record. Despite the confusing name, EXIF is just a metadata standard: it defines a way to store metadata properties in a variety of well-known image and audio formats. The EXIF tag structure is borrowed from TIFF files and declares tags that store technical details such as geolocation, the camera owner’s name, camera settings, and so on.
To access EXIF metadata in a file of any supported format, GroupDocs.Metadata provides the exif_package property on the root package.
fromgroupdocs.metadataimportMetadatadefread_basic_exif_properties():withMetadata("exif.tiff")asmetadata:root=metadata.get_root_package()# The EXIF package is exposed on the root; it may be absentexif=getattr(root,"exif_package",None)ifexifisnotNone:# Top-level EXIF tagsprint(exif.artist)print(exif.copyright)print(exif.image_description)print(exif.make)print(exif.model)print(exif.software)# The EXIF IFD sub-package holds camera/exposure detailsprint(exif.exif_ifd_package.body_serial_number)print(exif.exif_ifd_package.camera_owner_name)print(exif.exif_ifd_package.user_comment)# The GPS sub-package holds geolocation tagsprint(exif.gps_package.altitude)print(exif.gps_package.latitude_ref)print(exif.gps_package.longitude_ref)if__name__=="__main__":read_basic_exif_properties()
exif.tiff is the sample file used in this example. Click here to download it.
In some cases it’s necessary to read all EXIF tags from a file, including custom ones. The API provides direct access to the EXIF tags on different levels.
fromgroupdocs.metadataimportMetadatadefread_exif_tags():withMetadata("exif.jpg")asmetadata:root=metadata.get_root_package()exif=getattr(root,"exif_package",None)ifexifisnotNone:# to_list() yields every raw tag (id + value) at each levelfortaginexif.to_list():print(f"{tag.tag_id} = {tag.value}")# ...including the EXIF IFD sub-packagefortaginexif.exif_ifd_package.to_list():print(f"{tag.tag_id} = {tag.value}")# ...and the GPS sub-packagefortaginexif.gps_package.to_list():print(f"{tag.tag_id} = {tag.value}")if__name__=="__main__":read_exif_tags()
exif.jpg is the sample file used in this example. Click here to download it.
The API supports reading a specific EXIF tag through an indexer that takes a TiffTagID.
fromgroupdocs.metadataimportMetadatafromgroupdocs.metadata.formats.imageimportTiffTagIDdefread_specific_exif_tag():withMetadata("exif.tiff")asmetadata:root=metadata.get_root_package()exif=getattr(root,"exif_package",None)ifexifisnotNone:# Index the package by TiffTagID to read one specific tagsoftware=exif[TiffTagID.SOFTWARE]ifsoftwareisnotNone:print(f"Software: {software.value}")# The same indexer works on the EXIF IFD sub-packagecomment=exif.exif_ifd_package[TiffTagID.USER_COMMENT]ifcommentisnotNone:print(f"Comment: {comment.interpreted_value}")if__name__=="__main__":read_specific_exif_tag()
exif.tiff is the sample file used in this example. Click here to download it.
Software: Adobe Photoshop CS6 (Windows)
Comment: test comment
Update EXIF metadata in a convenient way using the ExifPackage properties. If the package is missing, create a new one.
fromgroupdocs.metadataimportMetadatafromgroupdocs.metadata.standards.exifimportExifPackagedefupdate_exif_properties():withMetadata("input.jpg")asmetadata:root=metadata.get_root_package()# Create an EXIF package if the image doesn't have one yetifgetattr(root,"exif_package",None)isNone:root.exif_package=ExifPackage()# Assign top-level EXIF propertiesroot.exif_package.copyright="Copyright (C) 2026 GroupDocs. All Rights Reserved."root.exif_package.image_description="test image"root.exif_package.software="GroupDocs.Metadata"# Assign properties on the EXIF IFD sub-packageroot.exif_package.exif_ifd_package.body_serial_number="test"root.exif_package.exif_ifd_package.camera_owner_name="GroupDocs"root.exif_package.exif_ifd_package.user_comment="test comment"# Persist the changesmetadata.save("output.jpg")if__name__=="__main__":update_exif_properties()
input.jpg is the sample file used in this example. Click here to download it.
The API allows adding or updating custom tags in an EXIF package using the typed TIFF tag classes.
fromgroupdocs.metadataimportMetadatafromgroupdocs.metadata.formats.imageimportTiffAsciiTag,TiffTagIDfromgroupdocs.metadata.standards.exifimportExifPackagedefset_custom_exif_tag():withMetadata("exif.tiff")asmetadata:root=metadata.get_root_package()ifgetattr(root,"exif_package",None)isNone:root.exif_package=ExifPackage()# Add known properties using typed TIFF tagsroot.exif_package.set(TiffAsciiTag(TiffTagID.ARTIST,"test artist"))root.exif_package.set(TiffAsciiTag(TiffTagID.SOFTWARE,"GroupDocs.Metadata"))metadata.save("output.tiff")if__name__=="__main__":set_custom_exif_tag()
exif.tiff is the sample file used in this example. Click here to download it.
The following typed tag classes are available in groupdocs.metadata.formats.image: TiffAsciiTag, TiffByteTag, TiffDoubleTag, TiffFloatTag, TiffLongTag, TiffRationalTag, TiffSByteTag, TiffShortTag, TiffSLongTag, TiffSRationalTag, TiffSShortTag, TiffUndefinedTag.
Removing EXIF metadata
To remove the EXIF package from a file, assign None to the exif_package property.
fromgroupdocs.metadataimportMetadatadefremove_exif_metadata():withMetadata("exif.jpg")asmetadata:root=metadata.get_root_package()# Assigning None drops the entire EXIF packageroot.exif_package=Nonemetadata.save("output.jpg")if__name__=="__main__":remove_exif_metadata()
exif.jpg is the sample file used in this example. Click here to download it.