1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qcolortrclut_p.h" |
5 | #include "qcolortransferfunction_p.h" |
6 | #include "qcolortransfergeneric_p.h" |
7 | #include "qcolortransfertable_p.h" |
8 | #include "qcolortrc_p.h" |
9 | #include <qmath.h> |
10 | |
11 | QT_BEGIN_NAMESPACE |
12 | std::shared_ptr<QColorTrcLut> QColorTrcLut::create() |
13 | { |
14 | struct Access : QColorTrcLut {}; |
15 | return std::make_shared<Access>(); |
16 | } |
17 | |
18 | std::shared_ptr<QColorTrcLut> QColorTrcLut::fromGamma(float gamma, Direction dir) |
19 | { |
20 | auto cp = create(); |
21 | cp->setFromGamma(gamma, dir); |
22 | return cp; |
23 | } |
24 | |
25 | std::shared_ptr<QColorTrcLut> QColorTrcLut::fromTrc(const QColorTrc &trc, Direction dir) |
26 | { |
27 | if (!trc.isValid()) |
28 | return nullptr; |
29 | auto cp = create(); |
30 | cp->setFromTrc(trc, dir); |
31 | return cp; |
32 | } |
33 | |
34 | void QColorTrcLut::setFromGamma(float gamma, Direction dir) |
35 | { |
36 | constexpr float iRes = 1.f / float(Resolution); |
37 | if (dir & ToLinear) { |
38 | if (!m_toLinear) |
39 | m_toLinear.reset(p: new ushort[Resolution + 1]); |
40 | for (int i = 0; i <= Resolution; ++i) { |
41 | const int val = qRound(f: qPow(x: i * iRes, y: gamma) * (255 * 256)); |
42 | m_toLinear[i] = qBound(min: 0, val, max: 65280); |
43 | } |
44 | } |
45 | |
46 | if (dir & FromLinear) { |
47 | const float iGamma = 1.f / gamma; |
48 | if (!m_fromLinear) |
49 | m_fromLinear.reset(p: new ushort[Resolution + 1]); |
50 | for (int i = 0; i <= Resolution; ++i) |
51 | m_fromLinear[i] = ushort(qRound(f: qBound(min: 0.f, val: qPow(x: i * iRes, y: iGamma), max: 1.f) * (255 * 256))); |
52 | } |
53 | } |
54 | |
55 | void QColorTrcLut::setFromTransferFunction(const QColorTransferFunction &fun, Direction dir) |
56 | { |
57 | constexpr float iRes = 1.f / float(Resolution); |
58 | if (dir & ToLinear) { |
59 | if (!m_toLinear) |
60 | m_toLinear.reset(p: new ushort[Resolution + 1]); |
61 | for (int i = 0; i <= Resolution; ++i) { |
62 | const int val = qRound(f: fun.apply(x: i * iRes)* (255 * 256)); |
63 | if (val > 65280 && i < m_unclampedToLinear) |
64 | m_unclampedToLinear = i; |
65 | m_toLinear[i] = qBound(min: 0, val, max: 65280); |
66 | } |
67 | } |
68 | |
69 | if (dir & FromLinear) { |
70 | if (!m_fromLinear) |
71 | m_fromLinear.reset(p: new ushort[Resolution + 1]); |
72 | QColorTransferFunction inv = fun.inverted(); |
73 | for (int i = 0; i <= Resolution; ++i) |
74 | m_fromLinear[i] = ushort(qRound(f: qBound(min: 0.f, val: inv.apply(x: i * iRes), max: 1.f) * (255 * 256))); |
75 | } |
76 | } |
77 | |
78 | void QColorTrcLut::setFromTransferGenericFunction(const QColorTransferGenericFunction &fun, Direction dir) |
79 | { |
80 | constexpr float iRes = 1.f / float(Resolution); |
81 | if (dir & ToLinear) { |
82 | if (!m_toLinear) |
83 | m_toLinear.reset(p: new ushort[Resolution + 1]); |
84 | for (int i = 0; i <= Resolution; ++i) { |
85 | const int val = qRound(f: fun.apply(x: i * iRes) * (255 * 256)); |
86 | if (val > 65280 && i < m_unclampedToLinear) |
87 | m_unclampedToLinear = i; |
88 | m_toLinear[i] = qBound(min: 0, val, max: 65280); |
89 | } |
90 | } |
91 | |
92 | if (dir & FromLinear) { |
93 | if (!m_fromLinear) |
94 | m_fromLinear.reset(p: new ushort[Resolution + 1]); |
95 | for (int i = 0; i <= Resolution; ++i) |
96 | m_fromLinear[i] = ushort(qRound(f: qBound(min: 0.f, val: fun.applyInverse(x: i * iRes), max: 1.f) * (255 * 256))); |
97 | } |
98 | } |
99 | |
100 | void QColorTrcLut::setFromTransferTable(const QColorTransferTable &table, Direction dir) |
101 | { |
102 | constexpr float iRes = 1.f / float(Resolution); |
103 | if (dir & ToLinear) { |
104 | if (!m_toLinear) |
105 | m_toLinear.reset(p: new ushort[Resolution + 1]); |
106 | for (int i = 0; i <= Resolution; ++i) |
107 | m_toLinear[i] = ushort(qRound(f: table.apply(x: i * iRes) * (255 * 256))); |
108 | } |
109 | |
110 | if (dir & FromLinear) { |
111 | if (!m_fromLinear) |
112 | m_fromLinear.reset(p: new ushort[Resolution + 1]); |
113 | float minInverse = 0.0f; |
114 | for (int i = 0; i <= Resolution; ++i) { |
115 | minInverse = table.applyInverse(x: i * iRes, resultLargerThan: minInverse); |
116 | m_fromLinear[i] = ushort(qRound(f: minInverse * (255 * 256))); |
117 | } |
118 | } |
119 | } |
120 | |
121 | void QColorTrcLut::setFromTrc(const QColorTrc &trc, Direction dir) |
122 | { |
123 | switch (trc.m_type) { |
124 | case QColorTrc::Type::ParameterizedFunction: |
125 | return setFromTransferFunction(fun: trc.fun(), dir); |
126 | case QColorTrc::Type::Table: |
127 | return setFromTransferTable(table: trc.table(), dir); |
128 | case QColorTrc::Type::GenericFunction: |
129 | return setFromTransferGenericFunction(fun: trc.hdr(), dir); |
130 | case QColorTrc::Type::Uninitialized: |
131 | break; |
132 | } |
133 | } |
134 | |
135 | QT_END_NAMESPACE |
136 | |