-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathrgb.go
116 lines (97 loc) · 3.36 KB
/
rgb.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package chromath
// RGBTransformer allows tranforms from a user-defined RGB color space to XYZ with optional scaling and adaptation
type RGBTransformer struct {
ws *RGBSpace
compander Compander
transform, transformInv Matrix
inScaler Scaler
outScale float64
spaceTm, adaptTm Matrix
}
// NewRGBTransformer initializes a transform operator from an RGB space to XYZ
// ws specifies the parameters (primaries, working illuminant, and linearization function) of the working RGB space
// adaptation specifies an optional adaptation method to transform into the target illuminant.
// targetIluminant specifies the target illuminant of the XYZ conversion. It is ignored if adaptation is nil.
// The default is CIE D50 (the ICC Profile Connection illuminant)
// scaler is an optional scaling function
// outscale provides a scaling factor into XYZ space, typical values are 1 and 100
// compander is an optional specification for the gamma function to linearize RGB points. This argument overrides
// any compander specified by ws.
func NewRGBTransformer(ws *RGBSpace, adaptation *Adaptation, targetIlluminant *IlluminantRef,
scaler Scaler, outScale float64,
compander Compander) *RGBTransformer {
t := &RGBTransformer{}
t.ws = ws
if compander != nil {
t.compander = compander
} else if ws.Compander != nil {
t.compander = ws.Compander.Init(ws)
}
t.inScaler = scaler
t.spaceTm = ws.XyYPrimary.RGBTransform(ws.IlluminantRef.XYZ)
x := t.spaceTm
if adaptation != nil {
if targetIlluminant == nil {
targetIlluminant = &IlluminantRefD50
}
if targetIlluminant.XYZ != ws.IlluminantRef.XYZ {
t.adaptTm = adaptation.Transform(ws.IlluminantRef.XYZ, targetIlluminant.XYZ)
x = t.adaptTm.Mul3(x)
}
}
if outScale != 0 {
t.outScale = outScale
x = x.Mul3(Matrix{outScale, 0, 0, 0, outScale, 0, 0, 0, outScale})
}
t.transform = x
t.transformInv = x.Inv()
return t
}
// Linearize will apply the current scaling and linearization function to the given RGB point
func (t *RGBTransformer) Linearize(rgb RGB) RGB {
p := Point(rgb)
if scaler := t.inScaler; scaler != nil {
p = scaler.Scale(p)
}
if compander := t.compander; compander != nil {
p = compander.Linearize(p)
}
return RGB(p)
}
// Convert an RGB colorpoint to XYZ based on the parameters of the receiver
func (t *RGBTransformer) Convert(rgb RGB) XYZ {
p := Point(rgb)
if scaler := t.inScaler; scaler != nil {
p = scaler.Scale(p)
}
if compander := t.compander; compander != nil {
p = compander.Linearize(p)
}
p = t.transform.Mul3x1(p)
return XYZ(p)
}
// Invert converts an XYZ point to RGB based on the parameters of the receiver
func (t *RGBTransformer) Invert(xyz XYZ) RGB {
p := Point(xyz)
p = t.transformInv.Mul3x1(p)
if compander := t.compander; compander != nil {
p = compander.Compand(p)
}
if scaler := t.inScaler; scaler != nil {
p = scaler.ScaleInv(p)
}
return RGB(p)
}
// Return the computed adaptation matrix for the transformer
func (t *RGBTransformer) AdaptTM() Matrix {
return t.adaptTm
}
// Return the computed linear RGB⇒XYZ matrix for the transformer
func (t *RGBTransformer) SpaceTM() Matrix {
return t.spaceTm
}
// Return the computed complete transformation matrix for the transformer
// This matrix includes adaptation, space transform, and output scaling
func (t *RGBTransformer) TM() Matrix {
return t.transform
}