exif
stableRead and inspect EXIF metadata embedded in JPEG and TIFF image files. Extract camera info, GPS coordinates, orientation, timestamps, and arbitrary tag values.
use plugin exif Plugin snippets can be edited in the Playground, but native capabilities are executed locally with the Zolo CLI.
Functions (10)
- read_file Read all EXIF tags from an image file
- get_tag Find a tag value by name in a tag table
- has_gps Check if a tag table contains GPS data
- image_dimensions Read pixel width and height from file
- camera_info Extract make and model from a tag table
- list_tags List all tag names from a tag table
- tag_count Count the number of tags in a table
- orientation Get the Orientation tag value
- gps_coords Extract latitude and longitude strings
- date_time Get the DateTimeOriginal or DateTime value
From import to result
- 01Import only what you use
- 02Copy the smallest example
- 03Run it with the Zolo CLI
Overview¶
exif reads the EXIF metadata block embedded in JPEG and TIFF photos and exposes
it to Zolo as plain tables of {tag, value_str} entries. The whole API is
stateless: read_file (or image_dimensions) opens a file once and hands back an
ordinary table, and every other function is a pure query over that table — there
are no handles to close and no mutable state to track. Pixel dimensions, camera
make/model, GPS coordinates, orientation, and capture timestamps are all just tags
in the same block, so the convenience helpers simply locate the right entries for
you.
The mental model is a two-step pipeline: call read_file(path) once to get the
entries table, then pass that table into the helpers (get_tag, camera_info,
gps_coords, orientation, date_time, list_tags, tag_count, has_gps).
The lone exception is image_dimensions, which takes a file path directly rather
than an entries table. Use this plugin whenever you need to inspect what a camera
recorded about a photo without decoding the image pixels themselves.
Common patterns¶
Read a photo once, then summarize the camera and capture details:
use plugin exif::{read_file, camera_info, date_time, orientation}
let tags = read_file("photo.jpg")
let cam = camera_info(tags)
print("camera: {cam["make"]} {cam["model"]}")
print("taken: {date_time(tags)}")
print("orient: {orientation(tags)}")Guard GPS access with has_gps before pulling coordinates:
use plugin exif::{read_file, has_gps, gps_coords}
let tags = read_file("photo.jpg")
if has_gps(tags) {
let coords = gps_coords(tags)
print("{coords["latitude"]} {coords["latitude_ref"]}")
print("{coords["longitude"]} {coords["longitude_ref"]}")
} else {
print("no location embedded")
}Combine the file-path and entries-table APIs into one report:
use plugin exif::{read_file, image_dimensions, tag_count, get_tag}
let path = "photo.jpg"
let tags = read_file(path)
let dims = image_dimensions(path)
print("{dims["width"]}x{dims["height"]} with {tag_count(tags)} tags")
print("exposure: {get_tag(tags, "ExposureTime")}")Read all EXIF tags from an image file
Opens an image file and reads all primary EXIF tags. Returns a table of {tag, value_str} entries. This table is the input for most other functions in this plugin.
use plugin exif::{read_file, list_tags}
let tags = read_file("photo.jpg")
let names = list_tags(tags)
print(names)Because the result is an ordinary table, you can feed it straight into the other helpers without re-reading the file:
use plugin exif::{read_file, tag_count, camera_info}
let tags = read_file("photo.jpg")
print("read {tag_count(tags)} tags")
print(camera_info(tags)["model"])Find a tag value by name in a tag table
Searches the tag table returned by read_file for an entry whose tag field matches tag_name. Returns the string value, or nil if not found.
use plugin exif::{read_file, get_tag}
let tags = read_file("photo.jpg")
let iso = get_tag(tags, "ISOSpeedRatings")
let focal = get_tag(tags, "FocalLength")
print("ISO: {iso}, focal: {focal}")Since a missing tag comes back as nil, you can branch on the result to handle photos that lack a particular field:
use plugin exif::{read_file, get_tag}
let tags = read_file("photo.jpg")
let lens = get_tag(tags, "LensModel")
if lens != nil {
print("shot with {lens}")
} else {
print("lens not recorded")
}Check if a tag table contains GPS data
Returns true if the tag table contains any GPS-related tags (GPSLatitude, GPSLongitude, etc.).
use plugin exif::{read_file, has_gps}
let tags = read_file("photo.jpg")
if has_gps(tags) {
print("image has location data")
}Read pixel width and height from file
Reads PixelXDimension and PixelYDimension directly from the file. Returns {width, height} as integers (0 if the tags are absent).
use plugin exif::{image_dimensions}
let dims = image_dimensions("photo.jpg")
print("size: {dims["width"]}x{dims["height"]}")The width and height are integers, so you can compute derived values like the aspect ratio or megapixel count directly:
use plugin exif::{image_dimensions}
let dims = image_dimensions("photo.jpg")
let mp = (dims["width"] * dims["height"]) / 1000000
print("{mp} megapixels")Extract make and model from a tag table
Extracts the Make and Model tag values from a tag table. Returns {make, model} as strings (empty if not present).
use plugin exif::{read_file, camera_info}
let tags = read_file("photo.jpg")
let cam = camera_info(tags)
print("{cam["make"]} {cam["model"]}")Count the number of tags in a table
Returns the number of EXIF tags in the table.
use plugin exif::{read_file, tag_count}
let tags = read_file("photo.jpg")
print(tag_count(tags))Get the Orientation tag value
Returns the value of the Orientation tag (e.g., "top-left", "right-top"). Returns nil if the tag is absent.
use plugin exif::{read_file, orientation}
let tags = read_file("photo.jpg")
let o = orientation(tags)
if o != nil {
print("orientation: {o}")
}Extract latitude and longitude strings
Extracts GPSLatitude, GPSLongitude, GPSLatitudeRef, and GPSLongitudeRef tag values. Returns a table with those four keys, or nil if GPS data is absent.
use plugin exif::{read_file, gps_coords}
let tags = read_file("photo.jpg")
let coords = gps_coords(tags)
if coords != nil {
print("{coords["latitude"]} {coords["latitude_ref"]}")
print("{coords["longitude"]} {coords["longitude_ref"]}")
}Pair it with has_gps so you only build the coordinate string when location data
is actually present:
use plugin exif::{read_file, has_gps, gps_coords}
let tags = read_file("photo.jpg")
if has_gps(tags) {
let c = gps_coords(tags)
print("located at {c["latitude"]}{c["latitude_ref"]}, {c["longitude"]}{c["longitude_ref"]}")
}Get the DateTimeOriginal or DateTime value
Returns the value of DateTimeOriginal (preferred) or DateTime, or nil if neither is present. The format is typically "YYYY:MM:DD HH:MM:SS".
use plugin exif::{read_file, date_time}
let tags = read_file("photo.jpg")
let dt = date_time(tags)
print("taken: {dt}")