Moved the ICC TRC patching code for RTv2 profiles from ImProcFunctions::lab2rgbOut to ICCStore
See #5026
This commit is contained in:
parent
23aa0562aa
commit
cfc947a865
@ -38,6 +38,8 @@
|
|||||||
#include "../rtgui/threadutils.h"
|
#include "../rtgui/threadutils.h"
|
||||||
#include "lcms2_plugin.h"
|
#include "lcms2_plugin.h"
|
||||||
|
|
||||||
|
#include "color.h"
|
||||||
|
|
||||||
#include "cJSON.h"
|
#include "cJSON.h"
|
||||||
#define inkc_constant 0x696E6B43
|
#define inkc_constant 0x696E6B43
|
||||||
namespace rtengine
|
namespace rtengine
|
||||||
@ -208,8 +210,85 @@ const char* wpnames[] = {"sRGB", "Adobe RGB", "ProPhoto", "WideGamut", "BruceRGB
|
|||||||
// high g=1.3 s=3.35 for high dynamic images
|
// high g=1.3 s=3.35 for high dynamic images
|
||||||
//low g=2.6 s=6.9 for low contrast images
|
//low g=2.6 s=6.9 for low contrast images
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// helper functions to fix V2 profiles TRCs, used in
|
||||||
|
// rtengine::ProfileContent::toProfile()
|
||||||
|
// see https://github.com/Beep6581/RawTherapee/issues/5026
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
bool is_RTv2_profile(cmsHPROFILE profile)
|
||||||
|
{
|
||||||
|
if (int(cmsGetProfileVersion(profile)) != 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const cmsMLU *mlu = static_cast<const cmsMLU *>(cmsReadTag(profile, cmsSigDeviceMfgDescTag));
|
||||||
|
if (!mlu) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cmsUInt32Number sz = cmsMLUgetASCII(mlu, "en", "US", nullptr, 0);
|
||||||
|
if (!sz) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::vector<char> buf(sz);
|
||||||
|
cmsMLUgetASCII(mlu, "en", "US", &buf[0], sz);
|
||||||
|
buf.back() = 0; // sanity
|
||||||
|
return strcmp(&buf[0], "RawTherapee") == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool get_RT_gamma_slope(cmsHPROFILE profile, double &gammatag, double &slopetag)
|
||||||
|
{
|
||||||
|
const cmsMLU *modelDescMLU = static_cast<const cmsMLU *>(cmsReadTag(profile, cmsSigDeviceModelDescTag));
|
||||||
|
if (modelDescMLU) {
|
||||||
|
cmsUInt32Number count = cmsMLUgetWide(modelDescMLU, "en", "US", nullptr, 0);
|
||||||
|
if (count) {
|
||||||
|
std::vector<wchar_t> vbuf(count);
|
||||||
|
wchar_t *buffer = &vbuf[0];
|
||||||
|
count = cmsMLUgetWide(modelDescMLU, "en", "US", buffer, count);
|
||||||
|
Glib::ustring modelDesc;
|
||||||
|
#if __SIZEOF_WCHAR_T__ == 2
|
||||||
|
char *cModelDesc = g_utf16_to_utf8((unsigned short int*)buffer, -1, nullptr, nullptr, nullptr); // convert to utf-8 in a buffer allocated by glib
|
||||||
|
if (cModelDesc) {
|
||||||
|
modelDesc.assign(cModelDesc);
|
||||||
|
g_free(cModelDesc);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
modelDesc = utf32_to_utf8(buffer, count);
|
||||||
|
#endif
|
||||||
|
if (!modelDesc.empty()) {
|
||||||
|
std::size_t pos = modelDesc.find("g");
|
||||||
|
std::size_t posmid = modelDesc.find("s");
|
||||||
|
std::size_t posend = modelDesc.find("!");
|
||||||
|
std::string strgamma = modelDesc.substr(pos + 1, (posmid - pos));
|
||||||
|
gammatag = std::stod(strgamma.c_str());
|
||||||
|
std::string strslope = modelDesc.substr(posmid + 1, (posend - posmid));
|
||||||
|
slopetag = std::stod(strslope.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Glib::ustring get_profile_description(cmsHPROFILE profile)
|
||||||
|
{
|
||||||
|
const cmsMLU *mlu = static_cast<const cmsMLU *>(cmsReadTag(profile, cmsSigProfileDescriptionTag));
|
||||||
|
if (!mlu) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
cmsUInt32Number sz = cmsMLUgetASCII(mlu, "en", "US", nullptr, 0);
|
||||||
|
if (!sz) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
std::vector<char> buf(sz);
|
||||||
|
cmsMLUgetASCII(mlu, "en", "US", &buf[0], sz);
|
||||||
|
buf.back() = 0; // sanity
|
||||||
|
return std::string(&buf[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
rtengine::ProfileContent::ProfileContent() = default;
|
rtengine::ProfileContent::ProfileContent() = default;
|
||||||
|
|
||||||
rtengine::ProfileContent::ProfileContent(const Glib::ustring& fileName)
|
rtengine::ProfileContent::ProfileContent(const Glib::ustring& fileName)
|
||||||
@ -255,11 +334,52 @@ rtengine::ProfileContent::ProfileContent(cmsHPROFILE hProfile)
|
|||||||
|
|
||||||
cmsHPROFILE rtengine::ProfileContent::toProfile() const
|
cmsHPROFILE rtengine::ProfileContent::toProfile() const
|
||||||
{
|
{
|
||||||
|
cmsHPROFILE profile = nullptr;
|
||||||
|
if (!data.empty()) {
|
||||||
|
profile = cmsOpenProfileFromMem(data.c_str(), data.size());
|
||||||
|
// if this is a V2 profile generated by RawTherapee, we rebuild the
|
||||||
|
// TRC. See https://github.com/Beep6581/RawTherapee/issues/5026 and
|
||||||
|
// the references in there
|
||||||
|
if (profile && is_RTv2_profile(profile)) {
|
||||||
|
double gammatag, slopetag;
|
||||||
|
if (get_RT_gamma_slope(profile, gammatag, slopetag)) {
|
||||||
|
constexpr double eps = 0.000000001; // not divide by zero
|
||||||
|
double pwr = 1.0 / gammatag;
|
||||||
|
double ts = slopetag;
|
||||||
|
double slope = slopetag == 0 ? eps : slopetag;
|
||||||
|
|
||||||
return
|
GammaValues g_b; //gamma parameters
|
||||||
!data.empty()
|
Color::calcGamma(pwr, ts, 0, g_b); // call to calcGamma with selected gamma and slope : return parameters for LCMS2
|
||||||
? cmsOpenProfileFromMem(data.c_str(), data.size())
|
cmsFloat64Number gammaParams[7]; //gamma parameters
|
||||||
: nullptr;
|
gammaParams[4] = g_b[3] * ts;
|
||||||
|
gammaParams[0] = gammatag;
|
||||||
|
gammaParams[1] = 1. / (1.0 + g_b[4]);
|
||||||
|
gammaParams[2] = g_b[4] / (1.0 + g_b[4]);
|
||||||
|
gammaParams[3] = 1. / slope;
|
||||||
|
gammaParams[5] = 0.0;
|
||||||
|
gammaParams[6] = 0.0;
|
||||||
|
|
||||||
|
cmsToneCurve* GammaTRC;
|
||||||
|
if (slopetag == 0.) {
|
||||||
|
//printf("gammatag=%f\n", gammatag);
|
||||||
|
GammaTRC = cmsBuildGamma(NULL, gammatag);
|
||||||
|
} else {
|
||||||
|
GammaTRC = cmsBuildParametricToneCurve(nullptr, 5, gammaParams); //5 = smoother than 4
|
||||||
|
}
|
||||||
|
cmsWriteTag(profile, cmsSigRedTRCTag, GammaTRC);
|
||||||
|
cmsWriteTag(profile, cmsSigGreenTRCTag, GammaTRC);
|
||||||
|
cmsWriteTag(profile, cmsSigBlueTRCTag, GammaTRC);
|
||||||
|
cmsFreeToneCurve(GammaTRC);
|
||||||
|
|
||||||
|
if (settings->verbose) {
|
||||||
|
std::cout << "ICCStore: rebuilt TRC for RTv2 profile " << get_profile_description(profile) << ": gamma=" << gammatag << ", slope=" << slopetag << std::endl;
|
||||||
|
}
|
||||||
|
} else if (settings->verbose) {
|
||||||
|
std::cout << "ICCStore: no gamma/slope info found for RTv2 profile " << get_profile_description(profile) << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& rtengine::ProfileContent::getData() const
|
const std::string& rtengine::ProfileContent::getData() const
|
||||||
|
@ -303,82 +303,7 @@ Imagefloat* ImProcFunctions::lab2rgbOut(LabImage* lab, int cx, int cy, int cw, i
|
|||||||
}
|
}
|
||||||
|
|
||||||
Imagefloat* image = new Imagefloat(cw, ch);
|
Imagefloat* image = new Imagefloat(cw, ch);
|
||||||
|
cmsHPROFILE oprof = ICCStore::getInstance()->getProfile(icm.outputProfile);
|
||||||
cmsHPROFILE oprof = nullptr;
|
|
||||||
|
|
||||||
oprof = ICCStore::getInstance()->getProfile(icm.outputProfile);
|
|
||||||
Glib::ustring outtest = icm.outputProfile;
|
|
||||||
std::string fileis_RTv2 = outtest.substr(0, 4);
|
|
||||||
//printf("IsRTv2=%s\n", fileis_RTv2.c_str());
|
|
||||||
if(fileis_RTv2 == "RTv2") {//Only fot ICC v2 : read tag from desc to retrieve gamma and slope save before in generate ICC v2
|
|
||||||
//due to bug in LCMS in CmsToneCurve
|
|
||||||
//printf("icmout=%s \n",icm.output.c_str());
|
|
||||||
GammaValues g_b; //gamma parameters
|
|
||||||
const double eps = 0.000000001; // not divide by zero
|
|
||||||
double gammatag = 2.4;
|
|
||||||
double slopetag = 12.92310;
|
|
||||||
cmsMLU *modelDescMLU = (cmsMLU*) (cmsReadTag(oprof, cmsSigDeviceModelDescTag));
|
|
||||||
if (modelDescMLU) {
|
|
||||||
cmsUInt32Number count = cmsMLUgetWide(modelDescMLU, "en", "US", nullptr, 0); // get buffer length first
|
|
||||||
if (count) {
|
|
||||||
wchar_t *buffer = new wchar_t[count];
|
|
||||||
count = cmsMLUgetWide(modelDescMLU, "en", "US", buffer, count); // now put the string in the buffer
|
|
||||||
Glib::ustring modelDesc;
|
|
||||||
#if __SIZEOF_WCHAR_T__ == 2
|
|
||||||
char* cModelDesc = g_utf16_to_utf8((unsigned short int*)buffer, -1, nullptr, nullptr, nullptr); // convert to utf-8 in a buffer allocated by glib
|
|
||||||
if (cModelDesc) {
|
|
||||||
modelDesc.assign(cModelDesc);
|
|
||||||
g_free(cModelDesc);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
modelDesc = utf32_to_utf8(buffer, count);
|
|
||||||
#endif
|
|
||||||
delete [] buffer;
|
|
||||||
if (!modelDesc.empty()) {
|
|
||||||
std::size_t pos = modelDesc.find("g");
|
|
||||||
std::size_t posmid = modelDesc.find("s");
|
|
||||||
std::size_t posend = modelDesc.find("!");
|
|
||||||
std::string strgamma = modelDesc.substr(pos + 1, (posmid - pos));
|
|
||||||
gammatag = std::stod(strgamma.c_str());
|
|
||||||
std::string strslope = modelDesc.substr(posmid + 1, (posend - posmid));
|
|
||||||
slopetag = std::stod(strslope.c_str());
|
|
||||||
// printf("gam=%f slo=%f\n", gammatag, slopetag);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
printf("Error: lab2rgbOut / String length is null!\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
printf("Error: lab2rgbOut / cmsReadTag/cmsSigDeviceModelDescTag failed!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
double pwr = 1.0 / gammatag;
|
|
||||||
double ts = slopetag;
|
|
||||||
double slope = slopetag == 0 ? eps : slopetag;
|
|
||||||
|
|
||||||
int mode = 0;
|
|
||||||
Color::calcGamma(pwr, ts, mode, g_b); // call to calcGamma with selected gamma and slope : return parameters for LCMS2
|
|
||||||
cmsFloat64Number gammaParams[7]; //gamma parameters
|
|
||||||
gammaParams[4] = g_b[3] * ts;
|
|
||||||
gammaParams[0] = gammatag;
|
|
||||||
gammaParams[1] = 1. / (1.0 + g_b[4]);
|
|
||||||
gammaParams[2] = g_b[4] / (1.0 + g_b[4]);
|
|
||||||
gammaParams[3] = 1. / slope;
|
|
||||||
gammaParams[5] = 0.0;
|
|
||||||
gammaParams[6] = 0.0;
|
|
||||||
|
|
||||||
cmsToneCurve* GammaTRC[3];
|
|
||||||
if(slopetag == 0.) {
|
|
||||||
//printf("gammatag=%f\n", gammatag);
|
|
||||||
GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildGamma(NULL, gammatag);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(nullptr, 5, gammaParams); //5 = smoother than 4
|
|
||||||
}
|
|
||||||
cmsWriteTag(oprof, cmsSigRedTRCTag, GammaTRC[0]);
|
|
||||||
cmsWriteTag(oprof, cmsSigGreenTRCTag, GammaTRC[1]);
|
|
||||||
cmsWriteTag(oprof, cmsSigBlueTRCTag, GammaTRC[2]);
|
|
||||||
cmsFreeToneCurve(GammaTRC[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oprof) {
|
if (oprof) {
|
||||||
cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE;
|
cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user