Skip to content

cigaleapp/exiv2-wasm

 
 

Repository files navigation

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.git

Prerequisites

Tools

  • CMake, Ninja
  • Emscripten SDK (emcmake / emcc / em++ / emar)

Windows (PowerShell)

winget install Kitware.CMake
winget install Ninja-build.Ninja

Linux (Debian/Ubuntu)

sudo apt update
sudo apt install -y cmake ninja-build python3

Emscripten 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.ps1

Re-run emsdk_env.sh / emsdk_env.ps1 in 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.ps1

Linux/macOS (bash/zsh)

cd exiv2-wasm
chmod +x scripts/build.bash

# clean build
./scripts/build.bash -c
# incremental build
./scripts/build.bash

Outputs: dist/exiv2.js and dist/exiv2.wasm


Run the demo

# from project root
python -m http.server 8080
# open:
# http://localhost:8080/index.html

JavaScript usage

Wrapper API:

  • read(u8: Uint8Array) -> { exif: Object, iptc: Object, xmp: Object }
  • readTagText(u8, key: string) -> string | null
  • readTagBytes(u8, key: string) -> Uint8Array | null
  • writeString(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 (or Exif.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)

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

About

No description, website, or topics provided.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • HTML 45.0%
  • Shell 19.8%
  • PowerShell 17.7%
  • C++ 17.5%