• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ANDROID_UI_COLOR_SPACE
18 #define ANDROID_UI_COLOR_SPACE
19 
20 #include <array>
21 #include <cmath>
22 #include <functional>
23 #include <memory>
24 #include <string>
25 
26 #include <math/mat3.h>
27 #include <math/scalar.h>
28 #include <math/vec2.h>
29 #include <math/vec3.h>
30 
31 namespace android {
32 
33 class ColorSpace {
34 public:
35     typedef std::function<float(float)> transfer_function;
36     typedef std::function<float(float)> clamping_function;
37 
38     struct TransferParameters {
39         float g = 0.0f;
40         float a = 0.0f;
41         float b = 0.0f;
42         float c = 0.0f;
43         float d = 0.0f;
44         float e = 0.0f;
45         float f = 0.0f;
46     };
47 
48     /**
49      * Creates a named color space with the specified RGB->XYZ
50      * conversion matrix. The white point and primaries will be
51      * computed from the supplied matrix.
52      *
53      * The default transfer functions are a linear response x->x
54      * and the default clamping function is a simple saturate
55      * (clamp(x, 0, 1)).
56      */
57     ColorSpace(
58             const std::string& name,
59             const mat3& rgbToXYZ,
60             transfer_function OETF = linearResponse,
61             transfer_function EOTF = linearResponse,
62             clamping_function clamper = saturate<float>
63     ) noexcept;
64 
65     /**
66      * Creates a named color space with the specified RGB->XYZ
67      * conversion matrix. The white point and primaries will be
68      * computed from the supplied matrix.
69      *
70      * The transfer functions are defined by the set of supplied
71      * transfer parameters. The default clamping function is a
72      * simple saturate (clamp(x, 0, 1)).
73      */
74     ColorSpace(
75             const std::string& name,
76             const mat3& rgbToXYZ,
77             const TransferParameters parameters,
78             clamping_function clamper = saturate<float>
79     ) noexcept;
80 
81     /**
82      * Creates a named color space with the specified RGB->XYZ
83      * conversion matrix. The white point and primaries will be
84      * computed from the supplied matrix.
85      *
86      * The transfer functions are defined by a simple gamma value.
87      * The default clamping function is a saturate (clamp(x, 0, 1)).
88      */
89     ColorSpace(
90             const std::string& name,
91             const mat3& rgbToXYZ,
92             float gamma,
93             clamping_function clamper = saturate<float>
94     ) noexcept;
95 
96     /**
97      * Creates a named color space with the specified primaries
98      * and white point. The RGB<>XYZ conversion matrices are
99      * computed from the primaries and white point.
100      *
101      * The default transfer functions are a linear response x->x
102      * and the default clamping function is a simple saturate
103      * (clamp(x, 0, 1)).
104      */
105     ColorSpace(
106             const std::string& name,
107             const std::array<float2, 3>& primaries,
108             const float2& whitePoint,
109             transfer_function OETF = linearResponse,
110             transfer_function EOTF = linearResponse,
111             clamping_function clamper = saturate<float>
112     ) noexcept;
113 
114     /**
115      * Creates a named color space with the specified primaries
116      * and white point. The RGB<>XYZ conversion matrices are
117      * computed from the primaries and white point.
118      *
119      * The transfer functions are defined by the set of supplied
120      * transfer parameters. The default clamping function is a
121      * simple saturate (clamp(x, 0, 1)).
122      */
123     ColorSpace(
124             const std::string& name,
125             const std::array<float2, 3>& primaries,
126             const float2& whitePoint,
127             const TransferParameters parameters,
128             clamping_function clamper = saturate<float>
129     ) noexcept;
130 
131     /**
132      * Creates a named color space with the specified primaries
133      * and white point. The RGB<>XYZ conversion matrices are
134      * computed from the primaries and white point.
135      *
136      * The transfer functions are defined by a single gamma value.
137      * The default clamping function is a saturate (clamp(x, 0, 1)).
138      */
139     ColorSpace(
140             const std::string& name,
141             const std::array<float2, 3>& primaries,
142             const float2& whitePoint,
143             float gamma,
144             clamping_function clamper = saturate<float>
145     ) noexcept;
146 
147     ColorSpace() noexcept = delete;
148 
149     /**
150      * Encodes the supplied RGB value using this color space's
151      * opto-electronic transfer function.
152      */
fromLinear(const float3 & v)153     constexpr float3 fromLinear(const float3& v) const noexcept {
154         return apply(v, mOETF);
155     }
156 
157     /**
158      * Decodes the supplied RGB value using this color space's
159      * electro-optical transfer function.
160      */
toLinear(const float3 & v)161     constexpr float3 toLinear(const float3& v) const noexcept {
162         return apply(v, mEOTF);
163     }
164 
165     /**
166      * Converts the supplied XYZ value to RGB. The returned value
167      * is encoded with this color space's opto-electronic transfer
168      * function and clamped by this color space's clamping function.
169      */
xyzToRGB(const float3 & xyz)170     constexpr float3 xyzToRGB(const float3& xyz) const noexcept {
171         return apply(fromLinear(mXYZtoRGB * xyz), mClamper);
172     }
173 
174     /**
175      * Converts the supplied RGB value to XYZ. The input RGB value
176      * is decoded using this color space's electro-optical function
177      * before being converted to XYZ.
178      */
rgbToXYZ(const float3 & rgb)179     constexpr float3 rgbToXYZ(const float3& rgb) const noexcept {
180         return mRGBtoXYZ * toLinear(rgb);
181     }
182 
getName()183     constexpr const std::string& getName() const noexcept {
184         return mName;
185     }
186 
getRGBtoXYZ()187     constexpr const mat3& getRGBtoXYZ() const noexcept {
188         return mRGBtoXYZ;
189     }
190 
getXYZtoRGB()191     constexpr const mat3& getXYZtoRGB() const noexcept {
192         return mXYZtoRGB;
193     }
194 
getOETF()195     constexpr const transfer_function& getOETF() const noexcept {
196         return mOETF;
197     }
198 
getEOTF()199     constexpr const transfer_function& getEOTF() const noexcept {
200         return mEOTF;
201     }
202 
getClamper()203     constexpr const clamping_function& getClamper() const noexcept {
204         return mClamper;
205     }
206 
getPrimaries()207     constexpr const std::array<float2, 3>& getPrimaries() const noexcept {
208         return mPrimaries;
209     }
210 
getWhitePoint()211     constexpr const float2& getWhitePoint() const noexcept {
212         return mWhitePoint;
213     }
214 
getTransferParameters()215     constexpr const TransferParameters& getTransferParameters() const noexcept {
216         return mParameters;
217     }
218 
219     /**
220      * Converts the supplied XYZ value to xyY.
221      */
xyY(const float3 & XYZ)222     static constexpr float2 xyY(const float3& XYZ) {
223         return XYZ.xy / dot(XYZ, float3{1});
224     }
225 
226     /**
227      * Converts the supplied xyY value to XYZ.
228      */
XYZ(const float3 & xyY)229     static constexpr float3 XYZ(const float3& xyY) {
230         return float3{(xyY.x * xyY.z) / xyY.y, xyY.z, ((1 - xyY.x - xyY.y) * xyY.z) / xyY.y};
231     }
232 
233     static const ColorSpace sRGB();
234     static const ColorSpace linearSRGB();
235     static const ColorSpace extendedSRGB();
236     static const ColorSpace linearExtendedSRGB();
237     static const ColorSpace NTSC();
238     static const ColorSpace BT709();
239     static const ColorSpace BT2020();
240     static const ColorSpace AdobeRGB();
241     static const ColorSpace ProPhotoRGB();
242     static const ColorSpace DisplayP3();
243     static const ColorSpace DCIP3();
244     static const ColorSpace ACES();
245     static const ColorSpace ACEScg();
246 
247     // Creates a NxNxN 3D LUT, where N is the specified size (min=2, max=256)
248     // The 3D lookup coordinates map to the RGB components: u=R, v=G, w=B
249     // The generated 3D LUT is meant to be used as a 3D texture and its Y
250     // axis is thus already flipped
251     // The source color space must define its values in the domain [0..1]
252     // The generated LUT transforms from gamma space to gamma space
253     static std::unique_ptr<float3> createLUT(uint32_t size,
254             const ColorSpace& src, const ColorSpace& dst);
255 
256 private:
257     static constexpr mat3 computeXYZMatrix(
258             const std::array<float2, 3>& primaries, const float2& whitePoint);
259 
linearResponse(float v)260     static constexpr float linearResponse(float v) {
261         return v;
262     }
263 
264     std::string mName;
265 
266     mat3 mRGBtoXYZ;
267     mat3 mXYZtoRGB;
268 
269     TransferParameters mParameters;
270     transfer_function mOETF;
271     transfer_function mEOTF;
272     clamping_function mClamper;
273 
274     std::array<float2, 3> mPrimaries;
275     float2 mWhitePoint;
276 };
277 
278 class ColorSpaceConnector {
279 public:
280     ColorSpaceConnector(const ColorSpace& src, const ColorSpace& dst) noexcept;
281 
getSource()282     constexpr const ColorSpace& getSource() const noexcept { return mSource; }
getDestination()283     constexpr const ColorSpace& getDestination() const noexcept { return mDestination; }
284 
getTransform()285     constexpr const mat3& getTransform() const noexcept { return mTransform; }
286 
transform(const float3 & v)287     constexpr float3 transform(const float3& v) const noexcept {
288         float3 linear = mSource.toLinear(apply(v, mSource.getClamper()));
289         return apply(mDestination.fromLinear(mTransform * linear), mDestination.getClamper());
290     }
291 
transformLinear(const float3 & v)292     constexpr float3 transformLinear(const float3& v) const noexcept {
293         float3 linear = apply(v, mSource.getClamper());
294         return apply(mTransform * linear, mDestination.getClamper());
295     }
296 
297 private:
298     ColorSpace mSource;
299     ColorSpace mDestination;
300     mat3 mTransform;
301 };
302 
303 }; // namespace android
304 
305 #endif // ANDROID_UI_COLOR_SPACE
306