tagkit.image.collection¶
Collection of EXIF image data for multiple files.
This module provides the ExifImageCollection class for working with EXIF data from multiple image files.
Module Contents¶
Classes¶
A collection of EXIF data for multiple image files. |
API¶
- class tagkit.image.collection.ExifImageCollection(files: Iterable[tagkit.core.types.FilePath], *, tag_filter: Optional[Iterable[Union[int, str]]] = None, ifd: Optional[tagkit.core.types.IfdName] = None)¶
A collection of EXIF data for multiple image files.
This class provides a convenient way to access EXIF data from multiple files.
- Args:
files: List of paths to image files. tag_filter: Optional list of tag names or IDs to filter by. ifd: Specific IFD to use.
- Attributes:
files (Dict[str, ExifImage]): Dictionary mapping file paths to their EXIF data.
Initialization
Initialize the collection with a list of file paths.
- Args:
files: List of paths to image files. tag_filter: Optional list of tag names or IDs to filter by. ifd: Specific IFD to use.
- as_dict(binary_format: Optional[str] = None) dict[str, dict[str, dict[str, Union[str, int]]]]¶
Convert the collection to a dictionary.
- Args:
- binary_format: Format for binary data (‘hex’, ‘base64’, or None for default).
If None, <bytes: N> will be shown as a placeholder.
- Returns:
Dictionary mapping file paths to their EXIF data dictionaries.
- Example:
>>> collection = ExifImageCollection(["image2.jpg", "image3.jpg"]) >>> collection.as_dict() {'image2.jpg': {'Make': {'id': 271, 'value': 'Tagkit', 'ifd': 'IFD0'}, 'DateTime': {'id': 306, 'value': '2025:05:02 14:30:00', 'ifd': 'IFD0'}}, 'image3.jpg': {'Make': {'id': 271, 'value': 'Tagkit', 'ifd': 'IFD0'}}}
- property n_tags: int¶
Get the total number of tags across all files.
- Returns:
Total number of tags.
- Example:
>>> collection = ExifImageCollection(["image1.jpg", "image2.jpg"]) >>> collection.n_tags 11
- property n_files: int¶
Get the number of files in the collection.
- Returns:
Number of files.
- Example:
>>> collection = ExifImageCollection(["image1.jpg", "image2.jpg"]) >>> collection.n_files 2
- _normalize_filenames(files: Optional[Iterable[tagkit.core.types.FilePath]]) list[str]¶
Normalize file names to string keys and validate their presence in the collection.
- Args:
files: Iterable of file paths (can be strings or Path objects).
- Returns:
List of normalized file names (strings).
- Raises:
KeyError: If a file is not found in the collection.
- write_tag(tag_key: Union[str, int], value: tagkit.core.types.TagValue, ifd: Optional[tagkit.core.types.IfdName] = None, files: Optional[Iterable[tagkit.core.types.FilePath]] = None)¶
Set the value of a specific EXIF tag for all or selected images in the collection.
- Args:
tag_key: Tag name or tag ID. value: Value to set. ifd: Specific IFD to use. files: Iterable of file names (keys in self.files) to update. If None, update all.
- Raises:
KeyError: If a file is not found in the collection. ValueError: If the tag or IFD is invalid.
- Example:
>>> from tagkit.image.collection import ExifImageCollection >>> collection = ExifImageCollection(["image1.jpg", "image2.jpg"]) >>> collection.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, files: Optional[Iterable[tagkit.core.types.FilePath]] = None)¶
Set multiple EXIF tags for all or selected images in the collection.
- Args:
tags: A dictionary mapping tag names or IDs to values. ifd: Specific IFD to use for all tags. files: Iterable of file names (keys in self.files) to update. If None, update all.
- Example:
>>> collection = ExifImageCollection(["image1.jpg", "image2.jpg"]) >>> collection.write_tags({'Artist': 'Jane', 'Copyright': '2025 John'})
- delete_tag(tag_key: Union[str, int], ifd: Optional[tagkit.core.types.IfdName] = None, files: Optional[Iterable[tagkit.core.types.FilePath]] = None)¶
Remove a specific EXIF tag from all or selected images in the collection. If a file does not contain the tag, it is silently ignored.
- Args:
tag_key: Tag name or tag ID. ifd: Specific IFD to use. files: Iterable of file names (keys in self.files) to update. If None, update all.
- Raises:
KeyError: If a file is not found in the collection. ValueError: If the tag or IFD is invalid.
- Example:
>>> from tagkit.image.collection import ExifImageCollection >>> collection = ExifImageCollection(["image1.jpg", "image2.jpg"]) >>> collection.write_tag('Artist', 'John Doe', ifd='IFD0') >>> collection.delete_tag('Artist', ifd='IFD0')
- delete_tags(tag_keys: Iterable[Union[str, int]], ifd: Optional[tagkit.core.types.IfdName] = None, files: Optional[Iterable[tagkit.core.types.FilePath]] = None)¶
Remove multiple EXIF tags from all or selected images in the collection. If a file does not contain a tag, it is silently ignored.
- Args:
tag_keys: A list of tag names or tag IDs to remove. ifd: Specific IFD to use for all tags. files: Iterable of file names (keys in self.files) to update. If None, update all.
- Example:
>>> collection = ExifImageCollection(["image1.jpg", "image2.jpg"]) >>> collection.delete_tags(['Artist', 'Copyright'])
- save_all(create_backup: bool = False)¶
Save all modified EXIF data back to their respective image files.
- Args:
create_backup: If True, create a backup of each file before saving.
- Example:
>>> from tagkit.image.collection import ExifImageCollection >>> collection = ExifImageCollection(["image1.jpg", "image2.jpg"]) >>> collection.write_tag('Artist', 'John Doe') >>> collection.save_all(create_backup=True)
- get_datetime(files: Optional[Iterable[tagkit.core.types.FilePath]] = None, tag: Optional[str] = None) dict[str, datetime.datetime]¶
Get datetime from EXIF tags for all or selected images in the collection.
- Args:
files: Iterable of file names to query. If None, queries all files. tag: Optional specific datetime tag name to retrieve. If tag is None, precedence order is used to select the most relevant datetime tag (DateTimeOriginal > DateTimeDigitized > DateTime).
- Returns:
Dictionary mapping file names to datetime objects (or None if not found).
- Example:
>>> collection = ExifImageCollection(['image1.jpg', 'image2.jpg']) >>> datetimes = collection.get_datetime() >>> for filename, dt in datetimes.items(): ... print(f"{filename}: {dt}") image1.jpg: 2025-05-01 14:30:00 image2.jpg: 2025-05-02 14:30:00
- set_datetime(dt: datetime.datetime, tags: Optional[Iterable[str]] = None, files: Optional[Iterable[tagkit.core.types.FilePath]] = None) None¶
Set datetime EXIF tags for all or selected images (in-memory, not saved).
- Args:
dt: Datetime object to set. tags: Optional list of specific datetime tag names to update. If None, updates all three datetime tags. files: Iterable of file names to update. If None, updates all files.
- Example:
>>> from datetime import datetime >>> collection = ExifImageCollection(['image1.jpg', 'image2.jpg']) >>> collection.set_datetime(datetime(2025, 6, 15, 10, 30, 0)) >>> collection.save_all()
- offset_datetime(delta: datetime.timedelta, tags: Optional[Iterable[str]] = None, files: Optional[Iterable[tagkit.core.types.FilePath]] = None) None¶
Offset datetime EXIF tags by a timedelta for all or selected images (in-memory).
- 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. files: Iterable of file names to update. If None, updates all files.
- Example:
>>> from datetime import timedelta >>> collection = ExifImageCollection(['image1.jpg', 'image2.jpg']) >>> collection.offset_datetime(timedelta(hours=-5)) >>> collection.save_all()
- get_all_datetimes(files: Optional[Iterable[tagkit.core.types.FilePath]] = None) dict[str, dict[str, datetime.datetime]]¶
Get all datetime EXIF tags for all or selected images in the collection.
- Args:
files: Iterable of file names to query. If None, queries all files.
- Returns:
Dictionary mapping file names to dictionaries of datetime tags.
- Example:
>>> collection = ExifImageCollection(['image1.jpg', 'image2.jpg']) >>> all_datetimes = collection.get_all_datetimes() >>> for filename, datetimes in all_datetimes.items(): ... print(f"{filename}:") ... for tag_name, dt in datetimes.items(): ... print(f" {tag_name}: {dt}") image1.jpg: DateTimeOriginal: 2025-05-01 14:30:00 DateTime: 2025-05-01 14:30:00 image2.jpg: DateTime: 2025-05-02 14:30:00
- read_tag(tag_key: Union[str, int], ifd: Optional[tagkit.core.types.IfdName] = None, format_value: bool = False, binary_format: Optional[str] = None, files: Optional[Iterable[tagkit.core.types.FilePath]] = None, skip_missing: bool = False) dict[str, tagkit.core.types.TagValue]¶
Read the value of a specific EXIF tag from all or selected images in the collection.
- Args:
tag_key: Tag name or tag ID. ifd: Specific IFD to use. 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. files: Iterable of file names (keys in self.files) to read from. If None, read from all. skip_missing: If True, skip files where the tag is missing; if False, raise if missing.
- Returns:
A dictionary mapping file names to tag values.
- Raises:
KeyError: If a file is not found in the collection, or if a tag is missing (when skip_missing=False). ValueError: If the tag or IFD is invalid.
- Example:
>>> from tagkit.image.collection import ExifImageCollection >>> collection = ExifImageCollection(["image1.jpg", "image2.jpg"]) >>> collection.read_tag('Make') {'image1.jpg': 'Tagkit', 'image2.jpg': 'Tagkit'} >>> collection.read_tag('Artist', skip_missing=True) {}
- read_tags(tag_keys: list[Union[str, int]], ifd: Optional[tagkit.core.types.IfdName] = None, format_value: bool = False, binary_format: Optional[str] = None, files: Optional[Iterable[tagkit.core.types.FilePath]] = None, skip_missing: bool = False) dict[str, dict[str, tagkit.core.types.TagValue]]¶
Read multiple EXIF tags from all or selected images in the collection.
- Args:
tag_keys: A list of tag names or tag IDs to read. ifd: Specific IFD to use for all tags. 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. files: Iterable of file names (keys in self.files) to read from. If None, read from all. skip_missing: If True, skip missing tags; if False, only include tags that exist.
- Returns:
dict[str, dict[str, Any]]: Dictionary mapping file names to dictionaries of tag names to values: {‘image1.jpg’: {‘Make’: ‘Canon’, ‘Model’: ‘EOS’}}
- Raises:
KeyError: If a file is not found in the collection. ValueError: If a tag or IFD is invalid.
- Example:
>>> from tagkit.image.collection import ExifImageCollection >>> collection = ExifImageCollection(["image1.jpg", "image20.jpg"]) >>> collection.read_tags(['Make', 'Model']) {'image1.jpg': {'Make': 'Tagkit', 'Model': 'Tagkit Camera'}, 'image20.jpg': {'Make': 'Tagkit', 'Model': 'Tagkit Camera'}}