• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "color_space.h"
17 
18 namespace OHOS {
19 namespace ColorManager {
20 const ColorSpacePrimaries CSP_ADOBE_RGB = {0.640f, 0.330f, 0.210f, 0.710f, 0.150f, 0.060f, 0.3127f, 0.3290f};
21 const ColorSpacePrimaries CSP_P3_DCI = {0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f, 0.314f, 0.351f};
22 const ColorSpacePrimaries CSP_P3_D65 = {0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f, 0.3127f, 0.3290f};
23 const ColorSpacePrimaries CSP_BT709 = {0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f, 0.3127f, 0.3290f};
24 const ColorSpacePrimaries CSP_BT601_P = {0.640f, 0.330f, 0.290f, 0.600f, 0.150f, 0.060f, 0.3127f, 0.3290f};
25 const ColorSpacePrimaries CSP_BT601_N = {0.630f, 0.340f, 0.310f, 0.595f, 0.155f, 0.070f, 0.3127f, 0.3290f};
26 const ColorSpacePrimaries CSP_BT2020 = {0.708f, 0.292f, 0.170f, 0.797f, 0.131f, 0.046f, 0.3127f, 0.3290f};
27 const ColorSpacePrimaries CSP_NTSC_1953 = {0.670f, 0.330f, 0.210f, 0.710f, 0.140f, 0.080f, 0.310f, 0.316f};
28 const ColorSpacePrimaries CSP_PRO_PHOTO_RGB = {0.7347f, 0.2653f, 0.1596f, 0.8404f, 0.0366f, 0.0001f, 0.34567f,
29     0.35850f};
30 
31 // use unique g value to represent HLG and PG transfer function
32 constexpr float HLG_G = -3.0f;
33 constexpr float PQ_G = -2.0f;
34 constexpr float LOG_G = -100.0f;
35 
36 const TransferFunc TF_ADOBE_RGB = {2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
37 const TransferFunc TF_GAMMA_2_6 = {2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
38 const TransferFunc TF_SRGB = {2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f, 0.0f, 0.0f};
39 const TransferFunc TF_BT709 = {1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f, 0.0f, 0.0f};
40 const TransferFunc TF_HLG = {HLG_G, 2.0f, 2.0f, 1 / 0.17883277f, 0.28466892f, 0.55991073f, 0.0f};
41 const TransferFunc TF_PQ = {PQ_G, -107 / 128.0f, 1.0f, 32 / 2523.0f, 2413 / 128.0f, -2392 / 128.0f, 8192 / 1305.0f};
42 const TransferFunc TF_LINEAR = {1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
43 const TransferFunc TF_PRO_PHOTO_RGB = {1.8f, 1.0f, 0.0f, 1 / 16.0f, 0.031248f, 0.0f, 0.0f};
44 const TransferFunc TF_LOG = {LOG_G, 5.555556f, 0.050943f, 0.130233f, 0.452962f, 6.842619f, 0.092864f};
45 
46 const ColorSpace CS_ADOBE_RGB = {CSP_ADOBE_RGB, TF_ADOBE_RGB};
47 const ColorSpace CS_DCI_P3 = {CSP_P3_DCI, TF_GAMMA_2_6};
48 const ColorSpace CS_DISPLAY_P3 = {CSP_P3_D65, TF_SRGB};
49 const ColorSpace CS_SRGB = {CSP_BT709, TF_SRGB};
50 const ColorSpace CS_BT709 = {CSP_BT709, TF_BT709};
51 const ColorSpace CS_BT601_EBU = {CSP_BT601_P, TF_BT709};
52 const ColorSpace CS_BT601_SMPTE_C = {CSP_BT601_N, TF_BT709};
53 const ColorSpace CS_BT2020_HLG = {CSP_BT2020, TF_HLG};
54 const ColorSpace CS_BT2020_PQ = {CSP_BT2020, TF_PQ};
55 const ColorSpace CS_P3_HLG = {CSP_P3_D65, TF_HLG};
56 const ColorSpace CS_P3_PQ = {CSP_P3_D65, TF_PQ};
57 const ColorSpace CS_LINEAR_P3 = {CSP_P3_D65, TF_LINEAR};
58 const ColorSpace CS_LINEAR_SRGB = {CSP_BT709, TF_LINEAR};
59 const ColorSpace CS_LINEAR_BT2020 = {CSP_BT2020, TF_LINEAR};
60 const ColorSpace CS_DISPLAY_BT2020_SRGB = {CSP_BT2020, TF_SRGB};
61 const ColorSpace CS_BT2020 = {CSP_BT2020, TF_BT709};
62 const ColorSpace CS_NTSC_1953 = {CSP_NTSC_1953, TF_BT709};
63 const ColorSpace CS_PRO_PHOTO_RGB = {CSP_PRO_PHOTO_RGB, TF_PRO_PHOTO_RGB};
64 const ColorSpace CS_H_LOG = {CSP_BT2020, TF_LOG};
65 
66 const std::map<ColorSpaceName, ColorSpace> NamedColorSpace = {
67     { ColorSpaceName::ADOBE_RGB, CS_ADOBE_RGB },
68     { ColorSpaceName::DCI_P3, CS_DCI_P3 },
69     { ColorSpaceName::DISPLAY_P3, CS_DISPLAY_P3 },
70     { ColorSpaceName::SRGB, CS_SRGB },
71     { ColorSpaceName::BT709, CS_BT709 },
72     { ColorSpaceName::BT601_EBU, CS_BT601_EBU },
73     { ColorSpaceName::BT601_SMPTE_C, CS_BT601_SMPTE_C },
74     { ColorSpaceName::BT2020_HLG, CS_BT2020_HLG },
75     { ColorSpaceName::BT2020_PQ, CS_BT2020_PQ },
76     { ColorSpaceName::P3_HLG, CS_P3_HLG },
77     { ColorSpaceName::P3_PQ, CS_P3_PQ },
78     { ColorSpaceName::ADOBE_RGB_LIMIT, CS_ADOBE_RGB },
79     { ColorSpaceName::DISPLAY_P3_LIMIT, CS_DISPLAY_P3 },
80     { ColorSpaceName::SRGB_LIMIT, CS_SRGB },
81     { ColorSpaceName::BT709_LIMIT, CS_BT709 },
82     { ColorSpaceName::BT601_EBU_LIMIT, CS_BT601_EBU },
83     { ColorSpaceName::BT601_SMPTE_C_LIMIT, CS_BT601_SMPTE_C },
84     { ColorSpaceName::BT2020_HLG_LIMIT, CS_BT2020_HLG },
85     { ColorSpaceName::BT2020_PQ_LIMIT, CS_BT2020_PQ },
86     { ColorSpaceName::P3_HLG_LIMIT, CS_P3_HLG },
87     { ColorSpaceName::P3_PQ_LIMIT, CS_P3_PQ },
88     { ColorSpaceName::LINEAR_P3, CS_LINEAR_P3 },
89     { ColorSpaceName::LINEAR_SRGB, CS_LINEAR_SRGB },
90     { ColorSpaceName::LINEAR_BT709, CS_LINEAR_SRGB },
91     { ColorSpaceName::LINEAR_BT2020, CS_LINEAR_BT2020 },
92     { ColorSpaceName::DISPLAY_SRGB, CS_SRGB },
93     { ColorSpaceName::DISPLAY_P3_SRGB, CS_DISPLAY_P3 },
94     { ColorSpaceName::DISPLAY_P3_HLG, CS_P3_HLG },
95     { ColorSpaceName::DISPLAY_P3_PQ, CS_P3_PQ },
96     { ColorSpaceName::DISPLAY_BT2020_SRGB, CS_DISPLAY_BT2020_SRGB },
97     { ColorSpaceName::DISPLAY_BT2020_HLG, CS_BT2020_HLG },
98     { ColorSpaceName::DISPLAY_BT2020_PQ, CS_BT2020_PQ },
99     { ColorSpaceName::BT2020, CS_BT2020 },
100     { ColorSpaceName::NTSC_1953, CS_NTSC_1953 },
101     { ColorSpaceName::PRO_PHOTO_RGB, CS_PRO_PHOTO_RGB },
102     { ColorSpaceName::H_LOG, CS_H_LOG },
103 };
104 
ColorSpace(ColorSpaceName name)105 ColorSpace::ColorSpace(ColorSpaceName name)
106 {
107     if (NamedColorSpace.find(name) != NamedColorSpace.end()) {
108         const ColorSpace &colorSpace = NamedColorSpace.at(name);
109         colorSpaceName = name;
110         whitePoint = colorSpace.whitePoint;
111         toXYZ = colorSpace.toXYZ;
112         transferFunc = colorSpace.transferFunc;
113     } else {
114         colorSpaceName = ColorSpaceName::NONE;
115     }
116 }
117 
ColorSpace(const ColorSpacePrimaries & primaries,const TransferFunc & transferFunc)118 ColorSpace::ColorSpace(const ColorSpacePrimaries &primaries, const TransferFunc &transferFunc)
119     : colorSpaceName(ColorSpaceName::CUSTOM),
120       toXYZ(ComputeXYZD50(primaries)),
121       transferFunc(transferFunc)
122 {
123     std::array<float, 2> whiteP = {primaries.wX, primaries.wY};  // 2 means two dimension x, y
124     whitePoint = whiteP;
125 }
126 
ColorSpace(const ColorSpacePrimaries & primaries,float gamma)127 ColorSpace::ColorSpace(const ColorSpacePrimaries &primaries, float gamma)
128     : colorSpaceName(ColorSpaceName::CUSTOM),
129       toXYZ(ComputeXYZD50(primaries))
130 {
131     std::array<float, 2> whiteP = {primaries.wX, primaries.wY};  // 2 means two dimension x, y
132     whitePoint = whiteP;
133     transferFunc = {};
134     transferFunc.g = gamma;
135     transferFunc.a = 1.0f;
136 }
137 
ColorSpace(const Matrix3x3 & toXYZ,const std::array<float,2> & whitePoint,const TransferFunc & transferFunc)138 ColorSpace::ColorSpace(const Matrix3x3& toXYZ, const std::array<float, 2>& whitePoint, const TransferFunc &transferFunc)
139     : colorSpaceName(ColorSpaceName::CUSTOM),
140       toXYZ(DXToD50(toXYZ, whitePoint)),
141       whitePoint(whitePoint),
142       transferFunc(transferFunc)
143 {
144 }
145 
ColorSpace(const Matrix3x3 & toXYZ,const std::array<float,2> & whitePoint,float gamma)146 ColorSpace::ColorSpace(const Matrix3x3 &toXYZ, const std::array<float, 2>& whitePoint, float gamma)
147     : colorSpaceName(ColorSpaceName::CUSTOM), toXYZ(DXToD50(toXYZ, whitePoint)), whitePoint(whitePoint)
148 {
149     transferFunc = {};
150     transferFunc.g = gamma;
151     transferFunc.a = 1.0f;
152 }
153 
ColorSpace(const sk_sp<SkColorSpace> src,ColorSpaceName name)154 ColorSpace::ColorSpace(const sk_sp<SkColorSpace> src, ColorSpaceName name)
155     : colorSpaceName(name)
156 {
157     if (src) {
158         float func[7];
159         src->transferFn(func);
160         transferFunc = {func[0], func[1], func[2], func[3], func[4], func[5], func[6]};
161         skcms_Matrix3x3 toXYZD50;
162         src->toXYZD50(&toXYZD50);
163         toXYZ = SkToXYZToMatrix3(toXYZD50);
164         whitePoint = ComputeWhitePoint(toXYZ);
165     }
166 }
167 
ColorSpace(const skcms_ICCProfile & srcIcc,ColorSpaceName name)168 ColorSpace::ColorSpace(const skcms_ICCProfile& srcIcc, ColorSpaceName name)
169     : colorSpaceName(name)
170 {
171     if (srcIcc.has_toXYZD50 && srcIcc.has_trc) {
172         skcms_TransferFunction func = srcIcc.trc[0].parametric;
173         transferFunc = {func.g, func.a, func.b, func.c, func.d, func.e, func.f};
174         toXYZ = SkToXYZToMatrix3(srcIcc.toXYZD50);
175         whitePoint = ComputeWhitePoint(toXYZ);
176     }
177 }
178 
operator *(const Matrix3x3 & a,const Matrix3x3 & b)179 Matrix3x3 operator*(const Matrix3x3& a, const Matrix3x3& b)
180 {
181     Matrix3x3 c = {};
182     for (size_t i = 0; i < a.size(); ++i) {
183         for (size_t j = 0; j < b.size(); ++j) {
184             for (size_t k = 0; k < b[0].size(); ++k) {
185                 c[i][j] += a[i][k] * b[k][j];
186             }
187         }
188     }
189     return c;
190 }
191 
operator *(const Vector3 & x,const Matrix3x3 & a)192 Vector3 operator*(const Vector3& x, const Matrix3x3& a)
193 {
194     Vector3 b = {};
195     for (size_t i = 0; i < x.size(); ++i) {
196         for (size_t j = 0; j < a.size(); ++j) {
197             b[i] += x[j] * a[j][i];
198         }
199     }
200     return b;
201 }
202 
operator *(const Matrix3x3 & a,const Vector3 & x)203 Vector3 operator*(const Matrix3x3& a, const Vector3& x)
204 {
205     Vector3 b = {};
206     for (size_t i = 0; i < a.size(); ++i) {
207         for (size_t j = 0; j < x.size(); ++j) {
208             b[i] += a[i][j] * x[j];
209         }
210     }
211     return b;
212 }
213 
operator /(const Vector3 & a,const Vector3 & b)214 Matrix3x3 operator/(const Vector3& a, const Vector3& b)
215 {
216     Matrix3x3 diag = {};
217     for (size_t i = 0; i < a.size(); ++i) {
218         diag[i][i] += a[i] / b[i];
219     }
220     return diag;
221 }
222 
ComputeXYZD50(const ColorSpacePrimaries & primaries)223 Matrix3x3 ComputeXYZD50(const ColorSpacePrimaries& primaries)
224 {
225     float oneRxRy = (1 - primaries.rX) / primaries.rY;
226     float oneGxGy = (1 - primaries.gX) / primaries.gY;
227     float oneBxBy = (1 - primaries.bX) / primaries.bY;
228     float oneWxWy = (1 - primaries.wX) / primaries.wY;
229 
230     float RxRy = primaries.rX / primaries.rY;
231     float GxGy = primaries.gX / primaries.gY;
232     float BxBy = primaries.bX / primaries.bY;
233     float WxWy = primaries.wX / primaries.wY;
234 
235     float BY = ((oneWxWy - oneRxRy) * (GxGy - RxRy) - (WxWy - RxRy) * (oneGxGy - oneRxRy)) /
236         ((oneBxBy - oneRxRy) * (GxGy - RxRy) - (BxBy - RxRy) * (oneGxGy - oneRxRy));
237     float GY = (WxWy - RxRy - BY * (BxBy - RxRy)) / (GxGy - RxRy);
238     float RY = 1 - GY - BY;
239 
240     float RYRy = RY / primaries.rY;
241     float GYGy = GY / primaries.gY;
242     float BYBy = BY / primaries.bY;
243 
244     Matrix3x3 toXYZ = {{{RYRy * primaries.rX, GYGy * primaries.gX, BYBy * primaries.bX},
245         {RY, GY, BY},
246         {RYRy * (1 - primaries.rX - primaries.rY),
247          GYGy * (1 - primaries.gX - primaries.gY),
248          BYBy * (1 - primaries.bX - primaries.bY)}}};
249     std::array<float, DIMES_2> wp = {primaries.wX, primaries.wY};
250 
251     return DXToD50(toXYZ, wp);
252 }
253 
AdaptationToD50(const Vector3 & srcWhitePoint)254 static Matrix3x3 AdaptationToD50(const Vector3& srcWhitePoint)
255 {
256     Vector3 srcLMS = BRADFORD * srcWhitePoint;
257     Vector3 dstLMS = BRADFORD * ILLUMINANT_D50_XYZ;
258     return BRADFORD_INV * (dstLMS / srcLMS) * BRADFORD;
259 }
260 
DXToD50(const Matrix3x3 & toXYZ,const std::array<float,DIMES_2> & wp)261 Matrix3x3 DXToD50(const Matrix3x3 &toXYZ, const std::array<float, DIMES_2> &wp)
262 {
263     if ((wp[0] == ILLUMINANT_D50_XY[0]) && (wp[1] == ILLUMINANT_D50_XY[1])) {
264         return toXYZ;
265     }
266     Vector3 srcXYZ = XYZ(Vector3 {wp[0], wp[1], 1.0f});
267     return AdaptationToD50(srcXYZ) * toXYZ;
268 }
269 
IsFinite(float x)270 static bool IsFinite(float x)
271 {
272     return x * 0 == 0;
273 }
274 
275 // inverse src Matrix to dst Matrix
Invert(const Matrix3x3 & src)276 Matrix3x3 Invert(const Matrix3x3& src)
277 {
278     double a00 = src[0][0];
279     double a01 = src[1][0];
280     double a02 = src[2][0];
281     double a10 = src[0][1];
282     double a11 = src[1][1];
283     double a12 = src[2][1];
284     double a20 = src[0][2];
285     double a21 = src[1][2];
286     double a22 = src[2][2];
287 
288     double b0 = a00 * a11 - a01 * a10;
289     double b1 = a00 * a12 - a02 * a10;
290     double b2 = a01 * a12 - a02 * a11;
291     double b3 = a20;
292     double b4 = a21;
293     double b5 = a22;
294 
295     double determinant = b0 * b5 - b1 * b4 + b2 * b3;
296 
297     if (determinant == 0) {
298         return {};
299     }
300 
301     double invdet = 1.0 / determinant;
302     if (invdet > +FLT_MAX || invdet < -FLT_MAX || !IsFinite((float)invdet)) {
303         return {};
304     }
305 
306     Matrix3x3 dst {};
307 
308     b0 *= invdet;
309     b1 *= invdet;
310     b2 *= invdet;
311     b3 *= invdet;
312     b4 *= invdet;
313     b5 *= invdet;
314 
315     dst[0][0] = static_cast<float>(a11 * b5 - a12 * b4); // compute dst[0][0] value
316     dst[1][0] = static_cast<float>(a02 * b4 - a01 * b5); // compute dst[1][0] value
317     dst[2][0] = static_cast<float>(+b2); // compute dst[2][0] value
318     dst[0][1] = static_cast<float>(a12 * b3 - a10 * b5); // compute dst[0][1] value
319     dst[1][1] = static_cast<float>(a00 * b5 - a02 * b3); // compute dst[1][1] value
320     dst[2][1] = static_cast<float>(-b1); // compute dst[2][1] value
321     dst[0][2] = static_cast<float>(a10 * b4 - a11 * b3); // compute dst[0][2] value
322     dst[1][2] = static_cast<float>(a01 * b3 - a00 * b4); // compute dst[1][2] value
323     dst[2][2] = static_cast<float>(+b0); // compute dst[2][2] value
324 
325     for (size_t r = 0; r < dst.size(); ++r) {
326         for (size_t c = 0; c < dst[0].size(); ++c) {
327             if (!IsFinite(dst[r][c])) {
328                 return {};
329             }
330         }
331     }
332     return dst;
333 }
334 
ToLinear(Vector3 v) const335 Vector3 ColorSpace::ToLinear(Vector3 v) const
336 {
337     auto &p = transferFunc;
338     Vector3 res = v;
339     for (auto& n : res) {
340         if (FloatEqual(p.g, HLG_G)) {
341             float coef = -1 / (p.g * p.a * p.b);
342             n = n > 1 / p.a ? coef * (std::exp(p.c * (n - p.e)) + p.d) : n * n / -p.g;
343         } else if (FloatEqual(p.g, PQ_G)) {
344             float tmp = std::pow(n, p.c);
345             n = std::pow(std::max(p.a + p.b * tmp, 0.0f) / (p.d + p.e * tmp), p.f);
346         } else if (FloatEqual(p.g, LOG_G)) {
347             float coef = p.e * (1 / -p.g) + p.f;
348             n = n > coef ? std::exp(n / p.c - p.d / p.c) / p.a - p.b / p.a : (n - p.f) / p.e;
349         } else {
350             n = n >= p.d ? std::pow(p.a * n + p.b, p.g) + p.e : p.c * n + p.f;
351         }
352     }
353     return res;
354 }
355 
ToNonLinear(Vector3 v) const356 Vector3 ColorSpace::ToNonLinear(Vector3 v) const
357 {
358     auto &p = transferFunc;
359     Vector3 res = v;
360     for (auto& n : res) {
361         if (FloatEqual(p.g, HLG_G)) {
362             float coef = -p.g * p.a * p.b;
363             n = n > 1 / coef ? std::log(coef * n - p.d) / p.c + p.e : std::sqrt(-p.g * n);
364         } else if (FloatEqual(p.g, PQ_G)) {
365             float tmp = std::pow(n, 1 / p.f);
366             n = std::pow((-p.a + p.d * tmp) / (p.b - p.e * tmp), 1 / p.c);
367         } else if (FloatEqual(p.g, LOG_G)) {
368             n = n > 1 / -p.g ? std::log(p.a * n + p.b) * p.c + p.d : p.e * n + p.f;
369         } else {
370             n = n >= p.d * p.c ? (std::pow(n - p.e, 1.0f / p.g) - p.b) / p.a : (n - p.f) / p.c;
371         }
372     }
373     return res;
374 }
375 
ToSkColorSpace() const376 sk_sp<SkColorSpace> ColorSpace::ToSkColorSpace() const
377 {
378     skcms_Matrix3x3 toXYZ = ToSkiaXYZ();
379     skcms_TransferFunction skTransferFun = {
380         transferFunc.g,
381         transferFunc.a,
382         transferFunc.b,
383         transferFunc.c,
384         transferFunc.d,
385         transferFunc.e,
386         transferFunc.f,
387     };
388     return SkColorSpace::MakeRGB(skTransferFun, toXYZ);
389 }
390 
ToSkiaXYZ() const391 skcms_Matrix3x3 ColorSpace::ToSkiaXYZ() const
392 {
393     skcms_Matrix3x3 skToXYZ;
394     for (int i = 0; i < DIMES_3; ++i) {
395         for (int j = 0; j < DIMES_3; ++j) {
396             skToXYZ.vals[i][j] = toXYZ[i][j];
397         }
398     }
399     return skToXYZ;
400 }
401 } //! namespace ColorManager
402 } //! namespace OHOS
403