exiv2-wasm
v0.5.13
Published
Exiv2 in the browser via WebAssembly (read/write EXIF/IPTC/XMP).
Maintainers
Readme
exiv2-wasm
🇰🇷 Read this in Korean: README.ko.md
Use Exiv2 in the browser via WebAssembly.
A tiny C++ wrapper (embind) exposes simple functions to read/write EXIF / IPTC / XMP.
Minimal deps are built for wasm (expat, brotli dec/common, inih); zlib comes from the Emscripten port.
Online Demo
Project structure
exiv2-wasm/
├─ exiv2/ # submodule (Exiv2)
├─ libexpat/ # submodule (expat)
├─ brotli/ # submodule (google/brotli)
├─ inih/ # submodule (benhoyt/inih)
├─ scripts/
│ ├─ build.ps1 # Windows PowerShell build
│ └─ build.bash # Linux/macOS bash build
├─ wrapper.cpp # embind wrapper (read/write metadata)
├─ index.html # demo UI page
├─ dist/ # build outputs: exiv2.js / exiv2.wasm
└─ (build/, deps/) # build cache / installed deps (git-ignored)Clone with submodules:
git clone --recurse-submodules https://github.com/gerosyab/exiv2-wasm.gitPrerequisites
Tools
- CMake, Ninja
- Emscripten SDK (emcmake / emcc / em++ / emar)
Windows (PowerShell)
winget install Kitware.CMake
winget install Ninja-build.NinjaLinux (Debian/Ubuntu)
sudo apt update
sudo apt install -y cmake ninja-build python3Emscripten SDK (all OS)
# anywhere you like
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
# new shell(s):
source ./emsdk_env.sh # Linux/macOS
# or on Windows PowerShell:
# .\emsdk_env.ps1Re-run
emsdk_env.sh/emsdk_env.ps1in each new shell.
Build
Windows (PowerShell)
cd exiv2-wasm
# one-session policy (optional)
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
# clean build
.\scripts\build.ps1 -Clean
# incremental build
.\scripts\build.ps1Linux/macOS (bash/zsh)
cd exiv2-wasm
chmod +x scripts/build.bash
# clean build
./scripts/build.bash -c
# incremental build
./scripts/build.bashOutputs: dist/exiv2.js and dist/exiv2.wasm
Run the demo
# from project root
python -m http.server 8080
# open:
# http://localhost:8080/index.htmlJavaScript usage
Wrapper API:
read(u8: Uint8Array) -> { exif: Object, iptc: Object, xmp: Object }readTagText(u8, key: string) -> string | nullreadTagBytes(u8, key: string) -> Uint8Array | nullwriteString(u8, key: string, value: string) -> Uint8Array(returns new buffer)writeBytes(u8, key: string, data: Uint8Array) -> Uint8Array
Browser (CDN + <script> global function)
<script src="https://unpkg.com/exiv2-wasm"></script>
<script>
(async () => {
const exiv2 = await createExiv2Module();
async function fileToU8(file) {
const buf = await file.arrayBuffer();
return new Uint8Array(buf);
}
document.querySelector('#file').addEventListener('change', async (e) => {
const u8 = await fileToU8(e.target.files[0]);
const meta = exiv2.read(u8);
console.log('Camera Model:', meta.exif['Exif.Image.Model']);
});
})();
</script>
<input id="file" type="file" accept="image/*">Browser (CDN + ESM import)
<script type="module">
import { createExiv2Module } from 'https://cdn.jsdelivr.net/npm/exiv2-wasm/+esm';
const exiv2 = await createExiv2Module();
const input = document.querySelector('#file');
input.addEventListener('change', async (e) => {
const file = e.target.files[0];
const buf = new Uint8Array(await file.arrayBuffer());
const meta = exiv2.read(buf);
console.log('Camera Model:', meta.exif['Exif.Image.Model']);
});
</script>
<input id="file" type="file" accept="image/*">ESM (Node.js / Vite / webpack / Rollup)
import { createExiv2Module } from 'exiv2-wasm';
const exiv2 = await createExiv2Module();
const fs = await import('fs/promises');
const u8 = new Uint8Array(await fs.readFile('image.jpg'));
const meta = exiv2.read(u8);
console.log('Model:', meta.exif['Exif.Image.Model']);CommonJS
const { createExiv2Module } = require('exiv2-wasm');
const fs = require('fs');
function fileToU8(path) {
return new Uint8Array(fs.readFileSync(path));
}
createExiv2Module().then((exiv2) => {
const u8 = fileToU8('image.jpg');
const meta = exiv2.read(u8);
console.log('Model:', meta.exif['Exif.Image.Model']);
});Common keys (examples)
- Camera:
Exif.Image.Make,Exif.Image.Model - Exposure:
Exif.Photo.ExposureTime,Exif.Photo.ShutterSpeedValue - Aperture:
Exif.Photo.FNumber,Exif.Photo.ApertureValue - ISO:
Exif.Photo.PhotographicSensitivity(orExif.Photo.ISOSpeedRatings) - Title/Author/Comment:
- XMP:
Xmp.dc.title,Xmp.dc.creator,Xmp.dc.description - EXIF:
Exif.Image.ImageDescription,Exif.Image.Artist,Exif.Photo.UserComment - Windows XP Unicode*:
Exif.Image.XPTitle,Exif.Image.XPAuthor,Exif.Image.XPComment(UTF-16LE)
- XMP:
Notes
- Exiv2 CLI build is disabled:
-DEXIV2_BUILD_EXIV2_COMMAND=OFF - BMFF/HEIF support enabled:
-DEXIV2_ENABLE_BMFF=ON - If submodules show empty after clone:
git submodule update --init --recursive
