Creation of the ICCProfileCreator

This commit is contained in:
Hombre
2018-06-25 00:43:11 +02:00
parent e2dc8ea2c3
commit fb0c95969b
35 changed files with 1330 additions and 1799 deletions

View File

@@ -201,9 +201,8 @@ cmsHPROFILE createXYZProfile()
const double(*wprofiles[])[3] = {xyz_sRGB, xyz_adobe, xyz_prophoto, xyz_widegamut, xyz_bruce, xyz_beta, xyz_best, xyz_rec2020, xyz_ACESp0, xyz_ACESp1};//
const double(*iwprofiles[])[3] = {sRGB_xyz, adobe_xyz, prophoto_xyz, widegamut_xyz, bruce_xyz, beta_xyz, best_xyz, rec2020_xyz, ACESp0_xyz, ACESp1_xyz};//
const char* wpnames[] = {"sRGB", "Adobe RGB", "ProPhoto", "WideGamut", "BruceRGB", "Beta RGB", "BestRGB", "Rec2020", "ACESp0", "ACESp1"};//
const char* wpgamma[] = {"Custom", "BT709_g2.2_s4.5", "sRGB_g2.4_s12.92", "linear_g1.0", "standard_g2.2", "standard_g1.8", "High_g1.3_s3.35", "Low_g2.6_s6.9", "Lab_g3.0s9.03296"}; //gamma free
//default = gamma inside profile
//BT709 g=2.22 s=4.5 sRGB g=2.4 s=12.92
//BT709 g=2.22 s=4.5 sRGB g=2.4 s=12.92310
//linear g=1.0
//std22 g=2.2 std18 g=1.8
// high g=1.3 s=3.35 for high dynamic images
@@ -1030,97 +1029,6 @@ std::vector<Glib::ustring> rtengine::ICCStore::getWorkingProfiles()
return implementation->getWorkingProfiles();
}
std::vector<Glib::ustring> rtengine::ICCStore::getGamma()
{
std::vector<Glib::ustring> res;
for (unsigned int i = 0; i < sizeof(wpgamma) / sizeof(wpgamma[0]); i++) {
res.push_back(wpgamma[i]);
}
return res;
}
void rtengine::ICCStore::getGammaArray(const procparams::ColorManagementParams &icm, GammaValues &ga)
{
const double eps = 0.000000001; // not divide by zero
if (icm.customOutputProfile && icm.outputGammaPreset != "Custom") { //if Free gamma selected with other than Free
// gamma : ga[0],ga[1],ga[2],ga[3],ga[4],ga[5] by calcul
if (icm.outputGammaPreset == "BT709_g2.2_s4.5") {
ga[0] = 2.22; //BT709 2.2 4.5 - my preferred as D.Coffin
ga[1] = 0.909995;
ga[2] = 0.090005;
ga[3] = 0.222222;
ga[4] = 0.081071;
} else if (icm.outputGammaPreset == "sRGB_g2.4_s12.92") {
ga[0] = 2.40; //sRGB 2.4 12.92 - RT default as Lightroom
ga[1] = 0.947858;
ga[2] = 0.052142;
ga[3] = 0.077399;
ga[4] = 0.039293;
} else if (icm.outputGammaPreset == "High_g1.3_s3.35") {
ga[0] = 1.3 ; //for high dynamic images
ga[1] = 0.998279;
ga[2] = 0.001721;
ga[3] = 0.298507;
ga[4] = 0.005746;
} else if (icm.outputGammaPreset == "Low_g2.6_s6.9") {
ga[0] = 2.6 ; //gamma 2.6 variable : for low contrast images
ga[1] = 0.891161;
ga[2] = 0.108839;
ga[3] = 0.144928;
ga[4] = 0.076332;
} else if (icm.outputGammaPreset == "standard_g2.2") {
ga[0] = 2.2; //gamma=2.2(as gamma of Adobe, Widegamut...)
ga[1] = 1.;
ga[2] = 0.;
ga[3] = 1. / eps;
ga[4] = 0.;
} else if (icm.outputGammaPreset == "standard_g1.8") {
ga[0] = 1.8; //gamma=1.8(as gamma of Prophoto)
ga[1] = 1.;
ga[2] = 0.;
ga[3] = 1. / eps;
ga[4] = 0.;
} else if (icm.outputGammaPreset == "Lab_g3.0s9.03296") {
ga[0] = 3.0; //Lab gamma =3 slope=9.03296
ga[1] = 0.8621;
ga[2] = 0.1379;
ga[3] = 0.1107;
ga[4] = 0.08;
} else { /* if (icm.gamma == "linear_g1.0") */
ga[0] = 1.0; //gamma=1 linear : for high dynamic images(cf : D.Coffin...)
ga[1] = 1.;
ga[2] = 0.;
ga[3] = 1. / eps;
ga[4] = 0.;
}
ga[5] = 0.0;
ga[6] = 0.0;
} else { //free gamma selected
GammaValues g_a; //gamma parameters
double pwr = 1.0 / icm.workingTRCGamma;
double ts = icm.workingTRCSlope;
double slope = icm.workingTRCSlope == 0 ? eps : icm.workingTRCSlope;
int mode = 0;
Color::calcGamma(pwr, ts, mode, g_a); // call to calcGamma with selected gamma and slope : return parameters for LCMS2
ga[4] = g_a[3] * ts;
//printf("g_a.gamma0=%f g_a.gamma1=%f g_a.gamma2=%f g_a.gamma3=%f g_a.gamma4=%f\n", g_a.gamma0,g_a.gamma1,g_a.gamma2,g_a.gamma3,g_a.gamma4);
ga[0] = icm.workingTRCGamma;
ga[1] = 1. / (1.0 + g_a[4]);
ga[2] = g_a[4] / (1.0 + g_a[4]);
ga[3] = 1. / slope;
ga[5] = 0.0;
ga[6] = 0.0;
// printf("ga[0]=%f ga[1]=%f ga[2]=%f ga[3]=%f ga[4]=%f\n", ga[0],ga[1],ga[2],ga[3],ga[4]);
}
}
// WARNING: the caller must lock lcmsMutex
cmsHPROFILE rtengine::ICCStore::makeStdGammaProfile(cmsHPROFILE iprof)
{
@@ -1247,7 +1155,7 @@ cmsHPROFILE rtengine::ICCStore::createFromMatrix(const double matrix[3][3], bool
pcurve[2] = 1;
// pcurve[3] = 0x1f00000;// pcurve for gamma BT709 : g=2.22 s=4.5
// normalize gamma in RT, default(Emil's choice = sRGB)
pcurve[3] = 0x2390000;//pcurve for gamma sRGB : g:2.4 s=12.92
pcurve[3] = 0x2390000;//pcurve for gamma sRGB : g:2.4 s=12.92310
} else {
// lcms2 up to 2.4 has a bug with linear gamma causing precision loss(banding)
@@ -1311,584 +1219,3 @@ cmsHPROFILE rtengine::ICCStore::createFromMatrix(const double matrix[3][3], bool
delete [] oprof;
return p;
}
cmsHPROFILE rtengine::ICCStore::createGammaProfile(const procparams::ColorManagementParams &icm, GammaValues &ga)
{
float p[6]; //primaries
ga[5] = 0.0;
ga[6] = 0.0;
enum class ColorTemp {
D50 = 5003, // for Widegamut, Prophoto Best, Beta -> D50
D65 = 6504, // for sRGB, AdobeRGB, Bruce Rec2020 -> D65
D60 = 6005 // for ACES AP0 and ACES AP1
};
ColorTemp temp = ColorTemp::D50;
//primaries for 10 working profiles ==> output profiles
if (icm.outputPimariesPreset == "Widegamut") {
p[0] = 0.7350; //Widegamut primaries
p[1] = 0.2650;
p[2] = 0.1150;
p[3] = 0.8260;
p[4] = 0.1570;
p[5] = 0.0180;
} else if (icm.outputPimariesPreset == "Adobe") {
p[0] = 0.6400; //Adobe primaries
p[1] = 0.3300;
p[2] = 0.2100;
p[3] = 0.7100;
p[4] = 0.1500;
p[5] = 0.0600;
temp = ColorTemp::D65;
} else if (icm.outputPimariesPreset == "sRGB") {
p[0] = 0.6400; // sRGB primaries
p[1] = 0.3300;
p[2] = 0.3000;
p[3] = 0.6000;
p[4] = 0.1500;
p[5] = 0.0600;
temp = ColorTemp::D65;
} else if (icm.outputPimariesPreset == "BruceRGB") {
p[0] = 0.6400; // Bruce primaries
p[1] = 0.3300;
p[2] = 0.2800;
p[3] = 0.6500;
p[4] = 0.1500;
p[5] = 0.0600;
temp = ColorTemp::D65;
} else if (icm.outputPimariesPreset == "BetaRGB") {
p[0] = 0.6888; // Beta primaries
p[1] = 0.3112;
p[2] = 0.1986;
p[3] = 0.7551;
p[4] = 0.1265;
p[5] = 0.0352;
} else if (icm.outputPimariesPreset == "BestRGB") {
p[0] = 0.7347; // Best primaries
p[1] = 0.2653;
p[2] = 0.2150;
p[3] = 0.7750;
p[4] = 0.1300;
p[5] = 0.0350;
} else if (icm.outputPimariesPreset == "Rec2020") {
p[0] = 0.7080; // Rec2020 primaries
p[1] = 0.2920;
p[2] = 0.1700;
p[3] = 0.7970;
p[4] = 0.1310;
p[5] = 0.0460;
temp = ColorTemp::D65;
} else if (icm.outputPimariesPreset == "ACES-AP0") {
p[0] = 0.7347; // ACES AP0 primaries
p[1] = 0.2653;
p[2] = 0.0000;
p[3] = 1.0;
p[4] = 0.0001;
p[5] = -0.0770;
temp = ColorTemp::D60;
} else if (icm.outputPimariesPreset == "ACES-AP1") {
p[0] = 0.713; // ACES AP1 primaries
p[1] = 0.293;
p[2] = 0.165;
p[3] = 0.830;
p[4] = 0.128;
p[5] = 0.044;
temp = ColorTemp::D60;
} else if (icm.outputPimariesPreset == "ProPhoto") {
p[0] = 0.7347; //ProPhoto and default primaries
p[1] = 0.2653;
p[2] = 0.1596;
p[3] = 0.8404;
p[4] = 0.0366;
p[5] = 0.0001;
} else if (icm.outputPimariesPreset == "pfree") {
p[0] = icm.redPrimaryX;
p[1] = icm.redPrimaryY;
p[2] = icm.greenPrimaryX;
p[3] = icm.greenPrimaryY;
p[4] = icm.bluePrimaryX;
p[5] = icm.bluePrimaryY;
} else {
p[0] = 0.7347; //default primaries
p[1] = 0.2653;
p[2] = 0.1596;
p[3] = 0.8404;
p[4] = 0.0366;
p[5] = 0.0001;
}
cmsCIExyY xyD;
cmsCIExyYTRIPLE Primaries = {
{p[0], p[1], 1.0}, // red
{p[2], p[3], 1.0}, // green
{p[4], p[5], 1.0} // blue
};
cmsToneCurve* GammaTRC[3];
// 7 parameters for smoother curves
cmsFloat64Number Parameters[7] = { ga[0], ga[1], ga[2], ga[3], ga[4], ga[5], ga[6] } ;
/*
if(icm.wprofile == "v4" && icm.wtemp != "DEF") {
if(icm.wtemp == "D41") outPr = outPr + "D41";
else if(icm.wtemp == "D50") outPr = outPr + "D50";
else if(icm.wtemp == "D55") outPr = outPr + "D55";
else if(icm.wtemp == "D60") outPr = outPr + "D60";
else if(icm.wtemp == "D65") outPr = outPr + "D65";
else if(icm.wtemp == "D80") outPr = outPr + "D80";
}
*/
//lcmsMutex->lock(); Mutex acquired by the caller
double tempv4 = 5000.;
if (icm.outputProfileVersion == "v4" && icm.outputIlluminant != "DEF") {
if (icm.outputIlluminant == "D41") {
tempv4 = 4100.;
} else if (icm.outputIlluminant == "D50") {
tempv4 = 5003.;
} else if (icm.outputIlluminant == "D55") {
tempv4 = 5500.;
} else if (icm.outputIlluminant == "D60") {
tempv4 = 6004.;
} else if (icm.outputIlluminant == "D65") {
tempv4 = 6504.;
} else if (icm.outputIlluminant == "D80") {
tempv4 = 8000.;
} else if (icm.outputIlluminant == "stdA") {
tempv4 = 5003.;
}
}
if (icm.outputProfileVersion == "v4" && icm.outputIlluminant != "DEF") {
cmsWhitePointFromTemp(&xyD, tempv4);
} else {
cmsWhitePointFromTemp(&xyD, (double)temp);
}
if (icm.outputIlluminant == "stdA") xyD = {0.447573, 0.407440, 1.0};
// cmsWhitePointFromTemp(&xyD, (double)temp);
GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(nullptr, 5, Parameters); //5 = smoother than 4
cmsHPROFILE oprofdef = cmsCreateRGBProfile(&xyD, &Primaries, GammaTRC); //oprofdef become Outputprofile
cmsFreeToneCurve(GammaTRC[0]);
//lcmsMutex->unlock();
return oprofdef;
}
// WARNING: the caller must lock lcmsMutex
cmsHPROFILE rtengine::ICCStore::createCustomGammaOutputProfile(const procparams::ColorManagementParams &icm, GammaValues &ga)
{
bool pro = false;
Glib::ustring outProfile;
cmsHPROFILE outputProfile = nullptr;
Glib::ustring outPr;
Glib::ustring gammaStr;
if (icm.customOutputProfile && icm.workingTRCGamma < 1.35) {
pro = true; //select profil with gammaTRC modified :
} else if (icm.outputGammaPreset == "linear_g1.0" || (icm.outputGammaPreset == "High_g1.3_s3.35")) {
pro = true; //pro=0 RT_sRGB || Prophoto
}
//necessary for V2 profile
if (icm.outputPimariesPreset == "Prophoto" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.prophoto) && !pro) {
outProfile = options.rtSettings.prophoto;
outPr = "Large_";
} else if (icm.outputPimariesPreset == "Adobe" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.adobe)) {
outProfile = options.rtSettings.adobe;
outPr = "Medium_";
} else if (icm.outputPimariesPreset == "Widegamut" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.widegamut)) {
outProfile = options.rtSettings.widegamut;
outPr = "Wide_";
} else if (icm.outputPimariesPreset == "BetaRGB" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.beta)) {
outProfile = options.rtSettings.beta;
outPr = "Beta_";
} else if (icm.outputPimariesPreset == "BestRGB" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.best)) {
outProfile = options.rtSettings.best;
outPr = "Best_";
} else if (icm.outputPimariesPreset == "BruceRGB" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.bruce)) {
outProfile = options.rtSettings.bruce;
outPr = "Bruce_";
} else if (icm.outputPimariesPreset == "sRGB" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.srgb) && !pro) {
outProfile = options.rtSettings.srgb;
outPr = "sRGB_";
} else if (icm.outputPimariesPreset == "sRGB" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.srgb10) && pro) {
outProfile = options.rtSettings.srgb10;
outPr = "sRGB_";
} else if (icm.outputPimariesPreset == "ProPhoto" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.prophoto10) && pro) {
outProfile = options.rtSettings.prophoto10;
outPr = "Large_";
} else if (icm.outputPimariesPreset == "Rec2020" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.rec2020)) {
outProfile = options.rtSettings.rec2020;
outPr = "Rec2020_";
} else if (icm.outputPimariesPreset == "ACES-AP0" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.ACESp0)) {
outProfile = options.rtSettings.ACESp0;
outPr = "ACES-AP0_";
} else if (icm.outputPimariesPreset == "ACES-AP1" && rtengine::ICCStore::getInstance()->outputProfileExist(options.rtSettings.ACESp1)) {
outProfile = options.rtSettings.ACESp1;
outPr = "ACES-AP1_";
} else if (icm.outputPimariesPreset == "pfree") {
outProfile = options.rtSettings.srgb;
printf("PFREE\n");
outPr = "pfree_";
} else {
// Should not occurs
if (settings->verbose) {
printf("\"%s\": unknown working profile! - use LCMS2 substitution\n", icm.workingProfile.c_str());
}
return nullptr;
}
//begin adaptation rTRC gTRC bTRC
//"outputProfile" profile has the same characteristics than RGB values, but TRC are adapted... for applying profile
if (settings->verbose) {
printf("Output Gamma - profile Primaries as RT profile: \"%s\"\n", outProfile.c_str()); //c_str()
}
outputProfile = ICCStore::getInstance()->getProfile(outProfile); //get output profile
if (outputProfile == nullptr) {
if (settings->verbose) {
printf("\"%s\" ICC output profile not found!\n", outProfile.c_str());
}
return nullptr;
}
// 7 parameters for smoother curves
cmsFloat64Number Parameters[7] = { ga[0], ga[1], ga[2], ga[3], ga[4], ga[5], ga[6] };
//change desc Tag , to "free gamma", or "BT709", etc.
cmsMLU *mlu;
cmsContext ContextID = cmsGetProfileContextID(outputProfile); // create context to modify some TAGs
mlu = cmsMLUalloc(ContextID, 1);
Glib::ustring outPro;
Glib::ustring outTemp;
double gammsave = 2.4;
double slopesave = 12.92;
if (icm.outputGammaPreset == "High_g1.3_s3.35") {
gammaStr = "_High_g=1.3_s=3.35";
gammsave = 1.3;
slopesave = 3.35;
} else if (icm.outputGammaPreset == "Low_g2.6_s6.9") {
gammaStr = "_Low_g=2.6_s=6.9";
gammsave = 2.6;
slopesave = 6.9;
} else if (icm.outputGammaPreset == "sRGB_g2.4_s12.92") {
gammaStr = "_sRGB_g=2.4_s=12.92";
gammsave = 2.4;
slopesave = 12.92;
} else if (icm.outputGammaPreset == "BT709_g2.2_s4.5") {
gammaStr = "_BT709_g=2.2_s=4.5";
gammsave = 2.22;
slopesave = 4.5;
} else if (icm.outputGammaPreset == "linear_g1.0") {
gammaStr = "_Linear_g=1.0";
gammsave = 1.;
slopesave = 0.;
} else if (icm.outputGammaPreset == "standard_g2.2") {
gammaStr = "_g=2.2";
gammsave = 2.2;
slopesave = 0.;
} else if (icm.outputGammaPreset == "standard_g1.8") {
gammaStr = "_g=1.8";
gammsave = 1.8;
slopesave = 0.;
} else if (icm.outputGammaPreset == "Lab_g3.0s9.03296") {
gammaStr = "_LAB_g3.0_s9.03296";
gammsave = 3.0;
slopesave = 9.03296;
}
outTemp = outPr;
if (icm.outputProfileVersion == "v4" && icm.outputIlluminant != "DEF") {
if (icm.outputIlluminant == "D41") {
outPr = outPr + "D41";
} else if (icm.outputIlluminant == "D50") {
outPr = outPr + "D50";
} else if (icm.outputIlluminant == "D55") {
outPr = outPr + "D55";
} else if (icm.outputIlluminant == "D60") {
outPr = outPr + "D60";
} else if (icm.outputIlluminant == "D65") {
outPr = outPr + "D65";
} else if (icm.outputIlluminant == "D80") {
outPr = outPr + "D80";
} else if (icm.outputIlluminant == "stdA") {
outPr = outPr + "stdA";
}
// printf("outpr=%s \n",outPr.c_str());
}
// create description with gamma + slope + primaries
std::wostringstream gammaWs;
std::wstring gammaStrICC;
gammaWs.precision(3);
Glib::ustring gammaGS;//to save gamma and slope in a tag
if (icm.outputGammaPreset == "Custom") {
if (icm.outputProfileVersion == "v4") {
outPro = "RTv4_" + outPr + std::to_string((float)icm.workingTRCGamma) + " " + std::to_string((float)icm.workingTRCSlope) + ".icc";
} else if (icm.outputProfileVersion == "v2" || icm.outputProfileVersion == "none") {
outPro = "RTv2_" + outPr + std::to_string((float)icm.workingTRCGamma) + " " + std::to_string((float)icm.workingTRCSlope) + ".icc";
}
gammaWs.precision(2);
gammaWs << outTemp << " g=" << (float)icm.workingTRCGamma << " s=" << (float)icm.workingTRCSlope;
gammaGS ="g" +std::to_string((double)icm.workingTRCGamma) + "s" + std::to_string((double)icm.workingTRCSlope) + "!";
} else {
if (icm.outputProfileVersion == "v4") {
outPro = "RTv4_" + outPr + gammaStr + ".icc";
} else if (icm.outputProfileVersion == "v2" || icm.outputProfileVersion == "none") {
outPro = "RTv2_" + outPr + gammaStr + ".icc";
}
gammaWs << outTemp << gammaStr;
gammaGS = "g" + std::to_string(gammsave) + "s" + std::to_string(slopesave) + "!";
}
//write in tag 'dmdd' values of current gamma and slope to retrive after in Output profile
wchar_t *wGammaGS = (wchar_t*)g_utf8_to_utf16 (gammaGS.c_str(), -1, NULL, NULL, NULL);
if (!wGammaGS) {
printf("Error: lab2rgbOut / g_utf8_to_utf16 failed!\n");
}
cmsMLU *description = cmsMLUalloc(NULL, 1);
// Language code (3 letters code) : https://www.iso.org/obp/ui/
// Country code (3 letters code) : http://www.loc.gov/standards/iso639-2/php/code_list.php
if (cmsMLUsetWide(description, "eng", "USA", wGammaGS)) {
cmsWriteTag(outputProfile, cmsSigDeviceModelDescTag, description); //save 'dmdd' in description
} else {
printf("Error: lab2rgbOut / cmsMLUsetWide failed for \"%s\" !\n", gammaGS.c_str());
}
cmsMLUsetWide(mlu, "en", "US", gammaWs.str().c_str());
cmsMLUfree(description);
// instruction with //ICC are used to generate ICC profile
if (mlu == nullptr) {
printf("Description error\n");
} else {
if (icm.outputProfileVersion == "v4") {
cmsSetProfileVersion(outputProfile, 4.3);
} else {
cmsSetProfileVersion(outputProfile, 2.0);
}
//change
float p[6]; //primaries
ga[6] = 0.0;
enum class ColorTemp {
D50 = 5003, // for Widegamut, Prophoto Best, Beta -> D50
D65 = 6504, // for sRGB, AdobeRGB, Bruce Rec2020 -> D65
D60 = 6005 //for ACESc->D60
};
ColorTemp temp = ColorTemp::D50;
if (icm.outputPimariesPreset == "Widegamut") {
p[0] = 0.7350; //Widegamut primaries
p[1] = 0.2650;
p[2] = 0.1150;
p[3] = 0.8260;
p[4] = 0.1570;
p[5] = 0.0180;
} else if (icm.outputPimariesPreset == "Adobe") {
p[0] = 0.6400; //Adobe primaries
p[1] = 0.3300;
p[2] = 0.2100;
p[3] = 0.7100;
p[4] = 0.1500;
p[5] = 0.0600;
temp = ColorTemp::D65;
} else if (icm.outputPimariesPreset == "sRGB") {
p[0] = 0.6400; // sRGB primaries
p[1] = 0.3300;
p[2] = 0.3000;
p[3] = 0.6000;
p[4] = 0.1500;
p[5] = 0.0600;
temp = ColorTemp::D65;
} else if (icm.outputPimariesPreset == "BruceRGB") {
p[0] = 0.6400; // Bruce primaries
p[1] = 0.3300;
p[2] = 0.2800;
p[3] = 0.6500;
p[4] = 0.1500;
p[5] = 0.0600;
temp = ColorTemp::D65;
} else if (icm.outputPimariesPreset == "BetaRGB") {
p[0] = 0.6888; // Beta primaries
p[1] = 0.3112;
p[2] = 0.1986;
p[3] = 0.7551;
p[4] = 0.1265;
p[5] = 0.0352;
} else if (icm.outputPimariesPreset == "BestRGB") {
p[0] = 0.7347; // Best primaries
p[1] = 0.2653;
p[2] = 0.2150;
p[3] = 0.7750;
p[4] = 0.1300;
p[5] = 0.0350;
} else if (icm.outputPimariesPreset == "Rec2020") {
p[0] = 0.7080; // Rec2020 primaries
p[1] = 0.2920;
p[2] = 0.1700;
p[3] = 0.7970;
p[4] = 0.1310;
p[5] = 0.0460;
temp = ColorTemp::D65;
} else if (icm.outputPimariesPreset == "ACES-AP0") {
p[0] = 0.7347; // ACES P0 primaries
p[1] = 0.2653;
p[2] = 0.0000;
p[3] = 1.0;
p[4] = 0.0001;
p[5] = -0.0770;
temp = ColorTemp::D60;
} else if (icm.outputPimariesPreset == "ACES-AP1") {
p[0] = 0.713; // ACES P1 primaries
p[1] = 0.293;
p[2] = 0.165;
p[3] = 0.830;
p[4] = 0.128;
p[5] = 0.044;
temp = ColorTemp::D60;
} else if (icm.outputPimariesPreset == "ProPhoto") {
p[0] = 0.7347; // ProPhoto and default primaries
p[1] = 0.2653;
p[2] = 0.1596;
p[3] = 0.8404;
p[4] = 0.0366;
p[5] = 0.0001;
} else if (icm.outputPimariesPreset == "pfree") {
p[0] = icm.redPrimaryX;
p[1] = icm.redPrimaryY;
p[2] = icm.greenPrimaryX;
p[3] = icm.greenPrimaryY;
p[4] = icm.bluePrimaryX;
p[5] = icm.bluePrimaryY;
} else {
p[0] = 0.7347; //default primaries
p[1] = 0.2653;
p[2] = 0.1596;
p[3] = 0.8404;
p[4] = 0.0366;
p[5] = 0.0001;
}
cmsCIExyY xyD;
cmsCIExyYTRIPLE Primaries = {
{p[0], p[1], 1.0}, // red
{p[2], p[3], 1.0}, // green
{p[4], p[5], 1.0} // blue
};
double tempv4 = 5000.;
if (icm.outputProfileVersion == "v4" && icm.outputIlluminant != "DEF") {
if (icm.outputIlluminant == "D41") {
tempv4 = 4100.;
} else if (icm.outputIlluminant == "D50") {
tempv4 = 5003.;
} else if (icm.outputIlluminant == "D55") {
tempv4 = 5500.;
} else if (icm.outputIlluminant == "D60") {
tempv4 = 6004.;
} else if (icm.outputIlluminant == "D65") {
tempv4 = 6504.;
} else if (icm.outputIlluminant == "D80") {
tempv4 = 8000.;
} else if (icm.outputIlluminant == "stdA") {
tempv4 = 5003.;
}
//printf("tempv4=%f \n", tempv4);
}
if (icm.outputProfileVersion == "v4" && icm.outputIlluminant != "DEF") {
cmsWhitePointFromTemp(&xyD, tempv4);
} else {
cmsWhitePointFromTemp(&xyD, (double)temp);
}
if (icm.outputIlluminant == "stdA") xyD = {0.447573, 0.407440, 1.0};
cmsToneCurve* GammaTRC[3];
// Calculate output profile's rTRC gTRC bTRC
GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(nullptr, 5, Parameters);
if (icm.outputProfileVersion == "v4") {
outputProfile = cmsCreateRGBProfile(&xyD, &Primaries, GammaTRC);
}
cmsWriteTag(outputProfile, cmsSigRedTRCTag, GammaTRC[0]);
cmsWriteTag(outputProfile, cmsSigGreenTRCTag, GammaTRC[1]);
cmsWriteTag(outputProfile, cmsSigBlueTRCTag, GammaTRC[2]);
cmsWriteTag(outputProfile, cmsSigProfileDescriptionTag, mlu);//desc changed
/* //to read XYZ values
cmsCIEXYZ *redT = static_cast<cmsCIEXYZ*>(cmsReadTag(outputProfile, cmsSigRedMatrixColumnTag));
cmsCIEXYZ *greenT = static_cast<cmsCIEXYZ*>(cmsReadTag(outputProfile, cmsSigGreenMatrixColumnTag));
cmsCIEXYZ *blueT = static_cast<cmsCIEXYZ*>(cmsReadTag(outputProfile, cmsSigBlueMatrixColumnTag));
printf("rx=%f gx=%f bx=%f ry=%f gy=%f by=%f rz=%f gz=%f bz=%f\n", redT->X, greenT->X, blueT->X, redT->Y, greenT->Y, blueT->Y, redT->Z, greenT->Z, blueT->Z);
*/
cmsMLUfree(mlu);
cmsMLU *copyright = cmsMLUalloc(NULL, 1);
cmsMLUsetASCII(copyright, "en", "US", "Copyright RawTherapee 2018, CC0");
cmsWriteTag(outputProfile, cmsSigCopyrightTag, copyright);
cmsMLUfree(copyright);
// cmsWriteTag(outputProfile, cmsSigProfileDescriptionTag, mlu);//desc changed
cmsMLU *MfgDesc;
MfgDesc = cmsMLUalloc(NULL, 1);
cmsMLUsetASCII(MfgDesc, "en", "US", "RawTherapee");
cmsWriteTag(outputProfile, cmsSigDeviceMfgDescTag, MfgDesc);
cmsMLUfree(MfgDesc);
Glib::ustring realoutPro;
realoutPro = options.cacheBaseDir + "/" + outPro;//ICC profile in cache
if (icm.outputProfileVersion == "v2" || icm.outputProfileVersion == "v4") {
cmsSaveProfileToFile(outputProfile, realoutPro.c_str());
}
// if (GammaTRC) {
cmsFreeToneCurve(GammaTRC[0]);
// }
}
return outputProfile;
}