Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_hdr_metadata_models.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2026 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
7#include <KLocalizedString>
8#include <lager/constant.hpp>
9#include <lager/setter.hpp>
10#include <KisZug.h>
11#include <KisLager.h>
12namespace {
13
14static constexpr std::array<double, 2> refWhiteList {
15 80.0,
16 203.0
17};
18
19double calcEffectiveReferenceWhite(bool imageProfileIsRelative, double imageProfileReferenceWhite, double imageMetadataReferenceWhite)
20{
21 return imageProfileIsRelative ? imageMetadataReferenceWhite : imageProfileReferenceWhite;
22}
23
24auto referenceWhiteToInt =
25 lager::lenses::getset(
26 [] (const double &value) -> int {
27 int index = -1;
28
29 for (size_t i = 0; i < refWhiteList.size(); i++) {
30 if (qFuzzyCompare(value, refWhiteList.at(i))) {
31 index = i;
32 break;
33 }
34 }
35 return index;
36 },
37 [] (double value, const int &newValue) {
38 if (newValue >= 0 && newValue < int(refWhiteList.size())) {
39 value = refWhiteList[newValue];
40 }
41 return value;
42 }
43 );
44
45ComboBoxState calcWhiteTypeToComboBoxState(int index, bool enabled)
46{
47 QStringList values;
48 QStringList toolTips;
49
50 for (size_t i = 0; i < refWhiteList.size(); i++) {
51 values << i18nc("Image reference white value", "%1 cd/m²", QString::number(refWhiteList.at(i)));
52 toolTips << "";
53 }
54
55 return {values, index, enabled, toolTips};
56}
57
58ComboBoxState calcTypeComboBoxState(KisRelativeContentLightLevelInformation::CalculationType type, bool enabled)
59{
60 QStringList values;
61 QStringList toolTips;
62
63 values << i18nc("CLLI calculation type", "XYZ Luminance");
64 values << i18nc("CLLI calculation type", "Rec 2020 Per Component");
65 values << i18nc("CLLI calculation type", "RGB Per Component");
66
67 toolTips << i18nc("@info:tooltip", "Calculate the brightness in nits against XYZ luminance.");
68 toolTips << i18nc("@info:tooltip", "Calculate the brightness in nits by testing the components in linear rec 2020.");
69 toolTips << i18nc("@info:tooltip", "Calculate the brightness in nits by testing the components in linear RGB, if possible, falls back to using XYZ luminance.");
70
71 return {values, static_cast<int>(type), enabled, toolTips};
72}
73
74auto noopSetter = [] (auto) {};
75
76auto calcRelativeToAbsoluteWhiteLevel = lager::lenses::getset(
77 // .first is relative white level
78 // .second is reference white level
79 [] (const std::tuple<double,double> &packed) -> double {
80 return std::get<0>(packed) * std::get<1>(packed);
81 },
82 [] (std::tuple<double,double> packed, double absoluteValue) {
83 if (!qFuzzyIsNull(std::get<1>(packed))) {
84 std::get<0>(packed) = absoluteValue / std::get<1>(packed);
85 }
86 return packed;
87 }
88);
89
90auto effectivePresetIndexForCvi =
91 lager::lenses::getset(
92 [] (const KisColorVolumeInformation &cvi) -> int {
94 return 0;
95 } else if (cvi == KisColorVolumeInformation::DCIP3D65) {
96 return 1;
97 } else {
98 return 2;
99 }
100 },
101 [] (KisColorVolumeInformation cvi, const int &index) {
102 if (index == 0) {
104 } else if (index == 1) {
106 } else {
107 // noop, just keep `cvi` unchanged
108 }
109 return cvi;
110 }
111 );
112
113 ComboBoxState calcCviEffectivePresetIndexState(int index, bool enabled) {
114 QStringList values;
115 QStringList toolTips;
116
117 values << i18n("Rec. 2100 PQ");
118 values << i18n("DCI-P3 D65");
119 values << i18n("Custom");
120
121 toolTips << i18nc("@info:tooltip", "Reset color volume to the values defined by Rec. 2100 PQ");
122 toolTips << i18nc("@info:tooltip", "Reset color volume to the values defined by DCI-P3 D65");
123 toolTips << i18nc("@info:tooltip", "Use custom values for color volume");
124
125 return {values, index, enabled, toolTips};
126}
127
128}
129
131
133 : QObject{parent}
135 , cviData(KisColorVolumeInformation())
136 , imageProfileReferenceWhiteData(203.0)
137 , referenceWhiteData(203.0)
138 , imageProfileIsRelativeData(false)
139 , referenceWhitePresentData(false)
140 , clliPresentData(false)
141 , cviPresentData(false)
142
143 , LAGER_QT(referenceWhitePresent) {referenceWhitePresentData}
144 , LAGER_QT(effectiveReferenceWhitePresent){
145 lager::with(referenceWhitePresentData,
146 imageProfileIsRelativeData.map(std::logical_not<>{})
147 ).map(std::logical_or<>{})}
148 , LAGER_QT(effectiveReferenceWhiteEnabled){imageProfileIsRelativeData}
149 , LAGER_QT(referenceWhitePresentState){lager::with(LAGER_QT(effectiveReferenceWhitePresent), LAGER_QT(effectiveReferenceWhiteEnabled)).map(ToControlState{})}
150
151 , LAGER_QT(referenceWhite){referenceWhiteData}
152 , LAGER_QT(referenceWhiteIndex){LAGER_QT(referenceWhite).zoom(referenceWhiteToInt)}
153 , LAGER_QT(effectiveReferenceWhite){
154 lager::with(
155 imageProfileIsRelativeData,
156 imageProfileReferenceWhiteData,
157 LAGER_QT(referenceWhite)
158 ).map(&calcEffectiveReferenceWhite)}
159 , LAGER_QT(effectiveReferenceWhiteIndex){LAGER_QT(effectiveReferenceWhite).zoom(referenceWhiteToInt)}
160 , LAGER_QT(referenceWhiteState){lager::with(LAGER_QT(effectiveReferenceWhiteIndex), LAGER_QT(effectiveReferenceWhitePresent))
161 .map(&calcWhiteTypeToComboBoxState)}
162
163 , LAGER_QT(clliPresent){clliPresentData}
164 , LAGER_QT(effectiveClliPresent){
165 lager::with(
166 clliPresentData,
167 LAGER_QT(effectiveReferenceWhitePresent)
168 ).map(std::logical_and<>{})}
169 , LAGER_QT(clliPresentState){lager::with(LAGER_QT(effectiveClliPresent), LAGER_QT(effectiveReferenceWhitePresent)).map(ToControlState{})}
170
171 , LAGER_QT(maxContentLightLevel){
172 lager::with(
174 lager::with_setter(LAGER_QT(effectiveReferenceWhite), noopSetter)
175 ).zoom(calcRelativeToAbsoluteWhiteLevel)}
176 , LAGER_QT(maxFrameAverageLightLevel){
177 lager::with(
179 lager::with_setter(LAGER_QT(effectiveReferenceWhite), noopSetter)
180 ).zoom(calcRelativeToAbsoluteWhiteLevel)}
181
183 , LAGER_QT(clliCalculationTypeState){lager::with(LAGER_QT(clliCalculationType), LAGER_QT(effectiveClliPresent))
184 .map(&calcTypeComboBoxState)}
185
186 , LAGER_QT(cviPresent){cviPresentData}
187
188 , LAGER_QT(cviEffectivePresetIndex){cviData.zoom(effectivePresetIndexForCvi)}
189 , LAGER_QT(cviEffectivePresetIndexState){
190 lager::with(
191 LAGER_QT(cviEffectivePresetIndex),
195 LAGER_QT(cviPresent)
196 ).map(&calcCviEffectivePresetIndexState)}
197
208{
209}
210
212
213}
214
215void KisHDRMetadataModel::setClli(const std::optional<KisRelativeContentLightLevelInformation> &clli)
216{
217 if (clli) {
218 clliPresentData.set(true);
219 clliData.set(*clli);
220 } else {
221 clliPresentData.set(false);
222 }
223}
224
225void KisHDRMetadataModel::setCvi(const std::optional<KisColorVolumeInformation> &cvi)
226{
227 if (cvi) {
228 cviPresentData.set(true);
229 cviData.set(*cvi);
230 } else {
231 cviPresentData.set(false);
233 }
234}
235
236void KisHDRMetadataModel::setImageHdrReferenceWhiteMetadata(const std::optional<double> &refWhite)
237{
238 if (refWhite) {
240 referenceWhiteData.set(*refWhite);
241 } else {
242 referenceWhitePresentData.set(false);
243 referenceWhiteData.set(203.0);
244 }
245}
246
247void KisHDRMetadataModel::setImageProfileHdrReferenceWhite(const std::optional<double> &refWhite)
248{
249 if (refWhite) {
251 imageProfileReferenceWhiteData.set(*refWhite);
252 } else {
255 }
256}
float value(const T *src, size_t ch)
lager::state< double, lager::automatic_tag > referenceWhiteData
void setImageProfileHdrReferenceWhite(const std::optional< double > &refWhite)
lager::state< bool, lager::automatic_tag > imageProfileIsRelativeData
KisHDRMetadataModel(QObject *parent=nullptr)
lager::state< bool, lager::automatic_tag > referenceWhitePresentData
lager::state< bool, lager::automatic_tag > cviPresentData
void setCvi(const std::optional< KisColorVolumeInformation > &cvi)
lager::state< bool, lager::automatic_tag > clliPresentData
void setClli(const std::optional< KisRelativeContentLightLevelInformation > &clli)
lager::state< KisRelativeContentLightLevelInformation, lager::automatic_tag > clliData
void setImageHdrReferenceWhiteMetadata(const std::optional< double > &refWhite)
lager::state< KisColorVolumeInformation, lager::automatic_tag > cviData
lager::state< double, lager::automatic_tag > imageProfileReferenceWhiteData
static bool qFuzzyCompare(half p1, half p2)
static bool qFuzzyIsNull(half h)
LAGER_QT(effectiveReferenceWhitePresent)
The KisColorVolumeInformation class is a struct that represents the 'mastering' display....
double maxLuminance
Maximum screen brightness in cd/m²
static const KisColorVolumeInformation BT2100PQ
KoColorimetryUtils::xy blue
xyY location of the blue colorant.
double minLuminance
Minimum screen brightness in cd/m²
KoColorimetryUtils::xy white
xyY location of the whitepoint.
KoColorimetryUtils::xy red
xyY location of the red colorant.
KoColorimetryUtils::xy green
xyY location of the green colorant.
static const KisColorVolumeInformation DCIP3D65
double maxFrameAverageLightLevel
maxFrameAverage MaxFrameAverageLightLevel or MaxFALL is the average of average pixel brightnesses in ...