1 | // LAF OS Library |
2 | // Copyright (C) 2018-2021 Igara Studio S.A. |
3 | // |
4 | // This file is released under the terms of the MIT license. |
5 | // Read LICENSE.txt for more information. |
6 | |
7 | #ifdef HAVE_CONFIG_H |
8 | #include "config.h" |
9 | #endif |
10 | |
11 | #include "os/skia/skia_color_space.h" |
12 | |
13 | #include "base/debug.h" |
14 | |
15 | #include "include/core/SkImageInfo.h" |
16 | #include "include/core/SkString.h" |
17 | #include "include/third_party/skcms/skcms.h" |
18 | #include "src/core/SkConvertPixels.h" |
19 | |
20 | #include <algorithm> |
21 | |
22 | // Defined in skia/src/core/SkICC.cpp |
23 | const char* get_color_profile_description(const skcms_TransferFunction& fn, |
24 | const skcms_Matrix3x3& toXYZD50); |
25 | |
26 | namespace os { |
27 | |
28 | // Copied from skia/src/core/SkColorSpacePriv.h |
29 | static constexpr float gSRGB_toXYZD50[] { |
30 | 0.4360747f, 0.3850649f, 0.1430804f, // Rx, Gx, Bx |
31 | 0.2225045f, 0.7168786f, 0.0606169f, // Ry, Gy, By |
32 | 0.0139322f, 0.0971045f, 0.7141733f, // Rz, Gz, Bz |
33 | }; |
34 | |
35 | SkiaColorSpace::SkiaColorSpace(const gfx::ColorSpaceRef& gfxcs) |
36 | : m_gfxcs(gfxcs), |
37 | m_skcs(nullptr) |
38 | { |
39 | switch (m_gfxcs->type()) { |
40 | |
41 | case gfx::ColorSpace::None: |
42 | if (m_gfxcs->name().empty()) |
43 | m_gfxcs->setName("None" ); |
44 | break; |
45 | |
46 | case gfx::ColorSpace::sRGB: |
47 | case gfx::ColorSpace::RGB: |
48 | if (gfxcs->hasGamma()) { |
49 | if (gfxcs->gamma() == 1.0) |
50 | m_skcs = SkColorSpace::MakeSRGBLinear(); |
51 | else { |
52 | skcms_TransferFunction fn; |
53 | fn.a = 1.0f; |
54 | fn.b = fn.c = fn.d = fn.e = fn.f = 0.0f; |
55 | fn.g = gfxcs->gamma(); |
56 | m_skcs = SkColorSpace::MakeRGB(fn, SkNamedGamut::kSRGB); |
57 | } |
58 | } |
59 | else { |
60 | skcms_TransferFunction skFn; |
61 | skcms_Matrix3x3 toXYZD50; |
62 | |
63 | if (m_gfxcs->hasPrimaries()) { |
64 | const gfx::ColorSpacePrimaries* primaries = m_gfxcs->primaries(); |
65 | if (!skcms_PrimariesToXYZD50(primaries->rx, primaries->ry, |
66 | primaries->gx, primaries->gy, |
67 | primaries->bx, primaries->by, |
68 | primaries->wx, primaries->wy, &toXYZD50)) { |
69 | toXYZD50 = skcms_sRGB_profile()->toXYZD50; |
70 | } |
71 | } |
72 | |
73 | if (m_gfxcs->hasTransferFn()) { |
74 | const gfx::ColorSpaceTransferFn* fn = m_gfxcs->transferFn(); |
75 | skFn.g = fn->g; |
76 | skFn.a = fn->a; |
77 | skFn.b = fn->b; |
78 | skFn.c = fn->c; |
79 | skFn.d = fn->d; |
80 | skFn.e = fn->e; |
81 | skFn.f = fn->f; |
82 | } |
83 | |
84 | if (m_gfxcs->hasTransferFn()) { |
85 | if (!m_gfxcs->hasPrimaries()) { |
86 | toXYZD50 = skcms_sRGB_profile()->toXYZD50; |
87 | } |
88 | m_skcs = SkColorSpace::MakeRGB(skFn, toXYZD50); |
89 | } |
90 | else if (m_gfxcs->hasPrimaries()) { |
91 | m_skcs = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, toXYZD50); |
92 | } |
93 | else { |
94 | m_skcs = SkColorSpace::MakeSRGB(); |
95 | } |
96 | } |
97 | break; |
98 | |
99 | case gfx::ColorSpace::ICC: { |
100 | skcms_ICCProfile icc; |
101 | if (skcms_Parse(m_gfxcs->iccData(), |
102 | m_gfxcs->iccSize(), &icc)) { |
103 | m_skcs = SkColorSpace::Make(icc); |
104 | } |
105 | break; |
106 | } |
107 | } |
108 | |
109 | // TODO read color profile name from ICC data |
110 | |
111 | if (m_skcs && m_gfxcs->name().empty()) { |
112 | skcms_TransferFunction fn; |
113 | skcms_Matrix3x3 toXYZD50; |
114 | if (m_skcs->isNumericalTransferFn(&fn) && |
115 | m_skcs->toXYZD50(&toXYZD50)) { |
116 | const char* desc = get_color_profile_description(fn, toXYZD50); |
117 | if (desc) |
118 | m_gfxcs->setName(desc); |
119 | } |
120 | } |
121 | |
122 | if (m_gfxcs->name().empty()) |
123 | m_gfxcs->setName("Custom Profile" ); |
124 | } |
125 | |
126 | SkiaColorSpaceConversion::SkiaColorSpaceConversion( |
127 | const os::ColorSpaceRef& srcColorSpace, |
128 | const os::ColorSpaceRef& dstColorSpace) |
129 | : m_srcCS(srcColorSpace), |
130 | m_dstCS(dstColorSpace) |
131 | { |
132 | ASSERT(srcColorSpace); |
133 | ASSERT(dstColorSpace); |
134 | } |
135 | |
136 | bool SkiaColorSpaceConversion::convertRgba(uint32_t* dst, const uint32_t* src, int n) |
137 | { |
138 | auto dstInfo = SkImageInfo::Make(n, 1, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType, |
139 | static_cast<const SkiaColorSpace*>(m_dstCS.get())->skColorSpace()); |
140 | auto srcInfo = SkImageInfo::Make(n, 1, kRGBA_8888_SkColorType, kUnpremul_SkAlphaType, |
141 | static_cast<const SkiaColorSpace*>(m_srcCS.get())->skColorSpace()); |
142 | return SkConvertPixels(dstInfo, dst, 4 * n, srcInfo, src, 4 * n); |
143 | } |
144 | |
145 | bool SkiaColorSpaceConversion::convertGray(uint8_t* dst, const uint8_t* src, int n) |
146 | { |
147 | auto dstInfo = SkImageInfo::Make(n, 1, kGray_8_SkColorType, kOpaque_SkAlphaType, |
148 | static_cast<const SkiaColorSpace*>(m_dstCS.get())->skColorSpace()); |
149 | auto srcInfo = SkImageInfo::Make(n, 1, kGray_8_SkColorType, kOpaque_SkAlphaType, |
150 | static_cast<const SkiaColorSpace*>(m_srcCS.get())->skColorSpace()); |
151 | return SkConvertPixels(dstInfo, dst, n, srcInfo, src, n); |
152 | } |
153 | |
154 | } // namespace os |
155 | |