Orfeus is a fast Common Lisp RAW processor for Olympus PEN-F and OM-1 files. The same processing core is used by its command-line and FLTK frontends.
nix developThe flake provides SBCL, Rust, Lensfun and the other native dependencies,
ExifTool, JPEG/TIFF support, and FLTK. Keep the sibling ../lightfast checkout
available when building the GUI.
cargo build --release --manifest-path native/Cargo.toml
make gui-native
sbcl --no-userinit --non-interactive \
--eval '(require :asdf)' \
--eval '(asdf:load-asd (truename "orfeus.asd"))' \
--eval '(asdf:make "orfeus/cli")'Inspect or extract the original ORF embedded in a DNG:
./orfeus info photograph.dng
./orfeus extract photograph.dng photograph.orfRender a preview or full JPEG/TIFF with default settings:
./orfeus preview photograph.orf preview.jpg
./orfeus render photograph.orf export.tiffCreate and run an editable S-expression batch project:
./orfeus init project.sexp exports/ first.orf second.orf
$EDITOR project.sexp
./orfeus batch project.sexpProjects contain shared defaults and per-photo overrides for exposure, white
balance, edge-aware and neural (FFDNet) noise reduction, lens/TCA correction
and correction strength, CUBE LUTs, and film grain. They are read with
*read-eval* disabled.
Grading works DaVinci Resolve style through an explicit node graph
(:graph per photo): piped filter nodes carrying one adjustment category
each — including repeated kinds, so two +2 EV exposure nodes make +4 —
reorderable and bypassable, with maskless blend nodes mixing scene-linear
branches by opacity. Color-subtract nodes (with palette and eyedropper
pickers) invert film negatives against a picked base, crop nodes use
resolution-independent oriented coordinates, and a negative autocrop detects
the central frame and film-base color. The GUI grabs auto-named stills into
a thumbnail gallery; right-clicking one applies its whole node graph to the
selection (optionally without optics or white balance — lens profiles always
re-match from each photo’s own metadata). Photos without a graph keep the
flat stage pipeline; both render identically through the CLI batch. Exports
preserve source EXIF and original filenames, optionally with a capture-time
prefix (:timestamp-filenames-p).
Adapted manual lenses can be associated with exact Lensfun profiles in
$XDG_CONFIG_HOME/orfeus/lenses.sexp (or the path in
ORFEUS_LENS_ALIASES). The file is a safely read association list; user entries
override built-ins:
(("Ultron 0.7x"
:lensfun-model "Voigtlander Ultron 40mm f/2 SLII Aspherical"
:focal-reducer 0.71
:crop-factor 2.0))The focal-reducer ratio converts Olympus’ effective EXIF focal length back to the Lensfun profile focal length. Crop factor describes the unreduced camera sensor crop. Explicit mappings bypass normal electronic mount matching.
Launch the FLTK frontend directly with an optional photograph or project:
./orfeus-gui
./orfeus-gui photograph.dng
./orfeus-gui project.sexpThe launcher enters the Nix development environment and builds missing native bridges when necessary. The GUI can also open photographs and projects from its File menu. It develops settings-keyed RAW previews, pre-renders neighboring photographs in the background, and rejects superseded generations. The inspector uses native FLTK tabs for Basic, Optics, and Effects settings, with scope and actions kept visible. White-balance mode, LUT state, and preview source remain visible in the status bar.
The bundled LUT library includes Agfa APX, Precisa, Ultra Color, and Vista looks,
plus Kodachrome 25, 64, 64 Generic, and 200. Their pinned provenance, checksums,
and license notice are recorded in THIRD-PARTY.md.
The optional Vulkan compute backend fuses display tone and sRGB transfer. It is
strictly opt-in because one-shot process initialization is expensive; set
ORFEUS_GPU=1. Any Vulkan initialization, dispatch, or readback failure falls
back to the CPU result. Set ORFEUS_PROFILE=1 to print per-stage timing, the
selected Vulkan adapter, GPU transfer-inclusive dispatch time, and fallback
reason.
cargo fmt --check --manifest-path native/Cargo.toml
cargo clippy --release --all-targets --all-features \
--manifest-path native/Cargo.toml -- -D warnings
cargo test --release --manifest-path native/Cargo.toml
sbcl --no-userinit --non-interactive \
--eval '(require :asdf)' \
--eval '(asdf:load-asd (truename "orfeus.asd"))' \
--eval '(asdf:test-system "orfeus")'