diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index f3ba11211..ebe2d8aee 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -16,6 +16,7 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ + #include #include @@ -609,10 +610,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : has_tone_curve(false), has_baseline_exposure_offset(false), will_interpolate(false), - baseline_exposure_offset(0.0), - deltas_1(nullptr), - deltas_2(nullptr), - look_table(nullptr) + baseline_exposure_offset(0.0) { constexpr int tiff_float_size = 4; @@ -709,9 +707,9 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_LOOK_TABLE_DATA)); look_info.array_count = tag->getCount() / 3; - look_table = new HSBModify[look_info.array_count]; + look_table.resize(look_info.array_count); - for (int i = 0; i < look_info.array_count; i++) { + for (unsigned int i = 0; i < look_info.array_count; i++) { look_table[i].hue_shift = tag->toDouble((i * 3) * tiff_float_size); look_table[i].sat_scale = tag->toDouble((i * 3 + 1) * tiff_float_size); look_table[i].val_scale = tag->toDouble((i * 3 + 2) * tiff_float_size); @@ -724,11 +722,11 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : : static_cast(look_info.hue_divisions) / 6.0f; look_info.pc.s_scale = look_info.sat_divisions - 1; look_info.pc.v_scale = look_info.val_divisions - 1; - look_info.pc.maxHueIndex0 = look_info.hue_divisions - 1; - look_info.pc.maxSatIndex0 = look_info.sat_divisions - 2; - look_info.pc.maxValIndex0 = look_info.val_divisions - 2; - look_info.pc.hueStep = look_info.sat_divisions; - look_info.pc.valStep = look_info.hue_divisions * look_info.pc.hueStep; + look_info.pc.max_hue_index0 = look_info.hue_divisions - 1; + look_info.pc.max_sat_index0 = look_info.sat_divisions - 2; + look_info.pc.max_val_index0 = look_info.val_divisions - 2; + look_info.pc.hue_step = look_info.sat_divisions; + look_info.pc.val_step = look_info.hue_divisions * look_info.pc.hue_step; } tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_HUE_SAT_MAP_DIMS)); @@ -744,9 +742,9 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_HUE_SAT_MAP_DATA_1)); delta_info.array_count = tag->getCount() / 3; - deltas_1 = new HSBModify[delta_info.array_count]; + deltas_1.resize(delta_info.array_count); - for (int i = 0; i < delta_info.array_count; ++i) { + for (unsigned int i = 0; i < delta_info.array_count; ++i) { deltas_1[i].hue_shift = tag->toDouble((i * 3) * tiff_float_size); deltas_1[i].sat_scale = tag->toDouble((i * 3 + 1) * tiff_float_size); deltas_1[i].val_scale = tag->toDouble((i * 3 + 2) * tiff_float_size); @@ -758,11 +756,11 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : : static_cast(delta_info.hue_divisions) / 6.0f; delta_info.pc.s_scale = delta_info.sat_divisions - 1; delta_info.pc.v_scale = delta_info.val_divisions - 1; - delta_info.pc.maxHueIndex0 = delta_info.hue_divisions - 1; - delta_info.pc.maxSatIndex0 = delta_info.sat_divisions - 2; - delta_info.pc.maxValIndex0 = delta_info.val_divisions - 2; - delta_info.pc.hueStep = delta_info.sat_divisions; - delta_info.pc.valStep = delta_info.hue_divisions * delta_info.pc.hueStep; + delta_info.pc.max_hue_index0 = delta_info.hue_divisions - 1; + delta_info.pc.max_sat_index0 = delta_info.sat_divisions - 2; + delta_info.pc.max_val_index0 = delta_info.val_divisions - 2; + delta_info.pc.hue_step = delta_info.sat_divisions; + delta_info.pc.val_step = delta_info.hue_divisions * delta_info.pc.hue_step; } if (light_source_2 != -1) { @@ -782,7 +780,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : // Second huesatmap if (has_second_hue_sat) { - deltas_2 = new HSBModify[delta_info.array_count]; + deltas_2.resize(delta_info.array_count); // Saturation maps. Need to be unwinded. tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_HUE_SAT_MAP_DATA_2)); @@ -862,7 +860,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : will_interpolate = true; } - if (deltas_1 && deltas_2) { + if (!deltas_1.empty() && !deltas_2.empty()) { // We assume tables are different will_interpolate = true; } @@ -874,7 +872,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : will_interpolate = true; } - if (deltas_1 && deltas_2) { + if (!deltas_1.empty() && !deltas_2.empty()) { will_interpolate = true; } } @@ -886,9 +884,6 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) : DCPProfile::~DCPProfile() { - delete[] deltas_1; - delete[] deltas_2; - delete[] look_table; } bool DCPProfile::getHasToneCurve() const @@ -898,12 +893,12 @@ bool DCPProfile::getHasToneCurve() const bool DCPProfile::getHasLookTable() const { - return look_table; + return !look_table.empty(); } bool DCPProfile::getHasHueSatMap() const { - return deltas_1; + return !deltas_1.empty(); } bool DCPProfile::getHasBaselineExposureOffset() const @@ -911,100 +906,129 @@ bool DCPProfile::getHasBaselineExposureOffset() const return has_baseline_exposure_offset; } -void DCPProfile::getIlluminants(int &i1, double &temp1, int &i2, double &temp2, bool &willInterpolate_) const +DCPProfile::Illuminants DCPProfile::getIlluminants() const { - i1 = light_source_1; - i2 = light_source_2; - temp1 = temperature_1, temp2 = temperature_2; - willInterpolate_ = will_interpolate; -}; + return { + light_source_1, + light_source_2, + temperature_1, + temperature_2, + will_interpolate + }; +} -void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, const Glib::ustring &workingSpace, const ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], bool useToneCurve, bool applyHueSatMap, bool applyLookTable) const +void DCPProfile::apply( + Imagefloat* img, + int preferred_illuminant, + const Glib::ustring& working_space, + const ColorTemp& white_balance, + double pre_mul[3], + double cam_wb_matrix[3][3], + bool use_tone_curve, + bool apply_hue_sat_map, + bool apply_look_table +) const { + const TMatrix work_matrix = iccStore->workingSpaceInverseMatrix(working_space); - TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace); + double xyz_cam[3][3]; // Camera RGB to XYZ D50 matrix + makeXyzCam(white_balance, pre_mul, cam_wb_matrix, preferred_illuminant, xyz_cam); - double mXYZCAM[3][3]; // Camera RGB to XYZ D50 matrix - MakeXYZCAM(wb, pre_mul, camWbMatrix, preferredIlluminant, mXYZCAM); - HSBModify *deleteTableHandle; - const HSBModify *deltaBase = MakeHueSatMap(wb, preferredIlluminant, &deleteTableHandle); + const std::vector delta_base = makeHueSatMap(white_balance, preferred_illuminant); - if (!deltaBase) { - applyHueSatMap = false; + if (delta_base.empty()) { + apply_hue_sat_map = false; } - if (!look_table) { - applyLookTable = false; + if (look_table.empty()) { + apply_look_table = false; } - useToneCurve &= tone_curve; + use_tone_curve = use_tone_curve && tone_curve; - if (!applyHueSatMap && !applyLookTable && !useToneCurve) { - //===== 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}}; + if (!apply_hue_sat_map && !apply_look_table && !use_tone_curve) { + // The fast path: No LUT and not tone curve --> Calculate matrix for direct conversion raw>working space + double mat[3][3] = {}; - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - for (int k = 0; k < 3; k++) { - mat[i][j] += mWork[i][k] * mXYZCAM[k][j]; + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + for (int k = 0; k < 3; ++k) { + mat[i][j] += work_matrix[i][k] * xyz_cam[k][j]; } + } + } // Apply the matrix part +#ifdef _OPENMP #pragma omp parallel for +#endif + for (int y = 0; y < img->height; ++y) { + for (int x = 0; x < img->width; x++) { + const float& newr = mat[0][0] * img->r(y, x) + mat[0][1] * img->g(y, x) + mat[0][2] * img->b(y, x); + const float& newg = mat[1][0] * img->r(y, x) + mat[1][1] * img->g(y, x) + mat[1][2] * img->b(y, x); + const float& newb = mat[2][0] * img->r(y, x) + mat[2][1] * img->g(y, x) + mat[2][2] * img->b(y, x); - for (int y = 0; y < pImg->height; y++) { - float newr, newg, newb; - - for (int x = 0; x < pImg->width; x++) { - newr = mat[0][0] * pImg->r(y, x) + mat[0][1] * pImg->g(y, x) + mat[0][2] * pImg->b(y, x); - newg = mat[1][0] * pImg->r(y, x) + mat[1][1] * pImg->g(y, x) + mat[1][2] * pImg->b(y, x); - newb = mat[2][0] * pImg->r(y, x) + mat[2][1] * pImg->g(y, x) + mat[2][2] * pImg->b(y, x); - - pImg->r(y, x) = newr; - pImg->g(y, x) = newg; - pImg->b(y, x) = newb; + img->r(y, x) = newr; + img->g(y, x) = newg; + img->b(y, x) = newb; } } } else { - //===== LUT available- Calculate matrix for conversion raw>ProPhoto - double m2ProPhoto[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + // LUT available --> Calculate matrix for conversion raw>ProPhoto + double pro_photo[3][3] = {}; - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - for (int k = 0; k < 3; k++) { - m2ProPhoto[i][j] += prophoto_xyz[i][k] * mXYZCAM[k][j]; + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + for (int k = 0; k < 3; ++k) { + pro_photo[i][j] += prophoto_xyz[i][k] * xyz_cam[k][j]; } + } + } - double m2Work[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; + double work[3][3] = {}; - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - for (int k = 0; k < 3; k++) { - m2Work[i][j] += mWork[i][k] * xyz_prophoto[k][j]; + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + for (int k = 0; k < 3; ++k) { + work[i][j] += work_matrix[i][k] * xyz_prophoto[k][j]; } + } + } - // Convert to prophoto and apply LUT + // Convert to ProPhoto and apply LUT +#ifdef _OPENMP #pragma omp parallel for +#endif + for (int y = 0; y < img->height; ++y) { + float h, s, v, hs, ss, vs; - for (int y = 0; y < pImg->height; y++) { - float newr, newg, newb, h, s, v, hs, ss, vs; + for (int x = 0; x < img->width; x++) { + float newr = pro_photo[0][0] * img->r(y, x) + pro_photo[0][1] * img->g(y, x) + pro_photo[0][2] * img->b(y, x); + float newg = pro_photo[1][0] * img->r(y, x) + pro_photo[1][1] * img->g(y, x) + pro_photo[1][2] * img->b(y, x); + float newb = pro_photo[2][0] * img->r(y, x) + pro_photo[2][1] * img->g(y, x) + pro_photo[2][2] * img->b(y, x); - for (int x = 0; x < pImg->width; x++) { - newr = m2ProPhoto[0][0] * pImg->r(y, x) + m2ProPhoto[0][1] * pImg->g(y, x) + m2ProPhoto[0][2] * pImg->b(y, x); - newg = m2ProPhoto[1][0] * pImg->r(y, x) + m2ProPhoto[1][1] * pImg->g(y, x) + m2ProPhoto[1][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 ((applyHueSatMap || applyLookTable) && newr >= 0 && newg >= 0 && newb >= 0) { + // If point is in negative area, just the matrix, but not the LUT + if ( + ( + apply_hue_sat_map + || apply_look_table + ) + && newr >= 0 + && newg >= 0 + && newb >= 0 + ) { + float h; + float s; + float v; Color::rgb2hsv(newr, newg, newb, h , s, v); - h *= 6.f; // RT calculates in [0,1] + h *= 6.0f; // RT calculates in [0,1] - if (applyHueSatMap) { - HSDApply(delta_info, deltaBase, h, s, v); + if (apply_hue_sat_map) { + hsdApply(delta_info, delta_base, h, s, v); } - if (applyLookTable) { - HSDApply(look_info, look_table, h, s, v); + if (apply_look_table) { + hsdApply(look_info, look_table, h, s, v); } // RT range correction @@ -1017,24 +1041,20 @@ void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, const Glib::us } h /= 6.f; - Color::hsv2rgb( h, s, v, newr, newg, newb); + + Color::hsv2rgb(h, s, v, newr, newg, newb); } - // tone curve - if (useToneCurve) { + if (use_tone_curve) { tone_curve.Apply(newr, newg, newb); } - pImg->r(y, x) = m2Work[0][0] * newr + m2Work[0][1] * newg + m2Work[0][2] * newb; - pImg->g(y, x) = m2Work[1][0] * newr + m2Work[1][1] * newg + m2Work[1][2] * newb; - pImg->b(y, x) = m2Work[2][0] * newr + m2Work[2][1] * newg + m2Work[2][2] * newb; + img->r(y, x) = work[0][0] * newr + work[0][1] * newg + work[0][2] * newb; + img->g(y, x) = work[1][0] * newr + work[1][1] * newg + work[1][2] * newb; + img->b(y, x) = work[2][0] * newr + work[2][1] * newg + work[2][2] * newb; } } } - - if (deleteTableHandle) { - delete[] deleteTableHandle; - } } void DCPProfile::setStep2ApplyState(const Glib::ustring &workingSpace, bool useToneCurve, bool applyLookTable, bool applyBaselineExposure, ApplyState &asOut) @@ -1044,7 +1064,7 @@ void DCPProfile::setStep2ApplyState(const Glib::ustring &workingSpace, bool useT asOut.applyLookTable = applyLookTable; asOut.blScale = 1.0; - if (!look_table) { + if (look_table.empty()) { asOut.applyLookTable = false; } @@ -1138,7 +1158,7 @@ void DCPProfile::step2ApplyTile(float *rc, float *gc, float *bc, int width, int Color::rgb2hsv(newr, newg, newb, h, s, v); h *= 6.f; // RT calculates in [0,1] - HSDApply(look_info, look_table, h, s, v); + hsdApply(look_info, look_table, h, s, v); s = CLIP01(s); v = CLIP01(v); @@ -1351,7 +1371,7 @@ void DCPProfile::dngref_NeutralToXY(double neutral[3], int preferredIlluminant, XY[1] = lastXY[1]; } -void DCPProfile::MakeXYZCAM(const ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], int preferredIlluminant, double (*mXYZCAM)[3]) const +void DCPProfile::makeXyzCam(const 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) @@ -1551,53 +1571,52 @@ void DCPProfile::MakeXYZCAM(const ColorTemp &wb, double pre_mul[3], double camWb } } -const DCPProfile::HSBModify* DCPProfile::MakeHueSatMap(const ColorTemp &wb, int preferredIlluminant, HSBModify **deleteHandle) const +std::vector DCPProfile::makeHueSatMap(const ColorTemp& white_balance, int preferred_illuminant) const { - - *deleteHandle = nullptr; - - if (!deltas_1) { - return nullptr; + if (deltas_1.empty()) { + return std::vector(); } - if (!deltas_2) { + if (deltas_2.empty()) { return deltas_1; } - if (preferredIlluminant == 1) { + if (preferred_illuminant == 1) { return deltas_1; - } else if (preferredIlluminant == 2) { + } else if (preferred_illuminant == 2) { return deltas_2; } - // Interpolate based on color temperature. - if (temperature_1 <= 0.0 || temperature_2 <= 0.0 || temperature_1 == temperature_2) { + // Interpolate based on color temperature + if ( + temperature_1 <= 0.0 + || temperature_2 <= 0.0 + || temperature_1 == temperature_2 + ) { return deltas_1; } - bool reverseOrder = temperature_1 > temperature_2; - double t1, t2; - - if (reverseOrder) { - t1 = temperature_2; - t2 = temperature_1; - } else { - t1 = temperature_1; - t2 = temperature_2; - } + const bool reverse = temperature_1 > temperature_2; + const double t1 = + reverse + ? temperature_2 + : temperature_1; + const double t2 = + reverse + ? temperature_1 + : temperature_2; double mix; - - if (wb.getTemp() <= t1) { + if (white_balance.getTemp() <= t1) { mix = 1.0; - } else if (wb.getTemp() >= t2) { + } else if (white_balance.getTemp() >= t2) { mix = 0.0; } else { - double invT = 1.0 / wb.getTemp(); + const double invT = 1.0 / white_balance.getTemp(); mix = (invT - (1.0 / t2)) / ((1.0 / t1) - (1.0 / t2)); } - if (reverseOrder) { + if (reverse) { mix = 1.0 - mix; } @@ -1608,156 +1627,139 @@ const DCPProfile::HSBModify* DCPProfile::MakeHueSatMap(const ColorTemp &wb, int } // Interpolate between the tables. - HSBModify *aDeltas = new HSBModify[delta_info.array_count]; - *deleteHandle = aDeltas; - float w1 = (float)mix; - float w2 = 1.0f - (float)mix; + std::vector res(delta_info.array_count); - for (int i = 0; i < delta_info.array_count; i++) { - aDeltas[i].hue_shift = w1 * deltas_1[i].hue_shift + w2 * deltas_2[i].hue_shift; - aDeltas[i].sat_scale = w1 * deltas_1[i].sat_scale + w2 * deltas_2[i].sat_scale; - aDeltas[i].val_scale = w1 * deltas_1[i].val_scale + w2 * deltas_2[i].val_scale; + const float w1 = mix; + const float w2 = 1.0f - w1; + + for (unsigned int i = 0; i < delta_info.array_count; ++i) { + res[i].hue_shift = w1 * deltas_1[i].hue_shift + w2 * deltas_2[i].hue_shift; + res[i].sat_scale = w1 * deltas_1[i].sat_scale + w2 * deltas_2[i].sat_scale; + res[i].val_scale = w1 * deltas_1[i].val_scale + w2 * deltas_2[i].val_scale; } - return aDeltas; + return res; } -void DCPProfile::HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, float &h, float &s, float &v) const +void DCPProfile::hsdApply(const HSDTableInfo& table_info, const std::vector& table_base, float& h, float& s, float& v) const { + // Apply the HueSatMap. Ported from Adobes reference implementation. + float hue_shift; + float sat_scale; + float val_scale; + float v_encoded = v; - // Apply the HueSatMap. Ported from Adobes reference implementation - float hueShift, satScale, valScale; - float vEncoded = v; + if (table_info.val_divisions < 2) { + // Optimize most common case of "2.5D" table + const float h_scaled = h * table_info.pc.h_scale; + const float s_scaled = s * table_info.pc.s_scale; - if (ti.val_divisions < 2) { // Optimize most common case of "2.5D" table. - float hScaled = h * ti.pc.h_scale; - float sScaled = s * ti.pc.s_scale; + int h_index0 = max(h_scaled, 0); + const int s_index0 = max(min(s_scaled, table_info.pc.max_sat_index0), 0); - int hIndex0 = max((int)hScaled, 0); - int sIndex0 = max(min((int)sScaled, ti.pc.maxSatIndex0), 0); + int h_index1 = h_index0 + 1; - int hIndex1 = hIndex0 + 1; - - if (hIndex0 >= ti.pc.maxHueIndex0) { - hIndex0 = ti.pc.maxHueIndex0; - hIndex1 = 0; + if (h_index0 >= table_info.pc.max_hue_index0) { + h_index0 = table_info.pc.max_hue_index0; + h_index1 = 0; } - float hFract1 = hScaled - (float) hIndex0; - float sFract1 = sScaled - (float) sIndex0; + const float h_fract1 = h_scaled - static_cast(h_index0); + const float s_fract1 = s_scaled - static_cast(s_index0); - float hFract0 = 1.0f - hFract1; - float sFract0 = 1.0f - sFract1; + const float h_fract0 = 1.0f - h_fract1; + const float s_fract0 = 1.0f - s_fract1; - const HSBModify *entry00 = tableBase + hIndex0 * ti.pc.hueStep + sIndex0; - const HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * ti.pc.hueStep; + std::vector::size_type e00_index = h_index0 * table_info.pc.hue_step + s_index0; + std::vector::size_type e01_index = e00_index + (h_index1 - h_index0) * table_info.pc.hue_step; - float hueShift0 = hFract0 * entry00->hue_shift + hFract1 * entry01->hue_shift; - float satScale0 = hFract0 * entry00->sat_scale + hFract1 * entry01->sat_scale; - float valScale0 = hFract0 * entry00->val_scale + hFract1 * entry01->val_scale; + const float hue_shift0 = h_fract0 * table_base[e00_index].hue_shift + h_fract1 * table_base[e01_index].hue_shift; + const float sat_scale0 = h_fract0 * table_base[e00_index].sat_scale + h_fract1 * table_base[e01_index].sat_scale; + const float val_scale0 = h_fract0 * table_base[e00_index].val_scale + h_fract1 * table_base[e01_index].val_scale; - entry00++; - entry01++; + ++e00_index; + ++e01_index; - float hueShift1 = hFract0 * entry00->hue_shift + - hFract1 * entry01->hue_shift; - - float satScale1 = hFract0 * entry00->sat_scale + - hFract1 * entry01->sat_scale; - - float valScale1 = hFract0 * entry00->val_scale + - hFract1 * entry01->val_scale; - - hueShift = sFract0 * hueShift0 + sFract1 * hueShift1; - satScale = sFract0 * satScale0 + sFract1 * satScale1; - valScale = sFract0 * valScale0 + sFract1 * valScale1; + const float hueShift1 = h_fract0 * table_base[e00_index].hue_shift + h_fract1 * table_base[e01_index].hue_shift; + const float satScale1 = h_fract0 * table_base[e00_index].sat_scale + h_fract1 * table_base[e01_index].sat_scale; + const float valScale1 = h_fract0 * table_base[e00_index].val_scale + h_fract1 * table_base[e01_index].val_scale; + hue_shift = s_fract0 * hue_shift0 + s_fract1 * hueShift1; + sat_scale = s_fract0 * sat_scale0 + s_fract1 * satScale1; + val_scale = s_fract0 * val_scale0 + s_fract1 * valScale1; } else { + const float h_scaled = h * table_info.pc.h_scale; + const float s_scaled = s * table_info.pc.s_scale; - float hScaled = h * ti.pc.h_scale; - float sScaled = s * ti.pc.s_scale; - - if (ti.srgb_gamma) { - vEncoded = sRGBGammaForward(v); + if (table_info.srgb_gamma) { + v_encoded = sRGBGammaForward(v); } - float vScaled = vEncoded * ti.pc.v_scale; + const float v_scaled = v_encoded * table_info.pc.v_scale; - 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 h_index0 = (int) h_scaled; + const int s_index0 = max(min(s_scaled, table_info.pc.max_sat_index0), 0); + const int v_index0 = max(min(v_scaled, table_info.pc.max_val_index0), 0); - int hIndex1 = hIndex0 + 1; + int h_index1 = h_index0 + 1; - if (hIndex0 >= ti.pc.maxHueIndex0) { - hIndex0 = ti.pc.maxHueIndex0; - hIndex1 = 0; + if (h_index0 >= table_info.pc.max_hue_index0) { + h_index0 = table_info.pc.max_hue_index0; + h_index1 = 0; } - float hFract1 = hScaled - (float) hIndex0; - float sFract1 = sScaled - (float) sIndex0; - float vFract1 = vScaled - (float) vIndex0; + const float h_fract1 = h_scaled - static_cast(h_index0); + const float s_fract1 = s_scaled - static_cast(s_index0); + const float v_fract1 = v_scaled - static_cast(v_index0); - float hFract0 = 1.0f - hFract1; - float sFract0 = 1.0f - sFract1; - float vFract0 = 1.0f - vFract1; + const float h_fract0 = 1.0f - h_fract1; + const float s_fract0 = 1.0f - s_fract1; + const float v_fract0 = 1.0f - v_fract1; - const HSBModify *entry00 = tableBase + vIndex0 * ti.pc.valStep + hIndex0 * ti.pc.hueStep + sIndex0; + std::vector::size_type e00_index = v_index0 * table_info.pc.val_step + h_index0 * table_info.pc.hue_step + s_index0; + std::vector::size_type e01_index = e00_index + (h_index1 - h_index0) * table_info.pc.hue_step; + std::vector::size_type e10_index = e00_index + table_info.pc.val_step; + std::vector::size_type e11_index = e01_index + table_info.pc.val_step; - const HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * ti.pc.hueStep; + const float hueShift0 = + v_fract0 * (h_fract0 * table_base[e00_index].hue_shift + h_fract1 * table_base[e01_index].hue_shift) + + v_fract1 * (h_fract0 * table_base[e10_index].hue_shift + h_fract1 * table_base[e11_index].hue_shift); + const float satScale0 = + v_fract0 * (h_fract0 * table_base[e00_index].sat_scale + h_fract1 * table_base[e01_index].sat_scale) + + v_fract1 * (h_fract0 * table_base[e10_index].sat_scale + h_fract1 * table_base[e11_index].sat_scale); + const float valScale0 = + v_fract0 * (h_fract0 * table_base[e00_index].val_scale + h_fract1 * table_base[e01_index].val_scale) + + v_fract1 * (h_fract0 * table_base[e10_index].val_scale + h_fract1 * table_base[e11_index].val_scale); - const HSBModify *entry10 = entry00 + ti.pc.valStep; - const HSBModify *entry11 = entry01 + ti.pc.valStep; + ++e00_index; + ++e01_index; + ++e10_index; + ++e11_index; - float hueShift0 = vFract0 * (hFract0 * entry00->hue_shift + - hFract1 * entry01->hue_shift) + - vFract1 * (hFract0 * entry10->hue_shift + - hFract1 * entry11->hue_shift); + const float hueShift1 = + v_fract0 * (h_fract0 * table_base[e00_index].hue_shift + h_fract1 * table_base[e01_index].hue_shift) + + v_fract1 * (h_fract0 * table_base[e10_index].hue_shift + h_fract1 * table_base[e11_index].hue_shift); + const float satScale1 = + v_fract0 * (h_fract0 * table_base[e00_index].sat_scale + h_fract1 * table_base[e01_index].sat_scale) + + v_fract1 * (h_fract0 * table_base[e10_index].sat_scale + h_fract1 * table_base[e11_index].sat_scale); + const float valScale1 = + v_fract0 * (h_fract0 * table_base[e00_index].val_scale + h_fract1 * table_base[e01_index].val_scale) + + v_fract1 * (h_fract0 * table_base[e10_index].val_scale + h_fract1 * table_base[e11_index].val_scale); - float satScale0 = vFract0 * (hFract0 * entry00->sat_scale + - hFract1 * entry01->sat_scale) + - vFract1 * (hFract0 * entry10->sat_scale + - hFract1 * entry11->sat_scale); - - float valScale0 = vFract0 * (hFract0 * entry00->val_scale + - hFract1 * entry01->val_scale) + - vFract1 * (hFract0 * entry10->val_scale + - hFract1 * entry11->val_scale); - - entry00++; - entry01++; - entry10++; - entry11++; - - float hueShift1 = vFract0 * (hFract0 * entry00->hue_shift + - hFract1 * entry01->hue_shift) + - vFract1 * (hFract0 * entry10->hue_shift + - hFract1 * entry11->hue_shift); - - float satScale1 = vFract0 * (hFract0 * entry00->sat_scale + - hFract1 * entry01->sat_scale) + - vFract1 * (hFract0 * entry10->sat_scale + - hFract1 * entry11->sat_scale); - - float valScale1 = vFract0 * (hFract0 * entry00->val_scale + - hFract1 * entry01->val_scale) + - vFract1 * (hFract0 * entry10->val_scale + - hFract1 * entry11->val_scale); - - hueShift = sFract0 * hueShift0 + sFract1 * hueShift1; - satScale = sFract0 * satScale0 + sFract1 * satScale1; - valScale = sFract0 * valScale0 + sFract1 * valScale1; + hue_shift = s_fract0 * hueShift0 + s_fract1 * hueShift1; + sat_scale = s_fract0 * satScale0 + s_fract1 * satScale1; + val_scale = s_fract0 * valScale0 + s_fract1 * valScale1; } - hueShift *= (6.0f / 360.0f); // Convert to internal hue range. + hue_shift *= 6.0f / 360.0f; // Convert to internal hue range. - h += hueShift; - s *= satScale; // no clipping here, we are RT float :-) + h += hue_shift; + s *= sat_scale; // No clipping here, we are RT float :-) - if (ti.srgb_gamma) { - v = sRGBGammaInverse(vEncoded * valScale); + if (table_info.srgb_gamma) { + v = sRGBGammaInverse(v_encoded * val_scale); } else { - v *= valScale; + v *= val_scale; } } diff --git a/rtengine/dcp.h b/rtengine/dcp.h index 1ab9d64b6..98dfff69a 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -20,6 +20,7 @@ #pragma once #include +#include #include @@ -44,6 +45,14 @@ public: float blScale; }; + struct Illuminants { + short light_source_1; + short light_source_2; + double temperature_1; + double temperature_2; + bool will_interpolate; + }; + DCPProfile(const Glib::ustring& filename); ~DCPProfile(); @@ -52,9 +61,19 @@ public: bool getHasHueSatMap() const; bool getHasBaselineExposureOffset() const; - void getIlluminants(int &i1, double &temp1, int &i2, double &temp2, bool &willInterpolate_) const; + Illuminants getIlluminants() const; - void Apply(Imagefloat *pImg, int preferredIlluminant, const Glib::ustring &workingSpace, const ColorTemp &wb, double pre_mul[3], double camMatrix[3][3], bool useToneCurve = false, bool applyHueSatMap = true, bool applyLookTable = false) const; + void apply( + Imagefloat* img, + int preferred_illuminant, + const Glib::ustring& working_space, + const ColorTemp& white_balance, + double pre_mul[3], + double cam_matrix[3][3], + bool use_tone_curve = false, + bool apply_hue_sat_map = true, + bool apply_look_table = false + ) const; void setStep2ApplyState(const Glib::ustring &workingSpace, bool useToneCurve, bool applyLookTable, bool applyBaselineExposure, ApplyState &asOut); void step2ApplyTile(float *r, float *g, float *b, int width, int height, int tileWidth, const ApplyState &asIn) const; @@ -69,28 +88,28 @@ private: int hue_divisions; int sat_divisions; int val_divisions; - int iHueStep; - int iValStep; - int array_count; + int hue_step; + int val_step; + unsigned int array_count; bool srgb_gamma; struct { float h_scale; float s_scale; float v_scale; - int maxHueIndex0; - int maxSatIndex0; - int maxValIndex0; - int hueStep; - int valStep; + int max_hue_index0; + int max_sat_index0; + int max_val_index0; + int hue_step; + int val_step; } pc; }; 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(const ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], int preferredIlluminant, double (*mXYZCAM)[3]) const; - const HSBModify* MakeHueSatMap(const ColorTemp &wb, int preferredIlluminant, HSBModify **deleteHandle) const; - void HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, float &h, float &s, float &v) const; + void makeXyzCam(const ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], int preferredIlluminant, double (*mXYZCAM)[3]) const; + std::vector makeHueSatMap(const ColorTemp& white_balance, int preferred_illuminant) const; + void hsdApply(const HSDTableInfo& table_info, const std::vector& table_base, float& h, float& s, float& v) const; double color_matrix_1[3][3]; double color_matrix_2[3][3]; @@ -106,9 +125,9 @@ private: double temperature_1; double temperature_2; double baseline_exposure_offset; - HSBModify* deltas_1; - HSBModify* deltas_2; - HSBModify* look_table; + std::vector deltas_1; + std::vector deltas_2; + std::vector look_table; HSDTableInfo delta_info; HSDTableInfo look_info; short light_source_1; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 18da69117..16c7fb21b 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -3727,7 +3727,7 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam if (dcpProf != NULL) { // DCP processing - dcpProf->Apply(im, cmp.dcpIlluminant, cmp.working, wb, pre_mul, camMatrix, false, cmp.applyHueSatMap, false); + dcpProf->apply(im, cmp.dcpIlluminant, cmp.working, wb, pre_mul, camMatrix, false, cmp.applyHueSatMap, false); return; } diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index 15a171efe..cc2cbc039 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -385,24 +385,21 @@ void ICMPanel::updateDCP (int dcpIlluminant, Glib::ustring dcp_name) ckbApplyHueSatMap->set_sensitive (true); } - int i1, i2; - double temp1, temp2; - bool willInterpolate; - dcp->getIlluminants(i1, temp1, i2, temp2, willInterpolate); + const DCPProfile::Illuminants illuminants = dcp->getIlluminants(); - if (willInterpolate) { - if (dcpTemperatures[0] != temp1 || dcpTemperatures[1] != temp2) { + if (illuminants.will_interpolate) { + if (dcpTemperatures[0] != illuminants.temperature_1 || dcpTemperatures[1] != illuminants.temperature_2) { char tempstr1[64], tempstr2[64]; - sprintf(tempstr1, "%.0fK", temp1); - sprintf(tempstr2, "%.0fK", temp2); + sprintf(tempstr1, "%.0fK", illuminants.temperature_1); + sprintf(tempstr2, "%.0fK", illuminants.temperature_2); 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; + dcpTemperatures[0] = illuminants.temperature_1; + dcpTemperatures[1] = illuminants.temperature_2; dcpIll->set_active (curr_active); ignoreDcpSignal = false; }