Embedding Custom EXIF Data
Relevant source files
The following files were used as context for generating this wiki page:
The picamera2 library provides functionality to embed Exchangeable Image File Format (EXIF) data into captured JPEG images. The system automatically generates a set of default EXIF tags based on the camera's metadata, such as exposure time and ISO. Users can extend or completely override this default information by providing their own custom EXIF data.
This feature is built upon the piexif library, which is a required dependency for the project. The process involves preparing a dictionary of EXIF tags, which is then merged with the automatically generated tags before being encoded into the final JPEG file. This allows for a high degree of customization, enabling users to add information like camera model, software version, or any other standard or custom EXIF tag.
Sources: picamera2/request.py:539-556, examples/exif_custom.py, setup.py:29
Core API and Workflow
The primary entry point for capturing an image with custom EXIF data is the capture_file method of the Picamera2 class. This method, along with its variants like switch_mode_and_capture_file, accepts an exif_data parameter. This parameter should be a dictionary structured according to the piexif library's format.
When capture_file is called, it initiates a capture job. Internally, this job eventually calls the save method on a CompletedRequest object. The save method is responsible for preparing the final EXIF data by merging the default and custom tags, and then embedding it into the output file.
Sources: picamera2/picamera2.py:1026-1049, picamera2/request.py:302-306
The following sequence diagram illustrates the high-level workflow from a user's perspective.
This diagram shows the sequence of calls when a user captures a file with custom EXIF data.
Sources: picamera2/picamera2.py:1026-1049, picamera2/request.py:302-349
EXIF Data Generation and Merging
The core logic for handling EXIF data resides in the _prepare_exif method within the Helpers class. This method is responsible for both generating default EXIF tags from the request's metadata and merging them with any user-provided custom data.
Sources: picamera2/request.py:539-556
Default EXIF Generation
The _prepare_exif method first checks for the presence of AnalogueGain and DigitalGain in the capture metadata. If they exist, it proceeds to create a default set of EXIF tags.
The default tags are organized into two standard EXIF IFDs (Image File Directories): 0th and Exif.
| IFD | Tag Name | Value Source |
|---|---|---|
0th | ImageIFD.Make | "Raspberry Pi" (hardcoded) |
0th | ImageIFD.Model | The camera's ID (self.picam2.camera.id) |
0th | ImageIFD.Software | "Picamera2" (hardcoded) |
0th | ImageIFD.DateTime | Current system time (datetime.now()) |
Exif | ExifIFD.DateTimeOriginal | Current system time (datetime.now()) |
Exif | ExifIFD.ExposureTime | metadata["ExposureTime"] (in microseconds) |
Exif | ExifIFD.ISOSpeedRatings | (metadata["AnalogueGain"] * metadata["DigitalGain"]) * 100 |
Sources: picamera2/request.py:542-552, CHANGELOG.md:143
Merging Logic
After generating the default EXIF dictionary, the _prepare_exif method merges it with the exif_data dictionary provided by the user. The merge operation is performed इलेक्ट्रिक that the user's data overwrites any default tags with the same key. This allows users to either add new tags or replace the default ones, such as ImageIFD.Model.
Finally, the merged dictionary is serialized into a byte string using piexif.dump(), ready for injection into the JPEG file.
The following diagram illustrates this merging process.
This flowchart shows the logic for preparing EXIF data, including the merging of default and custom tags.
Sources: picamera2/request.py:540-556
Saving with EXIF Data
The CompletedRequest.save method handles the final step of writing the image data and EXIF block to a file. For JPEG files, it uses an optimized path that leverages simplejpeg.
In this fast path, the method writes the JPEG header, then manually splices in the EXIF application marker (FFE1), the length of the EXIF block, the EXIF data itself, and finally the rest of the JPEG image data. This avoids re-encoding the image and is highly efficient.
For other formats, or if the fast JPEG path is not taken, the Helpers.save method is used, which relies on the Pillow library (PIL.Image). It passes the EXIF bytes to Pillow's save function via the exif keyword argument.
Sources: picamera2/request.py:326-343, picamera2/request.py:579-582
Practical Example
The examples/exif_custom.py file provides a concise demonstration of how to add custom EXIF data. The user defines a dictionary with the desired tags and passes it to capture_file.
#!/usr/bin/python3
import io
import piexif
import PIL.Image
from picamera2 import Picamera2
# We'll save a jpeg to memory with some custom exif in it...
mem = io.BytesIO()
my_name = "My Random Camera"
custom_exif = {'0th': {piexif.ImageIFD.Model: my_name}}
with Picamera2() as picam2:
picam2.start()
picam2.capture_file(mem, format='jpeg', exif_data=custom_exif)
# And read it back to check it was there!
exif_check = piexif.load(PIL.Image.open(mem).info['exif'])
my_name_check = exif_check['0th'][piexif.ImageIFD.Model]
if my_name_check.decode('ascii') != my_name:
print("ERROR: custom exif data was not respected")
In this example, the default ImageIFD.Model tag, which would normally be the camera's hardware ID, is overridden with the custom string "My Random Camera".
Sources: examples/exif_custom.py
Dependencies
The functionality પાણી EXIF data manipulation is entirely dependent on the piexif Python library. This is listed as a required dependency in the project's setup.py file.
Sources: setup.py:29