tagkit.image.exif

EXIF image handling functionality.

This module provides classes for reading, modifying, and removing EXIF tags from image files.

Module Contents

Classes

ExifImage

Handler for reading, modifying, and removing EXIF tags from a single image file.

Data

API

tagkit.image.exif.DATETIME_TAG_PRECEDENCE = ['DateTimeOriginal', 'DateTimeDigitized', 'DateTime']
class tagkit.image.exif.ExifImage(file_path: tagkit.core.types.FilePath, tag_filter: Optional[Iterable[Union[int, str]]] = None, thumbnail: Optional[bool] = None, ifd: Optional[tagkit.core.types.IfdName] = None, io_backend: Optional[tagkit.tag_io.base.ExifIOBackend] = None)

Handler for reading, modifying, and removing EXIF tags from a single image file.

Args:

file_path: Path to the image file. tag_filter: Optional list of tag names or IDs to filter by thumbnail: If True, use thumbnail IFD ifd: Specific IFD to use io_backend: Custom backend for EXIF IO. Defaults to piexif.

Example:
>>> exif = ExifImage('image1.jpg')
>>> exif.tags['Make']
ExifTag(id=271, value='Tagkit', ifd='IFD0')

Initialization

__len__() int

Return the number of tags in this image.

write_tag(tag_key: Union[str, int], value: tagkit.core.types.TagValue, ifd: Optional[tagkit.core.types.IfdName] = None)

Set the value of a specific EXIF tag.

Args:

tag_key: Tag name or tag ID. value: Value to set. ifd: Specific IFD to use.

Raises:

KeyError: If the tag is not found. ValueError: If the tag or IFD is invalid.

Example:
>>> exif = ExifImage('image1.jpg')
>>> exif.write_tag('Artist', 'John Doe', ifd='IFD0')
write_tags(tags: Mapping[Union[str, int], tagkit.core.types.TagValue], ifd: Optional[tagkit.core.types.IfdName] = None)

Set multiple EXIF tags at once.

Args:

tags: A dictionary mapping tag names or IDs to values. ifd: Specific IFD to use for all tags (overrides default logic).

Example:
>>> exif = ExifImage('image1.jpg')
>>> exif.write_tags({'Artist': 'Jane', 'Copyright': '2025 John'})
delete_tag(tag_key: Union[str, int], ifd: Optional[tagkit.core.types.IfdName] = None)

Remove a specific EXIF tag if it exists.

Args:

tag_key: Tag name or tag ID. ifd: Specific IFD to use.

Raises:

ValueError: If the tag or IFD is invalid.

Example:
>>> exif = ExifImage('image10.jpg')
>>> exif.delete_tag('Make', ifd='IFD0')
delete_tags(tag_keys: Iterable[Union[str, int]], ifd: Optional[tagkit.core.types.IfdName] = None)

Remove multiple EXIF tags at once.

Args:

tag_keys: A list of tag names or tag IDs to remove. ifd: Specific IFD to use for all tags (overrides default logic).

Example:
>>> exif = ExifImage('image1.jpg')
>>> exif.delete_tags(['Artist', 'Copyright'])
read_tag(tag_key: Union[str, int], ifd: Optional[tagkit.core.types.IfdName] = None, format_value: bool = False, binary_format: Optional[str] = None) tagkit.core.types.TagValue

Read the value of a specific EXIF tag.

Args:

tag_key: Tag name or tag ID. ifd: Specific IFD to use. format_value: If True, return formatted string value; if False, return raw value. binary_format: How to format binary data - ‘bytes’, ‘hex’, or ‘base64’. Only used when format_value=True.

Returns:

The tag value (formatted or raw depending on format_value parameter).

Raises:

TagNotFound: If the tag is not present in the image. InvalidTagName, InvalidTagId: If the provided tag name or id is invalid. ValueError: If the tag or IFD is invalid or if binary_format is unsupported.

Example:
>>> exif = ExifImage('image1.jpg')
>>> exif.read_tag('Make')
'Tagkit'
>>> exif.read_tag('Make', format_value=False)
'Tagkit'
read_tags(tag_keys: list[Union[str, int]], ifd: Optional[tagkit.core.types.IfdName] = None, format_value: bool = False, binary_format: Optional[str] = None, skip_missing: bool = False) dict[str, tagkit.core.types.TagValue]

Read multiple EXIF tags at once.

Args:

tag_keys: A list of tag names or tag IDs to read. ifd: Specific IFD to use for all tags (overrides default logic). format_value: If True, return formatted string values; if False, return raw values. binary_format: How to format binary data - ‘bytes’, ‘hex’, or ‘base64’. Only used when format_value=True. skip_missing: If True, skip tags that are not present in the image. If False, raise TagNotFound if any tag is missing.

Returns:

A dictionary mapping tag names to their values. Only tags that exist in the image are included in the result.

Example:
>>> exif = ExifImage('image1.jpg')
>>> exif.read_tags(['Make', 'Model'])
{'Make': 'Tagkit', 'Model': 'Tagkit Camera'}
property tags: Mapping[str, tagkit.core.tag.ExifTag]

Get the filtered tags based on tag_filter and ifd settings.

Returns:

dict: A dictionary of filtered tags with tag names as keys.

save(create_backup: bool = False)

Write the modified EXIF data back to the image file.

Raises:

IOError: If writing to the file fails.

as_dict(binary_format: Optional[str] = None) dict[str, dict[str, Union[str, int]]]

Convert the image data to a nested dictionary structure.

Args:
binary_format: How to format binary data - ‘bytes’, ‘hex’, or ‘base64’

If None, <bytes: N> will be shown as a placeholder.

Returns:

dict: A nested dictionary containing the EXIF data for the image.

Example:
>>> exif = ExifImage('image2.jpg')
>>> exif.as_dict()
{'Make': {'id': 271, 'value': 'Tagkit', 'ifd': 'IFD0'}, 'DateTime': {'id': 306, 'value': '2025:05:02 14:30:00', 'ifd': 'IFD0'}}
get_datetime(tag: Optional[str] = None) datetime.datetime

Get datetime from EXIF tags.

By default, uses precedence order: DateTimeOriginal > DateTimeDigitized > DateTime. Can also retrieve a specific datetime tag.

Args:

tag: Optional specific datetime tag name to retrieve

Returns:

datetime: datetime object for image.

Raises:

DateTimeError: If a datetime tag is found but cannot be parsed. TagNotFound: If no datetime tags are found. InvalidTagName: If the provided tag name is invalid.

Examples:
>>> exif = ExifImage('image1.jpg')
>>> dt = exif.get_datetime()
>>> print(dt)
2025-05-01 14:30:00
>>> dt = exif.get_datetime(tag='DateTimeOriginal')
>>> print(dt)
2025-05-01 14:30:00
set_datetime(dt: datetime.datetime, tags: Optional[Iterable[str]] = None) None

Set datetime EXIF tags (in-memory, not saved until save() is called).

By default, updates all three datetime tags (DateTime, DateTimeOriginal, DateTimeDigitized) to ensure consistency. Can optionally specify which tags to update.

Args:

dt: Datetime object to set. tags: Optional list of specific datetime tag names to update. If None, updates all three datetime tags. Valid values are ‘DateTime’, ‘DateTimeOriginal’, ‘DateTimeDigitized’

Examples:
>>> from datetime import datetime
>>> exif = ExifImage('image1.jpg')
>>> exif.set_datetime(datetime(2025, 6, 15, 10, 30, 0))
>>> exif.save()
>>> # Update only specific tags
>>> exif.set_datetime(
...     datetime(2025, 6, 15, 10, 30, 0),
...     tags=['DateTimeOriginal'],
... )
>>> exif.save()
offset_datetime(delta: datetime.timedelta, tags: Optional[Iterable[str]] = None) None

Offset datetime EXIF tags by a timedelta (in-memory, not saved until save() is called).

Adds (or subtracts if negative) a timedelta to existing datetime tags. By default, offsets all present datetime tags.

Args:

delta: Timedelta to add to existing datetime values. tags: Optional list of specific datetime tag names to offset. If None, offsets all present datetime tags. Valid values are ‘DateTime’, ‘DateTimeOriginal’, ‘DateTimeDigitized’

Raises:

DateTimeError: If a datetime tag is found but cannot be parsed.

Examples:
>>> from datetime import timedelta
>>> exif = ExifImage('image1.jpg')
>>> exif.offset_datetime(timedelta(hours=2))
>>> exif.save()
>>> # Offset only specific tag
>>> exif.offset_datetime(timedelta(days=-1), tags=['DateTimeOriginal'])
>>> exif.save()
get_all_datetimes() dict[str, datetime.datetime]

Get all datetime EXIF tags from the image.

Returns a dictionary mapping tag names to datetime objects for all datetime-related EXIF tags that are present.

Returns:

Dictionary mapping tag names to datetime objects. Only includes tags that are present in the image.

Raises:

DateTimeError: If a datetime tag is found but cannot be parsed.

Examples:
>>> exif = ExifImage('image1.jpg')
>>> datetimes = exif.get_all_datetimes()
>>> for tag_name, dt in datetimes.items():
...     print(f"{tag_name}: {dt}")
DateTimeOriginal: 2025-05-01 14:30:00
DateTime: 2025-05-01 14:30:00