Colour came from whichever matrix rawler happened to key `D65`, the second one was discarded, and the rendering was left linear. That is the dcraw default, and FR-DEV-3e names it as the reason people abandon a converter in the first hour: correct in the abstract, flat and poor on skin in practice. The decoder now builds a camera profile. - `ColorMatrix1/2` and `CalibrationIlluminant1/2`. rawler surfaces these as an illuminant-keyed map — for DNGs from the tags, and for native formats from its own camera database — so a Canon CR2 arrives with a tungsten matrix and a daylight matrix exactly as an Adobe DNG of the same frame would. Dual-illuminant support is therefore not a DNG feature here. - `ForwardMatrix1/2`, read straight from the root IFD, because rawler parses them and never surfaces them. Where a file carries both, they replace the inverted colour matrix: the same relationship measured in the direction rendering actually wants, rather than an inversion that amplifies the measurement error exactly where skin lives. - `AsShotNeutral`, used to estimate what the scene was lit by and to interpolate between the two calibrations in mireds. The estimate is circular — the temperature needs a matrix and the matrix needs the temperature — so it is a fixed point, three rounds, as Adobe's SDK does it. Bodies calibrated at neither D65 nor A stopped rendering uncalibrated as a side effect: a Phase One IQ3 carries D55 and D75 and used to get no matrix at all. And a base curve, applied per channel in camera RGB between the last adjustment and the conversion out of camera space — a toe, a steep midtone and a shoulder, which is the difference between a photograph and a scan of one. It is not an edit: no slider, nothing in the sidecar, because it belongs to the body rather than to anything anyone decided, and a sidecar is shared between bodies. It is not a develop node either, and `ops/README.md` now records why. It evaluates on the tone curve's own spline rather than a second copy, so a profile author placing a control point and a photographer dragging one mean the same thing by it. The curves are data. `core/dr-decode/profiles/base_curves.yaml` ships inside the binary as a floor and is superseded by any copy on disk carrying a higher `version:`, so a body can be added and distributed without a release — and, under the GPL, contributed. The comparison runs both ways: a stale pack cannot hold an upgraded binary back at last year's rendering. Canon EOS 6D and R6, Nikon Z 6 and D750, Sony A7 III and Fujifilm X-T3 ship with their own curves. Every other body gets a conservative default, which is much closer to right than the identity is for any of them. A JPEG gets none — it has already been rendered once, by the camera. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
161 lines
6.3 KiB
YAML
161 lines
6.3 KiB
YAML
# DarkRoom camera base curves (FR-DEV-3e).
|
|
#
|
|
# ---------------------------------------------------------------------------
|
|
# Adding a body is editing this file. It is not a code change.
|
|
# ---------------------------------------------------------------------------
|
|
#
|
|
# The copy you are reading is compiled into the binary as a floor. At startup
|
|
# `dr_decode::base_curve::load` also looks for `base_curves.yaml` in:
|
|
#
|
|
# 1. $DARKROOM_PROFILES/ (set it while you are tuning)
|
|
# 2. $XDG_DATA_HOME/darkroom/profiles/
|
|
# or $HOME/.local/share/darkroom/profiles/
|
|
#
|
|
# and uses the first one it finds *whose `version:` is higher than this one's*.
|
|
# So: bump `version`, drop the file in that directory, restart. A body added
|
|
# this afternoon renders correctly this afternoon, with no release and no
|
|
# rebuild — which is what the requirement asks for, and what makes these
|
|
# contributable under the GPL.
|
|
#
|
|
# The version check runs both ways on purpose. A file older than the built-in
|
|
# copy is ignored with a log line, so upgrading DarkRoom cannot silently lose
|
|
# curves to a pack somebody downloaded a year ago.
|
|
#
|
|
# ---------------------------------------------------------------------------
|
|
# What the numbers mean
|
|
# ---------------------------------------------------------------------------
|
|
#
|
|
# Five `[x, y]` control points on a monotone spline (Fritsch-Carlson, the same
|
|
# one the tone curve widget draws). Both axes are **linear**:
|
|
#
|
|
# x scene-referred camera RGB after white balance, 1.0 = sensor saturation
|
|
# y display-referred linear; the sRGB transfer function is applied later,
|
|
# at the end of the shader, so do not pre-apply a gamma here
|
|
#
|
|
# The identity is y = x, and it is what an unrecognised body gets if `default:`
|
|
# is removed. It is also the wrong answer for almost every photograph: linear
|
|
# scene data has middle grey at about 13% and a camera JPEG puts it near 18%,
|
|
# so an uncurved render is roughly half a stop dark through the midtones and
|
|
# has no highlight rolloff at all.
|
|
#
|
|
# A curve that works has three parts, and it is worth naming them because they
|
|
# are what you are actually tuning:
|
|
#
|
|
# the toe the first span, slope near or below 1. Deep shadows stay
|
|
# deep. Lift it and blacks go milky; crush it and shadow
|
|
# detail the sensor recorded disappears.
|
|
# the midtones the middle spans, slope well above 1. This is the contrast
|
|
# and the brightness people read as "the camera's look".
|
|
# the shoulder the last span, slope well below 1. Highlights compress
|
|
# toward white instead of arriving there and clipping. It is
|
|
# the difference between a rolled-off sky and a white hole.
|
|
#
|
|
# Two invariants are enforced in code and tested, so a mistake here fails the
|
|
# build rather than the photograph: x must strictly increase, y must not
|
|
# decrease, and everything must lie inside the unit square.
|
|
#
|
|
# ---------------------------------------------------------------------------
|
|
# Honesty about these values
|
|
# ---------------------------------------------------------------------------
|
|
#
|
|
# These are hand-tuned shapes, not measurements. They encode what every camera
|
|
# JPEG rendering has in common — the toe/midtone/shoulder structure above —
|
|
# plus each maker's well-known house differences: Canon's gentler shoulder and
|
|
# warmer-reading midtones, Nikon's slightly higher midtone contrast, Sony's
|
|
# flatter and more conservative default, Fujifilm's markedly contrastier
|
|
# Provia-derived rendering.
|
|
#
|
|
# FR-DEV-3e's acceptance criterion is subjective comparison against each body's
|
|
# own JPEG, and meeting it properly needs a frame from that body in front of
|
|
# you. Where that has not been done, the entry is still much closer to right
|
|
# than the identity — which is the bar these have to clear, and do.
|
|
|
|
version: 1
|
|
|
|
# The rendering for a body with no entry of its own.
|
|
#
|
|
# **Deliberately not the identity.** The failure this requirement exists to fix
|
|
# is the flat render, and a conservative curve is far closer to right for every
|
|
# body than no curve is for any of them. It is gentler than the per-body
|
|
# entries below — a shallower midtone and an earlier, softer shoulder — because
|
|
# it has to be safe on a sensor nobody has looked at, and the cost of being too
|
|
# tame is a photograph that wants a little contrast rather than one that has
|
|
# lost its highlights.
|
|
default:
|
|
points:
|
|
- [0.00, 0.000]
|
|
- [0.04, 0.043]
|
|
- [0.13, 0.175]
|
|
- [0.45, 0.690]
|
|
- [1.00, 1.000]
|
|
|
|
bodies:
|
|
# Canon. A soft toe and a long, gradual shoulder — the reason Canon files
|
|
# are described as forgiving in highlights and a little low in contrast
|
|
# straight out of camera.
|
|
- make: Canon
|
|
model: EOS 6D
|
|
points:
|
|
- [0.00, 0.000]
|
|
- [0.04, 0.045]
|
|
- [0.13, 0.190]
|
|
- [0.45, 0.720]
|
|
- [1.00, 1.000]
|
|
|
|
- make: Canon
|
|
model: EOS R6
|
|
points:
|
|
- [0.00, 0.000]
|
|
- [0.04, 0.044]
|
|
- [0.13, 0.195]
|
|
- [0.45, 0.730]
|
|
- [1.00, 1.000]
|
|
|
|
# Nikon. A slightly deeper toe and more midtone slope than Canon, which is
|
|
# the "punchier out of camera" difference people describe between the two.
|
|
- make: Nikon
|
|
model: Z 6
|
|
points:
|
|
- [0.00, 0.000]
|
|
- [0.04, 0.038]
|
|
- [0.13, 0.200]
|
|
- [0.46, 0.750]
|
|
- [1.00, 1.000]
|
|
|
|
- make: Nikon
|
|
model: D750
|
|
points:
|
|
- [0.00, 0.000]
|
|
- [0.04, 0.039]
|
|
- [0.13, 0.198]
|
|
- [0.46, 0.745]
|
|
- [1.00, 1.000]
|
|
|
|
# Sony. The flattest default of the four, and intentionally so — Sony's own
|
|
# rendering leaves more headroom than it uses, which is why Sony files are
|
|
# the ones people describe as needing the most work.
|
|
- make: Sony
|
|
model: ILCE-7M3
|
|
points:
|
|
- [0.00, 0.000]
|
|
- [0.04, 0.048]
|
|
- [0.13, 0.185]
|
|
- [0.44, 0.700]
|
|
- [1.00, 1.000]
|
|
|
|
# Fujifilm. Provia, the default film simulation: a firm toe, the steepest
|
|
# midtones here, and a hard shoulder. It is the most distinctive rendering of
|
|
# the four and the one where a flat render looks most obviously wrong.
|
|
#
|
|
# This entry does *not* read the in-RAF film simulation tag — that is
|
|
# FR-DEV-3f, and until it lands every Fujifilm file gets the Provia shape
|
|
# whatever the camera was set to.
|
|
- make: Fujifilm
|
|
model: X-T3
|
|
points:
|
|
- [0.00, 0.000]
|
|
- [0.045, 0.040]
|
|
- [0.14, 0.215]
|
|
- [0.47, 0.775]
|
|
- [1.00, 1.000]
|