File indexing completed on 2024-05-12 15:59:33
0001 /* 0002 * SPDX-FileCopyrightText: 2007 Cyrille Berger <cberger@cberger.net> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include <algorithm> 0008 #include <array> 0009 #include <cmath> 0010 0011 #include "KoColorProfile.h" 0012 #include "DebugPigment.h" 0013 #include "kis_assert.h" 0014 0015 struct Q_DECL_HIDDEN KoColorProfile::Private { 0016 QString name; 0017 QString info; 0018 QString fileName; 0019 QString manufacturer; 0020 QString copyright; 0021 int primaries {-1}; 0022 TransferCharacteristics characteristics {TRC_UNSPECIFIED}; 0023 }; 0024 0025 KoColorProfile::KoColorProfile(const QString &fileName) : d(new Private) 0026 { 0027 // dbgPigment <<" Profile filename =" << fileName; 0028 d->fileName = fileName; 0029 } 0030 0031 KoColorProfile::KoColorProfile(const KoColorProfile& profile) 0032 : d(new Private(*profile.d)) 0033 { 0034 } 0035 0036 KoColorProfile::~KoColorProfile() 0037 { 0038 delete d; 0039 } 0040 0041 bool KoColorProfile::load() 0042 { 0043 return false; 0044 } 0045 0046 bool KoColorProfile::save(const QString & filename) 0047 { 0048 Q_UNUSED(filename); 0049 return false; 0050 } 0051 0052 0053 QString KoColorProfile::name() const 0054 { 0055 return d->name; 0056 } 0057 0058 QString KoColorProfile::info() const 0059 { 0060 return d->info; 0061 } 0062 QString KoColorProfile::manufacturer() const 0063 { 0064 return d->manufacturer; 0065 } 0066 QString KoColorProfile::copyright() const 0067 { 0068 return d->copyright; 0069 } 0070 QString KoColorProfile::fileName() const 0071 { 0072 return d->fileName; 0073 } 0074 0075 void KoColorProfile::setFileName(const QString &f) 0076 { 0077 d->fileName = f; 0078 } 0079 0080 ColorPrimaries KoColorProfile::getColorPrimaries() const 0081 { 0082 if (d->primaries == -1) { 0083 ColorPrimaries primaries = PRIMARIES_UNSPECIFIED; 0084 QVector<qreal> wp = getWhitePointxyY(); 0085 0086 bool match = false; 0087 if (hasColorants()) { 0088 QVector<qreal> col = getColorantsxyY(); 0089 if (col.size()<8) { 0090 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(col.size() < 8, PRIMARIES_UNSPECIFIED); 0091 //too few colorants. 0092 d->primaries = int(primaries); 0093 return (primaries); 0094 } 0095 QVector<double> colorants = {wp[0], wp[1], col[0], col[1], col[3], col[4], col[6], col[7]}; 0096 QVector<double> compare; 0097 0098 QVector<ColorPrimaries> primariesList = {PRIMARIES_ITU_R_BT_709_5, PRIMARIES_ITU_R_BT_601_6, PRIMARIES_ITU_R_BT_470_6_SYSTEM_M, 0099 PRIMARIES_ITU_R_BT_2020_2_AND_2100_0, PRIMARIES_SMPTE_EG_432_1, PRIMARIES_SMPTE_RP_431_2, 0100 PRIMARIES_SMPTE_ST_428_1, PRIMARIES_GENERIC_FILM, PRIMARIES_SMPTE_240M, PRIMARIES_EBU_Tech_3213_E, 0101 PRIMARIES_ADOBE_RGB_1998, PRIMARIES_PROPHOTO, PRIMARIES_ITU_R_BT_470_6_SYSTEM_B_G}; 0102 0103 for (ColorPrimaries check: primariesList) { 0104 colorantsForType(check, compare); 0105 if (compare.size() <8) { 0106 KIS_SAFE_ASSERT_RECOVER(compare.size() < 8) { continue; } 0107 //too few colorants, skip. 0108 } 0109 match = true; 0110 for (int i=0; i<colorants.size(); i++) { 0111 match = std::fabs(colorants[i] - compare[i]) < 0.00001; 0112 if (!match) { 0113 break; 0114 } 0115 } 0116 if (match) { 0117 primaries = check; 0118 } 0119 } 0120 } 0121 0122 d->primaries = int(primaries); 0123 } 0124 return ColorPrimaries(d->primaries); 0125 } 0126 0127 QString KoColorProfile::getColorPrimariesName(ColorPrimaries primaries) 0128 { 0129 switch (primaries) { 0130 case PRIMARIES_ITU_R_BT_709_5: 0131 return QStringLiteral("Rec. 709"); 0132 case PRIMARIES_ITU_R_BT_470_6_SYSTEM_M: 0133 return QStringLiteral("BT. 470 System M"); 0134 case PRIMARIES_ITU_R_BT_470_6_SYSTEM_B_G: 0135 return QStringLiteral("BT. 470 System B, G"); 0136 case PRIMARIES_GENERIC_FILM: 0137 return QStringLiteral("Generic Film"); 0138 case PRIMARIES_SMPTE_240M: 0139 return QStringLiteral("SMPTE 240 M"); 0140 case PRIMARIES_ITU_R_BT_2020_2_AND_2100_0: 0141 return QStringLiteral("Rec. 2020"); 0142 case PRIMARIES_ITU_R_BT_601_6: 0143 return QStringLiteral("Rec. 601"); 0144 case PRIMARIES_SMPTE_EG_432_1: 0145 return QStringLiteral("Display P3"); 0146 case PRIMARIES_SMPTE_RP_431_2: 0147 return QStringLiteral("DCI P3"); 0148 case PRIMARIES_SMPTE_ST_428_1: 0149 return QStringLiteral("XYZ primaries"); 0150 case PRIMARIES_EBU_Tech_3213_E: 0151 return QStringLiteral("EBU Tech 3213 E"); 0152 case PRIMARIES_PROPHOTO: 0153 return QStringLiteral("ProPhoto"); 0154 case PRIMARIES_ADOBE_RGB_1998: 0155 return QStringLiteral("A98"); 0156 case PRIMARIES_UNSPECIFIED: 0157 break; 0158 } 0159 return QStringLiteral("Unspecified"); 0160 } 0161 0162 void KoColorProfile::colorantsForType(ColorPrimaries primaries, QVector<double> &colorants) 0163 { 0164 switch (ColorPrimaries(primaries)) { 0165 case PRIMARIES_UNSPECIFIED: 0166 break; 0167 case PRIMARIES_ITU_R_BT_470_6_SYSTEM_M: 0168 // Unquantisized. 0169 colorants = {0.310, 0.316}; 0170 colorants.append({0.67, 0.33}); 0171 colorants.append({0.21, 0.71}); 0172 colorants.append({0.14, 0.08}); 0173 //Illuminant C 0174 break; 0175 case PRIMARIES_ITU_R_BT_470_6_SYSTEM_B_G: 0176 // Unquantisized. 0177 colorants = {0.3127, 0.3290}; 0178 colorants.append({0.64, 0.33}); 0179 colorants.append({0.29, 0.60}); 0180 colorants.append({0.1500, 0.06}); 0181 break; 0182 case PRIMARIES_ITU_R_BT_601_6: 0183 colorants = {0.3127, 0.3290}; 0184 colorants.append({0.630, 0.340}); 0185 colorants.append({0.310, 0.595}); 0186 colorants.append({0.155, 0.070}); 0187 break; 0188 case PRIMARIES_SMPTE_240M: 0189 colorants = {0.3127, 0.3290}; 0190 colorants.append({0.630, 0.340}); 0191 colorants.append({0.310, 0.595}); 0192 colorants.append({0.155, 0.070}); 0193 break; 0194 case PRIMARIES_GENERIC_FILM: 0195 colorants = {0.310, 0.316}; 0196 colorants.append({0.681, 0.319}); 0197 colorants.append({0.243, 0.692}); 0198 colorants.append({0.145, 0.049}); 0199 //Illuminant C 0200 break; 0201 case PRIMARIES_ITU_R_BT_2020_2_AND_2100_0: 0202 //prequantization courtesy of Elle Stone. 0203 colorants = {0.3127, 0.3290}; 0204 colorants.append({0.708012540607, 0.291993664388}); 0205 colorants.append({0.169991652439, 0.797007778423}); 0206 colorants.append({0.130997824007, 0.045996550894}); 0207 break; 0208 case PRIMARIES_SMPTE_ST_428_1: 0209 colorants = {1.0/3, 1.0/3}; 0210 colorants.append({1.0, 0}); 0211 colorants.append({0, 1.0}); 0212 colorants.append({0, 0}); 0213 break; 0214 case PRIMARIES_SMPTE_RP_431_2: 0215 colorants = {0.314, 0.351}; 0216 colorants.append({0.6800, 0.3200}); 0217 colorants.append({0.2650, 0.6900}); 0218 colorants.append({0.1500, 0.0600}); 0219 break; 0220 case PRIMARIES_SMPTE_EG_432_1: 0221 colorants = {0.3127, 0.3290}; 0222 colorants.append({0.6800, 0.3200}); 0223 colorants.append({0.2650, 0.6900}); 0224 colorants.append({0.1500, 0.0600}); 0225 break; 0226 case PRIMARIES_EBU_Tech_3213_E: 0227 colorants = {0.3127, 0.3290}; 0228 colorants.append({0.63, 0.34}); 0229 colorants.append({0.295, 0.605}); 0230 colorants.append({0.155, 0.077}); 0231 break; 0232 case PRIMARIES_PROPHOTO: 0233 //prequantization courtesy of Elle Stone. 0234 colorants = {0.3457, 0.3585}; 0235 colorants.append({0.7347, 0.2653}); 0236 colorants.append({0.1596, 0.8404}); 0237 colorants.append({0.0366, 0.0001}); 0238 break; 0239 case PRIMARIES_ADOBE_RGB_1998: 0240 //prequantization courtesy of Elle Stone. 0241 colorants = {0.3127, 0.3290}; 0242 colorants.append({0.639996511, 0.329996864}); 0243 colorants.append({0.210005295, 0.710004866}); 0244 colorants.append({0.149997606, 0.060003644}); 0245 break; 0246 case PRIMARIES_ITU_R_BT_709_5: 0247 default: 0248 // Prequantisized colorants, courtesy of Elle Stone 0249 colorants = {0.3127, 0.3290}; 0250 colorants.append({0.639998686, 0.330010138}); 0251 colorants.append({0.300003784, 0.600003357}); 0252 colorants.append({0.150002046, 0.059997204}); 0253 break; 0254 0255 } 0256 } 0257 0258 TransferCharacteristics KoColorProfile::getTransferCharacteristics() const 0259 { 0260 // Parse from an estimated gamma 0261 const QVector<double> estimatedTRC = getEstimatedTRC(); 0262 const double error = 0.0001; 0263 // Make sure the TRC is uniform across all channels 0264 const bool isUniformTRC = (estimatedTRC[0] == estimatedTRC[1] && estimatedTRC[0] == estimatedTRC[2]); 0265 if (d->characteristics == TRC_UNSPECIFIED && isUniformTRC && hasTRC()) { 0266 if (isLinear()) { 0267 d->characteristics = TRC_LINEAR; 0268 } else if (std::fabs(estimatedTRC[0] - (461.0 / 256.0)) < error) { 0269 // ICC v2 u8Fixed8Number calculation 0270 // Or can be prequantized as 1.80078125, courtesy of Elle Stone 0271 d->characteristics = TRC_GAMMA_1_8; 0272 } else if (std::fabs(estimatedTRC[0] - (563.0 / 256.0)) < error) { 0273 // Or can be prequantized as 2.19921875, courtesy of Elle Stone 0274 d->characteristics = TRC_A98; 0275 } else if (std::fabs(estimatedTRC[0] - 1.8) < error) { 0276 d->characteristics = TRC_GAMMA_1_8; 0277 } else if (std::fabs(estimatedTRC[0] - 2.2) < error) { 0278 d->characteristics = TRC_ITU_R_BT_470_6_SYSTEM_M; 0279 } else if (std::fabs(estimatedTRC[0] - 2.4) < error) { 0280 d->characteristics = TRC_GAMMA_2_4; 0281 } else if (std::fabs(estimatedTRC[0] - 2.8) < error) { 0282 d->characteristics = TRC_ITU_R_BT_470_6_SYSTEM_B_G; 0283 } else { 0284 // Escort to curve matching if no gamma is matched 0285 static constexpr std::array<TransferCharacteristics, 12> trcList = {{TRC_ITU_R_BT_709_5, 0286 TRC_ITU_R_BT_470_6_SYSTEM_M, 0287 TRC_ITU_R_BT_470_6_SYSTEM_B_G, 0288 TRC_SMPTE_240M, 0289 TRC_IEC_61966_2_1, 0290 TRC_LOGARITHMIC_100, 0291 TRC_LOGARITHMIC_100_sqrt10, 0292 TRC_PROPHOTO, 0293 TRC_GAMMA_1_8, 0294 TRC_GAMMA_2_4, 0295 TRC_A98, 0296 TRC_LAB_L}}; 0297 const auto characteristic = 0298 std::find_if(trcList.begin(), trcList.end(), [&](const TransferCharacteristics &check) -> bool { 0299 return compareTRC(check, static_cast<float>(error)); 0300 }); 0301 if (characteristic != trcList.end()) { 0302 d->characteristics = *characteristic; 0303 } 0304 } 0305 } 0306 return d->characteristics; 0307 } 0308 0309 void KoColorProfile::setCharacteristics(ColorPrimaries primaries, TransferCharacteristics curve) 0310 { 0311 d->primaries = int(primaries); 0312 d->characteristics = curve; 0313 } 0314 0315 QString KoColorProfile::getTransferCharacteristicName(TransferCharacteristics curve) 0316 { 0317 switch (curve) { 0318 case TRC_ITU_R_BT_709_5: 0319 case TRC_ITU_R_BT_601_6: 0320 case TRC_ITU_R_BT_2020_2_10bit: 0321 return QString("rec 709 trc"); 0322 case TRC_ITU_R_BT_2020_2_12bit: 0323 return QString("rec 2020 12bit trc"); 0324 case TRC_ITU_R_BT_470_6_SYSTEM_M: 0325 return QString("Gamma 2.2"); 0326 case TRC_ITU_R_BT_470_6_SYSTEM_B_G: 0327 return QString("Gamma 2.8"); 0328 case TRC_SMPTE_240M: 0329 return QString("SMPTE 240 trc"); 0330 case TRC_LINEAR: 0331 return QString("Linear"); 0332 case TRC_LOGARITHMIC_100: 0333 return QString("Logarithmic 100"); 0334 case TRC_LOGARITHMIC_100_sqrt10: 0335 return QString("Logarithmic 100 sqrt10"); 0336 case TRC_IEC_61966_2_4: 0337 return QString("IEC 61966 2.4"); 0338 case TRC_ITU_R_BT_1361: 0339 case TRC_IEC_61966_2_1: 0340 return QString("sRGB trc"); 0341 case TRC_SMPTE_ST_428_1: 0342 return QString("SMPTE ST 428"); 0343 case TRC_ITU_R_BT_2100_0_PQ: 0344 return QString("Perceptual Quantizer"); 0345 case TRC_ITU_R_BT_2100_0_HLG: 0346 return QString("Hybrid Log Gamma"); 0347 case TRC_GAMMA_1_8: 0348 return QString("Gamma 1.8"); 0349 case TRC_GAMMA_2_4: 0350 return QString("Gamma 2.4"); 0351 case TRC_A98: 0352 return QString("Gamma A98"); 0353 case TRC_PROPHOTO: 0354 return QString("ProPhoto trc"); 0355 case TRC_LAB_L: 0356 return QString("Lab L* trc"); 0357 case TRC_UNSPECIFIED: 0358 break; 0359 } 0360 0361 return QString("Unspecified"); 0362 } 0363 0364 void KoColorProfile::setName(const QString &name) 0365 { 0366 d->name = name; 0367 } 0368 void KoColorProfile::setInfo(const QString &info) 0369 { 0370 d->info = info; 0371 } 0372 void KoColorProfile::setManufacturer(const QString &manufacturer) 0373 { 0374 d->manufacturer = manufacturer; 0375 } 0376 void KoColorProfile::setCopyright(const QString ©right) 0377 { 0378 d->copyright = copyright; 0379 }