Issue 1987: improved DCP support; Issue 2042: batch queue crash fix
This commit is contained in:
@@ -283,7 +283,7 @@ HISTORY_MSG_45;Lum. Denoising Edge Tolerance
|
|||||||
HISTORY_MSG_46;Color Denoising
|
HISTORY_MSG_46;Color Denoising
|
||||||
HISTORY_MSG_47;Blend ICC highlights with matrix
|
HISTORY_MSG_47;Blend ICC highlights with matrix
|
||||||
HISTORY_MSG_48;Use DCP's tone curve
|
HISTORY_MSG_48;Use DCP's tone curve
|
||||||
HISTORY_MSG_49;Edge Sensitive Color Denoising
|
HISTORY_MSG_49;DCP Illuminant
|
||||||
HISTORY_MSG_50;Shadow/Highlight
|
HISTORY_MSG_50;Shadow/Highlight
|
||||||
HISTORY_MSG_51;Highlights
|
HISTORY_MSG_51;Highlights
|
||||||
HISTORY_MSG_52;Shadows
|
HISTORY_MSG_52;Shadows
|
||||||
@@ -1234,6 +1234,9 @@ TP_HSVEQUALIZER_SAT;S
|
|||||||
TP_HSVEQUALIZER_VAL;V
|
TP_HSVEQUALIZER_VAL;V
|
||||||
TP_ICM_BLENDCMSMATRIX;Blend ICC highlights with matrix
|
TP_ICM_BLENDCMSMATRIX;Blend ICC highlights with matrix
|
||||||
TP_ICM_BLENDCMSMATRIX_TOOLTIP;Enable to recover blown highlights when using LUT based ICC profiles
|
TP_ICM_BLENDCMSMATRIX_TOOLTIP;Enable to recover blown highlights when using LUT based ICC profiles
|
||||||
|
TP_ICM_DCPILLUMINANT;Illuminant
|
||||||
|
TP_ICM_DCPILLUMINANT_TOOLTIP;Select which embedded DCP illuminant to employ. Default is "interpolated" which is a mix between the two based on white balance. The setting is only enabled if a Dual-Illuminant DCP with interpolation support is selected.
|
||||||
|
TP_ICM_DCPILLUMINANT_INTERPOLATED;Interpolated
|
||||||
TP_ICM_FILEDLGFILTERANY;Any files
|
TP_ICM_FILEDLGFILTERANY;Any files
|
||||||
TP_ICM_FILEDLGFILTERICM;Color profiles
|
TP_ICM_FILEDLGFILTERICM;Color profiles
|
||||||
TP_ICM_INPUTCAMERAICC;Auto-matched camera-specific color profile
|
TP_ICM_INPUTCAMERAICC;Auto-matched camera-specific color profile
|
||||||
@@ -1252,14 +1255,9 @@ TP_ICM_LABEL;Color Management
|
|||||||
TP_ICM_NOICM;No ICM: sRGB Output
|
TP_ICM_NOICM;No ICM: sRGB Output
|
||||||
TP_ICM_OUTPUTDLGLABEL;Select Output ICC Profile...
|
TP_ICM_OUTPUTDLGLABEL;Select Output ICC Profile...
|
||||||
TP_ICM_OUTPUTPROFILE;Output Profile
|
TP_ICM_OUTPUTPROFILE;Output Profile
|
||||||
TP_ICM_PREFERREDPROFILE;Preferred DCP profile
|
|
||||||
TP_ICM_PREFERREDPROFILE_1;Daylight
|
|
||||||
TP_ICM_PREFERREDPROFILE_2;Tungsten
|
|
||||||
TP_ICM_PREFERREDPROFILE_3;Fluorescent
|
|
||||||
TP_ICM_PREFERREDPROFILE_4;Flash
|
|
||||||
TP_ICM_SAVEREFERENCE;Save Reference Image for Profiling
|
TP_ICM_SAVEREFERENCE;Save Reference Image for Profiling
|
||||||
TP_ICM_TONECURVE;Use DCP's tone curve
|
TP_ICM_TONECURVE;Use DCP's tone curve
|
||||||
TP_ICM_TONECURVE_TOOLTIP;Enable to use tone curves that may be contained in DCP profiles.
|
TP_ICM_TONECURVE_TOOLTIP;Employ the embedded DCP tone curve. The setting is only enabled if the selected DCP has a tone curve.
|
||||||
TP_ICM_WORKINGPROFILE;Working Profile
|
TP_ICM_WORKINGPROFILE;Working Profile
|
||||||
TP_IMPULSEDENOISE_LABEL;Impulse Noise Reduction
|
TP_IMPULSEDENOISE_LABEL;Impulse Noise Reduction
|
||||||
TP_IMPULSEDENOISE_THRESH;Threshold
|
TP_IMPULSEDENOISE_THRESH;Threshold
|
||||||
|
@@ -62,6 +62,7 @@ class ColorTemp {
|
|||||||
void update (const double rmul, const double gmul, const double bmul, const double equal) { this->equal = equal; mul2temp (rmul, gmul, bmul, this->equal, temp, green); }
|
void update (const double rmul, const double gmul, const double bmul, const double equal) { this->equal = equal; mul2temp (rmul, gmul, bmul, this->equal, temp, green); }
|
||||||
void useDefaults (const double equal) { temp = 6504; green = 1.0; this->equal = equal; } // Values copied from procparams.cc
|
void useDefaults (const double equal) { temp = 6504; green = 1.0; this->equal = equal; } // Values copied from procparams.cc
|
||||||
|
|
||||||
|
inline Glib::ustring getMethod() { return method; }
|
||||||
inline double getTemp () { return temp; }
|
inline double getTemp () { return temp; }
|
||||||
inline double getGreen () { return green; }
|
inline double getGreen () { return green; }
|
||||||
inline double getEqual () { return equal; }
|
inline double getEqual () { return equal; }
|
||||||
|
805
rtengine/dcp.cc
805
rtengine/dcp.cc
@@ -30,15 +30,319 @@ using namespace std;
|
|||||||
using namespace rtengine;
|
using namespace rtengine;
|
||||||
using namespace rtexif;
|
using namespace rtexif;
|
||||||
|
|
||||||
|
static void Invert3x3(const double (*A)[3], double (*B)[3]) {
|
||||||
|
|
||||||
|
double a00 = A[0][0];
|
||||||
|
double a01 = A[0][1];
|
||||||
|
double a02 = A[0][2];
|
||||||
|
double a10 = A[1][0];
|
||||||
|
double a11 = A[1][1];
|
||||||
|
double a12 = A[1][2];
|
||||||
|
double a20 = A[2][0];
|
||||||
|
double a21 = A[2][1];
|
||||||
|
double a22 = A[2][2];
|
||||||
|
double temp [3][3];
|
||||||
|
|
||||||
|
temp[0][0] = a11 * a22 - a21 * a12;
|
||||||
|
temp[0][1] = a21 * a02 - a01 * a22;
|
||||||
|
temp[0][2] = a01 * a12 - a11 * a02;
|
||||||
|
temp[1][0] = a20 * a12 - a10 * a22;
|
||||||
|
temp[1][1] = a00 * a22 - a20 * a02;
|
||||||
|
temp[1][2] = a10 * a02 - a00 * a12;
|
||||||
|
temp[2][0] = a10 * a21 - a20 * a11;
|
||||||
|
temp[2][1] = a20 * a01 - a00 * a21;
|
||||||
|
temp[2][2] = a00 * a11 - a10 * a01;
|
||||||
|
|
||||||
|
double det = a00 * temp[0][0] + a01 * temp[1][0] + a02 * temp[2][0];
|
||||||
|
|
||||||
|
if (fabs(det) < 1.0E-10) {
|
||||||
|
abort(); // can't be inverted, we shouldn't be dealing with such matrices
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
|
for (int k = 0; k < 3; k++) {
|
||||||
|
B[j][k] = temp[j][k] / det;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Multiply3x3(const double (*A)[3], const double (*B)[3], double (*C)[3]) {
|
||||||
|
|
||||||
|
// use temp to support having output same as input
|
||||||
|
double M[3][3];
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
|
M[i][j] = 0;
|
||||||
|
for (int k = 0; k < 3; k++) {
|
||||||
|
M[i][j] += A[i][k] * B[k][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memcpy(C, M, 3 * 3 * sizeof(double));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Multiply3x3_v3(const double (*A)[3], const double B[3], double C[3]) {
|
||||||
|
|
||||||
|
// use temp to support having output same as input
|
||||||
|
double M[3] = { 0, 0, 0 };
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
|
M[i] += A[i][j] * B[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memcpy(C, M, 3 * sizeof(double));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Mix3x3(const double (*A)[3], double mulA, const double (*B)[3], double mulB, double (*C)[3]) {
|
||||||
|
|
||||||
|
double M[3][3];
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
|
M[i][j] = A[i][j] * mulA + B[i][j] * mulB;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
memcpy(C, M, 3 * 3 * sizeof(double));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MapWhiteMatrix(const double white1[3], const double white2[3], double (*B)[3]) {
|
||||||
|
|
||||||
|
// code adapted from dng_color_spec::MapWhiteMatrix
|
||||||
|
|
||||||
|
// Use the linearized Bradford adaptation matrix.
|
||||||
|
double Mb[3][3] = { { 0.8951, 0.2664, -0.1614 }, { -0.7502, 1.7135, 0.0367 }, { 0.0389, -0.0685, 1.0296 }};
|
||||||
|
|
||||||
|
double w1[3];
|
||||||
|
Multiply3x3_v3(Mb, white1, w1);
|
||||||
|
double w2[3];
|
||||||
|
Multiply3x3_v3(Mb, white2, w2);
|
||||||
|
|
||||||
|
// Negative white coordinates are kind of meaningless.
|
||||||
|
w1[0] = std::max(w1[0], 0.0);
|
||||||
|
w1[1] = std::max(w1[1], 0.0);
|
||||||
|
w1[2] = std::max(w1[2], 0.0);
|
||||||
|
w2[0] = std::max(w2[0], 0.0);
|
||||||
|
w2[1] = std::max(w2[1], 0.0);
|
||||||
|
w2[2] = std::max(w2[2], 0.0);
|
||||||
|
|
||||||
|
// Limit scaling to something reasonable.
|
||||||
|
double A[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
||||||
|
A[0][0] = std::max(0.1, std::min(w1[0] > 0.0 ? w2[0] / w1[0] : 10.0, 10.0));
|
||||||
|
A[1][1] = std::max(0.1, std::min(w1[1] > 0.0 ? w2[1] / w1[1] : 10.0, 10.0));
|
||||||
|
A[2][2] = std::max(0.1, std::min(w1[2] > 0.0 ? w2[2] / w1[2] : 10.0, 10.0));
|
||||||
|
|
||||||
|
double temp[3][3];
|
||||||
|
Invert3x3(Mb, temp);
|
||||||
|
Multiply3x3(temp, A, temp);
|
||||||
|
Multiply3x3(temp, Mb, B);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum dngCalibrationIlluminant {
|
||||||
|
lsUnknown = 0,
|
||||||
|
lsDaylight = 1,
|
||||||
|
lsFluorescent = 2,
|
||||||
|
lsTungsten = 3,
|
||||||
|
lsFlash = 4,
|
||||||
|
lsFineWeather = 9,
|
||||||
|
lsCloudyWeather = 10,
|
||||||
|
lsShade = 11,
|
||||||
|
lsDaylightFluorescent = 12, // D 5700 - 7100K
|
||||||
|
lsDayWhiteFluorescent = 13, // N 4600 - 5500K
|
||||||
|
lsCoolWhiteFluorescent = 14, // W 3800 - 4500K
|
||||||
|
lsWhiteFluorescent = 15, // WW 3250 - 3800K
|
||||||
|
lsWarmWhiteFluorescent = 16, // L 2600 - 3250K
|
||||||
|
lsStandardLightA = 17,
|
||||||
|
lsStandardLightB = 18,
|
||||||
|
lsStandardLightC = 19,
|
||||||
|
lsD55 = 20,
|
||||||
|
lsD65 = 21,
|
||||||
|
lsD75 = 22,
|
||||||
|
lsD50 = 23,
|
||||||
|
lsISOStudioTungsten = 24,
|
||||||
|
lsOther = 255
|
||||||
|
};
|
||||||
|
|
||||||
|
// should probably be moved to colortemp.cc
|
||||||
|
static double calibrationIlluminantToTemperature(int light) {
|
||||||
|
|
||||||
|
// these temperatures are those found in DNG SDK reference code.
|
||||||
|
switch (light) {
|
||||||
|
case lsStandardLightA:
|
||||||
|
case lsTungsten:
|
||||||
|
return 2850.0;
|
||||||
|
case lsISOStudioTungsten:
|
||||||
|
return 3200.0;
|
||||||
|
case lsD50:
|
||||||
|
return 5000.0;
|
||||||
|
case lsD55:
|
||||||
|
case lsDaylight:
|
||||||
|
case lsFineWeather:
|
||||||
|
case lsFlash:
|
||||||
|
case lsStandardLightB:
|
||||||
|
return 5500.0;
|
||||||
|
case lsD65:
|
||||||
|
case lsStandardLightC:
|
||||||
|
case lsCloudyWeather:
|
||||||
|
return 6500.0;
|
||||||
|
case lsD75:
|
||||||
|
case lsShade:
|
||||||
|
return 7500.0;
|
||||||
|
case lsDaylightFluorescent:
|
||||||
|
return (5700.0 + 7100.0) * 0.5;
|
||||||
|
case lsDayWhiteFluorescent:
|
||||||
|
return (4600.0 + 5500.0) * 0.5;
|
||||||
|
case lsCoolWhiteFluorescent:
|
||||||
|
case lsFluorescent:
|
||||||
|
return (3800.0 + 4500.0) * 0.5;
|
||||||
|
case lsWhiteFluorescent:
|
||||||
|
return (3250.0 + 3800.0) * 0.5;
|
||||||
|
case lsWarmWhiteFluorescent:
|
||||||
|
return (2600.0 + 3250.0) * 0.5;
|
||||||
|
default:
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DCPProfile::MakeXYZCAM(ColorTemp &wb, int preferredIlluminant, double (*mXYZCAM)[3]) const
|
||||||
|
{
|
||||||
|
// code adapted from dng_color_spec::FindXYZtoCamera
|
||||||
|
// note that we do not support monochrome or colorplanes > 3 (no reductionMatrix support)
|
||||||
|
// we do not support cameracalibration either
|
||||||
|
|
||||||
|
bool hasFwd1 = hasForwardMatrix1;
|
||||||
|
bool hasFwd2 = hasForwardMatrix2;
|
||||||
|
bool hasCol1 = hasColorMatrix1;
|
||||||
|
bool hasCol2 = hasColorMatrix2;
|
||||||
|
if (preferredIlluminant == 1) {
|
||||||
|
if (hasFwd1) hasFwd2 = false;
|
||||||
|
if (hasCol1) hasCol2 = false;
|
||||||
|
} else if (preferredIlluminant == 2) {
|
||||||
|
if (hasFwd2) hasFwd1 = false;
|
||||||
|
if (hasCol2) hasCol1 = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mix if we have two matrices
|
||||||
|
double mix;
|
||||||
|
if (wb.getTemp() <= temperature1) {
|
||||||
|
mix = 1.0;
|
||||||
|
} else if (wb.getTemp() >= temperature2) {
|
||||||
|
mix = 0.0;
|
||||||
|
} else {
|
||||||
|
double invT = 1.0 / wb.getTemp();
|
||||||
|
mix = (invT - (1.0 / temperature2)) / ((1.0 / temperature1) - (1.0 / temperature2));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasFwd1 || hasFwd2) {
|
||||||
|
// always prefer ForwardMatrix ahead of ColorMatrix
|
||||||
|
double mFwd[3][3];
|
||||||
|
if (hasFwd1 && hasFwd2) {
|
||||||
|
// interpolate
|
||||||
|
if (mix >= 1.0) {
|
||||||
|
memcpy(mFwd, mForwardMatrix1, sizeof(mFwd));
|
||||||
|
} else if (mix <= 0.0) {
|
||||||
|
memcpy(mFwd, mForwardMatrix2, sizeof(mFwd));
|
||||||
|
} else {
|
||||||
|
Mix3x3(mForwardMatrix1, mix, mForwardMatrix2, 1.0 - mix, mFwd);
|
||||||
|
}
|
||||||
|
} else if (hasFwd1) {
|
||||||
|
memcpy(mFwd, mForwardMatrix1, sizeof(mFwd));
|
||||||
|
} else {
|
||||||
|
memcpy(mFwd, mForwardMatrix2, sizeof(mFwd));
|
||||||
|
}
|
||||||
|
ConvertDNGForwardMatrix2XYZCAM(mFwd,mXYZCAM,wb);
|
||||||
|
} else {
|
||||||
|
// Colormatrix
|
||||||
|
double mCol[3][3];
|
||||||
|
if (hasCol1 && hasCol2) {
|
||||||
|
// interpolate
|
||||||
|
if (mix >= 1.0) {
|
||||||
|
memcpy(mCol, mColorMatrix1, sizeof(mCol));
|
||||||
|
} else if (mix <= 0.0) {
|
||||||
|
memcpy(mCol, mColorMatrix2, sizeof(mCol));
|
||||||
|
} else {
|
||||||
|
Mix3x3(mColorMatrix1, mix, mColorMatrix2, 1.0 - mix, mCol);
|
||||||
|
}
|
||||||
|
} else if (hasCol1) {
|
||||||
|
memcpy(mCol, mColorMatrix1, sizeof(mCol));
|
||||||
|
} else {
|
||||||
|
memcpy(mCol, mColorMatrix2, sizeof(mCol));
|
||||||
|
}
|
||||||
|
ConvertDNGMatrix2XYZCAM(mCol,mXYZCAM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const DCPProfile::HSBModify* DCPProfile::MakeHueSatMap(ColorTemp &wb, int preferredIlluminant, HSBModify **deleteHandle) const {
|
||||||
|
|
||||||
|
*deleteHandle = NULL;
|
||||||
|
if (!aDeltas1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!aDeltas2) {
|
||||||
|
return aDeltas1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preferredIlluminant == 1) {
|
||||||
|
return aDeltas1;
|
||||||
|
} else if (preferredIlluminant == 2) {
|
||||||
|
return aDeltas2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interpolate based on color temperature.
|
||||||
|
if (temperature1 <= 0.0 || temperature2 <= 0.0 || temperature1 == temperature2) {
|
||||||
|
return aDeltas1;
|
||||||
|
}
|
||||||
|
bool reverseOrder = temperature1 > temperature2;
|
||||||
|
double t1, t2;
|
||||||
|
if (reverseOrder) {
|
||||||
|
t1 = temperature2;
|
||||||
|
t2 = temperature1;
|
||||||
|
} else {
|
||||||
|
t1 = temperature1;
|
||||||
|
t2 = temperature2;
|
||||||
|
}
|
||||||
|
|
||||||
|
double mix;
|
||||||
|
if (wb.getTemp() <= t1) {
|
||||||
|
mix = 1.0;
|
||||||
|
} else if (wb.getTemp() >= t2) {
|
||||||
|
mix = 0.0;
|
||||||
|
} else {
|
||||||
|
double invT = 1.0 / wb.getTemp();
|
||||||
|
mix = (invT - (1.0 / t2)) / ((1.0 / t1) - (1.0 / t2));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reverseOrder) {
|
||||||
|
mix = 1.0 - mix;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mix >= 1.0) {
|
||||||
|
return aDeltas1;
|
||||||
|
} else if (mix <= 0.0) {
|
||||||
|
return aDeltas2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interpolate between the tables.
|
||||||
|
HSBModify *aDeltas = new HSBModify[DeltaInfo.iArrayCount];
|
||||||
|
*deleteHandle = aDeltas;
|
||||||
|
float w1 = (float)mix;
|
||||||
|
float w2 = 1.0f - (float)mix;
|
||||||
|
for (int i = 0; i < DeltaInfo.iArrayCount; i++) {
|
||||||
|
aDeltas[i].fHueShift = w1 * aDeltas1[i].fHueShift + w2 * aDeltas2[i].fHueShift;
|
||||||
|
aDeltas[i].fSatScale = w1 * aDeltas1[i].fSatScale + w2 * aDeltas2[i].fSatScale;
|
||||||
|
aDeltas[i].fValScale = w1 * aDeltas1[i].fValScale + w2 * aDeltas2[i].fValScale;
|
||||||
|
}
|
||||||
|
return aDeltas;
|
||||||
|
}
|
||||||
|
|
||||||
DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) {
|
DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) {
|
||||||
const int TIFFFloatSize=4;
|
const int TIFFFloatSize=4;
|
||||||
const int TagColorMatrix1=50721, TagColorMatrix2=50722, TagProfileHueSatMapDims=50937;
|
const int TagColorMatrix1=50721, TagColorMatrix2=50722, TagProfileHueSatMapDims=50937;
|
||||||
|
const int TagForwardMatrix1=50964, TagForwardMatrix2=50965;
|
||||||
const int TagProfileHueSatMapData1=50938, TagProfileHueSatMapData2=50939;
|
const int TagProfileHueSatMapData1=50938, TagProfileHueSatMapData2=50939;
|
||||||
const int TagCalibrationIlluminant1=50778, TagCalibrationIlluminant2=50779;
|
const int TagCalibrationIlluminant1=50778, TagCalibrationIlluminant2=50779;
|
||||||
const int TagProfileLookTableData=50982, TagProfileLookTableDims=50981; // ProfileLookup is the low quality variant
|
const int TagProfileLookTableData=50982, TagProfileLookTableDims=50981; // ProfileLookup is the low quality variant
|
||||||
const int TagProfileToneCurve=50940;
|
const int TagProfileToneCurve=50940;
|
||||||
|
|
||||||
aDeltas1=aDeltas2=NULL; iHueDivisions=iSatDivisions=iValDivisions=iArrayCount=0;
|
aDeltas1=aDeltas2=aLookTable=NULL;
|
||||||
|
|
||||||
FILE *pFile = safe_g_fopen(fname, "rb");
|
FILE *pFile = safe_g_fopen(fname, "rb");
|
||||||
|
|
||||||
@@ -46,47 +350,106 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) {
|
|||||||
|
|
||||||
Tag* tag = tagDir->getTag(TagCalibrationIlluminant1); iLightSource1 = (tag!=NULL ? tag->toInt(0,rtexif::SHORT) : -1);
|
Tag* tag = tagDir->getTag(TagCalibrationIlluminant1); iLightSource1 = (tag!=NULL ? tag->toInt(0,rtexif::SHORT) : -1);
|
||||||
tag = tagDir->getTag(TagCalibrationIlluminant2); iLightSource2 = (tag!=NULL ? tag->toInt(0,rtexif::SHORT) : -1);
|
tag = tagDir->getTag(TagCalibrationIlluminant2); iLightSource2 = (tag!=NULL ? tag->toInt(0,rtexif::SHORT) : -1);
|
||||||
|
temperature1 = calibrationIlluminantToTemperature(iLightSource1);
|
||||||
|
temperature2 = calibrationIlluminantToTemperature(iLightSource2);
|
||||||
|
|
||||||
bool hasSecondHueSat = tagDir->getTag(TagProfileHueSatMapData2)!=NULL; // some profiles have two matrices, but just one huesat
|
bool hasSecondHueSat = tagDir->getTag(TagProfileHueSatMapData2)!=NULL; // some profiles have two matrices, but just one huesat
|
||||||
|
|
||||||
|
// Fetch Forward Matrices, if any
|
||||||
|
hasForwardMatrix1 = false;
|
||||||
|
hasForwardMatrix2 = false;
|
||||||
|
hasColorMatrix1 = false;
|
||||||
|
hasColorMatrix2 = false;
|
||||||
|
hasToneCurve = false;
|
||||||
|
tag = tagDir->getTag(TagForwardMatrix1);
|
||||||
|
if (tag) {
|
||||||
|
hasForwardMatrix1 = true;
|
||||||
|
for (int row=0;row<3;row++) {
|
||||||
|
for (int col=0;col<3;col++) {
|
||||||
|
mForwardMatrix1[col][row]=(float)tag->toDouble((col+row*3)*8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tag = tagDir->getTag(TagForwardMatrix2);
|
||||||
|
if (tag) {
|
||||||
|
hasForwardMatrix2 = true;
|
||||||
|
for (int row=0;row<3;row++) {
|
||||||
|
for (int col=0;col<3;col++) {
|
||||||
|
mForwardMatrix2[col][row]=(float)tag->toDouble((col+row*3)*8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Color Matrix (1 is always there)
|
// Color Matrix (1 is always there)
|
||||||
tag = tagDir->getTag(TagColorMatrix1);
|
tag = tagDir->getTag(TagColorMatrix1);
|
||||||
|
if (!tag) {
|
||||||
|
// FIXME: better error handling
|
||||||
|
fprintf(stderr, "Bad DCP, no ColorMatrix1\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
hasColorMatrix1 = true;
|
||||||
|
|
||||||
for (int row=0;row<3;row++) {
|
for (int row=0;row<3;row++) {
|
||||||
for (int col=0;col<3;col++) {
|
for (int col=0;col<3;col++) {
|
||||||
mColorMatrix1[col][row]=(float)tag->toDouble((col+row*3)*8);
|
mColorMatrix1[col][row]=(float)tag->toDouble((col+row*3)*8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ConvertDNGMatrix2XYZCAM(mColorMatrix1,mXYZCAM1);
|
|
||||||
|
|
||||||
// LUT profile? Divisions counts
|
tag=tagDir->getTag(TagProfileLookTableDims);
|
||||||
bool useSimpleLookup=false;
|
if (tag!=NULL) {
|
||||||
tag = tagDir->getTag(TagProfileHueSatMapDims);
|
LookInfo.iHueDivisions=tag->toInt(0); LookInfo.iSatDivisions=tag->toInt(4); LookInfo.iValDivisions=tag->toInt(8);
|
||||||
if (tag==NULL) {
|
|
||||||
tag=tagDir->getTag(TagProfileLookTableDims);
|
tag = tagDir->getTag(TagProfileLookTableData);
|
||||||
useSimpleLookup=true;
|
LookInfo.iArrayCount = tag->getCount()/3;
|
||||||
|
|
||||||
|
aLookTable =new HSBModify[LookInfo.iArrayCount];
|
||||||
|
|
||||||
|
for (int i=0;i<LookInfo.iArrayCount;i++) {
|
||||||
|
aLookTable[i].fHueShift=tag->toDouble((i*3)*TIFFFloatSize);
|
||||||
|
aLookTable[i].fSatScale=tag->toDouble((i*3+1)*TIFFFloatSize);
|
||||||
|
aLookTable[i].fValScale=tag->toDouble((i*3+2)*TIFFFloatSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// precalculated constants for table application
|
||||||
|
LookInfo.pc.hScale = (LookInfo.iHueDivisions < 2) ? 0.0f : (LookInfo.iHueDivisions * (1.0f / 6.0f));
|
||||||
|
LookInfo.pc.sScale = (float) (LookInfo.iSatDivisions - 1);
|
||||||
|
LookInfo.pc.vScale = (float) (LookInfo.iValDivisions - 1);
|
||||||
|
LookInfo.pc.maxHueIndex0 = LookInfo.iHueDivisions - 1;
|
||||||
|
LookInfo.pc.maxSatIndex0 = LookInfo.iSatDivisions - 2;
|
||||||
|
LookInfo.pc.maxValIndex0 = LookInfo.iValDivisions - 2;
|
||||||
|
LookInfo.pc.hueStep = LookInfo.iSatDivisions;
|
||||||
|
LookInfo.pc.valStep = LookInfo.iHueDivisions * LookInfo.pc.hueStep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tag = tagDir->getTag(TagProfileHueSatMapDims);
|
||||||
if (tag!=NULL) {
|
if (tag!=NULL) {
|
||||||
iHueDivisions=tag->toInt(0); iSatDivisions=tag->toInt(4); iValDivisions=tag->toInt(8);
|
DeltaInfo.iHueDivisions=tag->toInt(0); DeltaInfo.iSatDivisions=tag->toInt(4); DeltaInfo.iValDivisions=tag->toInt(8);
|
||||||
|
|
||||||
// Saturation maps. Need to be unwinded.
|
tag = tagDir->getTag(TagProfileHueSatMapData1);
|
||||||
tag = tagDir->getTag(useSimpleLookup ? TagProfileLookTableData : TagProfileHueSatMapData1);
|
DeltaInfo.iArrayCount = tag->getCount()/3;
|
||||||
iArrayCount = tag->getCount()/3;
|
|
||||||
|
|
||||||
aDeltas1=new HSBModify[iArrayCount];
|
aDeltas1=new HSBModify[DeltaInfo.iArrayCount];
|
||||||
|
|
||||||
for (int i=0;i<iArrayCount;i++) {
|
for (int i=0;i<DeltaInfo.iArrayCount;i++) {
|
||||||
aDeltas1[i].fHueShift=tag->toDouble((i*3)*TIFFFloatSize);
|
aDeltas1[i].fHueShift=tag->toDouble((i*3)*TIFFFloatSize);
|
||||||
aDeltas1[i].fSatScale=tag->toDouble((i*3+1)*TIFFFloatSize);
|
aDeltas1[i].fSatScale=tag->toDouble((i*3+1)*TIFFFloatSize);
|
||||||
aDeltas1[i].fValScale=tag->toDouble((i*3+2)*TIFFFloatSize);
|
aDeltas1[i].fValScale=tag->toDouble((i*3+2)*TIFFFloatSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeltaInfo.pc.hScale = (DeltaInfo.iHueDivisions < 2) ? 0.0f : (DeltaInfo.iHueDivisions * (1.0f / 6.0f));
|
||||||
|
DeltaInfo.pc.sScale = (float) (DeltaInfo.iSatDivisions - 1);
|
||||||
|
DeltaInfo.pc.vScale = (float) (DeltaInfo.iValDivisions - 1);
|
||||||
|
DeltaInfo.pc.maxHueIndex0 = DeltaInfo.iHueDivisions - 1;
|
||||||
|
DeltaInfo.pc.maxSatIndex0 = DeltaInfo.iSatDivisions - 2;
|
||||||
|
DeltaInfo.pc.maxValIndex0 = DeltaInfo.iValDivisions - 2;
|
||||||
|
DeltaInfo.pc.hueStep = DeltaInfo.iSatDivisions;
|
||||||
|
DeltaInfo.pc.valStep = DeltaInfo.iHueDivisions * DeltaInfo.pc.hueStep;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For second profile, copy everything from first profile is no better data is available
|
|
||||||
if (iLightSource2!=-1) {
|
if (iLightSource2!=-1) {
|
||||||
// Second matrix
|
// Second matrix
|
||||||
tag = tagDir->getTag(TagColorMatrix2);
|
tag = tagDir->getTag(TagColorMatrix2);
|
||||||
|
hasColorMatrix2 = true;
|
||||||
|
|
||||||
for (int row=0;row<3;row++) {
|
for (int row=0;row<3;row++) {
|
||||||
for (int col=0;col<3;col++) {
|
for (int col=0;col<3;col++) {
|
||||||
@@ -94,25 +457,18 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConvertDNGMatrix2XYZCAM(mColorMatrix2,mXYZCAM2);
|
// Second huesatmap
|
||||||
|
|
||||||
// Second huesatmap, or copy of first
|
|
||||||
if (hasSecondHueSat) {
|
if (hasSecondHueSat) {
|
||||||
aDeltas2=new HSBModify[iArrayCount];
|
aDeltas2=new HSBModify[DeltaInfo.iArrayCount];
|
||||||
|
|
||||||
// Saturation maps. Need to be unwinded.
|
// Saturation maps. Need to be unwinded.
|
||||||
tag = tagDir->getTag(TagProfileHueSatMapData2);
|
tag = tagDir->getTag(TagProfileHueSatMapData2);
|
||||||
|
|
||||||
for (int i=0;i<iArrayCount;i++) {
|
for (int i=0;i<DeltaInfo.iArrayCount;i++) {
|
||||||
aDeltas2[i].fHueShift=tag->toDouble((i*3)*TIFFFloatSize);
|
aDeltas2[i].fHueShift=tag->toDouble((i*3)*TIFFFloatSize);
|
||||||
aDeltas2[i].fSatScale=tag->toDouble((i*3+1)*TIFFFloatSize);
|
aDeltas2[i].fSatScale=tag->toDouble((i*3+1)*TIFFFloatSize);
|
||||||
aDeltas2[i].fValScale=tag->toDouble((i*3+2)*TIFFFloatSize);
|
aDeltas2[i].fValScale=tag->toDouble((i*3+2)*TIFFFloatSize);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (aDeltas1!=NULL) {
|
|
||||||
aDeltas2=new HSBModify[iArrayCount];
|
|
||||||
for (int i=0;i<iArrayCount;i++) aDeltas2[i]=aDeltas1[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,12 +480,45 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) {
|
|||||||
cPoints.push_back(double(DCT_Spline)); // The first value is the curve type
|
cPoints.push_back(double(DCT_Spline)); // The first value is the curve type
|
||||||
|
|
||||||
// push back each X/Y coordinates in a loop
|
// push back each X/Y coordinates in a loop
|
||||||
for (int i=0;i<tag->getCount();i++) cPoints.push_back( tag->toDouble(i*TIFFFloatSize) );
|
bool curve_is_linear = true;
|
||||||
|
for (int i=0;i<tag->getCount(); i+= 2) {
|
||||||
|
double x = tag->toDouble((i+0)*TIFFFloatSize);
|
||||||
|
double y = tag->toDouble((i+1)*TIFFFloatSize);
|
||||||
|
if (x != y) {
|
||||||
|
curve_is_linear = false;
|
||||||
|
}
|
||||||
|
cPoints.push_back( x );
|
||||||
|
cPoints.push_back( y );
|
||||||
|
}
|
||||||
|
|
||||||
// Create the curve
|
if (!curve_is_linear) {
|
||||||
DiagonalCurve rawCurve(cPoints, CURVES_MIN_POLY_POINTS);
|
// Create the curve
|
||||||
|
DiagonalCurve rawCurve(cPoints, CURVES_MIN_POLY_POINTS);
|
||||||
|
|
||||||
toneCurve.Set((Curve*)&rawCurve);
|
toneCurve.Set((Curve*)&rawCurve);
|
||||||
|
hasToneCurve = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
willInterpolate = false;
|
||||||
|
if (hasForwardMatrix1) {
|
||||||
|
if (hasForwardMatrix2) {
|
||||||
|
if (memcmp(mForwardMatrix1, mForwardMatrix2, sizeof(mForwardMatrix1)) != 0) {
|
||||||
|
// common that forward matrices are the same!
|
||||||
|
willInterpolate = true;
|
||||||
|
}
|
||||||
|
if (aDeltas1 && aDeltas2) {
|
||||||
|
// we assume tables are different
|
||||||
|
willInterpolate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (hasColorMatrix1 && hasColorMatrix2) {
|
||||||
|
if (memcmp(mColorMatrix1, mColorMatrix2, sizeof(mColorMatrix1)) != 0) {
|
||||||
|
willInterpolate = true;
|
||||||
|
}
|
||||||
|
if (aDeltas1 && aDeltas2) {
|
||||||
|
willInterpolate = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pFile!=NULL) fclose(pFile);
|
if (pFile!=NULL) fclose(pFile);
|
||||||
@@ -141,7 +530,7 @@ DCPProfile::~DCPProfile() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert DNG color matrix to xyz_cam compatible matrix
|
// Convert DNG color matrix to xyz_cam compatible matrix
|
||||||
void DCPProfile::ConvertDNGMatrix2XYZCAM(const double (*mColorMatrix)[3], double (*mXYZCAM)[3]) {
|
void DCPProfile::ConvertDNGMatrix2XYZCAM(const double (*mColorMatrix)[3], double (*mXYZCAM)[3]) const {
|
||||||
int i,j,k;
|
int i,j,k;
|
||||||
|
|
||||||
double cam_xyz[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
double cam_xyz[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
||||||
@@ -177,60 +566,181 @@ void DCPProfile::ConvertDNGMatrix2XYZCAM(const double (*mColorMatrix)[3], double
|
|||||||
mXYZCAM[i][j] += xyz_sRGB[i][k] * rgb_cam[k][j];
|
mXYZCAM[i][j] += xyz_sRGB[i][k] * rgb_cam[k][j];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DCPProfile::HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, const float hs, const float ss, const float vs, float &h, float &s, float &v) const {
|
||||||
|
|
||||||
const DCPProfile::HSBModify* DCPProfile::GetBestProfile(DCPLightType preferredProfile, double (*mXYZCAM)[3]) const {
|
// Apply the HueSatMap. Ported from Adobes reference implementation
|
||||||
bool use2=false;
|
float hueShift, satScale, valScale;
|
||||||
|
|
||||||
if (iLightSource2!=-1) {
|
if (ti.iValDivisions < 2) // Optimize most common case of "2.5D" table.
|
||||||
DCPLightType t1=GetLightType(iLightSource1); DCPLightType t2=GetLightType(iLightSource2);
|
{
|
||||||
|
float hScaled = hs * ti.pc.hScale;
|
||||||
|
float sScaled = ss * ti.pc.sScale;
|
||||||
|
|
||||||
// usually second is the daylight (default if nothing else found)
|
int hIndex0 = max((int)hScaled, 0);
|
||||||
if (t2==Daylight) use2=true;
|
int sIndex0 = max(min((int)sScaled,ti.pc.maxSatIndex0),0);
|
||||||
|
|
||||||
switch (preferredProfile) {
|
int hIndex1 = hIndex0 + 1;
|
||||||
case Tungsten:
|
|
||||||
if (t1==Tungsten) use2=false; else if (t2==Tungsten) use2=true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Fluorescent:
|
if (hIndex0 >= ti.pc.maxHueIndex0)
|
||||||
if (t1==Fluorescent) use2=false; else if (t2==Fluorescent) use2=true;
|
{
|
||||||
break;
|
hIndex0 = ti.pc.maxHueIndex0;
|
||||||
|
hIndex1 = 0;
|
||||||
case Flash:
|
|
||||||
if (t1==Flash) use2=false; else if (t2==Flash) use2=true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: break; // e.g. Daylight
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float hFract1 = hScaled - (float) hIndex0;
|
||||||
|
float sFract1 = sScaled - (float) sIndex0;
|
||||||
|
|
||||||
|
float hFract0 = 1.0f - hFract1;
|
||||||
|
float sFract0 = 1.0f - sFract1;
|
||||||
|
|
||||||
|
const HSBModify *entry00 = tableBase + hIndex0 * ti.pc.hueStep + sIndex0;
|
||||||
|
const HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * ti.pc.hueStep;
|
||||||
|
|
||||||
|
float hueShift0 = hFract0 * entry00->fHueShift + hFract1 * entry01->fHueShift;
|
||||||
|
float satScale0 = hFract0 * entry00->fSatScale + hFract1 * entry01->fSatScale;
|
||||||
|
float valScale0 = hFract0 * entry00->fValScale + hFract1 * entry01->fValScale;
|
||||||
|
|
||||||
|
entry00++;
|
||||||
|
entry01++;
|
||||||
|
|
||||||
|
float hueShift1 = hFract0 * entry00->fHueShift +
|
||||||
|
hFract1 * entry01->fHueShift;
|
||||||
|
|
||||||
|
float satScale1 = hFract0 * entry00->fSatScale +
|
||||||
|
hFract1 * entry01->fSatScale;
|
||||||
|
|
||||||
|
float valScale1 = hFract0 * entry00->fValScale +
|
||||||
|
hFract1 * entry01->fValScale;
|
||||||
|
|
||||||
|
hueShift = sFract0 * hueShift0 + sFract1 * hueShift1;
|
||||||
|
satScale = sFract0 * satScale0 + sFract1 * satScale1;
|
||||||
|
valScale = sFract0 * valScale0 + sFract1 * valScale1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
float hScaled = hs * ti.pc.hScale;
|
||||||
|
float sScaled = ss * ti.pc.sScale;
|
||||||
|
float vScaled = vs * ti.pc.vScale;
|
||||||
|
|
||||||
|
int hIndex0 = (int) hScaled;
|
||||||
|
int sIndex0 = max(min((int)sScaled,ti.pc.maxSatIndex0),0);
|
||||||
|
int vIndex0 = max(min((int)vScaled,ti.pc.maxValIndex0),0);
|
||||||
|
|
||||||
|
int hIndex1 = hIndex0 + 1;
|
||||||
|
|
||||||
|
if (hIndex0 >= ti.pc.maxHueIndex0)
|
||||||
|
{
|
||||||
|
hIndex0 = ti.pc.maxHueIndex0;
|
||||||
|
hIndex1 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float hFract1 = hScaled - (float) hIndex0;
|
||||||
|
float sFract1 = sScaled - (float) sIndex0;
|
||||||
|
float vFract1 = vScaled - (float) vIndex0;
|
||||||
|
|
||||||
|
float hFract0 = 1.0f - hFract1;
|
||||||
|
float sFract0 = 1.0f - sFract1;
|
||||||
|
float vFract0 = 1.0f - vFract1;
|
||||||
|
|
||||||
|
const HSBModify *entry00 = tableBase + vIndex0 * ti.pc.valStep + hIndex0 * ti.pc.hueStep + sIndex0;
|
||||||
|
|
||||||
|
const HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * ti.pc.hueStep;
|
||||||
|
|
||||||
|
const HSBModify *entry10 = entry00 + ti.pc.valStep;
|
||||||
|
const HSBModify *entry11 = entry01 + ti.pc.valStep;
|
||||||
|
|
||||||
|
float hueShift0 = vFract0 * (hFract0 * entry00->fHueShift +
|
||||||
|
hFract1 * entry01->fHueShift) +
|
||||||
|
vFract1 * (hFract0 * entry10->fHueShift +
|
||||||
|
hFract1 * entry11->fHueShift);
|
||||||
|
|
||||||
|
float satScale0 = vFract0 * (hFract0 * entry00->fSatScale +
|
||||||
|
hFract1 * entry01->fSatScale) +
|
||||||
|
vFract1 * (hFract0 * entry10->fSatScale +
|
||||||
|
hFract1 * entry11->fSatScale);
|
||||||
|
|
||||||
|
float valScale0 = vFract0 * (hFract0 * entry00->fValScale +
|
||||||
|
hFract1 * entry01->fValScale) +
|
||||||
|
vFract1 * (hFract0 * entry10->fValScale +
|
||||||
|
hFract1 * entry11->fValScale);
|
||||||
|
|
||||||
|
entry00++;
|
||||||
|
entry01++;
|
||||||
|
entry10++;
|
||||||
|
entry11++;
|
||||||
|
|
||||||
|
float hueShift1 = vFract0 * (hFract0 * entry00->fHueShift +
|
||||||
|
hFract1 * entry01->fHueShift) +
|
||||||
|
vFract1 * (hFract0 * entry10->fHueShift +
|
||||||
|
hFract1 * entry11->fHueShift);
|
||||||
|
|
||||||
|
float satScale1 = vFract0 * (hFract0 * entry00->fSatScale +
|
||||||
|
hFract1 * entry01->fSatScale) +
|
||||||
|
vFract1 * (hFract0 * entry10->fSatScale +
|
||||||
|
hFract1 * entry11->fSatScale);
|
||||||
|
|
||||||
|
float valScale1 = vFract0 * (hFract0 * entry00->fValScale +
|
||||||
|
hFract1 * entry01->fValScale) +
|
||||||
|
vFract1 * (hFract0 * entry10->fValScale +
|
||||||
|
hFract1 * entry11->fValScale);
|
||||||
|
|
||||||
|
hueShift = sFract0 * hueShift0 + sFract1 * hueShift1;
|
||||||
|
satScale = sFract0 * satScale0 + sFract1 * satScale1;
|
||||||
|
valScale = sFract0 * valScale0 + sFract1 * valScale1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// printf("DCP using LightSource %i: %i for requested %i\n", use2?2:1, use2?iLightSource2:iLightSource1, (int)preferredProfile);
|
hueShift *= (6.0f / 360.0f); // Convert to internal hue range.
|
||||||
|
|
||||||
for (int row=0;row<3;row++) {
|
h += hueShift;
|
||||||
for (int col=0;col<3;col++) {
|
s *= satScale; // no clipping here, we are RT float :-)
|
||||||
mXYZCAM[col][row]= (use2 ? mXYZCAM2[col][row] : mXYZCAM1[col][row]);
|
v *= valScale;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return use2?aDeltas2:aDeltas1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DCPLightType DCPProfile::GetLightType(short iLightSource) const {
|
// Convert DNG forward matrix to xyz_cam compatible matrix
|
||||||
if (iLightSource==3 || iLightSource==17 || iLightSource==24) return Tungsten;
|
void DCPProfile::ConvertDNGForwardMatrix2XYZCAM(const double (*mForwardMatrix)[3], double (*mXYZCAM)[3], ColorTemp &wb) const {
|
||||||
if (iLightSource==2 || (iLightSource>=12 && iLightSource<=15)) return Fluorescent;
|
|
||||||
if (iLightSource==4) return Flash;
|
// Convert ForwardMatrix (white-balanced CameraRGB -> XYZ D50 matrix)
|
||||||
return Daylight;
|
// into a ColorMatrix (XYZ -> CameraRGB)
|
||||||
|
|
||||||
|
double X, Z;
|
||||||
|
ColorTemp::temp2mulxyz(wb.getTemp(), wb.getGreen(), wb.getMethod(), X, Z);
|
||||||
|
|
||||||
|
const double white_xyz[3] = { X, 1, Z };
|
||||||
|
const double white_d50[3] = { 0.3457, 0.3585, 0.2958 }; // D50
|
||||||
|
|
||||||
|
// Cancel out the white balance to get a CameraRGB -> XYZ D50 matrixx (CameraToPCS in dng terminology)
|
||||||
|
double whiteDiag[3][3] = {{white_xyz[0], 0, 0}, {0, white_xyz[1], 0}, {0, 0, white_xyz[2]}};
|
||||||
|
double whiteDiagInv[3][3];
|
||||||
|
Invert3x3(whiteDiag, whiteDiagInv);
|
||||||
|
double rgb2xyzD50[3][3];
|
||||||
|
Multiply3x3(mForwardMatrix, whiteDiagInv, rgb2xyzD50);
|
||||||
|
|
||||||
|
// Through chromatic adaptation convert XYZ D50 to XYZ camera white
|
||||||
|
double whiteMatrix[3][3];
|
||||||
|
MapWhiteMatrix(white_d50, white_xyz, whiteMatrix);
|
||||||
|
double rgb2xyz[3][3];
|
||||||
|
Multiply3x3(rgb2xyzD50, whiteMatrix, rgb2xyz);
|
||||||
|
|
||||||
|
// Now we have CameraRGB -> XYZ, invert so we get XYZ -> CameraRGB (ColorMatrix format)
|
||||||
|
double dngColorMatrix[3][3];
|
||||||
|
Invert3x3(rgb2xyz, dngColorMatrix);
|
||||||
|
|
||||||
|
// now we can run the ordinary ColorMatrix conversion
|
||||||
|
ConvertDNGMatrix2XYZCAM(dngColorMatrix, mXYZCAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DCPProfile::Apply(Imagefloat *pImg, DCPLightType preferredProfile, Glib::ustring workingSpace, float rawWhiteFac, bool useToneCurve) const {
|
void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, float rawWhiteFac, bool useToneCurve) const {
|
||||||
|
|
||||||
TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace);
|
TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace);
|
||||||
|
|
||||||
double mXYZCAM[3][3];
|
double mXYZCAM[3][3];
|
||||||
const HSBModify* tableBase=GetBestProfile(preferredProfile,mXYZCAM);
|
MakeXYZCAM(wb, preferredIlluminant, mXYZCAM);
|
||||||
|
HSBModify *deleteTableHandle;
|
||||||
|
const HSBModify *deltaBase = MakeHueSatMap(wb, preferredIlluminant, &deleteTableHandle);
|
||||||
|
|
||||||
bool hasLUT=(iArrayCount>0); useToneCurve&=toneCurve;
|
useToneCurve&=toneCurve;
|
||||||
|
|
||||||
if (!hasLUT && !useToneCurve) {
|
if (deltaBase == NULL && aLookTable == NULL && !useToneCurve) {
|
||||||
//===== The fast path: no LUT and not tone curve- Calculate matrix for direct conversion raw>working space
|
//===== The fast path: no LUT and not tone curve- Calculate matrix for direct conversion raw>working space
|
||||||
double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
|
||||||
for (int i=0; i<3; i++)
|
for (int i=0; i<3; i++)
|
||||||
@@ -265,18 +775,6 @@ void DCPProfile::Apply(Imagefloat *pImg, DCPLightType preferredProfile, Glib::us
|
|||||||
for (int k=0; k<3; k++)
|
for (int k=0; k<3; k++)
|
||||||
m2Work[i][j] += mWork[i][k] * xyz_prophoto[k][j];
|
m2Work[i][j] += mWork[i][k] * xyz_prophoto[k][j];
|
||||||
|
|
||||||
// Preperations for LUT
|
|
||||||
float hScale = (iHueDivisions < 2) ? 0.0f : (iHueDivisions * (1.0f / 6.0f));
|
|
||||||
float sScale = (float) (iSatDivisions - 1);
|
|
||||||
float vScale = (float) (iValDivisions - 1);
|
|
||||||
|
|
||||||
int maxHueIndex0 = iHueDivisions - 1;
|
|
||||||
int maxSatIndex0 = iSatDivisions - 2;
|
|
||||||
int maxValIndex0 = iValDivisions - 2;
|
|
||||||
|
|
||||||
int hueStep = iSatDivisions;
|
|
||||||
int valStep = iHueDivisions * hueStep;
|
|
||||||
|
|
||||||
bool useRawWhite=fabs(rawWhiteFac)>0.001;
|
bool useRawWhite=fabs(rawWhiteFac)>0.001;
|
||||||
|
|
||||||
// Convert to prophoto and apply LUT
|
// Convert to prophoto and apply LUT
|
||||||
@@ -289,7 +787,7 @@ void DCPProfile::Apply(Imagefloat *pImg, DCPLightType preferredProfile, Glib::us
|
|||||||
newb = m2ProPhoto[2][0]*pImg->r(y,x) + m2ProPhoto[2][1]*pImg->g(y,x) + m2ProPhoto[2][2]*pImg->b(y,x);
|
newb = m2ProPhoto[2][0]*pImg->r(y,x) + m2ProPhoto[2][1]*pImg->g(y,x) + m2ProPhoto[2][2]*pImg->b(y,x);
|
||||||
|
|
||||||
// if point is in negative area, just the matrix, but not the LUT
|
// if point is in negative area, just the matrix, but not the LUT
|
||||||
if (hasLUT && newr>=0 && newg>=0 && newb>=0) {
|
if ((deltaBase || aLookTable) && newr>=0 && newg>=0 && newb>=0) {
|
||||||
Color::rgb2hsv(newr, newg, newb, h , s, v);
|
Color::rgb2hsv(newr, newg, newb, h , s, v);
|
||||||
h*=6.f; // RT calculates in [0,1]
|
h*=6.f; // RT calculates in [0,1]
|
||||||
|
|
||||||
@@ -301,141 +799,12 @@ void DCPProfile::Apply(Imagefloat *pImg, DCPLightType preferredProfile, Glib::us
|
|||||||
hs=h; ss=s; vs=v;
|
hs=h; ss=s; vs=v;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the HueSatMap. Ported from Adobes reference implementation
|
if (deltaBase) {
|
||||||
float hueShift, satScale, valScale;
|
HSDApply(DeltaInfo, deltaBase, hs, ss, vs, h, s, v);
|
||||||
|
}
|
||||||
if (iValDivisions < 2) // Optimize most common case of "2.5D" table.
|
if (aLookTable) {
|
||||||
{
|
HSDApply(LookInfo, aLookTable, hs, ss, vs, h, s, v);
|
||||||
float hScaled = hs * hScale;
|
|
||||||
float sScaled = ss * sScale;
|
|
||||||
|
|
||||||
int hIndex0 = max((int)hScaled, 0);
|
|
||||||
int sIndex0 = max(min((int)sScaled,maxSatIndex0),0);
|
|
||||||
|
|
||||||
int hIndex1 = hIndex0 + 1;
|
|
||||||
|
|
||||||
if (hIndex0 >= maxHueIndex0)
|
|
||||||
{
|
|
||||||
hIndex0 = maxHueIndex0;
|
|
||||||
hIndex1 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float hFract1 = hScaled - (float) hIndex0;
|
|
||||||
float sFract1 = sScaled - (float) sIndex0;
|
|
||||||
|
|
||||||
float hFract0 = 1.0f - hFract1;
|
|
||||||
float sFract0 = 1.0f - sFract1;
|
|
||||||
|
|
||||||
const HSBModify *entry00 = tableBase + hIndex0 * hueStep +
|
|
||||||
sIndex0;
|
|
||||||
|
|
||||||
const HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * hueStep;
|
|
||||||
|
|
||||||
float hueShift0 = hFract0 * entry00->fHueShift +
|
|
||||||
hFract1 * entry01->fHueShift;
|
|
||||||
|
|
||||||
float satScale0 = hFract0 * entry00->fSatScale +
|
|
||||||
hFract1 * entry01->fSatScale;
|
|
||||||
|
|
||||||
float valScale0 = hFract0 * entry00->fValScale +
|
|
||||||
hFract1 * entry01->fValScale;
|
|
||||||
|
|
||||||
entry00++;
|
|
||||||
entry01++;
|
|
||||||
|
|
||||||
float hueShift1 = hFract0 * entry00->fHueShift +
|
|
||||||
hFract1 * entry01->fHueShift;
|
|
||||||
|
|
||||||
float satScale1 = hFract0 * entry00->fSatScale +
|
|
||||||
hFract1 * entry01->fSatScale;
|
|
||||||
|
|
||||||
float valScale1 = hFract0 * entry00->fValScale +
|
|
||||||
hFract1 * entry01->fValScale;
|
|
||||||
|
|
||||||
hueShift = sFract0 * hueShift0 + sFract1 * hueShift1;
|
|
||||||
satScale = sFract0 * satScale0 + sFract1 * satScale1;
|
|
||||||
valScale = sFract0 * valScale0 + sFract1 * valScale1;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
float hScaled = hs * hScale;
|
|
||||||
float sScaled = ss * sScale;
|
|
||||||
float vScaled = vs * vScale;
|
|
||||||
|
|
||||||
int hIndex0 = (int) hScaled;
|
|
||||||
int sIndex0 = max(min((int)sScaled,maxSatIndex0),0);
|
|
||||||
int vIndex0 = max(min((int)vScaled,maxValIndex0),0);
|
|
||||||
|
|
||||||
int hIndex1 = hIndex0 + 1;
|
|
||||||
|
|
||||||
if (hIndex0 >= maxHueIndex0)
|
|
||||||
{
|
|
||||||
hIndex0 = maxHueIndex0;
|
|
||||||
hIndex1 = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
float hFract1 = hScaled - (float) hIndex0;
|
|
||||||
float sFract1 = sScaled - (float) sIndex0;
|
|
||||||
float vFract1 = vScaled - (float) vIndex0;
|
|
||||||
|
|
||||||
float hFract0 = 1.0f - hFract1;
|
|
||||||
float sFract0 = 1.0f - sFract1;
|
|
||||||
float vFract0 = 1.0f - vFract1;
|
|
||||||
|
|
||||||
const HSBModify *entry00 = tableBase + vIndex0 * valStep +
|
|
||||||
hIndex0 * hueStep +
|
|
||||||
sIndex0;
|
|
||||||
|
|
||||||
const HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * hueStep;
|
|
||||||
|
|
||||||
const HSBModify *entry10 = entry00 + valStep;
|
|
||||||
const HSBModify *entry11 = entry01 + valStep;
|
|
||||||
|
|
||||||
float hueShift0 = vFract0 * (hFract0 * entry00->fHueShift +
|
|
||||||
hFract1 * entry01->fHueShift) +
|
|
||||||
vFract1 * (hFract0 * entry10->fHueShift +
|
|
||||||
hFract1 * entry11->fHueShift);
|
|
||||||
|
|
||||||
float satScale0 = vFract0 * (hFract0 * entry00->fSatScale +
|
|
||||||
hFract1 * entry01->fSatScale) +
|
|
||||||
vFract1 * (hFract0 * entry10->fSatScale +
|
|
||||||
hFract1 * entry11->fSatScale);
|
|
||||||
|
|
||||||
float valScale0 = vFract0 * (hFract0 * entry00->fValScale +
|
|
||||||
hFract1 * entry01->fValScale) +
|
|
||||||
vFract1 * (hFract0 * entry10->fValScale +
|
|
||||||
hFract1 * entry11->fValScale);
|
|
||||||
|
|
||||||
entry00++;
|
|
||||||
entry01++;
|
|
||||||
entry10++;
|
|
||||||
entry11++;
|
|
||||||
|
|
||||||
float hueShift1 = vFract0 * (hFract0 * entry00->fHueShift +
|
|
||||||
hFract1 * entry01->fHueShift) +
|
|
||||||
vFract1 * (hFract0 * entry10->fHueShift +
|
|
||||||
hFract1 * entry11->fHueShift);
|
|
||||||
|
|
||||||
float satScale1 = vFract0 * (hFract0 * entry00->fSatScale +
|
|
||||||
hFract1 * entry01->fSatScale) +
|
|
||||||
vFract1 * (hFract0 * entry10->fSatScale +
|
|
||||||
hFract1 * entry11->fSatScale);
|
|
||||||
|
|
||||||
float valScale1 = vFract0 * (hFract0 * entry00->fValScale +
|
|
||||||
hFract1 * entry01->fValScale) +
|
|
||||||
vFract1 * (hFract0 * entry10->fValScale +
|
|
||||||
hFract1 * entry11->fValScale);
|
|
||||||
|
|
||||||
hueShift = sFract0 * hueShift0 + sFract1 * hueShift1;
|
|
||||||
satScale = sFract0 * satScale0 + sFract1 * satScale1;
|
|
||||||
valScale = sFract0 * valScale0 + sFract1 * valScale1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hueShift *= (6.0f / 360.0f); // Convert to internal hue range.
|
|
||||||
|
|
||||||
h += hueShift;
|
|
||||||
s *= satScale; // no clipping here, we are RT float :-)
|
|
||||||
v *= valScale;
|
|
||||||
|
|
||||||
// RT range correction
|
// RT range correction
|
||||||
if (h < 0.0f) h += 6.0f;
|
if (h < 0.0f) h += 6.0f;
|
||||||
@@ -453,14 +822,16 @@ void DCPProfile::Apply(Imagefloat *pImg, DCPLightType preferredProfile, Glib::us
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deleteTableHandle) delete deleteTableHandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Integer variant is legacy, only used for thumbs. Simply take the matrix here
|
// Integer variant is legacy, only used for thumbs. Simply take the matrix here
|
||||||
void DCPProfile::Apply(Image16 *pImg, DCPLightType preferredProfile, Glib::ustring workingSpace, bool useToneCurve) const {
|
void DCPProfile::Apply(Image16 *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, bool useToneCurve) const {
|
||||||
TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace);
|
TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace);
|
||||||
|
|
||||||
double mXYZCAM[3][3];
|
double mXYZCAM[3][3];
|
||||||
// unused //const HSBModify* tableBase=GetBestProfile(preferredProfile,mXYZCAM);
|
MakeXYZCAM(wb, preferredIlluminant, mXYZCAM);
|
||||||
|
|
||||||
useToneCurve&=toneCurve;
|
useToneCurve&=toneCurve;
|
||||||
|
|
||||||
|
@@ -22,15 +22,13 @@
|
|||||||
|
|
||||||
#include "imagefloat.h"
|
#include "imagefloat.h"
|
||||||
#include "curves.h"
|
#include "curves.h"
|
||||||
|
#include "colortemp.h"
|
||||||
#include "../rtgui/threadutils.h"
|
#include "../rtgui/threadutils.h"
|
||||||
#include <glibmm.h>
|
#include <glibmm.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace rtengine {
|
namespace rtengine {
|
||||||
enum DCPLightType {
|
|
||||||
Daylight=1, Tungsten=2, Fluorescent=3, Flash=4
|
|
||||||
};
|
|
||||||
|
|
||||||
class DCPProfile {
|
class DCPProfile {
|
||||||
struct HSBModify
|
struct HSBModify
|
||||||
@@ -39,30 +37,42 @@ namespace rtengine {
|
|||||||
float fSatScale;
|
float fSatScale;
|
||||||
float fValScale;
|
float fValScale;
|
||||||
};
|
};
|
||||||
|
struct HSDTableInfo
|
||||||
|
{
|
||||||
|
int iHueDivisions, iSatDivisions, iValDivisions;
|
||||||
|
int iHueStep, iValStep, iArrayCount;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
float hScale, sScale, vScale;
|
||||||
|
int maxHueIndex0, maxSatIndex0, maxValIndex0;
|
||||||
|
int hueStep, valStep;
|
||||||
|
} pc;
|
||||||
|
};
|
||||||
|
|
||||||
double mColorMatrix1[3][3],mColorMatrix2[3][3];
|
double mColorMatrix1[3][3],mColorMatrix2[3][3];
|
||||||
double mXYZCAM1[3][3],mXYZCAM2[3][3]; // compatible to RTs xyz_cam
|
bool hasColorMatrix1, hasColorMatrix2, hasForwardMatrix1, hasForwardMatrix2, hasToneCurve, willInterpolate;
|
||||||
HSBModify *aDeltas1,*aDeltas2;
|
double mForwardMatrix1[3][3],mForwardMatrix2[3][3];
|
||||||
|
double temperature1, temperature2;
|
||||||
|
HSBModify *aDeltas1,*aDeltas2,*aLookTable;
|
||||||
|
HSDTableInfo DeltaInfo,LookInfo;
|
||||||
short iLightSource1,iLightSource2;
|
short iLightSource1,iLightSource2;
|
||||||
|
|
||||||
int iHueDivisions, iSatDivisions, iValDivisions;
|
|
||||||
|
|
||||||
int iHueStep, iValStep, iArrayCount;
|
|
||||||
|
|
||||||
AdobeToneCurve toneCurve;
|
AdobeToneCurve toneCurve;
|
||||||
|
|
||||||
void ConvertDNGMatrix2XYZCAM(const double (*mColorMatrix)[3], double (*mXYZCAM)[3]);
|
void MakeXYZCAM(ColorTemp &wb, int preferredIlluminant, double (*mXYZCAM)[3]) const;
|
||||||
|
const HSBModify* MakeHueSatMap(ColorTemp &wb, int preferredIlluminant, HSBModify **deleteHandle) const;
|
||||||
const HSBModify* GetBestProfile(DCPLightType preferredProfile, double (*mXYZCAM)[3]) const;
|
void ConvertDNGMatrix2XYZCAM(const double (*mColorMatrix)[3], double (*mXYZCAM)[3]) const;
|
||||||
|
void ConvertDNGForwardMatrix2XYZCAM(const double (*mForwardMatrix)[3], double (*mXYZCAM)[3], ColorTemp &wb) const;
|
||||||
DCPLightType GetLightType(short iLightSource) const;
|
void HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, const float hs, const float ss, const float vs, float &h, float &s, float &v) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DCPProfile(Glib::ustring fname, bool isRTProfile);
|
DCPProfile(Glib::ustring fname, bool isRTProfile);
|
||||||
~DCPProfile();
|
~DCPProfile();
|
||||||
|
|
||||||
void Apply(Imagefloat *pImg, DCPLightType preferredProfile, Glib::ustring workingSpace, float rawWhiteFac=1, bool useToneCurve=false) const;
|
bool getHasToneCurve() { return hasToneCurve; }
|
||||||
void Apply(Image16 *pImg, DCPLightType preferredProfile, Glib::ustring workingSpace, bool useToneCurve) const;
|
void getIlluminants(int &i1, double &temp1, int &i2, double &temp2, bool &willInterpolate_) { i1 = iLightSource1; i2 = iLightSource2; temp1 = temperature1, temp2 = temperature2; willInterpolate_ = willInterpolate; };
|
||||||
|
void Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, float rawWhiteFac=1, bool useToneCurve=false) const;
|
||||||
|
void Apply(Image16 *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, bool useToneCurve) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DCPStore {
|
class DCPStore {
|
||||||
|
@@ -70,7 +70,7 @@ enum ProcEvent {
|
|||||||
EvCDNEnabled=45, // obsolete
|
EvCDNEnabled=45, // obsolete
|
||||||
EvBlendCMSMatrix=46,
|
EvBlendCMSMatrix=46,
|
||||||
EvDCPToneCurve=47,
|
EvDCPToneCurve=47,
|
||||||
EvPrefProfile=48,
|
EvDCPIlluminant=48,
|
||||||
EvSHEnabled=49,
|
EvSHEnabled=49,
|
||||||
EvSHHighlights=50,
|
EvSHHighlights=50,
|
||||||
EvSHShadows=51,
|
EvSHShadows=51,
|
||||||
|
@@ -408,7 +408,7 @@ void ProcParams::setDefaults () {
|
|||||||
icm.input = "(cameraICC)";
|
icm.input = "(cameraICC)";
|
||||||
icm.blendCMSMatrix = false;
|
icm.blendCMSMatrix = false;
|
||||||
icm.toneCurve = false;
|
icm.toneCurve = false;
|
||||||
icm.preferredProfile = (short)rtengine::Daylight;
|
icm.dcpIlluminant = 0;
|
||||||
icm.working = "sRGB";
|
icm.working = "sRGB";
|
||||||
icm.output = "sRGB";
|
icm.output = "sRGB";
|
||||||
icm.gamma = "default";
|
icm.gamma = "default";
|
||||||
@@ -966,7 +966,7 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, bool fnameAbsol
|
|||||||
if (!pedited || pedited->icm.input) keyFile.set_string ("Color Management", "InputProfile", relativePathIfInside(fname, fnameAbsolute, icm.input));
|
if (!pedited || pedited->icm.input) keyFile.set_string ("Color Management", "InputProfile", relativePathIfInside(fname, fnameAbsolute, icm.input));
|
||||||
if (!pedited || pedited->icm.toneCurve) keyFile.set_boolean ("Color Management", "ToneCurve", icm.toneCurve);
|
if (!pedited || pedited->icm.toneCurve) keyFile.set_boolean ("Color Management", "ToneCurve", icm.toneCurve);
|
||||||
if (!pedited || pedited->icm.blendCMSMatrix) keyFile.set_boolean ("Color Management", "BlendCMSMatrix", icm.blendCMSMatrix);
|
if (!pedited || pedited->icm.blendCMSMatrix) keyFile.set_boolean ("Color Management", "BlendCMSMatrix", icm.blendCMSMatrix);
|
||||||
if (!pedited || pedited->icm.preferredProfile) keyFile.set_boolean ("Color Management", "PreferredProfile", icm.preferredProfile);
|
if (!pedited || pedited->icm.dcpIlluminant) keyFile.set_integer ("Color Management", "DCPIlluminant", icm.dcpIlluminant);
|
||||||
if (!pedited || pedited->icm.working) keyFile.set_string ("Color Management", "WorkingProfile", icm.working);
|
if (!pedited || pedited->icm.working) keyFile.set_string ("Color Management", "WorkingProfile", icm.working);
|
||||||
if (!pedited || pedited->icm.output) keyFile.set_string ("Color Management", "OutputProfile", icm.output);
|
if (!pedited || pedited->icm.output) keyFile.set_string ("Color Management", "OutputProfile", icm.output);
|
||||||
if (!pedited || pedited->icm.gamma) keyFile.set_string ("Color Management", "Gammafree", icm.gamma);
|
if (!pedited || pedited->icm.gamma) keyFile.set_string ("Color Management", "Gammafree", icm.gamma);
|
||||||
@@ -1573,7 +1573,7 @@ if (keyFile.has_group ("Color Management")) {
|
|||||||
if (keyFile.has_key ("Color Management", "InputProfile")) { icm.input = expandRelativePath(fname, "file:", keyFile.get_string ("Color Management", "InputProfile")); if (pedited) pedited->icm.input = true; }
|
if (keyFile.has_key ("Color Management", "InputProfile")) { icm.input = expandRelativePath(fname, "file:", keyFile.get_string ("Color Management", "InputProfile")); if (pedited) pedited->icm.input = true; }
|
||||||
if (keyFile.has_key ("Color Management", "ToneCurve")) { icm.toneCurve = keyFile.get_boolean ("Color Management", "ToneCurve"); if (pedited) pedited->icm.toneCurve = true; }
|
if (keyFile.has_key ("Color Management", "ToneCurve")) { icm.toneCurve = keyFile.get_boolean ("Color Management", "ToneCurve"); if (pedited) pedited->icm.toneCurve = true; }
|
||||||
if (keyFile.has_key ("Color Management", "BlendCMSMatrix")) { icm.blendCMSMatrix = keyFile.get_boolean ("Color Management", "BlendCMSMatrix"); if (pedited) pedited->icm.blendCMSMatrix = true; }
|
if (keyFile.has_key ("Color Management", "BlendCMSMatrix")) { icm.blendCMSMatrix = keyFile.get_boolean ("Color Management", "BlendCMSMatrix"); if (pedited) pedited->icm.blendCMSMatrix = true; }
|
||||||
if (keyFile.has_key ("Color Management", "PreferredProfile")) { icm.preferredProfile = keyFile.get_boolean ("Color Management", "PreferredProfile"); if (pedited) pedited->icm.preferredProfile = true; }
|
if (keyFile.has_key ("Color Management", "DCPIlluminant")) { icm.dcpIlluminant = keyFile.get_integer ("Color Management", "DCPIlluminant"); if (pedited) pedited->icm.dcpIlluminant = true; }
|
||||||
if (keyFile.has_key ("Color Management", "WorkingProfile")) { icm.working = keyFile.get_string ("Color Management", "WorkingProfile"); if (pedited) pedited->icm.working = true; }
|
if (keyFile.has_key ("Color Management", "WorkingProfile")) { icm.working = keyFile.get_string ("Color Management", "WorkingProfile"); if (pedited) pedited->icm.working = true; }
|
||||||
if (keyFile.has_key ("Color Management", "OutputProfile")) { icm.output = keyFile.get_string ("Color Management", "OutputProfile"); if (pedited) pedited->icm.output = true; }
|
if (keyFile.has_key ("Color Management", "OutputProfile")) { icm.output = keyFile.get_string ("Color Management", "OutputProfile"); if (pedited) pedited->icm.output = true; }
|
||||||
if (keyFile.has_key ("Color Management", "Gammafree")) { icm.gamma = keyFile.get_string ("Color Management", "Gammafree"); if (pedited) pedited->icm.gamfree = true; }
|
if (keyFile.has_key ("Color Management", "Gammafree")) { icm.gamma = keyFile.get_string ("Color Management", "Gammafree"); if (pedited) pedited->icm.gamfree = true; }
|
||||||
@@ -1941,7 +1941,7 @@ bool ProcParams::operator== (const ProcParams& other) {
|
|||||||
&& icm.input == other.icm.input
|
&& icm.input == other.icm.input
|
||||||
&& icm.toneCurve == other.icm.toneCurve
|
&& icm.toneCurve == other.icm.toneCurve
|
||||||
&& icm.blendCMSMatrix == other.icm.blendCMSMatrix
|
&& icm.blendCMSMatrix == other.icm.blendCMSMatrix
|
||||||
&& icm.preferredProfile == other.icm.preferredProfile
|
&& icm.dcpIlluminant == other.icm.dcpIlluminant
|
||||||
&& icm.working == other.icm.working
|
&& icm.working == other.icm.working
|
||||||
&& icm.output == other.icm.output
|
&& icm.output == other.icm.output
|
||||||
&& icm.gamma == other.icm.gamma
|
&& icm.gamma == other.icm.gamma
|
||||||
|
@@ -706,7 +706,7 @@ class ColorManagementParams {
|
|||||||
Glib::ustring input;
|
Glib::ustring input;
|
||||||
bool toneCurve;
|
bool toneCurve;
|
||||||
bool blendCMSMatrix;
|
bool blendCMSMatrix;
|
||||||
short preferredProfile;
|
int dcpIlluminant;
|
||||||
Glib::ustring working;
|
Glib::ustring working;
|
||||||
Glib::ustring output;
|
Glib::ustring output;
|
||||||
static const Glib::ustring NoICMString;
|
static const Glib::ustring NoICMString;
|
||||||
|
@@ -426,7 +426,7 @@ void RawImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, Pre
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RawImageSource::convertColorSpace(Imagefloat* image, ColorManagementParams cmp, RAWParams raw) {
|
void RawImageSource::convertColorSpace(Imagefloat* image, ColorManagementParams cmp, RAWParams raw) {
|
||||||
colorSpaceConversion (image, cmp, raw, embProfile, camProfile, imatrices.xyz_cam, (static_cast<const ImageData*>(getMetaData()))->getCamera());
|
colorSpaceConversion (image, cmp, wb, raw, embProfile, camProfile, imatrices.xyz_cam, (static_cast<const ImageData*>(getMetaData()))->getCamera());
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
@@ -1647,7 +1647,7 @@ void RawImageSource::getProfilePreprocParams(cmsHPROFILE in, float& gammaFac, fl
|
|||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
// Converts raw image including ICC input profile to working space - floating point version
|
// Converts raw image including ICC input profile to working space - floating point version
|
||||||
void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams &cmp, float rawWhitePoint, cmsHPROFILE embedded, cmsHPROFILE camprofile, double camMatrix[3][3], const std::string &camName) {
|
void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams &cmp, ColorTemp &wb, float rawWhitePoint, cmsHPROFILE embedded, cmsHPROFILE camprofile, double camMatrix[3][3], const std::string &camName) {
|
||||||
|
|
||||||
//MyTime t1, t2, t3;
|
//MyTime t1, t2, t3;
|
||||||
//t1.set ();
|
//t1.set ();
|
||||||
@@ -1657,7 +1657,7 @@ void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams
|
|||||||
if (!findInputProfile(cmp.input, embedded, camName, &dcpProf, in)) return;
|
if (!findInputProfile(cmp.input, embedded, camName, &dcpProf, in)) return;
|
||||||
|
|
||||||
if (dcpProf!=NULL) {
|
if (dcpProf!=NULL) {
|
||||||
dcpProf->Apply(im, (DCPLightType)cmp.preferredProfile, cmp.working, rawWhitePoint, cmp.toneCurve);
|
dcpProf->Apply(im, cmp.dcpIlluminant, cmp.working, wb, rawWhitePoint, cmp.toneCurve);
|
||||||
} else {
|
} else {
|
||||||
// Calculate matrix for direct conversion raw>working space
|
// Calculate matrix for direct conversion raw>working space
|
||||||
TMatrix work = iccStore->workingSpaceInverseMatrix (cmp.working);
|
TMatrix work = iccStore->workingSpaceInverseMatrix (cmp.working);
|
||||||
|
@@ -66,7 +66,7 @@ class RawImageSource : public ImageSource {
|
|||||||
static LUTf invGrad; // for fast_demosaic
|
static LUTf invGrad; // for fast_demosaic
|
||||||
static LUTf initInvGrad ();
|
static LUTf initInvGrad ();
|
||||||
static bool findInputProfile(Glib::ustring inProfile, cmsHPROFILE embedded, std::string camName, DCPProfile **dcpProf, cmsHPROFILE& in);
|
static bool findInputProfile(Glib::ustring inProfile, cmsHPROFILE embedded, std::string camName, DCPProfile **dcpProf, cmsHPROFILE& in);
|
||||||
static void colorSpaceConversion (Imagefloat* im, ColorManagementParams &cmp, float rawWhitePoint, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName);
|
static void colorSpaceConversion (Imagefloat* im, ColorManagementParams &cmp, ColorTemp &wb, float rawWhitePoint, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MyMutex getImageMutex; // locks getImage
|
MyMutex getImageMutex; // locks getImage
|
||||||
@@ -176,11 +176,11 @@ class RawImageSource : public ImageSource {
|
|||||||
|
|
||||||
void convertColorSpace(Imagefloat* image, ColorManagementParams cmp, RAWParams raw);
|
void convertColorSpace(Imagefloat* image, ColorManagementParams cmp, RAWParams raw);
|
||||||
//static void colorSpaceConversion16 (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName);
|
//static void colorSpaceConversion16 (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName);
|
||||||
static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName) {
|
static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, ColorTemp &wb, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName) {
|
||||||
colorSpaceConversion (im, cmp, 0.0f, embedded, camprofile, cam, camName);
|
colorSpaceConversion (im, cmp, wb, 0.0f, embedded, camprofile, cam, camName);
|
||||||
}
|
}
|
||||||
static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, RAWParams raw, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName) {
|
static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, ColorTemp &wb, RAWParams raw, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName) {
|
||||||
colorSpaceConversion (im, cmp, float(raw.expos), embedded, camprofile, cam, camName);
|
colorSpaceConversion (im, cmp, wb, float(raw.expos), embedded, camprofile, cam, camName);
|
||||||
}
|
}
|
||||||
static void inverse33 (const double (*coeff)[3], double (*icoeff)[3]);
|
static void inverse33 (const double (*coeff)[3], double (*icoeff)[3]);
|
||||||
|
|
||||||
|
@@ -68,7 +68,7 @@ RGBCURVE, // EvToneCurveMode2,
|
|||||||
0, // EvCDNEnabled:obsolete,
|
0, // EvCDNEnabled:obsolete,
|
||||||
ALL, // EvBlendCMSMatrix,
|
ALL, // EvBlendCMSMatrix,
|
||||||
ALL, // EvDCPToneCurve,
|
ALL, // EvDCPToneCurve,
|
||||||
ALL, // EvPrefProfile,
|
ALL, // EvDCPIlluminant,
|
||||||
RETINEX, // EvSHEnabled,
|
RETINEX, // EvSHEnabled,
|
||||||
RGBCURVE, // EvSHHighlights,
|
RGBCURVE, // EvSHHighlights,
|
||||||
RGBCURVE, // EvSHShadows,
|
RGBCURVE, // EvSHShadows,
|
||||||
|
@@ -420,6 +420,7 @@ namespace rtengine {
|
|||||||
* @param img is the result of the last ProcessingJob
|
* @param img is the result of the last ProcessingJob
|
||||||
* @return the next ProcessingJob to process */
|
* @return the next ProcessingJob to process */
|
||||||
virtual ProcessingJob* imageReady (IImage16* img) =0;
|
virtual ProcessingJob* imageReady (IImage16* img) =0;
|
||||||
|
virtual void error(Glib::ustring message) =0;
|
||||||
};
|
};
|
||||||
/** This function performs all the image processinf steps corresponding to the given ProcessingJob. It runs in the background, thus it returns immediately,
|
/** This function performs all the image processinf steps corresponding to the given ProcessingJob. It runs in the background, thus it returns immediately,
|
||||||
* When it finishes, it calls the BatchProcessingListener with the resulting image and asks for the next job. It the listener gives a new job, it goes on
|
* When it finishes, it calls the BatchProcessingListener with the resulting image and asks for the next job. It the listener gives a new job, it goes on
|
||||||
|
@@ -679,7 +679,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei
|
|||||||
|
|
||||||
// perform color space transformation
|
// perform color space transformation
|
||||||
if (isRaw)
|
if (isRaw)
|
||||||
RawImageSource::colorSpaceConversion (baseImg, params.icm, embProfile, camProfile, cam2xyz, camName );
|
RawImageSource::colorSpaceConversion (baseImg, params.icm, currWB, embProfile, camProfile, cam2xyz, camName );
|
||||||
else
|
else
|
||||||
StdImageSource::colorSpaceConversion (baseImg, params.icm, embProfile, thumbImg->getSampleFormat());
|
StdImageSource::colorSpaceConversion (baseImg, params.icm, embProfile, thumbImg->getSampleFormat());
|
||||||
|
|
||||||
|
@@ -681,9 +681,17 @@ void batchProcessingThread (ProcessingJob* job, BatchProcessingListener* bpl, bo
|
|||||||
while (currentJob) {
|
while (currentJob) {
|
||||||
int errorCode;
|
int errorCode;
|
||||||
IImage16* img = processImage (currentJob, errorCode, bpl, tunnelMetaData);
|
IImage16* img = processImage (currentJob, errorCode, bpl, tunnelMetaData);
|
||||||
if (errorCode)
|
if (errorCode) {
|
||||||
bpl->error ("Can not load input image.");
|
bpl->error ("Can not load input image.");
|
||||||
currentJob = bpl->imageReady (img);
|
currentJob = NULL;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
currentJob = bpl->imageReady (img);
|
||||||
|
} catch (Glib::Exception& ex) {
|
||||||
|
bpl->error (ex.what());
|
||||||
|
currentJob = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -594,7 +594,7 @@ rtengine::ProcessingJob* BatchQueue::imageReady (rtengine::IImage16* img) {
|
|||||||
err = img->saveAsJPEG (fname, saveFormat.jpegQuality, saveFormat.jpegSubSamp);
|
err = img->saveAsJPEG (fname, saveFormat.jpegQuality, saveFormat.jpegSubSamp);
|
||||||
img->free ();
|
img->free ();
|
||||||
|
|
||||||
if (err) throw "Unable to save output file";
|
if (err) throw Glib::FileError(Glib::FileError::FAILED, "Unable to save output file");
|
||||||
|
|
||||||
if (saveFormat.saveParams) {
|
if (saveFormat.saveParams) {
|
||||||
// We keep the extension to avoid overwriting the profile when we have
|
// We keep the extension to avoid overwriting the profile when we have
|
||||||
@@ -848,12 +848,14 @@ struct NLParams {
|
|||||||
BatchQueueListener* listener;
|
BatchQueueListener* listener;
|
||||||
int qsize;
|
int qsize;
|
||||||
bool queueEmptied;
|
bool queueEmptied;
|
||||||
|
bool queueError;
|
||||||
|
Glib::ustring queueErrorMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
int bqnotifylistenerUI (void* data) {
|
int bqnotifylistenerUI (void* data) {
|
||||||
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
GThreadLock lock; // All GUI acces from idle_add callbacks or separate thread HAVE to be protected
|
||||||
NLParams* params = static_cast<NLParams*>(data);
|
NLParams* params = static_cast<NLParams*>(data);
|
||||||
params->listener->queueSizeChanged (params->qsize, params->queueEmptied);
|
params->listener->queueSizeChanged (params->qsize, params->queueEmptied, params->queueError, params->queueErrorMessage);
|
||||||
delete params;
|
delete params;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -871,6 +873,7 @@ void BatchQueue::notifyListener (bool queueEmptied) {
|
|||||||
params->qsize = fd.size();
|
params->qsize = fd.size();
|
||||||
}
|
}
|
||||||
params->queueEmptied = queueEmptied;
|
params->queueEmptied = queueEmptied;
|
||||||
|
params->queueError = false;
|
||||||
g_idle_add (bqnotifylistenerUI, params);
|
g_idle_add (bqnotifylistenerUI, params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -879,3 +882,15 @@ void BatchQueue::redrawNeeded (LWButton* button) {
|
|||||||
GThreadLock lock;
|
GThreadLock lock;
|
||||||
queue_draw ();
|
queue_draw ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BatchQueue::error (Glib::ustring msg) {
|
||||||
|
|
||||||
|
if (listener) {
|
||||||
|
NLParams* params = new NLParams;
|
||||||
|
params->listener = listener;
|
||||||
|
params->queueEmptied = false;
|
||||||
|
params->queueError = true;
|
||||||
|
params->queueErrorMessage = msg;
|
||||||
|
g_idle_add (bqnotifylistenerUI, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
3
rtgui/batchqueue.h
Normal file → Executable file
3
rtgui/batchqueue.h
Normal file → Executable file
@@ -30,7 +30,7 @@ class BatchQueueListener {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~BatchQueueListener () {}
|
virtual ~BatchQueueListener () {}
|
||||||
virtual void queueSizeChanged (int qsize, bool queueEmptied) =0;
|
virtual void queueSizeChanged (int qsize, bool queueEmptied, bool queueError, Glib::ustring queueErrorMessage) =0;
|
||||||
virtual bool canStartNext () =0;
|
virtual bool canStartNext () =0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -86,6 +86,7 @@ class BatchQueue : public ThumbBrowserBase,
|
|||||||
}
|
}
|
||||||
|
|
||||||
rtengine::ProcessingJob* imageReady (rtengine::IImage16* img);
|
rtengine::ProcessingJob* imageReady (rtengine::IImage16* img);
|
||||||
|
void error (Glib::ustring msg);
|
||||||
void setProgress (double p);
|
void setProgress (double p);
|
||||||
void rightClicked (ThumbBrowserEntryBase* entry);
|
void rightClicked (ThumbBrowserEntryBase* entry);
|
||||||
bool keyPressed (GdkEventKey* event);
|
bool keyPressed (GdkEventKey* event);
|
||||||
|
@@ -223,17 +223,21 @@ void BatchQueuePanel::updateTab (int qsize)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BatchQueuePanel::queueSizeChanged (int qsize, bool queueEmptied)
|
void BatchQueuePanel::queueSizeChanged (int qsize, bool queueEmptied, bool queueError, Glib::ustring queueErrorMessage)
|
||||||
{
|
{
|
||||||
updateTab ( qsize);
|
updateTab ( qsize);
|
||||||
|
|
||||||
if (queueEmptied) {
|
if (queueEmptied || queueError) {
|
||||||
stopBatchProc ();
|
stopBatchProc ();
|
||||||
fdir->set_sensitive (true);
|
fdir->set_sensitive (true);
|
||||||
fformat->set_sensitive (true);
|
fformat->set_sensitive (true);
|
||||||
|
|
||||||
SoundManager::playSoundAsync(options.sndBatchQueueDone);
|
SoundManager::playSoundAsync(options.sndBatchQueueDone);
|
||||||
}
|
}
|
||||||
|
if (queueError) {
|
||||||
|
Gtk::MessageDialog msgd (queueErrorMessage, true, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
||||||
|
msgd.run ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BatchQueuePanel::startBatchProc () {
|
void BatchQueuePanel::startBatchProc () {
|
||||||
|
@@ -59,7 +59,7 @@ class BatchQueuePanel : public Gtk::VBox,
|
|||||||
void addBatchQueueJobs (std::vector<BatchQueueEntry*> &entries , bool head=false);
|
void addBatchQueueJobs (std::vector<BatchQueueEntry*> &entries , bool head=false);
|
||||||
|
|
||||||
// batchqueuelistener interface
|
// batchqueuelistener interface
|
||||||
void queueSizeChanged (int qsize, bool queueEmptied);
|
void queueSizeChanged (int qsize, bool queueEmptied, bool queueError, Glib::ustring queueErrorMessage);
|
||||||
bool canStartNext ();
|
bool canStartNext ();
|
||||||
|
|
||||||
void startBatchProc ();
|
void startBatchProc ();
|
||||||
|
@@ -82,16 +82,20 @@ ICMPanel::ICMPanel () : Gtk::VBox(), FoldableToolPanel(this), iunchanged(NULL),
|
|||||||
|
|
||||||
Gtk::HBox* hb = Gtk::manage (new Gtk::HBox ());
|
Gtk::HBox* hb = Gtk::manage (new Gtk::HBox ());
|
||||||
hb->show ();
|
hb->show ();
|
||||||
Gtk::Label* ppl = Gtk::manage (new Gtk::Label (M("TP_ICM_PREFERREDPROFILE")+":"));
|
dcpIllLabel = Gtk::manage (new Gtk::Label ("DCP " + M("TP_ICM_DCPILLUMINANT")+":"));
|
||||||
ppl->show ();
|
dcpIllLabel->set_tooltip_text (M("TP_ICM_DCPILLUMINANT_TOOLTIP"));
|
||||||
prefprof = Gtk::manage (new MyComboBoxText ());
|
dcpIllLabel->show ();
|
||||||
prefprof->append_text (M("TP_ICM_PREFERREDPROFILE_1"));
|
dcpIll = Gtk::manage (new MyComboBoxText ());
|
||||||
prefprof->append_text (M("TP_ICM_PREFERREDPROFILE_2"));
|
dcpIll->set_tooltip_text (M("TP_ICM_DCPILLUMINANT_TOOLTIP"));
|
||||||
prefprof->append_text (M("TP_ICM_PREFERREDPROFILE_3"));
|
dcpIll->append_text (M("TP_ICM_DCPILLUMINANT_INTERPOLATED"));
|
||||||
prefprof->append_text (M("TP_ICM_PREFERREDPROFILE_4"));
|
dcpIll->append_text (M("TP_ICM_DCPILLUMINANT") + " 1");
|
||||||
prefprof->show ();
|
dcpIll->append_text (M("TP_ICM_DCPILLUMINANT") + " 2");
|
||||||
hb->pack_start(*ppl, Gtk::PACK_SHRINK, 4);
|
dcpIll->show ();
|
||||||
hb->pack_start(*prefprof);
|
dcpTemperatures[0] = 0;
|
||||||
|
dcpTemperatures[1] = 0;
|
||||||
|
ignoreDcpSignal = true;
|
||||||
|
hb->pack_start(*dcpIllLabel, Gtk::PACK_SHRINK, 4);
|
||||||
|
hb->pack_start(*dcpIll);
|
||||||
iVBox->pack_start (*hb, Gtk::PACK_SHRINK, 2);
|
iVBox->pack_start (*hb, Gtk::PACK_SHRINK, 2);
|
||||||
|
|
||||||
ckbToneCurve = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_TONECURVE")));
|
ckbToneCurve = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_TONECURVE")));
|
||||||
@@ -229,7 +233,7 @@ ICMPanel::ICMPanel () : Gtk::VBox(), FoldableToolPanel(this), iunchanged(NULL),
|
|||||||
wnames->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::wpChanged) );
|
wnames->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::wpChanged) );
|
||||||
onames->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::opChanged) );
|
onames->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::opChanged) );
|
||||||
wgamma->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::gpChanged) );
|
wgamma->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::gpChanged) );
|
||||||
prefprof->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::prefProfChanged) );
|
dcpIll->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::dcpIlluminantChanged) );
|
||||||
|
|
||||||
gamcsconn = freegamma->signal_toggled().connect ( sigc::mem_fun(*this, &ICMPanel::GamChanged));
|
gamcsconn = freegamma->signal_toggled().connect ( sigc::mem_fun(*this, &ICMPanel::GamChanged));
|
||||||
tcurveconn = ckbToneCurve->signal_toggled().connect ( sigc::mem_fun(*this, &ICMPanel::toneCurveChanged));
|
tcurveconn = ckbToneCurve->signal_toggled().connect ( sigc::mem_fun(*this, &ICMPanel::toneCurveChanged));
|
||||||
@@ -246,6 +250,100 @@ ICMPanel::ICMPanel () : Gtk::VBox(), FoldableToolPanel(this), iunchanged(NULL),
|
|||||||
show_all ();
|
show_all ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ICMPanel::updateDCP (int dcpIlluminant, Glib::ustring dcp_name) {
|
||||||
|
|
||||||
|
if (isBatchMode) {
|
||||||
|
ckbToneCurve->set_sensitive (true);
|
||||||
|
dcpIllLabel->set_sensitive (true);
|
||||||
|
dcpIll->set_sensitive (true);
|
||||||
|
if (dcpTemperatures[0] != 0 || dcpTemperatures[1] != 0) {
|
||||||
|
int curr_active = dcpIll->get_active_row_number();
|
||||||
|
ignoreDcpSignal = true;
|
||||||
|
dcpIll->clear_items ();
|
||||||
|
dcpIll->append_text (M("TP_ICM_DCPILLUMINANT_INTERPOLATED"));
|
||||||
|
dcpIll->append_text (M("TP_ICM_DCPILLUMINANT") + " 1");
|
||||||
|
dcpIll->append_text (M("TP_ICM_DCPILLUMINANT") + " 2");
|
||||||
|
dcpIll->append_text (M("GENERAL_UNCHANGED"));
|
||||||
|
dcpTemperatures[0] = 0;
|
||||||
|
dcpTemperatures[1] = 0;
|
||||||
|
dcpIll->set_active (curr_active);
|
||||||
|
ignoreDcpSignal = false;
|
||||||
|
}
|
||||||
|
if (dcpIll->get_active_row_number() == -1 && dcpIlluminant == -1) {
|
||||||
|
dcpIll->set_active(0);
|
||||||
|
} else if (dcpIlluminant >= 0 && dcpIlluminant != dcpIll->get_active_row_number()) {
|
||||||
|
dcpIll->set_active(dcpIlluminant);
|
||||||
|
}
|
||||||
|
dcpIll->set_sensitive (true);
|
||||||
|
dcpIllLabel->set_sensitive (true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ckbToneCurve->set_sensitive (false);
|
||||||
|
dcpIllLabel->set_sensitive (false);
|
||||||
|
dcpIll->set_sensitive (false);
|
||||||
|
if (ifromfile->get_active() && dcpStore->isValidDCPFileName(dcp_name)) {
|
||||||
|
DCPProfile* dcp = dcpStore->getProfile(dcp_name, false);
|
||||||
|
if (dcp) {
|
||||||
|
if (dcp->getHasToneCurve()) {
|
||||||
|
ckbToneCurve->set_sensitive (true);
|
||||||
|
} else {
|
||||||
|
ckbToneCurve->set_active (false);
|
||||||
|
}
|
||||||
|
int i1, i2;
|
||||||
|
double temp1, temp2;
|
||||||
|
bool willInterpolate;
|
||||||
|
dcp->getIlluminants(i1, temp1, i2, temp2, willInterpolate);
|
||||||
|
if (willInterpolate) {
|
||||||
|
if (dcpTemperatures[0] != temp1 || dcpTemperatures[1] != temp2) {
|
||||||
|
char tempstr1[64], tempstr2[64];
|
||||||
|
sprintf(tempstr1, "%.0fK", temp1);
|
||||||
|
sprintf(tempstr2, "%.0fK", temp2);
|
||||||
|
int curr_active = dcpIll->get_active_row_number();
|
||||||
|
ignoreDcpSignal = true;
|
||||||
|
dcpIll->clear_items ();
|
||||||
|
dcpIll->append_text (M("TP_ICM_DCPILLUMINANT_INTERPOLATED"));
|
||||||
|
dcpIll->append_text (tempstr1);
|
||||||
|
dcpIll->append_text (tempstr2);
|
||||||
|
dcpTemperatures[0] = temp1;
|
||||||
|
dcpTemperatures[1] = temp2;
|
||||||
|
dcpIll->set_active (curr_active);
|
||||||
|
ignoreDcpSignal = false;
|
||||||
|
}
|
||||||
|
if (dcpIlluminant > 2) {
|
||||||
|
dcpIlluminant = 0;
|
||||||
|
}
|
||||||
|
if (dcpIll->get_active_row_number() == -1 && dcpIlluminant == -1) {
|
||||||
|
dcpIll->set_active(0);
|
||||||
|
} else if (dcpIlluminant >= 0 && dcpIlluminant != dcpIll->get_active_row_number()) {
|
||||||
|
dcpIll->set_active(dcpIlluminant);
|
||||||
|
}
|
||||||
|
dcpIll->set_sensitive (true);
|
||||||
|
dcpIllLabel->set_sensitive (true);
|
||||||
|
} else {
|
||||||
|
if (dcpIll->get_active_row_number() != -1) {
|
||||||
|
dcpIll->set_active(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!dcpIllLabel->get_sensitive() && dcpIll->get_active_row_number() != 0) {
|
||||||
|
if (dcpTemperatures[0] != 0 || dcpTemperatures[1] != 0) {
|
||||||
|
int curr_active = dcpIll->get_active_row_number();
|
||||||
|
ignoreDcpSignal = true;
|
||||||
|
dcpIll->clear_items ();
|
||||||
|
dcpIll->append_text (M("TP_ICM_DCPILLUMINANT_INTERPOLATED"));
|
||||||
|
dcpIll->append_text (M("TP_ICM_DCPILLUMINANT") + " 1");
|
||||||
|
dcpIll->append_text (M("TP_ICM_DCPILLUMINANT") + " 2");
|
||||||
|
if (isBatchMode)
|
||||||
|
dcpIll->append_text (M("GENERAL_UNCHANGED"));
|
||||||
|
dcpTemperatures[0] = 0;
|
||||||
|
dcpTemperatures[1] = 0;
|
||||||
|
dcpIll->set_active (curr_active);
|
||||||
|
ignoreDcpSignal = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) {
|
void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) {
|
||||||
|
|
||||||
disableListener ();
|
disableListener ();
|
||||||
@@ -256,33 +354,38 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) {
|
|||||||
blendcmsconn.block(true);
|
blendcmsconn.block(true);
|
||||||
|
|
||||||
if (pp->icm.input == "(none)" && icamera->get_state()!=Gtk::STATE_INSENSITIVE) {
|
if (pp->icm.input == "(none)" && icamera->get_state()!=Gtk::STATE_INSENSITIVE) {
|
||||||
inone->set_active (true); prefprof->set_sensitive (false); ckbToneCurve->set_sensitive (false);
|
inone->set_active (true);
|
||||||
ckbBlendCMSMatrix->set_sensitive (false);
|
ckbBlendCMSMatrix->set_sensitive (false);
|
||||||
|
updateDCP(pp->icm.dcpIlluminant, "");
|
||||||
}
|
}
|
||||||
else if (pp->icm.input == "(embedded)" || ((pp->icm.input == "(camera)" || pp->icm.input=="") && icamera->get_state()==Gtk::STATE_INSENSITIVE)) {
|
else if (pp->icm.input == "(embedded)" || ((pp->icm.input == "(camera)" || pp->icm.input=="") && icamera->get_state()==Gtk::STATE_INSENSITIVE)) {
|
||||||
iembedded->set_active (true); prefprof->set_sensitive (false); ckbToneCurve->set_sensitive (false);
|
iembedded->set_active (true);
|
||||||
ckbBlendCMSMatrix->set_sensitive (false);
|
ckbBlendCMSMatrix->set_sensitive (false);
|
||||||
|
updateDCP(pp->icm.dcpIlluminant, "");
|
||||||
}
|
}
|
||||||
else if ((pp->icm.input == "(cameraICC)") && icameraICC->get_state()!=Gtk::STATE_INSENSITIVE) {
|
else if ((pp->icm.input == "(cameraICC)") && icameraICC->get_state()!=Gtk::STATE_INSENSITIVE) {
|
||||||
icameraICC->set_active (true); prefprof->set_sensitive (true); ckbToneCurve->set_sensitive (true);
|
icameraICC->set_active (true);
|
||||||
ckbBlendCMSMatrix->set_sensitive (true);
|
ckbBlendCMSMatrix->set_sensitive (true);
|
||||||
|
updateDCP(pp->icm.dcpIlluminant, "");
|
||||||
}
|
}
|
||||||
else if ((pp->icm.input == "(cameraICC)") && icameraICC->get_state()==Gtk::STATE_INSENSITIVE) {
|
else if ((pp->icm.input == "(cameraICC)") && icameraICC->get_state()==Gtk::STATE_INSENSITIVE) {
|
||||||
// this is the case when (cameraICC) is instructed by packaged profiles, but ICC file is not found
|
// this is the case when (cameraICC) is instructed by packaged profiles, but ICC file is not found
|
||||||
// therefore falling back UI to explicitly reflect the (camera) option
|
// therefore falling back UI to explicitly reflect the (camera) option
|
||||||
icamera->set_active (true);
|
icamera->set_active (true);
|
||||||
prefprof->set_sensitive (false); ckbToneCurve->set_sensitive (false); // RT's own are always single-illuminant and tone curve disabled
|
|
||||||
ckbBlendCMSMatrix->set_sensitive (false);
|
ckbBlendCMSMatrix->set_sensitive (false);
|
||||||
|
updateDCP(pp->icm.dcpIlluminant, "");
|
||||||
}
|
}
|
||||||
else if ((pp->icm.input == "(camera)" || pp->icm.input=="") && icamera->get_state()!=Gtk::STATE_INSENSITIVE) {
|
else if ((pp->icm.input == "(camera)" || pp->icm.input=="") && icamera->get_state()!=Gtk::STATE_INSENSITIVE) {
|
||||||
icamera->set_active (true);
|
icamera->set_active (true);
|
||||||
ckbBlendCMSMatrix->set_sensitive (false); prefprof->set_sensitive (false); ckbToneCurve->set_sensitive (false);
|
ckbBlendCMSMatrix->set_sensitive (false);
|
||||||
|
updateDCP(pp->icm.dcpIlluminant, "");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ifromfile->set_active (true);
|
ifromfile->set_active (true);
|
||||||
oldip = pp->icm.input.substr(5); // cut of "file:"
|
oldip = pp->icm.input.substr(5); // cut of "file:"
|
||||||
ipDialog->set_filename (pp->icm.input.substr(5));
|
ipDialog->set_filename (pp->icm.input.substr(5));
|
||||||
ckbBlendCMSMatrix->set_sensitive (true); prefprof->set_sensitive (true); ckbToneCurve->set_sensitive (true);
|
ckbBlendCMSMatrix->set_sensitive (true);
|
||||||
|
updateDCP(pp->icm.dcpIlluminant, pp->icm.input.substr(5));
|
||||||
}
|
}
|
||||||
|
|
||||||
wnames->set_active_text (pp->icm.working);
|
wnames->set_active_text (pp->icm.working);
|
||||||
@@ -296,8 +399,6 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) {
|
|||||||
if (onames->get_active_row_number()==-1)
|
if (onames->get_active_row_number()==-1)
|
||||||
onames->set_active_text (M("TP_ICM_NOICM"));
|
onames->set_active_text (M("TP_ICM_NOICM"));
|
||||||
|
|
||||||
prefprof->set_active(pp->icm.preferredProfile-1);
|
|
||||||
|
|
||||||
ckbToneCurve->set_active (pp->icm.toneCurve);
|
ckbToneCurve->set_active (pp->icm.toneCurve);
|
||||||
lastToneCurve = pp->icm.toneCurve;
|
lastToneCurve = pp->icm.toneCurve;
|
||||||
|
|
||||||
@@ -321,8 +422,8 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) {
|
|||||||
wnames->set_active_text(M("GENERAL_UNCHANGED"));
|
wnames->set_active_text(M("GENERAL_UNCHANGED"));
|
||||||
if (!pedited->icm.output)
|
if (!pedited->icm.output)
|
||||||
onames->set_active_text(M("GENERAL_UNCHANGED"));
|
onames->set_active_text(M("GENERAL_UNCHANGED"));
|
||||||
if (!pedited->icm.preferredProfile)
|
if (!pedited->icm.dcpIlluminant)
|
||||||
prefprof->set_active_text(M("GENERAL_UNCHANGED"));
|
dcpIll->set_active_text(M("GENERAL_UNCHANGED"));
|
||||||
if (!pedited->icm.gamma){
|
if (!pedited->icm.gamma){
|
||||||
wgamma->set_active_text(M("GENERAL_UNCHANGED"));
|
wgamma->set_active_text(M("GENERAL_UNCHANGED"));
|
||||||
wgamma->set_active_text(M("GENERAL_UNCHANGED"));
|
wgamma->set_active_text(M("GENERAL_UNCHANGED"));
|
||||||
@@ -361,7 +462,9 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) {
|
|||||||
|
|
||||||
pp->icm.working = wnames->get_active_text ();
|
pp->icm.working = wnames->get_active_text ();
|
||||||
pp->icm.gamma = wgamma->get_active_text ();
|
pp->icm.gamma = wgamma->get_active_text ();
|
||||||
pp->icm.preferredProfile = prefprof->get_active_row_number()+1;
|
pp->icm.dcpIlluminant = dcpIll->get_active_row_number();
|
||||||
|
if (pp->icm.dcpIlluminant < 0)
|
||||||
|
pp->icm.dcpIlluminant = 0;
|
||||||
|
|
||||||
if (onames->get_active_text()==M("TP_ICM_NOICM"))
|
if (onames->get_active_text()==M("TP_ICM_NOICM"))
|
||||||
pp->icm.output = ColorManagementParams::NoICMString;
|
pp->icm.output = ColorManagementParams::NoICMString;
|
||||||
@@ -377,7 +480,7 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) {
|
|||||||
pedited->icm.input = !iunchanged->get_active ();
|
pedited->icm.input = !iunchanged->get_active ();
|
||||||
pedited->icm.working = wnames->get_active_text()!=M("GENERAL_UNCHANGED");
|
pedited->icm.working = wnames->get_active_text()!=M("GENERAL_UNCHANGED");
|
||||||
pedited->icm.output = onames->get_active_text()!=M("GENERAL_UNCHANGED");
|
pedited->icm.output = onames->get_active_text()!=M("GENERAL_UNCHANGED");
|
||||||
pedited->icm.preferredProfile = prefprof->get_active_text()!=M("GENERAL_UNCHANGED");
|
pedited->icm.dcpIlluminant = dcpIll->get_active_text()!=M("GENERAL_UNCHANGED");
|
||||||
pedited->icm.toneCurve = !ckbToneCurve->get_inconsistent ();
|
pedited->icm.toneCurve = !ckbToneCurve->get_inconsistent ();
|
||||||
pedited->icm.blendCMSMatrix = !ckbBlendCMSMatrix->get_inconsistent ();
|
pedited->icm.blendCMSMatrix = !ckbBlendCMSMatrix->get_inconsistent ();
|
||||||
pedited->icm.gamma = wgamma->get_active_text()!=M("GENERAL_UNCHANGED");
|
pedited->icm.gamma = wgamma->get_active_text()!=M("GENERAL_UNCHANGED");
|
||||||
@@ -433,9 +536,10 @@ void ICMPanel::gpChanged () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ICMPanel::prefProfChanged() {
|
void ICMPanel::dcpIlluminantChanged() {
|
||||||
if (listener)
|
if (listener && !ignoreDcpSignal) {
|
||||||
listener->panelChanged (EvPrefProfile, prefprof->get_active_text ());
|
listener->panelChanged (EvDCPIlluminant, dcpIll->get_active_text ());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ICMPanel::toneCurveChanged() {
|
void ICMPanel::toneCurveChanged() {
|
||||||
@@ -458,27 +562,28 @@ void ICMPanel::toneCurveChanged() {
|
|||||||
|
|
||||||
void ICMPanel::ipChanged () {
|
void ICMPanel::ipChanged () {
|
||||||
|
|
||||||
std::string profname;
|
Glib::ustring profname;
|
||||||
if (inone->get_active()) {
|
if (inone->get_active()) {
|
||||||
profname = "(none)";
|
profname = "(none)";
|
||||||
ckbBlendCMSMatrix->set_sensitive(false); prefprof->set_sensitive (false); ckbToneCurve->set_sensitive (false);
|
ckbBlendCMSMatrix->set_sensitive(false);
|
||||||
}
|
}
|
||||||
else if (iembedded->get_active ()) {
|
else if (iembedded->get_active ()) {
|
||||||
profname = "(embedded)";
|
profname = "(embedded)";
|
||||||
ckbBlendCMSMatrix->set_sensitive(false); prefprof->set_sensitive (false); ckbToneCurve->set_sensitive (false);
|
ckbBlendCMSMatrix->set_sensitive(false);
|
||||||
}
|
}
|
||||||
else if (icamera->get_active ()) {
|
else if (icamera->get_active ()) {
|
||||||
profname = "(camera)";
|
profname = "(camera)";
|
||||||
ckbBlendCMSMatrix->set_sensitive(false); prefprof->set_sensitive (false); ckbToneCurve->set_sensitive (false);
|
ckbBlendCMSMatrix->set_sensitive(false);
|
||||||
}
|
}
|
||||||
else if (icameraICC->get_active ()) {
|
else if (icameraICC->get_active ()) {
|
||||||
profname = "(cameraICC)";
|
profname = "(cameraICC)";
|
||||||
ckbBlendCMSMatrix->set_sensitive(true); prefprof->set_sensitive (false); ckbToneCurve->set_sensitive (false);
|
ckbBlendCMSMatrix->set_sensitive(true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
profname = ipDialog->get_filename ();
|
profname = ipDialog->get_filename ();
|
||||||
ckbBlendCMSMatrix->set_sensitive(true); prefprof->set_sensitive (true); ckbToneCurve->set_sensitive (true);
|
ckbBlendCMSMatrix->set_sensitive(true);
|
||||||
}
|
}
|
||||||
|
updateDCP(-1, profname);
|
||||||
|
|
||||||
if (listener && profname!=oldip)
|
if (listener && profname!=oldip)
|
||||||
listener->panelChanged (EvIProfile, profname);
|
listener->panelChanged (EvIProfile, profname);
|
||||||
@@ -604,6 +709,8 @@ void ICMPanel::saveReferencePressed () {
|
|||||||
|
|
||||||
void ICMPanel::setBatchMode (bool batchMode) {
|
void ICMPanel::setBatchMode (bool batchMode) {
|
||||||
|
|
||||||
|
isBatchMode = true;
|
||||||
|
ignoreDcpSignal = false;
|
||||||
ToolPanel::setBatchMode (batchMode);
|
ToolPanel::setBatchMode (batchMode);
|
||||||
iunchanged = Gtk::manage (new Gtk::RadioButton (M("GENERAL_UNCHANGED")));
|
iunchanged = Gtk::manage (new Gtk::RadioButton (M("GENERAL_UNCHANGED")));
|
||||||
iunchanged->set_group (opts);
|
iunchanged->set_group (opts);
|
||||||
@@ -613,9 +720,8 @@ void ICMPanel::setBatchMode (bool batchMode) {
|
|||||||
onames->append_text (M("GENERAL_UNCHANGED"));
|
onames->append_text (M("GENERAL_UNCHANGED"));
|
||||||
wnames->append_text (M("GENERAL_UNCHANGED"));
|
wnames->append_text (M("GENERAL_UNCHANGED"));
|
||||||
wgamma->append_text (M("GENERAL_UNCHANGED"));
|
wgamma->append_text (M("GENERAL_UNCHANGED"));
|
||||||
prefprof->append_text (M("GENERAL_UNCHANGED"));
|
dcpIll->append_text (M("GENERAL_UNCHANGED"));
|
||||||
gampos->showEditedCB ();
|
gampos->showEditedCB ();
|
||||||
slpos->showEditedCB ();
|
slpos->showEditedCB ();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
rtgui/icmpanel.h
Normal file → Executable file
10
rtgui/icmpanel.h
Normal file → Executable file
@@ -46,6 +46,7 @@ class ICMPanel : public Gtk::VBox, public AdjusterListener, public FoldableToolP
|
|||||||
bool lastToneCurve;
|
bool lastToneCurve;
|
||||||
sigc::connection tcurveconn;
|
sigc::connection tcurveconn;
|
||||||
bool lastBlendCMSMatrix;
|
bool lastBlendCMSMatrix;
|
||||||
|
bool isBatchMode;
|
||||||
sigc::connection blendcmsconn;
|
sigc::connection blendcmsconn;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -58,7 +59,8 @@ class ICMPanel : public Gtk::VBox, public AdjusterListener, public FoldableToolP
|
|||||||
Gtk::RadioButton* icamera;
|
Gtk::RadioButton* icamera;
|
||||||
Gtk::RadioButton* icameraICC;
|
Gtk::RadioButton* icameraICC;
|
||||||
Gtk::RadioButton* ifromfile;
|
Gtk::RadioButton* ifromfile;
|
||||||
MyComboBoxText* prefprof;
|
Gtk::Label* dcpIllLabel;
|
||||||
|
MyComboBoxText* dcpIll;
|
||||||
Gtk::CheckButton* ckbToneCurve;
|
Gtk::CheckButton* ckbToneCurve;
|
||||||
Gtk::CheckButton* ckbBlendCMSMatrix;
|
Gtk::CheckButton* ckbBlendCMSMatrix;
|
||||||
MyComboBoxText* wnames;
|
MyComboBoxText* wnames;
|
||||||
@@ -76,9 +78,11 @@ class ICMPanel : public Gtk::VBox, public AdjusterListener, public FoldableToolP
|
|||||||
Glib::ustring oldip;
|
Glib::ustring oldip;
|
||||||
ICMPanelListener* icmplistener;
|
ICMPanelListener* icmplistener;
|
||||||
|
|
||||||
|
bool ignoreDcpSignal;
|
||||||
|
double dcpTemperatures[2];
|
||||||
bool enableLastICCWorkDirChange;
|
bool enableLastICCWorkDirChange;
|
||||||
Glib::ustring lastRefFilename;
|
Glib::ustring lastRefFilename;
|
||||||
|
void updateDCP(int dcpIlluminant, Glib::ustring dcp_name);
|
||||||
public:
|
public:
|
||||||
ICMPanel ();
|
ICMPanel ();
|
||||||
|
|
||||||
@@ -96,7 +100,7 @@ class ICMPanel : public Gtk::VBox, public AdjusterListener, public FoldableToolP
|
|||||||
void GamChanged ();
|
void GamChanged ();
|
||||||
void ipSelectionChanged ();
|
void ipSelectionChanged ();
|
||||||
void blendCMSMatrixChanged();
|
void blendCMSMatrixChanged();
|
||||||
void prefProfChanged();
|
void dcpIlluminantChanged();
|
||||||
void toneCurveChanged();
|
void toneCurveChanged();
|
||||||
|
|
||||||
void setRawMeta (bool raw, const rtengine::ImageData* pMeta);
|
void setRawMeta (bool raw, const rtengine::ImageData* pMeta);
|
||||||
|
@@ -251,7 +251,7 @@ void ParamsEdited::set (bool v) {
|
|||||||
icm.input = v;
|
icm.input = v;
|
||||||
icm.toneCurve = v;
|
icm.toneCurve = v;
|
||||||
icm.blendCMSMatrix = v;
|
icm.blendCMSMatrix = v;
|
||||||
icm.preferredProfile = v;
|
icm.dcpIlluminant = v;
|
||||||
icm.working = v;
|
icm.working = v;
|
||||||
icm.output = v;
|
icm.output = v;
|
||||||
icm.gamma = v;
|
icm.gamma = v;
|
||||||
@@ -530,7 +530,7 @@ void ParamsEdited::initFrom (const std::vector<rtengine::procparams::ProcParams>
|
|||||||
icm.input = icm.input && p.icm.input == other.icm.input;
|
icm.input = icm.input && p.icm.input == other.icm.input;
|
||||||
icm.toneCurve = icm.toneCurve && p.icm.toneCurve == other.icm.toneCurve;
|
icm.toneCurve = icm.toneCurve && p.icm.toneCurve == other.icm.toneCurve;
|
||||||
icm.blendCMSMatrix = icm.blendCMSMatrix && p.icm.blendCMSMatrix == other.icm.blendCMSMatrix;
|
icm.blendCMSMatrix = icm.blendCMSMatrix && p.icm.blendCMSMatrix == other.icm.blendCMSMatrix;
|
||||||
icm.preferredProfile = icm.preferredProfile && p.icm.preferredProfile == other.icm.preferredProfile;
|
icm.dcpIlluminant = icm.dcpIlluminant && p.icm.dcpIlluminant == other.icm.dcpIlluminant;
|
||||||
icm.working = icm.working && p.icm.working == other.icm.working;
|
icm.working = icm.working && p.icm.working == other.icm.working;
|
||||||
icm.output = icm.output && p.icm.output == other.icm.output;
|
icm.output = icm.output && p.icm.output == other.icm.output;
|
||||||
icm.gamma = icm.gamma && p.icm.gamma == other.icm.gamma;
|
icm.gamma = icm.gamma && p.icm.gamma == other.icm.gamma;
|
||||||
@@ -825,7 +825,7 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten
|
|||||||
if (icm.input) toEdit.icm.input = mods.icm.input;
|
if (icm.input) toEdit.icm.input = mods.icm.input;
|
||||||
if (icm.toneCurve) toEdit.icm.toneCurve = mods.icm.toneCurve;
|
if (icm.toneCurve) toEdit.icm.toneCurve = mods.icm.toneCurve;
|
||||||
if (icm.blendCMSMatrix) toEdit.icm.blendCMSMatrix = mods.icm.blendCMSMatrix;
|
if (icm.blendCMSMatrix) toEdit.icm.blendCMSMatrix = mods.icm.blendCMSMatrix;
|
||||||
if (icm.preferredProfile) toEdit.icm.preferredProfile = mods.icm.preferredProfile;
|
if (icm.dcpIlluminant) toEdit.icm.dcpIlluminant = mods.icm.dcpIlluminant;
|
||||||
if (icm.working) toEdit.icm.working = mods.icm.working;
|
if (icm.working) toEdit.icm.working = mods.icm.working;
|
||||||
if (icm.output) toEdit.icm.output = mods.icm.output;
|
if (icm.output) toEdit.icm.output = mods.icm.output;
|
||||||
//if (icm.gampos) toEdit.icm.gampos = mods.icm.gampos;
|
//if (icm.gampos) toEdit.icm.gampos = mods.icm.gampos;
|
||||||
|
@@ -412,7 +412,7 @@ class ColorManagementParamsEdited {
|
|||||||
bool input;
|
bool input;
|
||||||
bool toneCurve;
|
bool toneCurve;
|
||||||
bool blendCMSMatrix;
|
bool blendCMSMatrix;
|
||||||
bool preferredProfile;
|
bool dcpIlluminant;
|
||||||
bool working;
|
bool working;
|
||||||
bool output;
|
bool output;
|
||||||
bool gamma;
|
bool gamma;
|
||||||
|
Reference in New Issue
Block a user