An open-source imaging workbench for making and studying SDR and HDR images from sensor data.
dngscan began with one practical question: how can I develop a RAW with AgX without opening a full editor? Once that worked, the more interesting questions surfaced. How much highlight signal did the sensor actually preserve? Which pixels came from reconstruction? How should one scene become both SDR and HDR? Can film white balance, spectral response, and formation curves be studied separately instead of baked into one filter?
dngscan gives those questions a measurable pipeline. It keeps sensor data from before demosaic, forms a scene-linear Rec.2020 image with LibRaw or Core Image, combines measurements with explicit image-making choices, then writes color-managed SDR or HDR and checks what was actually delivered.
It already works as a local RAW processor, but its broader value is as an imaging workbench. Decoding, sensor analysis, display transforms, film observation, and delivery have explicit boundaries. New decoders, tone cores, film models, and delivery formats can be compared against the same RAW evidence and validation instead of rebuilding the whole pipeline.
简体中文 · License · Third-party notices
Documentation: User guide (supported cameras, interface fields, export choices) · Architecture and technical details (the full pipeline and why each stage is built this way) · Engineering notes (problems, evidence and reasoning; Chinese) · Design contract (film observation contract and boundaries; Chinese) · Sensor support (per-body data, degradation policy, LibRaw upgrades; Chinese)
From left to right: ordinary SDR, an independently formed HDR rendition, and a map of the HDR luminance expansion. In the map, black means no expansion; white means the full headroom supported by the evidence in this RAW.
The additional brightness stays around lamps and reflections instead of lifting the entire frame. HDR-capable devices display those highlights; an ordinary screen still receives a normal SDR JPEG. If the RAW contains no reliable highlight information, dngscan does not invent HDR headroom.
One RAW, four observation positions: the AgX baseline (no film), Kodak Portra 400 (negative + paper), Fujifilm Velvia 100 (reversal), and Vision3 250D in its theatrical quotation. Every preset is constructed declaratively from datasheet data — the WB Kelvin, the layer separation, the development curve, the layer-saturation differential — with no hand-tuned sliders and no baked LUT. All twenty stocks and five theatrical variants are described in the architecture notes.
- Read the capture: before demosaic, dngscan measures black and white levels, per-channel clipping, CFA geometry, noise, usable dynamic range, and reliable highlight headroom.
- Choose the scene decoder: LibRaw and Core Image / RAW 9 are independent choices, but both hand the rest of the system a scene-linear Rec.2020 image.
- Experiment with image formation: AgX is the default, alongside RAW-gated, luminance-only, and diagnostic tone cores. Exposure, white balance, highlight handling, scene transforms, lens filters, and film observation remain explicit choices.
- Form SDR and HDR separately: SDR targets sRGB or Display P3. HDR starts again from the same scene image and uses only the extra brightness supported by un-clipped RAW highlights.
- Observe and reproduce: the local GUI and CLI share the same controls; a diagnostic dashboard and CSV reports make measurements inspectable and comparisons repeatable. RAW files are never uploaded.
- Deliver, then verify: archive/share profiles control encoding without changing image formation. On macOS, HDR becomes an ISO 21496-1 gain-map JPEG or HEIC and is read back to verify the color profile, gain map, declared headroom, and pixel error.
Python 3.10 or newer is required. The validated rawpy/LibRaw dependency is built from its pinned source revision on first install, so Git and a native compiler are also required (Xcode Command Line Tools on macOS, or the standard build toolchain on Linux).
git clone https://github.com/Gen-416/dngscan.git
cd dngscan
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python -m dngscan.guiOpen the localhost address printed in the terminal. A practical starting point is EV 0 with AgX,
base primaries, camera WB, and highlight reconstruction; adjust from there according to the
photograph.
The RAW field uses the browser's native file picker. The selected file is sent only to the localhost dngscan service on the same computer and kept in a process-scoped temporary directory; the temporary copy is removed when dngscan exits and is never sent to an external service.
# Default AgX JPEG
python -m dngscan photo.dng --jpeg photo.jpg
# Highlight reconstruction and Display P3
python -m dngscan photo.dng --jpeg photo_p3.jpg \
--highlight-mode reconstruct --output-gamut p3
# HDR gain-map JPEG (macOS, Display P3, AgX only)
python -m dngscan photo.dng --jpeg photo_hdr.jpg \
--output-format ultrahdr --hdr-headroom 3
# RAW analysis dashboard and CSV
python -m dngscan photo.dng --jpeg photo.jpg --scan --csv photo.csv
# Compare the experimental RAW-gated tone core
python -m dngscan photo.dng --jpeg photo_gated.jpg --tone-core gated
# Use a film observation position
python -m dngscan photo.dng --jpeg photo_portra.jpg --film portra400Run python -m dngscan --help for the complete option list.
NumPy is the reference implementation and works without a native extension. The optional pybind11 C++ kernel accelerates the AgX core and the shared SDR output finalizer (16-step Oklab gamut fit, transfer, dither, and quantization); RAW analysis, render planning, and fallback policy remain in Python.
pip install pybind11 cmake
tools/build_native.shdngscan keeps measured sensor facts separate from viewing intent until they need to meet in the render plan.
flowchart TB
RAW["RAW / DNG"]
E["1. Read the sensor data<br/>before demosaic: CFA layout · black/white levels<br/>measure clipping · noise · dynamic range"]
D["2. Form the scene image<br/>LibRaw or Core Image<br/>scene-linear Rec.2020"]
I["User choices<br/>exposure · white balance · look<br/>output gamut"]
P["3. Analyze and plan the render<br/>scene body · reliable highlights · clipped areas<br/>exposure anchor · curves · color · HDR headroom"]
S["4. Form SDR<br/>AgX by default · alternate tone cores for experiments<br/>produce the sRGB or Display P3 base image"]
H["5. Form HDR<br/>develop an independent pass from the same scene<br/>limit brightness to un-clipped RAW highlights"]
V["6. Encode and verify delivery<br/>SDR → JPEG<br/>HDR → gain-map JPEG / HEIC, then read back and check"]
OUT["SDR JPEG<br/>or HDR gain-map JPEG / HEIC"]
RAW --> E
RAW --> D
E -- "sensor measurements" --> P
D -- "scene pixels" --> P
I -- "viewing intent" --> P
P --> S
P --> H
S --> V
H --> V
V --> OUT
classDef source fill:#ede9fe,stroke:#7c3aed,color:#1f2937
classDef process fill:#eff6ff,stroke:#2563eb,color:#1f2937
classDef intent fill:#fff7ed,stroke:#ea580c,color:#1f2937
classDef render fill:#ecfdf5,stroke:#059669,color:#1f2937
classDef delivery fill:#f8fafc,stroke:#475569,color:#1f2937
class RAW source
class E,D,P process
class I intent
class S,H render
class V,OUT delivery
- Read the sensor data. Before demosaic, dngscan records CFA clipping, per-channel full well, noise, and spatial position. Later stages can still distinguish measured highlights from pixels created by highlight reconstruction.
- Form the scene image. LibRaw or Core Image decodes the RAW into scene-linear Rec.2020. The decoder determines how pixels are formed, not how their brightness and color are subsequently compressed.
- Bring measurement and intent together. Analysis separates the scene body, reliable highlights, and clipped areas. Those measurements meet the chosen exposure, white balance, look, and output gamut in one render plan.
- Form SDR. AgX is the default display transform; alternate tone cores provide controlled experiments and diagnostics. The result is an sRGB or Display P3 base image.
- Form HDR independently. This branch starts from the same scene image instead of brightening the finished SDR, and uses only the highlight headroom supported by the RAW.
- Encode and check the result. SDR becomes a regular JPEG. HDR packages the SDR and HDR images with an ISO 21496-1 gain map, then opens the file again to verify delivery.
The main difference is not the number of controls. It is when the RAW evidence is discarded.
darktable's AgX module, like many display transforms, receives a decoded floating-point image. dngscan carries pre-demosaic CFA evidence into the final display transform, so the curve still knows which highlights are trustworthy and color processing can avoid regions that have clipped or been reconstructed.
dngscan also keeps measurement separate from taste. Black and white levels, clipping, noise, dynamic range, and the highlight tail belong to analysis. Exposure compensation, white balance, looks, and LUTs remain explicit user choices. Automatic decisions describe the photograph; they do not choose its appearance.
HDR is not a stronger version of SDR. The two renditions are formed independently from the same scene-linear image and share only capture evidence and viewing intent. dngscan also does not treat “the encoder returned no error” as proof of delivery: it reads the result back and verifies that the SDR, HDR, and gain map are present as intended.
Those boundaries also leave room to grow. A new decoder can target the common scene contract; a new tone core or film model can consume the same analysis; a new delivery format can encode finished images without quietly changing their formation. Each extension remains comparable because the measurements and validation stay visible.
dngscan does not currently manage a library or perform local retouching. That is a boundary of the current product, not the full ambition of the project. Its larger potential is an open, explainable imaging workbench: useful both for making photographs and for comparing algorithms, testing standards, and developing new image-formation methods on the same captures.
dngscan is released under GPL-3.0-or-later.

