main f2d166b

pattern.go RawHistoryFolder

1// Package pattern defines the colour patches of the testpattern client and
2// the transfer functions that say what each patch must look like. It has no
3// Wayland imports so tests can reuse it as an oracle; it is deliberately
4// independent of the renderer's own colour code.
5package pattern
6
7import (
8	"image"
9	"math"
10)
11
12const (
13	// Columns and Rows give the patch grid.
14	Columns = 6
15	Rows    = 2
16)
17
18// Patch is one solid rectangle of the test pattern. SRGB is set in "sdr"
19// mode, Nits (linear BT.2020, absolute luminance) in "hdr" mode.
20type Patch struct {
21	Rect image.Rectangle
22	SRGB [3]uint8
23	Nits [3]float64
24}
25
26// Centre returns the middle of the patch.
27func (p Patch) Centre() image.Point {
28	return image.Pt((p.Rect.Min.X+p.Rect.Max.X)/2, (p.Rect.Min.Y+p.Rect.Max.Y)/2)
29}
30
31// sdrColours are the sRGB patches in row-major order.
32var sdrColours = [Columns * Rows][3]uint8{
33	{0, 0, 0}, {64, 64, 64}, {128, 128, 128}, {192, 192, 192}, {255, 255, 255}, {255, 128, 0},
34	{255, 0, 0}, {0, 255, 0}, {0, 0, 255}, {0, 255, 255}, {255, 0, 255}, {255, 255, 0},
35}
36
37// BT709ToBT2020 converts linear BT.709 RGB to linear BT.2020 RGB.
38var BT709ToBT2020 = [3][3]float64{
39	{0.627404, 0.329283, 0.043313},
40	{0.069097, 0.919540, 0.011362},
41	{0.016391, 0.088013, 0.895595},
42}
43
44// ReferenceWhite is the luminance of SDR white in an HDR signal, in nits.
45const ReferenceWhite = 203
46
47// hdrNits are the BT.2020 linear patches in row-major order.
48var hdrNits = func() (n [Columns * Rows][3]float64) {
49	for i, v := range []float64{0, 1, 100, ReferenceWhite, 400, 1000} {
50		n[i] = [3]float64{v, v, v}
51	}
52	n[6] = [3]float64{ReferenceWhite, 0, 0}
53	n[7] = [3]float64{0, ReferenceWhite, 0}
54	n[8] = [3]float64{0, 0, ReferenceWhite}
55	for c := range 3 {
56		var v [3]float64
57		for r := range 3 {
58			v[r] = BT709ToBT2020[r][c] * ReferenceWhite
59		}
60		n[9+c] = v
61	}
62	return
63}()
64
65// Patches lays the mode's patches out as a 6×2 grid filling w×h. Cell sizes
66// use integer division; the last column and row take the remainder. Mode is
67// "sdr" or "hdr"; any other value yields nil.
68func Patches(mode string, w, h int) []Patch {
69	if mode != "sdr" && mode != "hdr" {
70		return nil
71	}
72	patches := make([]Patch, 0, Columns*Rows)
73	for i := range Columns * Rows {
74		col, row := i%Columns, i/Columns
75		x0, x1 := col*(w/Columns), (col+1)*(w/Columns)
76		y0, y1 := row*(h/Rows), (row+1)*(h/Rows)
77		if col == Columns-1 {
78			x1 = w
79		}
80		if row == Rows-1 {
81			y1 = h
82		}
83		p := Patch{Rect: image.Rect(x0, y0, x1, y1)}
84		if mode == "sdr" {
85			p.SRGB = sdrColours[i]
86		} else {
87			p.Nits = hdrNits[i]
88		}
89		patches = append(patches, p)
90	}
91	return patches
92}
93
94// PQEncode encodes absolute luminance in nits with SMPTE ST 2084, clamped to
95// 0–10000 nits, and returns a unit-range signal.
96func PQEncode(nits float64) float64 {
97	if nits <= 0 {
98		return 0
99	}
100	x := math.Pow(min(nits, 10000)/10000, 2610.0/16384)
101	return math.Pow((3424.0/4096+2413.0/128*x)/(1+2392.0/128*x), 2523.0/32)
102}
103
104// PQDecode is the SMPTE ST 2084 EOTF: it turns a unit-range PQ signal into
105// absolute luminance in nits (0–10000). It inverts PQEncode.
106func PQDecode(signal float64) float64 {
107	if signal <= 0 {
108		return 0
109	}
110	e := math.Pow(min(signal, 1), 32.0/2523)
111	num := max(e-3424.0/4096, 0)
112	den := 2413.0/128 - 2392.0/128*e
113	return 10000 * math.Pow(num/den, 16384.0/2610)
114}
115
116// SRGBToLinear decodes a unit-range sRGB component.
117func SRGBToLinear(v float64) float64 {
118	if v <= 0.04045 {
119		return v / 12.92
120	}
121	return math.Pow((v+0.055)/1.055, 2.4)
122}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 25

Tags 10

↑↓ moveenter openesc close