1 /*
2  * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef COLORSPACE
17 #define COLORSPACE
18 
19 #include <array>
20 #include <cfloat>
21 #include <cmath>
22 #include <map>
23 #include <utility>
24 
25 #include "include/core/SkColorSpace.h"
26 #include "include/third_party/skcms/skcms.h"
27 
28 namespace OHOS {
29 namespace ColorManager {
30 #define DIMES_3 3
31 #define DIMES_2 2
32 
33 using Vector3 = std::array<float, DIMES_3>;
34 using Matrix3x3 = std::array<Vector3, DIMES_3>;
35 static constexpr float COLOR_EPSILON = 0.0018f; // 1/255/2 = 0.00196
36 static const std::array<float, DIMES_2> ILLUMINANT_D50_XY = {0.34567f, 0.35850f};
37 static const Vector3 ILLUMINANT_D50_XYZ = {0.964212f, 1.0f, 0.825188f};
38 static const Matrix3x3 BRADFORD = {{
39     {0.8951f, 0.2664f, -0.1614f},
40     {-0.7502f, 1.7135f, 0.0367f},
41     {0.0389f, -0.0685f, 1.0296f}}};
42 static const Matrix3x3 BRADFORD_INV = {{
43     {0.9869929f, -0.1470543f, 0.1599627f},
44     {0.4323053f,  0.5183603f, 0.0492912f},
45     {-0.0085287f, 0.0400428f, 0.9684867f},
46 }};
47 
48 enum ColorSpaceName : uint32_t {
49     NONE = 0,
50     ADOBE_RGB = 1,
51     DCI_P3 = 2,
52     DISPLAY_P3 = 3,
53     SRGB = 4,
54     BT709 = 6,
55     BT601_EBU = 7,
56     BT601_SMPTE_C = 8,
57     BT2020_HLG = 9,
58     BT2020_PQ = 10,
59     P3_HLG = 11,
60     P3_PQ = 12,
61     ADOBE_RGB_LIMIT = 13,
62     DISPLAY_P3_LIMIT = 14,
63     SRGB_LIMIT = 15,
64     BT709_LIMIT = 16,
65     BT601_EBU_LIMIT = 17,
66     BT601_SMPTE_C_LIMIT = 18,
67     BT2020_HLG_LIMIT = 19,
68     BT2020_PQ_LIMIT = 20,
69     P3_HLG_LIMIT = 21,
70     P3_PQ_LIMIT = 22,
71     LINEAR_P3 = 23,
72     LINEAR_SRGB = 24,
73     LINEAR_BT709 = LINEAR_SRGB,
74     LINEAR_BT2020 = 25,
75     DISPLAY_SRGB = SRGB,
76     DISPLAY_P3_SRGB = DISPLAY_P3,
77     DISPLAY_P3_HLG = P3_HLG,
78     DISPLAY_P3_PQ = P3_PQ,
79     DISPLAY_BT2020_SRGB = 26,
80     DISPLAY_BT2020_HLG = BT2020_HLG,
81     DISPLAY_BT2020_PQ = BT2020_PQ,
82     BT2020 = 27,
83     NTSC_1953 = 28,
84     PRO_PHOTO_RGB = 29,
85     ACES = 30,
86     ACESCG = 31,
87     CIE_LAB = 32,
88     CIE_XYZ = 33,
89     EXTENDED_SRGB = 34,
90     LINEAR_EXTENDED_SRGB = 35,
91     SMPTE_C = 36,
92     CUSTOM = 5,
93 };
94 
95 enum GamutMappingMode : uint32_t {
96     GAMUT_MAP_CONSTANT = 0,
97     GAMUT_MAP_EXPENSION,
98     GAMUT_MAP_HDR_CONSTANT,
99     GAMUT_MAP_HDR_EXPENSION,
100 };
101 
102 struct ColorSpacePrimaries {
103     float rX;
104     float rY;
105     float gX;
106     float gY;
107     float bX;
108     float bY;
109     float wX;
110     float wY;
111 };
112 
113 struct TransferFunc {
114     float g;
115     float a;
116     float b;
117     float c;
118     float d;
119     float e;
120     float f;
121 };
122 
123 Matrix3x3 operator*(const Matrix3x3& a, const Matrix3x3& b);
124 
125 Vector3 operator*(const Vector3& x, const Matrix3x3& a);
126 
127 Vector3 operator*(const Matrix3x3& a, const Vector3& x);
128 
129 Matrix3x3 operator/(const Vector3& a, const Vector3& b);
130 
131 Matrix3x3 Invert(const Matrix3x3& src);
132 
XYZ(const Vector3 & xyY)133 inline Vector3 XYZ(const Vector3& xyY)
134 {
135     return Vector3 {(xyY[0] * xyY[2]) / xyY[1], xyY[2],
136         ((1 - xyY[0] - xyY[1]) * xyY[2]) / xyY[1]};
137 }
138 
FloatEqual(const float src,const float dst)139 inline bool FloatEqual(const float src, const float dst)
140 {
141     return fabs(src - dst) < COLOR_EPSILON;
142 }
143 
ComputeWhitePoint(Matrix3x3 & toXYZ)144 inline std::array<float, DIMES_2> ComputeWhitePoint(Matrix3x3 &toXYZ)
145 {
146     Vector3 w = toXYZ * Vector3 {1.0f};
147     float sumW = w[0] + w[1] + w[2];
148     return {{w[0] / sumW, w[1] / sumW}};
149 }
150 
SkToXYZToMatrix3(const skcms_Matrix3x3 & skToXYZ)151 inline Matrix3x3 SkToXYZToMatrix3(const skcms_Matrix3x3 &skToXYZ)
152 {
153     return {{{skToXYZ.vals[0][0], skToXYZ.vals[0][1], skToXYZ.vals[0][2]},
154         {skToXYZ.vals[1][0], skToXYZ.vals[1][1], skToXYZ.vals[1][2]},
155         {skToXYZ.vals[2][0], skToXYZ.vals[2][1], skToXYZ.vals[2][2]}}};
156 }
157 
158 // Compute a toXYZD50 matrix from a given rgb and white point
159 Matrix3x3 ComputeXYZD50(const ColorSpacePrimaries& primaries);
160 
161 // Convert toXYZ to toXYZD50 matrix with its white point
162 Matrix3x3 DXToD50(const Matrix3x3 &toXYZ, const std::array<float, DIMES_2> &wp);
163 
164 class ColorSpace {
165 public:
166     ColorSpace(ColorSpaceName name);
167 
168     ColorSpace(const ColorSpacePrimaries &primaries, const TransferFunc &transferFunc);
169 
170     ColorSpace(const ColorSpacePrimaries &primaries, float gamma);
171 
172     ColorSpace(const Matrix3x3& toXYZ, const std::array<float, 2> &whitePoint, const TransferFunc& transferFunc);
173 
174     ColorSpace(const Matrix3x3& toXYZ, const std::array<float, 2>& whitePoint, float gamma);
175 
176     // convert SKColorSpace to OHOS ColorSpce
177     ColorSpace(const sk_sp<SkColorSpace> src, ColorSpaceName name = ColorSpaceName::CUSTOM);
178 
179     ColorSpace(const skcms_ICCProfile& srcIcc, ColorSpaceName name = ColorSpaceName::CUSTOM);
180 
GetColorSpaceName()181     ColorSpaceName GetColorSpaceName() const
182     {
183         return colorSpaceName;
184     }
185 
GetRGBToXYZ()186     Matrix3x3 GetRGBToXYZ() const
187     {
188         return toXYZ;
189     }
190 
GetXYZToRGB()191     Matrix3x3 GetXYZToRGB() const
192     {
193         auto toRGB = Invert(toXYZ);
194         return toRGB;
195     }
196 
GetWhitePoint()197     std::array<float, DIMES_2> GetWhitePoint() const
198     {
199         return whitePoint;
200     }
201 
GetGamma()202     float GetGamma() const
203     {
204         return transferFunc.g;
205     }
206 
207     Vector3 ToLinear(Vector3 color) const;
208     Vector3 ToNonLinear(Vector3 color) const;
209 
210     // convert OHOS ColorSpce to SKColorSpace
211     sk_sp<SkColorSpace> ToSkColorSpace() const;
212 
213     float clampMin = 0.0f;
214     float clampMax = 1.0f;
215 
216 private:
217     skcms_Matrix3x3 ToSkiaXYZ() const;
218 
219     ColorSpaceName colorSpaceName = ColorSpaceName::SRGB;
220     Matrix3x3 toXYZ;
221     std::array<float, DIMES_2> whitePoint;
222     TransferFunc transferFunc = {};
223 };
224 } // namespace ColorSpace
225 } // namespace OHOS
226 #endif  // COLORSPACE
227