Skip to content
Redlamp
Articles

Linear vs scene-referred

Two words that often get used as if they meant the same thing, explained with figures you can try and Redlamp's own tone curve.

· Pedro

Redlamp is a free, open-source raw photo editor for the Mac that works like Lightroom. Some feedback I got recently pointed out two things: Redlamp has no scene-referred mode, and in its exports, the L* of a grey scale's patches isn't linear against the chart's own values. Exports of metered shots of a target also came out slightly dark.

Answering that properly meant untangling two words that often get used as if they meant the same thing. They don't. Linear and scene-referred answer different questions about a pixel's numbers, so they aren't opposites: a pixel can be linear and scene-referred, either one, or neither.

This article works through both, with figures you can try. The curves in them are Redlamp's own, as its code has them on 9 October 2026.

Linear

How the numbers are written: twice the light, twice the number.

Scene-referred

Whose light they describe: the light in front of the camera, which has no ceiling, rather than the light a screen gives off, which stops at white.

The tone curve

What turns scene light into screen light. A scene-referred mode, which the feedback asks for, would leave it out, without changing how files are encoded.

Two questions, four combinations

Follow a grey card, at 0.18 in scene light, and a sunlit cloud, at 2.0, into each corner. The same two lights get different numbers in each.

Scene-referred, written linearly

Scene-linear

Redlamp edits here

Proportional to the light in front of the camera, with no ceiling: a street lamp can read 20 while the grey card reads 0.18.

Grey card

0.18

Sunlit cloud

2.00

In Redlamp

White balance, Exposure, the tone sliders, halation and bloom, in linear Rec. 2020.

Elsewhere

A raw file's sensor values, OpenEXR, ACEScg.

Scene-referred, written with a curve

Scene-referred, log-encoded

The same scene light on a log scale: every stop gets an equal share of the numbers, so a wide range fits between 0 and 1.

Grey card

0.606

Sunlit cloud

0.817

In Redlamp

Film looks read their tables from it, over −10 to +6.5 stops around the grey card.

Elsewhere

Camera log video (S-Log3, LogC), ACEScct.

Display-referred, written linearly

Display-linear

Proportional to the light the screen gives off. 1.0 is the screen's white and nothing goes above it: the tone curve has already fitted the scene in.

Grey card

0.332

Sunlit cloud

0.999

In Redlamp

Vibrance, Saturation, the Color Mixer, Point Color and Color Grading, in OKLab worked out from this light.

Elsewhere

A TIFF of a finished render saved with linear numbers.

Display-referred, written with a curve

Display-encoded

What JPEGs, PNGs and the screen's signal carry: screen light written with the sRGB curve, which gives the darks more of the 256 levels.

Grey card

156 of 255

Sunlit cloud

255 of 255

In Redlamp

Curves, vignette and grain; then the export and the screen.

Elsewhere

Every JPEG. sRGB and Display P3 share this curve.

Across a row, the light stays the same and only its numbers change: re-encoding is arithmetic, exact in both directions. Down a column, the light itself changes: the tone curve decides how the scene's range fits between black and the screen's white, and whatever it presses into white can't be told apart afterwards. The cloud's 2.00 has nowhere to go on a screen but 0.999.

Linear: how the numbers are written

Light adds up: two lamps give twice the light of one. Linear numbers keep that proportion, so the arithmetic of light works on them directly: a stop of Exposure is ×2, and a blur averages light. Eyes don't see light that way: the step from 1% to 2% of white looks about as big as the step from 50% to 100%. So files and screens write light with a curve that gives the darks more numbers. Converting between the two is a formula, exact both ways: it changes the numbers, not the picture.

Stored value for each amount of light

Three ways of writing the same light, from black to white. Drag the light to compare them.

000.250.250.50.50.750.7511Light, as a fraction of whiteStored value (× 255 for 8 bits)
LinearsRGB curveL* curve (eciRGB v2): L* ÷ 100

Light: 18.0% of white, 2.47 stops below it

Written asStored value8-bit level
Linear0.18046
sRGB curve (sRGB, Display P3)0.461118
L* curve (eciRGB v2)0.495126

Middle grey, 18% of white, is 46 of 255 written linearly, 118 with the sRGB curve and 126 with the L* curve that eciRGB v2 uses. L* is also the scale the feedback measured in: 18% of white is L* 49.5, near the middle, which is about where it looks.

8-bit levels in each stop below white

How many of an 8-bit file's 256 levels fall in each stop, written linearly and with the sRGB curve.

0326496128128671645123238316284821541662127198Stop below white (1 is the brightest)Levels, of 256
LinearsRGB curve
Linear spends half of its 256 levels on the brightest stop and leaves 2 for the seventh, where shadows would band; the sRGB curve spreads them out. Redlamp computes in floating point, where linear numbers lose nothing.

Light adds; stored numbers don't

Half black, half white: what's the average?

Black and white lines

half of white's light

188 of 255

averaging the light: 50%

128 of 255

averaging the numbers: 22%

Step back or squint: the lines blend into the middle patch, not the right one. A blur, resize or blend done on sRGB-encoded numbers makes mixes too dark, and leaves dark fringes around bright edges. View at 100% zoom.

Linear is a property of the numbers, not of the light. The same light can be written linearly, with the sRGB curve, with gamma 1.8 or on a log scale, and a colour-managed reader gets the same light back from each. So whether a file is linear says nothing about whose light it holds. That's the second question.

Scene-referred: whose light the numbers describe

A scene-referred number describes the light that was in front of the camera, relative to the rest of the scene: if a grey card is 0.18, a sunlit cloud is about 2 and a street lamp about 20. There's no ceiling, because scenes have none. A display-referred number describes the light a screen should give off, and 1.0 is the screen's white.

Getting from one to the other means deciding how the scene's range fits between the screen's black and white. That decision is the tone curve: a choice, not arithmetic, and different curves make different pictures of the same scene.

Exposure playground

An illustrative scene, from a deep shadow to a street lamp. Exposure multiplies every scene value, so dragging it slides every object along the scale.

Exposure 0.0 EV: every scene value × 1.00

Compare with

Above 1.0: scene-referred only0255075100−8−6−4−20+2+4+6+8Scene value0.181.02.88Deep shadowDark coatGrey cardWhite paperSunlit cloudStreet lampScene light after Exposure, in stops from the grey cardDisplayed lightness, L*
Exposure, then Redlamp's tone curveThe tone curve, then Exposure

Deep shadow

Dark coat

Grey card

White paper

Sunlit cloud

Street lamp

Scene value

After Exposure; above 1.0 in colour

0.008

0.040

0.18

0.80

2.00

20.0

Exposure, then the curve

Scene-referred editing, as Redlamp does it; L* under each patch

3

23

64

97

99.9

white

The curve, then Exposure

Editing the finished render

3

23

64

97

99.9

white

Try −2: with Exposure first, the cloud comes back (L* 90) and the lamp stays white. With Exposure after the curve, both had already been written as white, or within a hair of it, so they darken to the same flat grey (L* 57 and L* 57): the curve threw away the difference between 2 and 20. Try +2: with Exposure first, the grey card rolls off to L* 96; after the curve, it clips to white. Redlamp applies Exposure first, in scene light.

Where Redlamp does each

One render passes through all four corners of the grid, in this order. Every change of encoding on the way is exact. The one change of reference is stage 2, the tone curve, which a scene-referred mode would replace with scene light copied straight up to white.

One render, in order

Each stage marked by the light it describes and how its numbers are written.

  1. Scene · Linear

    1Develop

    White balance, the camera's colour, Exposure (a multiply), halation and bloom (light added), the tone sliders, black and white points.

  2. Scene → display · Log, for film looks

    2Tone curve

    Scene light to screen light, reaching white at 2.88, 4 stops over the grey card. A film look takes its place, reading a log encoding of the scene.

  3. Display · Linear

    3Colour

    Vibrance, Saturation, the Color Mixer, Point Color and Color Grading, in OKLab worked out from linear light.

  4. Display · sRGB curve

    4Finishing

    Curves, vignette, grain, light leaks and the frame, on values written with the sRGB curve.

  5. Display · sRGB curve

    5Output

    Fitted into sRGB or Display P3, which share the sRGB curve, for the screen, JPEG and TIFF.

Source: the order in Develop.metal, the Metal shader that renders every edit.

The colour controls sit after the curve on purpose. There, Saturation and Vibrance know how close each colour already is to the edge of what the output can show, so they hold hue and clip nothing. How Redlamp handles raw files describes everything before the develop stage, from the file on disk to the camera colour it starts from.

What the feedback asked for

The feedback measured a grey scale: plotted against each patch's reference L*, the L* in Redlamp's export bends away from a straight line. Two meanings of "linear" meet in that sentence.

Linear numbers

Values proportional to light, as in Redlamp's working space. They say nothing about the tone curve: today's render saved as a TIFF with linear numbers would fail the same check as the sRGB export, because those numbers hold screen light, curve and all.

Linear response

Screen light proportional to scene light up to white, with no curve bending it. Then every patch's L* lands on its reference, a straight line with a slope of 1, whatever curve the file is written with, because L* is measured after decoding. This is what the feedback is asking for.

A ColorChecker's grey row through Redlamp's tone curve

A linear response is the dashed diagonal: every patch at its own L*. Drag Exposure, or anchor middle grey, and try to put all six on it. Redlamp Neutral and Redlamp Color are two of its built-in looks; Neutral has the lower contrast.

Exposure 0.00 EV: an 18% grey sits at 0.180 in scene light

00252550507575100100Patch's reference L*, the chart's ownRendered L*
Linear response: no curveRedlamp Neutral
PatchChart, renderRefRenderGap
Black 220.524.2+3.7
Neutral 3.535.746.4+10.7
Neutral 550.965.9+15.0
Neutral 6.566.880.7+13.9
Neutral 881.389.5+8.2
White 9.596.595.2−1.3

+15.0

Largest gap in L*, at Neutral 5

Anchoring puts Neutral 5 on its reference, but the curve's toe still pulls the dark patches down and its shoulder pulls White down: no exposure puts all six on the diagonal. A reproduction mode has to replace the curve, not adjust it.

Model: Redlamp's tone curve with each look's contrast, as greyscale.py models it, with each patch's scene value at its reflectance × 2Exposure, so 0 EV puts an 18% grey at 0.18. Anchored under Neutral, it gives White 86.9, Neutral 8 78.4 and Black 15.0. Redlamp's renders of a CC0 raw of a ColorChecker from a Sigma fp, anchored the same way, measured 86.3, 78.1 and 17.3: flare in a real photo lifts the black. Reference L*: BabelColor's averages for the ColorChecker.

What would fix it

A scene-referred mode fixes the shape. It's a rendering with no tone curve and no look: screen light equals scene light up to white. In the figure above, the curve becomes the diagonal, and once exposure is anchored, a metered 18% grey reads L* 49.5. Its exports can keep an ordinary curve, sRGB or a reference space for archive masters: their numbers aren't linear, but the light they describe is the scene's.

Tying exposure to each camera's metering fixes the position. Redlamp scales each sensor's clip point to 1.0, and cameras put a metered 18% grey roughly 3.3 to 3.7 stops below clip, depending on how each maker calibrates ISO. Redlamp only adds a baseline exposure for DNG files, which carry one; other raws get none. So Exposure 0 means a different grey on each camera, which would explain exports coming out slightly dark. Anchoring slides the line along; it doesn't straighten it.

Neither exists in Redlamp yet.

In one line

Linear is how the numbers are written; scene-referred is whose light they describe. Redlamp edits scene-linear, renders through the tone curve and writes display-encoded files. The feedback asks for files that still describe the scene: that's a change of rendering and of how exposure is anchored, not of encoding.

The tone curve, its constants and the render order are Develop.metal's. The grey-scale model is greyscale.py's, which also measures Redlamp's renders of chart raws. The sRGB curve is IEC 61966-2-1's, and the lightness scale is CIE 1976 L*.