Desktop app and CLI for converting between video and OpenEXR sequences with OpenColorIO color management and built-in slate rendering. Uses PyAV for decode/encode, OpenImageIO for EXR I/O, PySide6 for the GUI, and Qt WebEngine for HTML/CSS slate capture.
Targets the VFX Reference Platform CY2026: Python 3.13, Qt/PySide 6.8, OpenColorIO 2.5, OpenEXR 3.4, NumPy 2.3.
| Platform | Download |
|---|---|
| Windows x64 | Installer (.exe) |
| macOS Apple Silicon | DMG |
| macOS Intel | DMG |
| Linux x86_64 | AppImage |
All release artifacts are signed with Sigstore Cosign — see the releases page for verification instructions.
macOS Gatekeeper: Like most open-source macOS apps distributed outside the App Store, these builds are not Apple-notarized. On first launch macOS may block the app — right-click it and choose Open, or run
xattr -cr /Applications/exr_converter.app. This is a standard macOS security prompt for apps without a paid Apple Developer signature.
| Layer | Notes |
|---|---|
| Language & tooling | Python 3.13, uv for deps and runs, Ruff in CI, Nuitka for standalone bundles |
| UI | PySide6 (Qt 6.8), Nuke-inspired dark theme |
| Imaging & color | OpenImageIO (oiio-python), OpenColorIO 2.5 for display/render transforms |
| Video & sequences | PyAV (FFmpeg bindings) for video I/O, fileseq for frame sequences & ranges |
| Slate rendering | Qt WebEngine for HTML/CSS slate preview and capture, Tailwind CSS in the slate template |
CI runs on GitHub Actions; releases publish binaries for Linux, macOS (Apple Silicon + Intel), and Windows.
uv run python main.pyNo subcommand — opens the main window. OCIO resolution follows $OCIO when set, otherwise built-in configs (see in-app / CLI --ocio).
Enable the Prepend slate checkbox to add a 1-frame slate image before the converted output.
Use the video2exr or exr2video subcommand.
Video → EXR
uv run python main.py video2exr -i clip.mov -o ./exr_out/EXR → video
uv run python main.py exr2video -i "./plate.####.exr" -o review.mov --fps 24Common options:
| Option | Applies to | Notes |
|---|---|---|
--ocio PATH |
both | OCIO config file (overrides $OCIO) |
--src / --dst |
both | OCIO display / scene color space names |
--workers N |
both | 0 = auto, 1 = single-threaded |
--scale FACTOR |
both | e.g. 0.5 for half resolution |
--exr-compression NAME |
video2exr |
e.g. dwaa, zip, none (see --help) |
--codec KEY |
exr2video |
e.g. prores, h264, prores_4444, dnxhr_hq, ffv1 |
Run uv run python main.py video2exr --help or exr2video --help for the full list.
- Python 3.13
- uv (recommended) or another PEP 621-compatible installer
git clone https://github.com/derek-rein/vfx-tools.git
cd vfx-tools
uv syncPrerequisites: Python 3.13, uv, and a C compiler (Xcode CLT on macOS, MSVC on Windows, gcc on Linux).
uv sync
make bundleThis uses Nuitka to produce a standalone distributable:
| Platform | Output |
|---|---|
| macOS | dist/exr_converter.app |
| Linux | dist/exr_converter (single binary) |
| Windows | dist\main.dist\ (folder with exr_converter.exe + dependencies) |
Nuitka will auto-download ccache on first run. See the Makefile for the full set of flags.
| Target | Purpose |
|---|---|
make run |
Start the GUI |
make lint / make fmt |
Ruff check / format |
make resources |
Regenerate src/rc_resources.py from resources.qrc (needed after icon changes) |
make bundle |
Nuitka standalone bundle under dist/ |
make clean |
Remove all build artifacts |
Icons live under public/ (icon.icns / icon.ico / icon.png).
Tags use plain semver: v1.2.3. Pushing a tag runs .github/workflows/release.yml and publishes a GitHub Release with Linux AppImage, macOS DMGs (ARM64 + Intel), and a Windows installer.
make help
make release PART=patch # bump + commit + tag + push (triggers Release workflow)
make release PUSH=0 # local only; push branch + tag yourself when readyCI for lint: .github/workflows/ci.yml.
MIT — see LICENSE.
