From 6c089a86545cea516c35a8a1b552f0623ba847e9 Mon Sep 17 00:00:00 2001 From: torger Date: Thu, 27 Feb 2014 08:52:33 +0100 Subject: [PATCH] Fixed forward matrix transpose bug; use DNG reference code white balance derivation for DCP renditions to better handle extreme white balances. --- rtengine/dcp.cc | 330 ++++++++++++++++++++++++++++++++++--- rtengine/dcp.h | 11 +- rtengine/rawimagesource.cc | 7 +- rtengine/rawimagesource.h | 10 +- rtengine/rtthumbnail.cc | 8 +- 5 files changed, 325 insertions(+), 41 deletions(-) diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index 18b72810c..b067b2120 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -136,6 +136,37 @@ static void MapWhiteMatrix(const double white1[3], const double white2[3], doubl Multiply3x3(temp, Mb, B); } +static void XYZtoXY(const double XYZ[3], double XY[2]) { + double X = XYZ[0]; + double Y = XYZ[1]; + double Z = XYZ[2]; + double total = X + Y + Z; + if (total > 0.0) { + XY[0] = X / total; + XY[1] = Y / total; + } else { + XY[0] = 0.3457; + XY[1] = 0.3585; + } +} + +static void XYtoXYZ(const double XY[2], double XYZ[3]) { + double temp[2] = { XY[0], XY[1] }; + // Restrict xy coord to someplace inside the range of real xy coordinates. + // This prevents math from doing strange things when users specify + // extreme temperature/tint coordinates. + temp[0] = std::max(0.000001, std::min(temp[0], 0.999999)); + temp[1] = std::max(0.000001, std::min(temp[1], 0.999999)); + if (temp[0] + temp[1] > 0.999999) { + double scale = 0.999999 / (temp[0] + temp[1]); + temp[0] *= scale; + temp[1] *= scale; + } + XYZ[0] = temp[0] / temp[1]; + XYZ[1] = 1.0; + XYZ[2] = (1.0 - temp[0] - temp[1]) / temp[1]; +} + enum dngCalibrationIlluminant { lsUnknown = 0, lsDaylight = 1, @@ -201,13 +232,48 @@ static double calibrationIlluminantToTemperature(int light) { return 0.0; } } - -void DCPProfile::MakeXYZCAM(ColorTemp &wb, int preferredIlluminant, double (*mXYZCAM)[3]) const +void DCPProfile::MakeXYZCAM(ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], 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 + double neutral[3]; // same as the DNG "AsShotNeutral" tag if white balance is Camera's own + { + /* A bit messy matrixing and conversions to get the neutral[] array from RT's own white balance which is stored in + sRGB space, while the DCP code needs multipliers in CameraRGB space */ + double r, g, b; + wb.getMultipliers(r, g, b); + + // camWbMatrix == imatrices.xyz_cam + double cam_xyz[3][3]; + Invert3x3(camWbMatrix, cam_xyz); + double cam_rgb[3][3]; + Multiply3x3(cam_xyz, xyz_sRGB, cam_rgb); + double camwb_red = cam_rgb[0][0]*r + cam_rgb[0][1]*g + cam_rgb[0][2]*b; + double camwb_green = cam_rgb[1][0]*r + cam_rgb[1][1]*g + cam_rgb[1][2]*b; + double camwb_blue = cam_rgb[2][0]*r + cam_rgb[2][1]*g + cam_rgb[2][2]*b; + neutral[0] = camwb_red / pre_mul[0]; + neutral[1] = camwb_green / pre_mul[1]; + neutral[2] = camwb_blue / pre_mul[2]; + double maxentry = 0; + for (int i = 0; i < 3; i++) { + if (neutral[i] > maxentry) { + maxentry = neutral[i]; + } + } + for (int i = 0; i < 3; i++) { + neutral[i] /= maxentry; + } + } + + /* Calculate what the RGB multipliers corresponds to as a white XY coordinate, based on the + DCP ColorMatrix or ColorMatrices if dual-illuminant. This is the DNG reference code way to + do it, which is a bit different from RT's own white balance model at the time of writing. + When RT's white balance can make use of the DCP color matrices we could use that instead. */ + double white_xy[2]; + dngref_NeutralToXY(neutral, preferredIlluminant, white_xy); + bool hasFwd1 = hasForwardMatrix1; bool hasFwd2 = hasForwardMatrix2; bool hasCol1 = hasColorMatrix1; @@ -222,13 +288,20 @@ void DCPProfile::MakeXYZCAM(ColorTemp &wb, int preferredIlluminant, double (*mXY // 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 ((hasCol1 && hasCol2) || (hasFwd1 && hasFwd2)) { + double wbtemp; + /* DNG ref way to convert XY to temperature, which affect matrix mixing. A different model here + typically does not affect the result too much, ie it's probably not strictly necessary to + use the DNG reference code here, but we do it for now. */ + dngref_XYCoord2Temperature(white_xy, &wbtemp, NULL); + if (wbtemp <= temperature1) { + mix = 1.0; + } else if (wbtemp >= temperature2) { + mix = 0.0; + } else { + double invT = 1.0 / wbtemp; + mix = (invT - (1.0 / temperature2)) / ((1.0 / temperature1) - (1.0 / temperature2)); + } } if (hasFwd1 || hasFwd2) { @@ -248,7 +321,14 @@ void DCPProfile::MakeXYZCAM(ColorTemp &wb, int preferredIlluminant, double (*mXY } else { memcpy(mFwd, mForwardMatrix2, sizeof(mFwd)); } - ConvertDNGForwardMatrix2XYZCAM(mFwd,mXYZCAM,wb); + /* + The exact position of the white XY coordinate affects the result very much, thus + it's important that the result is very similar or the same as DNG reference code. + Especially important is it that the raw-embedded "AsShot" multipliers is translated + to the same white XY coordinate as the DNG reference code, or else third party DCPs + will show incorrect color. + */ + ConvertDNGForwardMatrix2XYZCAM(mFwd,mXYZCAM,white_xy); } else { // Colormatrix double mCol[3][3]; @@ -366,7 +446,7 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) { 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); + mForwardMatrix1[row][col]=(float)tag->toDouble((col+row*3)*8); } } } @@ -375,7 +455,7 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) { 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); + mForwardMatrix2[row][col]=(float)tag->toDouble((col+row*3)*8); } } } @@ -391,7 +471,7 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) { for (int row=0;row<3;row++) { for (int col=0;col<3;col++) { - mColorMatrix1[col][row]=(float)tag->toDouble((col+row*3)*8); + mColorMatrix1[row][col]=(float)tag->toDouble((col+row*3)*8); } } @@ -453,7 +533,7 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) { for (int row=0;row<3;row++) { for (int col=0;col<3;col++) { - mColorMatrix2[col][row]= (tag!=NULL ? (float)tag->toDouble((col+row*3)*8) : mColorMatrix1[col][row]); + mColorMatrix2[row][col]= (tag!=NULL ? (float)tag->toDouble((col+row*3)*8) : mColorMatrix1[row][col]); } } @@ -512,7 +592,8 @@ DCPProfile::DCPProfile(Glib::ustring fname, bool isRTProfile) { willInterpolate = true; } } - } else if (hasColorMatrix1 && hasColorMatrix2) { + } + if (hasColorMatrix1 && hasColorMatrix2) { if (memcmp(mColorMatrix1, mColorMatrix2, sizeof(mColorMatrix1)) != 0) { willInterpolate = true; } @@ -537,7 +618,7 @@ void DCPProfile::ConvertDNGMatrix2XYZCAM(const double (*mColorMatrix)[3], double for (i=0; i<3; i++) for (j=0; j<3; j++) for (k=0; k<3; k++) - cam_xyz[i][j] += mColorMatrix[j][k] * (i==k); + cam_xyz[i][j] += mColorMatrix[k][j] * (i==k); // Multiply out XYZ colorspace @@ -696,19 +777,217 @@ void DCPProfile::HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, co v *= valScale; } +struct ruvt { + double r; + double u; + double v; + double t; +}; + +static const double kTintScale = -3000.0; +static const ruvt kTempTable [] = + { + { 0, 0.18006, 0.26352, -0.24341 }, + { 10, 0.18066, 0.26589, -0.25479 }, + { 20, 0.18133, 0.26846, -0.26876 }, + { 30, 0.18208, 0.27119, -0.28539 }, + { 40, 0.18293, 0.27407, -0.30470 }, + { 50, 0.18388, 0.27709, -0.32675 }, + { 60, 0.18494, 0.28021, -0.35156 }, + { 70, 0.18611, 0.28342, -0.37915 }, + { 80, 0.18740, 0.28668, -0.40955 }, + { 90, 0.18880, 0.28997, -0.44278 }, + { 100, 0.19032, 0.29326, -0.47888 }, + { 125, 0.19462, 0.30141, -0.58204 }, + { 150, 0.19962, 0.30921, -0.70471 }, + { 175, 0.20525, 0.31647, -0.84901 }, + { 200, 0.21142, 0.32312, -1.0182 }, + { 225, 0.21807, 0.32909, -1.2168 }, + { 250, 0.22511, 0.33439, -1.4512 }, + { 275, 0.23247, 0.33904, -1.7298 }, + { 300, 0.24010, 0.34308, -2.0637 }, + { 325, 0.24702, 0.34655, -2.4681 }, + { 350, 0.25591, 0.34951, -2.9641 }, + { 375, 0.26400, 0.35200, -3.5814 }, + { 400, 0.27218, 0.35407, -4.3633 }, + { 425, 0.28039, 0.35577, -5.3762 }, + { 450, 0.28863, 0.35714, -6.7262 }, + { 475, 0.29685, 0.35823, -8.5955 }, + { 500, 0.30505, 0.35907, -11.324 }, + { 525, 0.31320, 0.35968, -15.628 }, + { 550, 0.32129, 0.36011, -23.325 }, + { 575, 0.32931, 0.36038, -40.770 }, + { 600, 0.33724, 0.36051, -116.45 } + }; + +void DCPProfile::dngref_XYCoord2Temperature(const double whiteXY[2], double *temp, double *tint) const { + double fTemperature = 0; + double fTint = 0; + + // Convert to uv space. + double u = 2.0 * whiteXY[0] / (1.5 - whiteXY[0] + 6.0 * whiteXY[1]); + double v = 3.0 * whiteXY[1] / (1.5 - whiteXY[0] + 6.0 * whiteXY[1]); + + // Search for line pair coordinate is between. + double last_dt = 0.0; + double last_dv = 0.0; + double last_du = 0.0; + + for (uint32_t index = 1; index <= 30; index++) { + // Convert slope to delta-u and delta-v, with length 1. + double du = 1.0; + double dv = kTempTable [index] . t; + double len = sqrt (1.0 + dv * dv); + du /= len; + dv /= len; + + // Find delta from black body point to test coordinate. + double uu = u - kTempTable [index] . u; + double vv = v - kTempTable [index] . v; + + // Find distance above or below line. + double dt = - uu * dv + vv * du; + + // If below line, we have found line pair. + if (dt <= 0.0 || index == 30) { + // Find fractional weight of two lines. + if (dt > 0.0) + dt = 0.0; + dt = -dt; + double f; + if (index == 1) + { + f = 0.0; + } + else + { + f = dt / (last_dt + dt); + } + + // Interpolate the temperature. + fTemperature = 1.0E6 / (kTempTable [index - 1] . r * f + + kTempTable [index ] . r * (1.0 - f)); + + // Find delta from black body point to test coordinate. + uu = u - (kTempTable [index - 1] . u * f + + kTempTable [index ] . u * (1.0 - f)); + vv = v - (kTempTable [index - 1] . v * f + + kTempTable [index ] . v * (1.0 - f)); + // Interpolate vectors along slope. + du = du * (1.0 - f) + last_du * f; + dv = dv * (1.0 - f) + last_dv * f; + len = sqrt (du * du + dv * dv); + du /= len; + dv /= len; + + // Find distance along slope. + fTint = (uu * du + vv * dv) * kTintScale; + break; + } + // Try next line pair. + last_dt = dt; + last_du = du; + last_dv = dv; + } + if (temp != NULL) + *temp = fTemperature; + if (tint != NULL) + *tint = fTint; +} + +void DCPProfile::dngref_FindXYZtoCamera(const double whiteXY[2], int preferredIlluminant, double (*xyzToCamera)[3]) const { + + bool hasCol1 = hasColorMatrix1; + bool hasCol2 = hasColorMatrix2; + if (preferredIlluminant == 1) { + if (hasCol1) hasCol2 = false; + } else if (preferredIlluminant == 2) { + if (hasCol2) hasCol1 = false; + } + + // mix if we have two matrices + double mix; + if (hasCol1 && hasCol2) { + double wbtemp; + /* + Note: we're using DNG SDK reference code for XY to temperature translation to get the exact same mix as + the reference code does. + */ + dngref_XYCoord2Temperature(whiteXY, &wbtemp, NULL); + if (wbtemp <= temperature1) { + mix = 1.0; + } else if (wbtemp >= temperature2) { + mix = 0.0; + } else { + double invT = 1.0 / wbtemp; + mix = (invT - (1.0 / temperature2)) / ((1.0 / temperature1) - (1.0 / temperature2)); + } + } + + // Interpolate the color matrix. + 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)); + } + memcpy(xyzToCamera, mCol, sizeof(mCol)); +} + +void DCPProfile::dngref_NeutralToXY(double neutral[3], int preferredIlluminant, double XY[2]) const { + const int kMaxPasses = 30; + double lastXY[2] = { 0.3457, 0.3585 }; // D50 + for (int pass = 0; pass < kMaxPasses; pass++) { + double xyzToCamera[3][3]; + dngref_FindXYZtoCamera(lastXY, preferredIlluminant, xyzToCamera); + + double invM[3][3], nextXYZ[3], nextXY[2]; + Invert3x3(xyzToCamera, invM); + Multiply3x3_v3(invM, neutral, nextXYZ); + XYZtoXY(nextXYZ, nextXY); + + if (fabs(nextXY[0] - lastXY[0]) + + fabs(nextXY[1] - lastXY[1]) < 0.0000001) + { + XY[0] = nextXY[0]; + XY[1] = nextXY[1]; + return; + } + // If we reach the limit without converging, we are most likely + // in a two value oscillation. So take the average of the last + // two estimates and give up. + if (pass == kMaxPasses - 1) { + nextXY[0] = (lastXY[0] + nextXY[0]) * 0.5; + nextXY[1] = (lastXY[1] + nextXY[1]) * 0.5; + } + lastXY[0] = nextXY[0]; + lastXY[1] = nextXY[1]; + } + XY[0] = lastXY[0]; + XY[1] = lastXY[1]; +} + // Convert DNG forward matrix to xyz_cam compatible matrix -void DCPProfile::ConvertDNGForwardMatrix2XYZCAM(const double (*mForwardMatrix)[3], double (*mXYZCAM)[3], ColorTemp &wb) const { +void DCPProfile::ConvertDNGForwardMatrix2XYZCAM(const double (*mForwardMatrix)[3], double (*mXYZCAM)[3], const double whiteXY[2]) const { // Convert ForwardMatrix (white-balanced CameraRGB -> XYZ D50 matrix) // into a ColorMatrix (XYZ -> CameraRGB) - double X, Z; - ColorTemp::temp2mulxyz(wb.getTemp(), wb.getGreen(), wb.getMethod(), X, Z); + double white_xyz[3]; + XYtoXYZ(whiteXY, white_xyz); - 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) + // Cancel out the white balance to get a CameraRGB -> XYZ D50 matrix (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); @@ -729,12 +1008,12 @@ void DCPProfile::ConvertDNGForwardMatrix2XYZCAM(const double (*mForwardMatrix)[3 ConvertDNGMatrix2XYZCAM(dngColorMatrix, mXYZCAM); } -void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, float rawWhiteFac, bool useToneCurve) const { +void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], float rawWhiteFac, bool useToneCurve) const { TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace); double mXYZCAM[3][3]; - MakeXYZCAM(wb, preferredIlluminant, mXYZCAM); + MakeXYZCAM(wb, pre_mul, camWbMatrix, preferredIlluminant, mXYZCAM); HSBModify *deleteTableHandle; const HSBModify *deltaBase = MakeHueSatMap(wb, preferredIlluminant, &deleteTableHandle); @@ -812,7 +1091,6 @@ void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring h/=6.f; Color::hsv2rgb( h, s, v, newr, newg, newb); } - // tone curve if (useToneCurve) toneCurve.Apply(newr, newg, newb); @@ -827,11 +1105,11 @@ void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring } // Integer variant is legacy, only used for thumbs. Simply take the matrix here -void DCPProfile::Apply(Image16 *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, bool useToneCurve) const { +void DCPProfile::Apply(Image16 *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], bool useToneCurve) const { TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace); double mXYZCAM[3][3]; - MakeXYZCAM(wb, preferredIlluminant, mXYZCAM); + MakeXYZCAM(wb, pre_mul, camWbMatrix, preferredIlluminant, mXYZCAM); useToneCurve&=toneCurve; diff --git a/rtengine/dcp.h b/rtengine/dcp.h index b7a3fdbbc..d5b9a43fb 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -59,10 +59,13 @@ namespace rtengine { AdobeToneCurve toneCurve; - void MakeXYZCAM(ColorTemp &wb, int preferredIlluminant, double (*mXYZCAM)[3]) const; + void dngref_XYCoord2Temperature(const double whiteXY[2], double *temp, double *tint) const; + void dngref_FindXYZtoCamera(const double whiteXY[2], int preferredIlluminant, double (*xyzToCamera)[3]) const; + void dngref_NeutralToXY(double neutral[3], int preferredIlluminant, double XY[2]) const; + void MakeXYZCAM(ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], int preferredIlluminant, double (*mXYZCAM)[3]) const; const HSBModify* MakeHueSatMap(ColorTemp &wb, int preferredIlluminant, HSBModify **deleteHandle) const; void ConvertDNGMatrix2XYZCAM(const double (*mColorMatrix)[3], double (*mXYZCAM)[3]) const; - void ConvertDNGForwardMatrix2XYZCAM(const double (*mForwardMatrix)[3], double (*mXYZCAM)[3], ColorTemp &wb) const; + void ConvertDNGForwardMatrix2XYZCAM(const double (*mForwardMatrix)[3], double (*mXYZCAM)[3], const double whiteXY[2]) 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: @@ -71,8 +74,8 @@ namespace rtengine { bool getHasToneCurve() { return hasToneCurve; } 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; + void Apply(Imagefloat *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, double pre_mul[3], double camMatrix[3][3], float rawWhiteFac=1, bool useToneCurve=false) const; + void Apply(Image16 *pImg, int preferredIlluminant, Glib::ustring workingSpace, ColorTemp &wb, double pre_mul[3], double camMatrix[3][3], bool useToneCurve) const; }; class DCPStore { diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 94d897744..f717fd5eb 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -435,7 +435,8 @@ void RawImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, Pre } void RawImageSource::convertColorSpace(Imagefloat* image, ColorManagementParams cmp, ColorTemp &wb, RAWParams raw) { - colorSpaceConversion (image, cmp, wb, raw, embProfile, camProfile, imatrices.xyz_cam, (static_cast(getMetaData()))->getCamera()); + double pre_mul[3] = { ri->get_pre_mul(0), ri->get_pre_mul(1), ri->get_pre_mul(2) }; + colorSpaceConversion (image, cmp, wb, pre_mul, raw, embProfile, camProfile, imatrices.xyz_cam, (static_cast(getMetaData()))->getCamera()); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1755,7 +1756,7 @@ lab2ProphotoRgbD50(float L, float A, float B, float& r, float& g, float& b) } // Converts raw image including ICC input profile to working space - floating point version -void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams &cmp, ColorTemp &wb, float rawWhitePoint, cmsHPROFILE embedded, cmsHPROFILE camprofile, double camMatrix[3][3], const std::string &camName) { +void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams &cmp, ColorTemp &wb, double pre_mul[3], float rawWhitePoint, cmsHPROFILE embedded, cmsHPROFILE camprofile, double camMatrix[3][3], const std::string &camName) { //MyTime t1, t2, t3; //t1.set (); @@ -1768,7 +1769,7 @@ void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams if (dcpProf!=NULL) { // DCP processing - dcpProf->Apply(im, cmp.dcpIlluminant, cmp.working, wb, rawWhitePoint, cmp.toneCurve); + dcpProf->Apply(im, cmp.dcpIlluminant, cmp.working, wb, pre_mul, camMatrix, rawWhitePoint, cmp.toneCurve); return; } diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index adb356854..54dd59985 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -68,7 +68,7 @@ class RawImageSource : public ImageSource { static LUTf invGrad; // for fast_demosaic static LUTf initInvGrad (); static bool findInputProfile(Glib::ustring inProfile, cmsHPROFILE embedded, std::string camName, DCPProfile **dcpProf, cmsHPROFILE& in); - static void colorSpaceConversion (Imagefloat* im, ColorManagementParams &cmp, ColorTemp &wb, float rawWhitePoint, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName); + static void colorSpaceConversion (Imagefloat* im, ColorManagementParams &cmp, ColorTemp &wb, double pre_mul[3], float rawWhitePoint, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName); protected: MyMutex getImageMutex; // locks getImage @@ -181,11 +181,11 @@ class RawImageSource : public ImageSource { void convertColorSpace(Imagefloat* image, ColorManagementParams cmp, ColorTemp &wb, RAWParams raw); //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, ColorTemp &wb, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName) { - colorSpaceConversion (im, cmp, wb, 0.0f, embedded, camprofile, cam, camName); + static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName) { + colorSpaceConversion (im, cmp, wb, pre_mul, 0.0f, embedded, camprofile, cam, 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, wb, float(raw.expos), embedded, camprofile, cam, camName); + static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, ColorTemp &wb, double pre_mul[3], RAWParams raw, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName) { + colorSpaceConversion (im, cmp, wb, pre_mul, float(raw.expos), embedded, camprofile, cam, camName); } static void inverse33 (const double (*coeff)[3], double (*icoeff)[3]); diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 6234af15c..3067167cd 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -670,10 +670,12 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei // if luma denoise has to be done for thumbnails, it should be right here // perform color space transformation - if (isRaw) - RawImageSource::colorSpaceConversion (baseImg, params.icm, currWB, embProfile, camProfile, cam2xyz, camName ); - else + if (isRaw) { + double pre_mul[3] = { redMultiplier, greenMultiplier, blueMultiplier }; + RawImageSource::colorSpaceConversion (baseImg, params.icm, currWB, pre_mul, embProfile, camProfile, cam2xyz, camName ); + } else { StdImageSource::colorSpaceConversion (baseImg, params.icm, embProfile, thumbImg->getSampleFormat()); + } int fw = baseImg->width; int fh = baseImg->height;