Go library that runs ExifTool in-process: embedded Perl via
zeroperl (Perl compiled to WebAssembly), executed
as native Go via a wasm2go-generated module. You do not need a system exiftool binary or a
separate Perl install.
Upstream ExifTool (Phil Harvey) and metadata: exiftool.org, exiftool/exiftool.
- Self-contained — Perl stdlib, ExifTool, and the interpreter ship inside the module (
embed/). The stdlib is stored LZ4-compressed;perlFS()transparently decompresses files on first read using a 2000-entry LRU cache (lbe/cfsread). - Same behavior everywhere — one toolchain-based interpreter implementation on Linux, macOS, Windows, etc.
- Trade-off — cold start is heavy (on the order of ~7–10 seconds to initialize the
wasm2go-backed Perl runtime). For many operations, use
NewServerandServer.Commandso ExifTool stays open (-stay_open) and work is amortized.
- Go 1.26+
- Dependencies are listed in
go.mod.
// One-shot: paths are relative to the process working directory (host cwd is
// layered read-only under "/" alongside the embedded perl prefix).
out, err := exiftool.Command(nil, "-json", "photo.jpg")
// Batch: one Perl startup, many commands.
e, err := exiftool.NewServer("-fast")
if err != nil { /* ... */ }
defer e.Shutdown()
out, err = e.Command("-Artist", "photo.jpg")Package docs, API details, and filesystem semantics (mount layout, temp dir, Arg1 / Config): run
go doc -all or open pkg.go.dev.
go test ./... -timeout 10m # allow several minutes for interpreter-heavy pathsThe generated zeroperl Go source and Perl install prefix come from
zeroperl. Follow that repository’s Build section
(Docker or Apple Container): build the image, run the container, and copy /artifacts into a
host directory (as shown there, e.g. ./output/).
From the build output directory, install these into this repo under embed/:
| Artifact from zeroperl output | Path in go-exiftool |
|---|---|
zeroperl.go |
internal/zeroperl/zeroperl.go |
perl-wasi-prefix/ (entire tree) |
embed/perl-wasi-prefix/ |
Use the generated zeroperl.go artifact unless you intentionally switch runtimes. The ExifTool
script is loaded from embed/perl-wasi-prefix/bin/exiftool in the embedded prefix.
After copying perl-wasi-prefix/ into embed/, run go generate ./... to re-compress the tree
with cfsread-lz4. This updates the LZ4-compressed files in place so the embedded binary reflects
the new Perl build.
zeroperl’s README also documents build arguments (PERL_VERSION, EXIFTOOL_VERSION,
BUILD_EXIFTOOL, memory/stack, etc.). If you change PERL_VERSION, update the perl5Lib
segment in perlversion.go so the runtime PERL5LIB path (/lib/<segment>/…)
stays aligned with the embedded prefix layout.
Use dist.pl to download, build, minify, test, and install ExifTool into embed/perl-wasi-prefix/.
perl dist.pl --exiftool-version 13.56Version resolution precedence is:
--exiftool-versionEXIFTOOL_VERSIONenvironment variable- Latest version parsed from
https://exiftool.org/history.html
Command and CommandContext run ExifTool in the caller's working directory, which is mounted
writable inside the WASM sandbox. ExifTool can therefore write (or overwrite) files in the working
directory using flags like -overwrite_original or -o <outfile>.
See LICENSE. ExifTool and embedded components carry their own licenses under embed/.