forked from Pissandshittium/pissandshittium
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathskcolorspace_trfn.cc
112 lines (98 loc) · 2.66 KB
/
skcolorspace_trfn.cc
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
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "skia/ext/skcolorspace_trfn.h"
#include <cmath>
namespace skia {
namespace {
// Solve `y` = `alpha` * `x` for `alpha`. Return false if there is no
// solution, or the solution is 0.
bool GetLinearScale(float x, float y, float& alpha) {
if (x == 0.f && y == 0.f) {
alpha = 0.f;
return true;
}
if (x == 0.f || y == 0.f) {
return false;
}
alpha = y / x;
return true;
}
// Solve `y` = pow(`alpha`, 1/`g`) * `x` for `alpha`. Return false if
// there is no solution, or the solution is 0.
bool GetPowerScale(float x, float y, float g, float& alpha) {
if (x == 0.f && y == 0.f) {
alpha = 0.f;
return true;
}
if (x == 0.f || y == 0.f) {
return false;
}
float alpha_to_ginv = y / x;
alpha = std::pow(alpha_to_ginv, g);
return true;
}
} // namespace
skcms_TransferFunction ScaleTransferFunction(const skcms_TransferFunction& f,
float alpha) {
float alpha_to_ginv = std::pow(alpha, 1 / f.g);
return {
f.g, alpha_to_ginv * f.a, alpha_to_ginv * f.b, alpha * f.c,
f.d, alpha * f.e, alpha * f.f,
};
}
bool IsScaledTransferFunction(const skcms_TransferFunction& x,
const skcms_TransferFunction& y,
float* out_alpha) {
// The g and d parameters are unaffected by a scale. Require that they be
// exactly the same.
if (x.g != y.g) {
return false;
}
if (x.d != y.d) {
return false;
}
// Compute alpha for all all variables. If alpha is 0 then the unscaled
// parameter was 0 (and so alpha cannot be computed from it).
float alphas[5] = {0.f, 0.f, 0.f, 0.f, 0.f};
if (!GetLinearScale(x.c, y.c, alphas[0])) {
return false;
}
if (!GetLinearScale(x.e, y.e, alphas[1])) {
return false;
}
if (!GetLinearScale(x.f, y.f, alphas[2])) {
return false;
}
if (!GetPowerScale(x.a, y.a, x.g, alphas[3])) {
return false;
}
if (!GetPowerScale(x.b, y.b, x.g, alphas[4])) {
return false;
}
// Ensure all non-zero alphas are close to each other.
constexpr float kEpsilon = 1e-5f;
float alpha = 0.f;
for (size_t i = 0; i < 5; ++i) {
if (alphas[i] == 0.f) {
continue;
}
if (alpha == 0.f) {
alpha = alphas[i];
continue;
}
if (std::abs(alpha - alphas[i]) > kEpsilon) {
return false;
}
}
// Scaling by zero will just cause bugs, so reject it.
if (alpha == 0.f) {
return false;
}
// Return the result.
if (out_alpha) {
*out_alpha = alpha;
}
return true;
}
} // namespace skia