From 4a639a0f09bb96d668b620d0b9e13750159e124f Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Mon, 7 Sep 2020 19:04:09 +0200 Subject: [PATCH 01/15] Initial improvements to change main histogram to 65535 bins --- rtengine/improccoordinator.cc | 23 ++++---- rtengine/improccoordinator.h | 5 +- rtengine/rawimagesource.cc | 10 ++-- rtgui/histogrampanel.cc | 104 ++++++++++++---------------------- 4 files changed, 57 insertions(+), 85 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index a538391c4d..cf0bc11b4f 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -111,10 +111,14 @@ ImProcCoordinator::ImProcCoordinator() : lhist16CCAM(65536), lhist16RETI(), lhist16LClad(65536), - histRed(256), histRedRaw(256), - histGreen(256), histGreenRaw(256), - histBlue(256), histBlueRaw(256), - histLuma(256), + + // Main histogram + histRed(65536), histRedRaw(65536), + histGreen(65536), histGreenRaw(65536), + histBlue(65536), histBlueRaw(65536), + histLuma(65536), + histChroma(65536), + histToneCurve(256), histToneCurveBW(256), histLCurve(256), @@ -125,7 +129,6 @@ ImProcCoordinator::ImProcCoordinator() : histCCAM(256), histClad(256), bcabhist(256), - histChroma(256), histLRETI(256), @@ -1759,7 +1762,7 @@ void ImProcCoordinator::updateLRGBHistograms() for (int i = y1; i < y2; i++) for (int j = x1; j < x2; j++) { - histChroma[(int)(sqrtf(SQR(nprevl->a[i][j]) + SQR(nprevl->b[i][j])) / 188.f)]++; //188 = 48000/256 + histChroma[(int)(sqrtf(SQR(nprevl->a[i][j]) + SQR(nprevl->b[i][j])) * 1.3653333333f)]++; // = 65536/48000 } } #ifdef _OPENMP @@ -1771,7 +1774,7 @@ void ImProcCoordinator::updateLRGBHistograms() for (int i = y1; i < y2; i++) for (int j = x1; j < x2; j++) { - histLuma[(int)(nprevl->L[i][j] / 128.f)]++; + histLuma[2 * (int)(nprevl->L[i][j])]++; // L = [0..32768] map to [0..65535] } } #ifdef _OPENMP @@ -1787,9 +1790,9 @@ void ImProcCoordinator::updateLRGBHistograms() int ofs = (i * pW + x1) * 3; for (int j = x1; j < x2; j++) { - int r = workimg->data[ofs++]; - int g = workimg->data[ofs++]; - int b = workimg->data[ofs++]; + int r = workimg->data[ofs++] * 256; // scale up, because workimg is 8 bit + int g = workimg->data[ofs++] * 256; + int b = workimg->data[ofs++] * 256; histRed[r]++; histGreen[g]++; diff --git a/rtengine/improccoordinator.h b/rtengine/improccoordinator.h index d90ee68ae2..1fb74d4d96 100644 --- a/rtengine/improccoordinator.h +++ b/rtengine/improccoordinator.h @@ -124,8 +124,9 @@ class ImProcCoordinator final : public StagedImageProcessor LUTu histRed, histRedRaw; LUTu histGreen, histGreenRaw; LUTu histBlue, histBlueRaw; - LUTu histLuma, histToneCurve, histToneCurveBW, histLCurve, histCCurve; - LUTu histLLCurve, histLCAM, histCCAM, histClad, bcabhist, histChroma, histLRETI; + LUTu histLuma, histChroma; + LUTu histToneCurve, histToneCurveBW, histLCurve, histCCurve; + LUTu histLLCurve, histLCAM, histCCAM, histClad, bcabhist, histLRETI; LUTf CAMBrightCurveJ, CAMBrightCurveQ; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 8bfcaa5ab5..d209cab04a 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -3729,7 +3729,7 @@ void RawImageSource::getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LU const float maxWhite = rtengine::max(c_white[0], c_white[1], c_white[2], c_white[3]); const float scale = maxWhite <= 1.f ? 65535.f : 1.f; // special case for float raw images in [0.0;1.0] range - const float multScale = maxWhite <= 1.f ? 1.f / 255.f : 255.f; + const float multScale = maxWhite <= 1.f ? 1.f / 65535.f : 65535.f; const float mult[4] = { multScale / (c_white[0] - cblacksom[0]), multScale / (c_white[1] - cblacksom[1]), multScale / (c_white[2] - cblacksom[2]), @@ -3838,12 +3838,12 @@ void RawImageSource::getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LU } } // end of critical region } // end of parallel region - + const auto getidx = [&](int c, int i) -> int { float f = mult[c] * std::max(0.f, i - cblacksom[c]); - return f > 0.f ? (f < 1.f ? 1 : std::min(int(f), 255)) : 0; + return f > 0.f ? (f < 1.f ? 1 : std::min(int(f), 65535)) : 0; }; for (int i = 0; i < histoSize; i++) { @@ -3865,11 +3865,11 @@ void RawImageSource::getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LU } if (ri->getSensorType() == ST_BAYER) // since there are twice as many greens, correct for it - for (int i = 0; i < 256; i++) { + for (int i = 0; i < 65536; i++) { histGreenRaw[i] >>= 1; } else if (ri->getSensorType() == ST_FUJI_XTRANS) // since Xtrans has 2.5 as many greens, correct for it - for (int i = 0; i < 256; i++) { + for (int i = 0; i < 65536; i++) { histGreenRaw[i] = (histGreenRaw[i] * 2) / 5; } else if (ri->get_colors() == 1) { // monochrome sensor => set all histograms equal diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 62be4c1f42..6331e83643 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -670,9 +670,9 @@ HistogramArea::HistogramArea (DrawModeListener *fml) : isPressed(false), movingPosition(0.0) { - rhist(256); - ghist(256); - bhist(256); + rhist(65536); + ghist(65536); + bhist(65536); lhist(256); chist(256); @@ -869,66 +869,33 @@ void HistogramArea::updateBackBuffer () LUTu& gh = rawMode ? ghistRaw : ghist; LUTu& bh = rawMode ? bhistRaw : bhist; - // make double copies of LUT, one for faster access, another one to scale down the raw histos - LUTu rhchanged(256), ghchanged(256), bhchanged(256); - unsigned int lhisttemp[256] ALIGNED16 {0}, chisttemp[256] ALIGNED16 {0}, rhtemp[256] ALIGNED16 {0}, ghtemp[256] ALIGNED16 {0}, bhtemp[256] ALIGNED16 {0}; - const int scale = (rawMode ? 8 : 1); - - for(int i = 0; i < 256; i++) { - if(needLuma) { - lhisttemp[i] = lhist[i]; - } - - if(needChroma) { - chisttemp[i] = chist[i]; - } - - if(needRed) { - rhchanged[i] = rhtemp[i] = rh[i] / scale; - } - - if(needGreen) { - ghchanged[i] = ghtemp[i] = gh[i] / scale; - } - - if(needBlue) { - bhchanged[i] = bhtemp[i] = bh[i] / scale; - } - } - // Compute the highest point of the histogram for scaling - // Values at far left and right end (0 and 255) are handled differently - - unsigned int histheight = 0; + unsigned int rgbmax = 0; + unsigned int lumamax = 0; + unsigned int chromamax = 0; - for (int i = 1; i < 255; i++) { - if (needLuma && lhisttemp[i] > histheight) { - histheight = lhisttemp[i]; + for (int i = 1; i < 65535; i++) { // Values at far left and right end are handled differently + if (needLuma && lhist[i] > lumamax) { + lumamax = lhist[i]; } - if (needChroma && chisttemp[i] > histheight) { - histheight = chisttemp[i]; + if (needChroma && chist[i] > chromamax) { + chromamax = chist[i]; } - if (needRed && rhtemp[i] > histheight) { - histheight = rhtemp[i]; + if (needRed && rh[i] > rgbmax) { + rgbmax = rh[i]; } - if (needGreen && ghtemp[i] > histheight) { - histheight = ghtemp[i]; + if (needGreen && gh[i] > rgbmax) { + rgbmax = gh[i]; } - if (needBlue && bhtemp[i] > histheight) { - histheight = bhtemp[i]; + if (needBlue && bh[i] > rgbmax) { + rgbmax = bh[i]; } } - int realhistheight = histheight; - - if (realhistheight < winh - 2) { - realhistheight = winh - 2; - } - cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL); cr->set_line_width (1.0 * s); cr->set_operator (Cairo::OPERATOR_OVER); @@ -936,38 +903,38 @@ void HistogramArea::updateBackBuffer () int ui = 0, oi = 0; if (needLuma && !rawMode) { - drawCurve(cr, lhist, realhistheight, w, h); - cr->set_source_rgba (0.65, 0.65, 0.65, 0.65); - cr->fill (); - drawMarks(cr, lhist, realhistheight, w, ui, oi); + drawCurve(cr, lhist, lumamax, w, h); + cr->set_source_rgb (0.7, 0.7, 0.7); + cr->stroke (); + drawMarks(cr, lhist, lumamax, w, ui, oi); } if (needChroma && !rawMode) { - drawCurve(cr, chist, realhistheight, w, h); + drawCurve(cr, chist, chromamax, w, h); cr->set_source_rgb (0.9, 0.9, 0.); cr->stroke (); - drawMarks(cr, chist, realhistheight, w, ui, oi); + drawMarks(cr, chist, chromamax, w, ui, oi); } if (needRed) { - drawCurve(cr, rhchanged, realhistheight, w, h); + drawCurve(cr, rh, rgbmax, w, h); cr->set_source_rgb (1.0, 0.0, 0.0); cr->stroke (); - drawMarks(cr, rhchanged, realhistheight, w, ui, oi); + drawMarks(cr, rh, rgbmax, w, ui, oi); } if (needGreen) { - drawCurve(cr, ghchanged, realhistheight, w, h); + drawCurve(cr, gh, rgbmax, w, h); cr->set_source_rgb (0.0, 1.0, 0.0); cr->stroke (); - drawMarks(cr, ghchanged, realhistheight, w, ui, oi); + drawMarks(cr, gh, rgbmax, w, ui, oi); } if (needBlue) { - drawCurve(cr, bhchanged, realhistheight, w, h); + drawCurve(cr, bh, rgbmax, w, h); cr->set_source_rgb (0.0, 0.4, 1.0); cr->stroke (); - drawMarks(cr, bhchanged, realhistheight, w, ui, oi); + drawMarks(cr, bh, rgbmax, w, ui, oi); } } @@ -994,10 +961,10 @@ void HistogramArea::drawCurve(Cairo::RefPtr &cr, double s = RTScalable::getScale(); cr->set_line_width(s); - cr->move_to (padding, vsize - 1); + //cr->move_to (padding, vsize - 1); scale = scale <= 0.0 ? 0.001 : scale; // avoid division by zero and negative values - for (int i = 0; i < 256; i++) { + for (int i = 0; i < 65536; i++) { double val = data[i] * (double)vsize / scale; if (drawMode > 0) { // scale y for single and double log-scale @@ -1006,16 +973,17 @@ void HistogramArea::drawCurve(Cairo::RefPtr &cr, double iscaled = i; if (drawMode == 2) { // scale x for double log-scale - iscaled = HistogramScaling::log (255.0, (double)i); + iscaled = HistogramScaling::log (65535.0, (double)i); } - double posX = padding + iscaled * (hsize - padding * 2.0) / 255.0; + double posX = padding + iscaled * (hsize - padding * 2.0) / 65535.0; double posY = vsize - 2 + val * (4 - vsize) / vsize; + cr->move_to (posX, vsize - 2); cr->line_to (posX, posY); } - cr->line_to (hsize - padding, vsize - 1); + //cr->line_to (hsize - padding, vsize - 1); } void HistogramArea::drawMarks(Cairo::RefPtr &cr, @@ -1027,7 +995,7 @@ void HistogramArea::drawMarks(Cairo::RefPtr &cr, cr->rectangle(padding, (ui++)*s, s, s); } - if(data[255] > scale) { + if(data[65535] > scale) { cr->rectangle(hsize - s - padding, (oi++)*s, s, s); } From fd125c6c51d8d253c6833982ffd4c0f5d2ab6f88 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Tue, 8 Sep 2020 14:33:02 +0200 Subject: [PATCH 02/15] Speedup for log histogram --- rtgui/histogrampanel.cc | 39 +++++++++++++++++++++++++-------------- rtgui/histogrampanel.h | 8 +++++--- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 6331e83643..7f508ce36e 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -25,6 +25,9 @@ #include "../rtengine/LUT.h" #include "rtimage.h" #include "../rtengine/color.h" +#include "../rtengine/sleef.h" +#define BENCHMARK +#include "../rtengine/StopWatch.h" using namespace rtengine; @@ -365,12 +368,19 @@ void HistogramPanel::toggleButtonMode () // // // HistogramScaling -double HistogramScaling::log(double vsize, double val) +float HistogramScaling::log(float vsize, float val) const { //double factor = 10.0; // can be tuned if necessary - higher is flatter curve - return vsize * std::log(factor / (factor + val)) / std::log(factor / (factor + vsize)); + return vsize * xlogf(factor / (factor + val)) / xlogf(factor / (factor + vsize)); } +float HistogramScaling::logMult(float vsize, float val, float mult) const +{ + //double factor = 10.0; // can be tuned if necessary - higher is flatter curve + return vsize * xlogf(factor / (factor + val)) * mult; +} + + // // // @@ -958,26 +968,27 @@ void HistogramArea::on_realize () void HistogramArea::drawCurve(Cairo::RefPtr &cr, const LUTu & data, double scale, int hsize, int vsize) { - double s = RTScalable::getScale(); + BENCHFUNMICRO - cr->set_line_width(s); + cr->set_line_width(RTScalable::getScale()); //cr->move_to (padding, vsize - 1); - scale = scale <= 0.0 ? 0.001 : scale; // avoid division by zero and negative values + const float scalef = rtengine::max(scale, 0.001); // avoid division by zero and negative values + const float mult1 = 1.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + vsize)); + const float mult2 = 1.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); for (int i = 0; i < 65536; i++) { - double val = data[i] * (double)vsize / scale; + float val = data[i] * vsize / scalef; + float iscaled = i; if (drawMode > 0) { // scale y for single and double log-scale - val = HistogramScaling::log ((double)vsize, val); - } - - double iscaled = i; - if (drawMode == 2) { // scale x for double log-scale - iscaled = HistogramScaling::log (65535.0, (double)i); + val = HistogramScaling::logMult (vsize, val, mult1); + if (drawMode == 2) { // scale x for double log-scale + iscaled = HistogramScaling::logMult (65535.f, i, mult2); + } } - double posX = padding + iscaled * (hsize - padding * 2.0) / 65535.0; - double posY = vsize - 2 + val * (4 - vsize) / vsize; + const double posX = padding + iscaled * (hsize - padding * 2.f) / 65535.f; + const double posY = vsize - 2 + val * (4 - vsize) / vsize; cr->move_to (posX, vsize - 2); cr->line_to (posX, posY); diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 740b0a12ca..ec6c4125c6 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -30,6 +30,7 @@ #include "../rtengine/LUT.h" #include "../rtengine/noncopyable.h" +#include "../rtengine/opthelper.h" class HistogramArea; @@ -49,9 +50,10 @@ struct HistogramRGBAreaIdleHelper { class HistogramScaling { public: - double factor; - HistogramScaling() : factor(10.0) {} - double log (double vsize, double val); + float factor; + HistogramScaling() : factor(10.f) {} + float log (float vsize, float val) const; + float logMult (float vsize, float val, float mult) const; }; class HistogramRGBArea final : public Gtk::DrawingArea, public BackBuffer, private HistogramScaling, public rtengine::NonCopyable From 0b7391802b4000f8abc6232a687f8888694183a2 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Wed, 9 Sep 2020 13:40:25 +0200 Subject: [PATCH 03/15] HistogramArea::drawCurve(): further speedup for log mode --- rtgui/histogrampanel.cc | 84 +- rtgui/histogrampanel.cc.save-failed | 1093 +++++++++++++++++++++++++++ rtgui/histogrampanel.h | 24 +- 3 files changed, 1158 insertions(+), 43 deletions(-) create mode 100644 rtgui/histogrampanel.cc.save-failed diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 7f508ce36e..0ff91b6d81 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -25,7 +25,6 @@ #include "../rtengine/LUT.h" #include "rtimage.h" #include "../rtengine/color.h" -#include "../rtengine/sleef.h" #define BENCHMARK #include "../rtengine/StopWatch.h" @@ -364,26 +363,6 @@ void HistogramPanel::toggleButtonMode () showMode->set_image(*mode2Image); } -// -// -// -// HistogramScaling -float HistogramScaling::log(float vsize, float val) const -{ - //double factor = 10.0; // can be tuned if necessary - higher is flatter curve - return vsize * xlogf(factor / (factor + val)) / xlogf(factor / (factor + vsize)); -} - -float HistogramScaling::logMult(float vsize, float val, float mult) const -{ - //double factor = 10.0; // can be tuned if necessary - higher is flatter curve - return vsize * xlogf(factor / (factor + val)) * mult; -} - - -// -// -// // HistogramRGBArea HistogramRGBArea::HistogramRGBArea () : val(0), r(0), g(0), b(0), valid(false), @@ -966,35 +945,62 @@ void HistogramArea::on_realize () } void HistogramArea::drawCurve(Cairo::RefPtr &cr, - const LUTu & data, double scale, int hsize, int vsize) + const LUTu & data, float scale, float hsize, float vsize) { BENCHFUNMICRO cr->set_line_width(RTScalable::getScale()); - //cr->move_to (padding, vsize - 1); - const float scalef = rtengine::max(scale, 0.001); // avoid division by zero and negative values - const float mult1 = 1.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + vsize)); - const float mult2 = 1.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); - for (int i = 0; i < 65536; i++) { - float val = data[i] * vsize / scalef; - float iscaled = i; - - if (drawMode > 0) { // scale y for single and double log-scale - val = HistogramScaling::logMult (vsize, val, mult1); - if (drawMode == 2) { // scale x for double log-scale - iscaled = HistogramScaling::logMult (65535.f, i, mult2); - } + std::vector iscaled(65536); + std::vector vals(65536); + + if (drawMode == 2) { // scale x for double log-scale + const float mult = 65535.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); +#ifdef __SSE2__ + const vfloat multv = F2V(mult); + const vfloat fourv = F2V(4.f); + vfloat iv = _mm_setr_ps(0.f, 1.f, 2.f, 3.f); + for (int i = 0; i < 65536; i += 4, iv += fourv) { + STVFU(iscaled[i], HistogramScaling::logMult(iv, multv)); + } +#else + for (int i = 0; i < 65536; ++i) { + iscaled[i] = HistogramScaling::logMult(i, mult); + } +#endif + } else { + for (int i = 0; i < 65536; ++i) { + iscaled[i] = i; + } + } + const float scalef = rtengine::max(scale, 0.001f); // avoid division by zero and negative values + const float scaleFactor = vsize / scalef; + if (drawMode > 0) { // scale y for single and double log-scale + const float mult = vsize / xlogf(HistogramScaling::factor / (HistogramScaling::factor + vsize)); +#ifdef __SSE2__ + const vfloat scaleFactorv = F2V(scaleFactor); + const vfloat multv = F2V(mult); + for (int i = 0; i < 65536; i += 4) { + STVFU(vals[i], HistogramScaling::logMult(_mm_cvtepi32_ps(_mm_loadu_si128((__m128i_u*)&data[i])) * scaleFactorv, multv)); } +#else + for (int i = 0; i < 65536; ++i) { + vals[i] = HistogramScaling::logMult(data[i] * scaleFactor, mult); + } +#endif + } else { + for (int i = 0; i < 65536; ++i) { + vals[i] = data[i] * scaleFactor; + } + } - const double posX = padding + iscaled * (hsize - padding * 2.f) / 65535.f; - const double posY = vsize - 2 + val * (4 - vsize) / vsize; + for (int i = 0; i < 65536; i++) { + const double posX = padding + iscaled[i] * (hsize - padding * 2.f) / 65535.f; + const double posY = vsize - 2 + vals[i] * (4 - vsize) / vsize; cr->move_to (posX, vsize - 2); cr->line_to (posX, posY); } - - //cr->line_to (hsize - padding, vsize - 1); } void HistogramArea::drawMarks(Cairo::RefPtr &cr, diff --git a/rtgui/histogrampanel.cc.save-failed b/rtgui/histogrampanel.cc.save-failed new file mode 100644 index 0000000000..25a8acc50b --- /dev/null +++ b/rtgui/histogrampanel.cc.save-failed @@ -0,0 +1,1093 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#include "histogrampanel.h" +#include "multilangmgr.h" +#include "guiutils.h" +#include "options.h" +#include +#include +#include "../rtengine/LUT.h" +#include "rtimage.h" +#include "../rtengine/color.h" +#include "../rtengine/sleef.h" +#define BENCHMARK +#include "../rtengine/StopWatch.h" + +using namespace rtengine; + + +// +// +// HistogramPanel +HistogramPanel::HistogramPanel() : + pointer_moved_delayed_call( + [this](bool validPos, const Glib::ustring &profile, const Glib::ustring &profileW, int r, int g, int b) + { + if (!validPos) { + // do something to un-show vertical bars + histogramRGBArea->updateBackBuffer(-1, -1, -1); + } else { + // do something to show vertical bars + histogramRGBArea->updateBackBuffer(r, g, b, profile, profileW); + } + histogramRGBArea->queue_draw (); + }, + 50, + 100 + ) +{ + setExpandAlignProperties(this, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + set_name("HistogramPanel"); + + histogramArea = Gtk::manage (new HistogramArea (this)); + setExpandAlignProperties(histogramArea, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); + + histogramRGBArea = Gtk::manage (new HistogramRGBArea ()); + setExpandAlignProperties(histogramRGBArea, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_END); + histogramRGBArea->show(); + + // connecting the two childs + histogramArea->signal_factor_changed().connect( sigc::mem_fun(*histogramRGBArea, &HistogramRGBArea::factorChanged) ); + + gfxGrid = Gtk::manage (new Gtk::Grid ()); + gfxGrid->set_orientation(Gtk::ORIENTATION_VERTICAL); + gfxGrid->set_row_spacing(1); + gfxGrid->set_column_spacing(1); + histogramRGBArea->setParent(gfxGrid); + gfxGrid->add(*histogramArea); + + if (options.histogramBar) { + gfxGrid->add (*histogramRGBArea); + } + + redImage = new RTImage ("histogram-red-on-small.png"); + greenImage = new RTImage ("histogram-green-on-small.png"); + blueImage = new RTImage ("histogram-blue-on-small.png"); + valueImage = new RTImage ("histogram-silver-on-small.png"); + chroImage = new RTImage ("histogram-gold-on-small.png"); + rawImage = new RTImage ("histogram-bayer-on-small.png"); + barImage = new RTImage ("histogram-bar-on-small.png"); + + redImage_g = new RTImage ("histogram-red-off-small.png"); + greenImage_g = new RTImage ("histogram-green-off-small.png"); + blueImage_g = new RTImage ("histogram-blue-off-small.png"); + valueImage_g = new RTImage ("histogram-silver-off-small.png"); + chroImage_g = new RTImage ("histogram-gold-off-small.png"); + rawImage_g = new RTImage ("histogram-bayer-off-small.png"); + barImage_g = new RTImage ("histogram-bar-off-small.png"); + + mode0Image = new RTImage ("histogram-mode-linear-small.png"); + mode1Image = new RTImage ("histogram-mode-logx-small.png"); + mode2Image = new RTImage ("histogram-mode-logxy-small.png"); + + showRed = Gtk::manage (new Gtk::ToggleButton ()); + showGreen = Gtk::manage (new Gtk::ToggleButton ()); + showBlue = Gtk::manage (new Gtk::ToggleButton ()); + showValue = Gtk::manage (new Gtk::ToggleButton ()); + showChro = Gtk::manage (new Gtk::ToggleButton ()); + showRAW = Gtk::manage (new Gtk::ToggleButton ()); + showMode = Gtk::manage (new Gtk::Button ()); + showBAR = Gtk::manage (new Gtk::ToggleButton ()); + + showRed->set_name("histButton"); + showRed->set_can_focus(false); + showGreen->set_name("histButton"); + showGreen->set_can_focus(false); + showBlue->set_name("histButton"); + showBlue->set_can_focus(false); + showValue->set_name("histButton"); + showValue->set_can_focus(false); + showChro->set_name("histButton"); + showChro->set_can_focus(false); + showRAW->set_name("histButton"); + showRAW->set_can_focus(false); + showMode->set_name("histButton"); + showMode->set_can_focus(false); + showBAR->set_name("histButton"); + showBAR->set_can_focus(false); + + showRed->set_relief (Gtk::RELIEF_NONE); + showGreen->set_relief (Gtk::RELIEF_NONE); + showBlue->set_relief (Gtk::RELIEF_NONE); + showValue->set_relief (Gtk::RELIEF_NONE); + showChro->set_relief (Gtk::RELIEF_NONE); + showRAW->set_relief (Gtk::RELIEF_NONE); + showMode->set_relief (Gtk::RELIEF_NONE); + showBAR->set_relief (Gtk::RELIEF_NONE); + + showRed->set_tooltip_text (M("HISTOGRAM_TOOLTIP_R")); + showGreen->set_tooltip_text (M("HISTOGRAM_TOOLTIP_G")); + showBlue->set_tooltip_text (M("HISTOGRAM_TOOLTIP_B")); + showValue->set_tooltip_text (M("HISTOGRAM_TOOLTIP_L")); + showChro->set_tooltip_text (M("HISTOGRAM_TOOLTIP_CHRO")); + showRAW->set_tooltip_text (M("HISTOGRAM_TOOLTIP_RAW")); + showMode->set_tooltip_text (M("HISTOGRAM_TOOLTIP_MODE")); + showBAR->set_tooltip_text (M("HISTOGRAM_TOOLTIP_BAR")); + + buttonGrid = Gtk::manage (new Gtk::Grid ()); + buttonGrid->set_orientation(Gtk::ORIENTATION_VERTICAL); + showRed->set_active (options.histogramRed); + showGreen->set_active (options.histogramGreen); + showBlue->set_active (options.histogramBlue); + showValue->set_active (options.histogramLuma); + showChro->set_active (options.histogramChroma); + showRAW->set_active (options.histogramRAW); + // no showMode->set_active(), as it's not a ToggleButton + showBAR->set_active (options.histogramBar); + + showRed->set_image (showRed->get_active() ? *redImage : *redImage_g); + showGreen->set_image (showGreen->get_active() ? *greenImage : *greenImage_g); + showBlue->set_image (showBlue->get_active() ? *blueImage : *blueImage_g); + showValue->set_image (showValue->get_active() ? *valueImage : *valueImage_g); + showChro->set_image (showChro->get_active() ? *chroImage : *chroImage_g); + showRAW->set_image (showRAW->get_active() ? *rawImage : *rawImage_g); + if (options.histogramDrawMode == 0) + showMode->set_image(*mode0Image); + else if (options.histogramDrawMode == 1) + showMode->set_image(*mode1Image); + else + showMode->set_image(*mode2Image); + showBAR->set_image (showBAR->get_active() ? *barImage : *barImage_g); + + raw_toggled(); // Make sure the luma/chroma toggles are enabled or disabled + + setExpandAlignProperties(showRed , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showGreen, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showBlue , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showValue, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showChro , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showRAW , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showMode , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + setExpandAlignProperties(showBAR , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); + + showRed->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::red_toggled), showRed ); + showGreen->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::green_toggled), showGreen ); + showBlue->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::blue_toggled), showBlue ); + showValue->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::value_toggled), showValue ); + showChro->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::chro_toggled), showChro ); + showRAW->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::raw_toggled), showRAW ); + showMode->signal_released().connect( sigc::mem_fun(*this, &HistogramPanel::mode_released), showMode ); + showBAR->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::bar_toggled), showBAR ); + + buttonGrid->add (*showRed); + buttonGrid->add (*showGreen); + buttonGrid->add (*showBlue); + buttonGrid->add (*showValue); + buttonGrid->add (*showChro); + buttonGrid->add (*showRAW); + buttonGrid->add (*showMode); + buttonGrid->add (*showBAR); + + // Put the button vbox next to the window's border to be less disturbing + if (options.histogramPosition == 1) { + add (*buttonGrid); + add (*gfxGrid); + } else { + add (*gfxGrid); + add (*buttonGrid); + } + + show_all (); + + rconn = signal_size_allocate().connect( sigc::mem_fun(*this, &HistogramPanel::resized) ); +} + +HistogramPanel::~HistogramPanel () +{ + pointer_moved_delayed_call.cancel(); + + delete redImage; + delete greenImage; + delete blueImage; + delete valueImage; + delete chroImage; + delete rawImage; + delete mode0Image; + delete mode1Image; + delete mode2Image; + delete barImage; + + delete redImage_g; + delete greenImage_g; + delete blueImage_g; + delete valueImage_g; + delete chroImage_g; + delete rawImage_g; + delete barImage_g; + +} + +void HistogramPanel::resized (Gtk::Allocation& req) +{ + + histogramArea->updateBackBuffer (); + histogramArea->queue_draw (); + + // set histogramRGBArea invalid; + histogramRGBArea->updateBackBuffer(-1, -1, -1); + histogramRGBArea->queue_draw (); + + // Store current height of the histogram + options.histogramHeight = get_height(); + +} + +void HistogramPanel::red_toggled () +{ + showRed->set_image(showRed->get_active() ? *redImage : *redImage_g); + rgbv_toggled(); +} +void HistogramPanel::green_toggled () +{ + showGreen->set_image(showGreen->get_active() ? *greenImage : *greenImage_g); + rgbv_toggled(); +} +void HistogramPanel::blue_toggled () +{ + showBlue->set_image(showBlue->get_active() ? *blueImage : *blueImage_g); + rgbv_toggled(); +} +void HistogramPanel::value_toggled () +{ + removeIfThere(showValue, valueImage, false); + removeIfThere(showValue, valueImage_g, false); + showValue->set_image(showValue->get_active() ? *valueImage : *valueImage_g); + rgbv_toggled(); +} +void HistogramPanel::chro_toggled () +{ + removeIfThere(showChro, chroImage, false); + removeIfThere(showChro, chroImage_g, false); + showChro->set_image(showChro->get_active() ? *chroImage : *chroImage_g); + rgbv_toggled(); +} + +void HistogramPanel::raw_toggled () +{ + if (showRAW->get_active()) { + showRAW->set_image(*rawImage); + showValue->set_sensitive(false); + showChro->set_sensitive(false); + } else { + showRAW->set_image(*rawImage_g); + showValue->set_sensitive(true); + showChro->set_sensitive(true); + } + + rgbv_toggled(); +} + +void HistogramPanel::mode_released () +{ + options.histogramDrawMode = (options.histogramDrawMode + 1) % 3; + if (options.histogramDrawMode == 0) + showMode->set_image(*mode0Image); + else if (options.histogramDrawMode == 1) + showMode->set_image(*mode1Image); + else + showMode->set_image(*mode2Image); + rgbv_toggled(); +} + +void HistogramPanel::bar_toggled () +{ + showBAR->set_image(showBAR->get_active() ? *barImage : *barImage_g); + rgbv_toggled(); +} + +void HistogramPanel::rgbv_toggled () +{ + // Update Display + histogramArea->updateOptions (showRed->get_active(), showGreen->get_active(), showBlue->get_active(), showValue->get_active(), showChro->get_active(), showRAW->get_active(), options.histogramDrawMode); + histogramArea->queue_draw (); + + histogramRGBArea->updateOptions (showRed->get_active(), showGreen->get_active(), showBlue->get_active(), showValue->get_active(), showChro->get_active(), showRAW->get_active(), showBAR->get_active()); + histogramRGBArea->updateBackBuffer (0, 0, 0); + histogramRGBArea->queue_draw (); +} + +void HistogramPanel::setHistRGBInvalid () +{ + // do something to un-show vertical bars + histogramRGBArea->updateBackBuffer(-1, -1, -1); + histogramRGBArea->queue_draw (); +} + +void HistogramPanel::pointerMoved (bool validPos, const Glib::ustring &profile, const Glib::ustring &profileW, int x, int y, int r, int g, int b, bool isRaw) +{ + pointer_moved_delayed_call(validPos, profile, profileW, r, g, b); +} + +/* + * Move the vertical button bar to the right side + * only allowed values for align are Gtk::POS_LEFT and Gtk::POS_RIGHT + */ +void HistogramPanel::reorder (Gtk::PositionType align) +{ + if (align == Gtk::POS_LEFT) { + gfxGrid->reference(); + removeIfThere(this, gfxGrid, false); + add (*gfxGrid); + gfxGrid->unreference(); + } else { + buttonGrid->reference(); + removeIfThere(this, buttonGrid, false); + add (*buttonGrid); + buttonGrid->unreference(); + } +} + +// DrawModeListener interface: +void HistogramPanel::toggleButtonMode () +{ + if (options.histogramDrawMode == 0) + showMode->set_image(*mode0Image); + else if (options.histogramDrawMode == 1) + showMode->set_image(*mode1Image); + else + showMode->set_image(*mode2Image); +} + +// +// +// +// HistogramScaling +float HistogramScaling::log(float vsize, float val) const +{ + //double factor = 10.0; // can be tuned if necessary - higher is flatter curve + return vsize * xlogf(factor / (factor + val)) / xlogf(factor / (factor + vsize)); +} + +float HistogramScaling::logMult(float vsize, float val, float mult) const +{ + //double factor = 10.0; // can be tuned if necessary - higher is flatter curve + return vsize * xlogf(factor / (factor + val)) * mult; +} + + +// +// +// +// HistogramRGBArea +HistogramRGBArea::HistogramRGBArea () : + val(0), r(0), g(0), b(0), valid(false), + needRed(options.histogramRed), needGreen(options.histogramGreen), needBlue(options.histogramBlue), + needLuma(options.histogramLuma), needChroma(options.histogramChroma), rawMode(options.histogramRAW), + showMode(options.histogramBar), barDisplayed(options.histogramBar), parent(nullptr) +{ + get_style_context()->add_class("drawingarea"); + set_name("HistogramRGBArea"); + + harih = new HistogramRGBAreaIdleHelper; + harih->harea = this; + harih->destroyed = false; + harih->pending = 0; +} + +HistogramRGBArea::~HistogramRGBArea () +{ + idle_register.destroy(); + + if (harih->pending) { + harih->destroyed = true; + } else { + delete harih; + } +} + + +Gtk::SizeRequestMode HistogramRGBArea::get_request_mode_vfunc () const +{ + return Gtk::SIZE_REQUEST_HEIGHT_FOR_WIDTH; +} + +void HistogramRGBArea::get_preferred_height_vfunc (int &minimum_height, int &natural_height) const +{ + int minimumWidth = 0; + int naturalWidth = 0; + get_preferred_width_vfunc(minimumWidth, naturalWidth); + get_preferred_height_for_width_vfunc (minimumWidth, minimum_height, natural_height); +} + +void HistogramRGBArea::get_preferred_width_vfunc (int &minimum_width, int &natural_width) const +{ + int s = RTScalable::getScale(); + minimum_width = 60 * s; + natural_width = 200 * s; +} + +void HistogramRGBArea::get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const +{ + int bHeight = width / 30; + + int s = RTScalable::getScale(); + + if (bHeight > (10 * s)) { + bHeight = 10 * s; + } else if (bHeight < (5 * s)) { + bHeight = 5 * s; + } + + minimum_height = bHeight; + natural_height = bHeight; +} + +// unused? +void HistogramRGBArea::get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const +{ + get_preferred_width_vfunc (minimum_width, natural_width); +} + +bool HistogramRGBArea::getShow() +{ + return(showMode); +} + +void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustring &profile, const Glib::ustring &profileW) +{ + if (!get_realized () || !showMode || rawMode) { + return; + } + + // Mostly not necessary, but should be in some case + GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected + + Glib::RefPtr window = get_window(); + int winx, winy, winw, winh; + window->get_geometry(winx, winy, winw, winh); + + double s = RTScalable::getScale(); + + // This will create or update the size of the BackBuffer::surface + setDrawRectangle(Cairo::FORMAT_ARGB32, 0, 0, winw, winh, true); + + if (surface) { + Cairo::RefPtr cc = Cairo::Context::create(surface); + + cc->set_source_rgba (0., 0., 0., 0.); + cc->set_operator (Cairo::OPERATOR_CLEAR); + cc->paint (); + cc->set_operator (Cairo::OPERATOR_OVER); + + cc->set_antialias(Cairo::ANTIALIAS_NONE); + cc->set_line_width (1.0 * s); + + if ( r != -1 && g != -1 && b != -1 ) { + double xpos; + if (needRed) { + // Red + cc->set_source_rgb(1.0, 0.0, 0.0); + if (options.histogramDrawMode < 2) { + xpos = padding + r * (winw - padding * 2.0) / 255.0 + 0.5*s; + } else { + xpos = padding + HistogramScaling::log (255, r) * (winw - padding * 2.0) / 255.0 + 0.5*s; + } + cc->move_to(xpos, 0.0); + cc->line_to(xpos, winh - 0.0); + cc->stroke(); + } + + if (needGreen) { + // Green + cc->set_source_rgb(0.0, 1.0, 0.0); + if (options.histogramDrawMode < 2) { + xpos = padding + g * (winw - padding * 2.0) / 255.0 + 0.5*s; + } else { + xpos = padding + HistogramScaling::log (255, g) * (winw - padding * 2.0) / 255.0 + 0.5*s; + } + cc->move_to(xpos, 0.0); + cc->line_to(xpos, winh - 0.0); + cc->stroke(); + } + + if (needBlue) { + // Blue + cc->set_source_rgb(0.0, 0.4, 1.0); + if (options.histogramDrawMode < 2) { + xpos = padding + b * (winw - padding * 2.0) / 255.0 + 0.5*s; + } else { + xpos = padding + HistogramScaling::log (255, b) * (winw - padding * 2.0) / 255.0 + 0.5*s; + } + cc->move_to(xpos, 0.0); + cc->line_to(xpos, winh - 0.0); + cc->stroke(); + } + + if(needLuma || needChroma) { + float Lab_L, Lab_a, Lab_b; + rtengine::Color::rgb2lab01(profile, profileW, r / 255.f, g / 255.f, b / 255.f, Lab_L, Lab_a, Lab_b, options.rtSettings.HistogramWorking); + + if (needLuma) { + // Luma + cc->set_source_rgb(1.0, 1.0, 1.0); + if (options.histogramDrawMode < 2) { + xpos = padding + static_cast(Lab_L) * (winw - padding * 2.0) / 100.0 + 0.5*s; + } else { + xpos = padding + HistogramScaling::log(100, Lab_L) * (winw - padding * 2.0) / 100.0 + 0.5*s; + } + cc->move_to(xpos, 0.0); + cc->line_to(xpos, winh - 0.0); + cc->stroke(); + } + + if (needChroma) { + // Chroma + double chromaval = sqrt(Lab_a * Lab_a + Lab_b * Lab_b) / 1.8; + cc->set_source_rgb(0.9, 0.9, 0.0); + if (options.histogramDrawMode < 2) { + xpos = padding + chromaval * (winw - padding * 2.0) / 100.0 + 0.5*s; + } else { + xpos = padding + HistogramScaling::log(100, chromaval) * (winw - padding * 2.0) / 100.0 + 0.5*s; + } + cc->move_to(xpos, 0.0); + cc->line_to(xpos, winh - 0.0); + cc->stroke(); + } + } + } + } + + setDirty(false); +} + +void HistogramRGBArea::update (int valh, int rh, int gh, int bh) +{ + + if (valh) { + val = valh; + r = rh; + g = gh; + b = bh; + valid = true; + } else { + valid = false; + } + + harih->pending++; + + idle_register.add( + [this]() -> bool + { + if (harih->destroyed) { + if (harih->pending == 1) { + delete harih; + } else { + --harih->pending; + } + + return false; + } + + harih->harea->updateBackBuffer(-1, -1, -1); + harih->harea->queue_draw (); + + --harih->pending; + + return false; + } + ); +} + +void HistogramRGBArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, bool bar) +{ + + options.histogramRed = needRed = r; + options.histogramGreen = needGreen = g; + options.histogramBlue = needBlue = b; + options.histogramLuma = needLuma = l; + options.histogramChroma = needChroma = c; + options.histogramRAW = rawMode = raw; + options.histogramBar = showMode = bar; + + // Show/hide the RGB bar widget + if (bar && !barDisplayed) { + parent->add(*this); + barDisplayed = true; + } else if (!bar && barDisplayed) { + removeIfThere(parent, this, false); + barDisplayed = false; + } + +} + +void HistogramRGBArea::on_realize () +{ + + Gtk::DrawingArea::on_realize(); + add_events(Gdk::BUTTON_PRESS_MASK); +} + +bool HistogramRGBArea::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) +{ + + const Glib::RefPtr style = get_style_context(); + style->render_background(cr, 0, 0, get_width(), get_height()); + + // on_realize & updateBackBuffer have to be called before + if (surface) { + if (isDirty()) { // not sure this could happen... + updateBackBuffer(-1, -1, -1); + } + + copySurface(cr, NULL); + } + + style->render_frame (cr, 0, 0, get_width(), get_height()); + + return true; +} + +bool HistogramRGBArea::on_button_press_event (GdkEventButton* event) +{ + + if (event->type == GDK_2BUTTON_PRESS && event->button == 1) { + // do something? + } + + return true; +} + +void HistogramRGBArea::factorChanged (double newFactor) +{ + factor = newFactor; +} + +// +// +// +// HistogramArea +HistogramArea::HistogramArea (DrawModeListener *fml) : + valid(false), drawMode(options.histogramDrawMode), myDrawModeListener(fml), + oldwidth(-1), oldheight(-1), + needRed(options.histogramRed), needGreen(options.histogramGreen), needBlue(options.histogramBlue), + needLuma(options.histogramLuma), needChroma(options.histogramChroma), rawMode(options.histogramRAW), + isPressed(false), movingPosition(0.0) +{ + + rhist(65536); + ghist(65536); + bhist(65536); + lhist(256); + chist(256); + + get_style_context()->add_class("drawingarea"); + set_name("HistogramArea"); + + haih = new HistogramAreaIdleHelper; + haih->harea = this; + haih->destroyed = false; + haih->pending = 0; +} + +HistogramArea::~HistogramArea () +{ + idle_register.destroy(); + + if (haih->pending) { + haih->destroyed = true; + } else { + delete haih; + } +} + +Gtk::SizeRequestMode HistogramArea::get_request_mode_vfunc () const +{ + return Gtk::SIZE_REQUEST_CONSTANT_SIZE; +} + +void HistogramArea::get_preferred_height_vfunc (int &minimum_height, int &natural_height) const +{ + int s = (int)RTScalable::getScale(); + minimum_height = 100 * s; + natural_height = 200 * s; +} + +void HistogramArea::get_preferred_width_vfunc (int &minimum_width, int &natural_width) const +{ + + int s = (int)RTScalable::getScale(); + minimum_width = 200 * s; + natural_width = 400 * s; +} + +void HistogramArea::get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const +{ + + minimum_height = 0; + natural_height = 0; +} + +void HistogramArea::get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const +{ + get_preferred_width_vfunc (minimum_width, natural_width); +} + +void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode) +{ + + options.histogramRed = needRed = r; + options.histogramGreen = needGreen = g; + options.histogramBlue = needBlue = b; + options.histogramLuma = needLuma = l; + options.histogramChroma = needChroma = c; + options.histogramRAW = rawMode = raw; + options.histogramDrawMode = drawMode = mode; + + updateBackBuffer (); +} + +void HistogramArea::update( + const LUTu& histRed, + const LUTu& histGreen, + const LUTu& histBlue, + const LUTu& histLuma, + const LUTu& histChroma, + const LUTu& histRedRaw, + const LUTu& histGreenRaw, + const LUTu& histBlueRaw +) +{ + if (histRed) { + rhist = histRed; + ghist = histGreen; + bhist = histBlue; + lhist = histLuma; + chist = histChroma; + rhistRaw = histRedRaw; + ghistRaw = histGreenRaw; + bhistRaw = histBlueRaw; + valid = true; + } else { + valid = false; + } + + haih->pending++; + + // Can be done outside of the GUI thread + idle_register.add( + [this]() -> bool + { + if (haih->destroyed) { + if (haih->pending == 1) { + delete haih; + } else { + --haih->pending; + } + + return false; + } + + haih->harea->setDirty(true); + haih->harea->updateBackBuffer(); + haih->harea->queue_draw(); + + --haih->pending; + + return false; + } + ); +} + +void HistogramArea::updateBackBuffer () +{ + + if (!get_realized ()) { + return; + } + + Glib::RefPtr window = get_window(); + int winx, winy, winw, winh; + window->get_geometry(winx, winy, winw, winh); + + // This will create or update the size of the BackBuffer::surface + setDrawRectangle(Cairo::FORMAT_ARGB32, 0, 0, winw, winh, true); + + Cairo::RefPtr cr = Cairo::Context::create(surface); + const Glib::RefPtr style = get_style_context(); + + double s = RTScalable::getScale(); + + // Setup drawing + cr->set_source_rgba (0., 0., 0., 0.); + cr->set_operator (Cairo::OPERATOR_CLEAR); + cr->paint (); + cr->set_operator (Cairo::OPERATOR_SOURCE); + + // Prepare drawing gridlines first + cr->set_source_rgba (1., 1., 1., 0.25); + cr->set_line_width (1.0 * s); + cr->set_antialias(Cairo::ANTIALIAS_NONE); + cr->set_line_join(Cairo::LINE_JOIN_MITER); + cr->set_line_cap(Cairo::LINE_CAP_BUTT); + std::valarray ch_ds (1); + ch_ds[0] = 4; + cr->set_dash (ch_ds, 0); + + // determine the number of h-gridlines based on current h + int nrOfHGridPartitions = (int)rtengine::min (16.0, pow (2.0, floor ((h - 100) / 250) + 2)); + int nrOfVGridPartitions = 8; // always show 8 stops (lines at 1,3,7,15,31,63,127) + + // draw vertical gridlines + for (int i = 0; i <= nrOfVGridPartitions; i++) { + double xpos = padding + 0.5; + if (options.histogramDrawMode < 2) { + xpos += (pow(2.0,i) - 1) * (w - padding * 2.0) / 255.0; + } else { + xpos += HistogramScaling::log (255, pow(2.0,i) - 1) * (w - padding * 2.0) / 255.0; + } + cr->move_to (xpos, 0.); + cr->line_to (xpos, h); + cr->stroke (); + } + + // draw horizontal gridlines + if (options.histogramDrawMode == 0) { + for (int i = 1; i < nrOfHGridPartitions; i++) { + cr->move_to (padding, i * (double)h / nrOfHGridPartitions + 0.5); + cr->line_to (w - padding, i * (double)h / nrOfHGridPartitions + 0.5); + cr->stroke (); + } + } else { + for (int i = 1; i < nrOfHGridPartitions; i++) { + cr->move_to (padding, h - HistogramScaling::log (h, i * (double)h / nrOfHGridPartitions) + 0.5); + cr->line_to (w - padding, h - HistogramScaling::log (h, i * (double)h / nrOfHGridPartitions) + 0.5); + cr->stroke (); + } + } + + cr->unset_dash(); + + if (valid) { + // For RAW mode use the other hists + LUTu& rh = rawMode ? rhistRaw : rhist; + LUTu& gh = rawMode ? ghistRaw : ghist; + LUTu& bh = rawMode ? bhistRaw : bhist; + + // Compute the highest point of the histogram for scaling + unsigned int rgbmax = 0; + unsigned int lumamax = 0; + unsigned int chromamax = 0; + + for (int i = 1; i < 65535; i++) { // Values at far left and right end are handled differently + if (needLuma && lhist[i] > lumamax) { + lumamax = lhist[i]; + } + + if (needChroma && chist[i] > chromamax) { + chromamax = chist[i]; + } + + if (needRed && rh[i] > rgbmax) { + rgbmax = rh[i]; + } + + if (needGreen && gh[i] > rgbmax) { + rgbmax = gh[i]; + } + + if (needBlue && bh[i] > rgbmax) { + rgbmax = bh[i]; + } + } + + cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL); + cr->set_line_width (1.0 * s); + cr->set_operator (Cairo::OPERATOR_OVER); + + int ui = 0, oi = 0; + + if (needLuma && !rawMode) { + drawCurve(cr, lhist, lumamax, w, h); + cr->set_source_rgb (0.7, 0.7, 0.7); + cr->stroke (); + drawMarks(cr, lhist, lumamax, w, ui, oi); + } + + if (needChroma && !rawMode) { + drawCurve(cr, chist, chromamax, w, h); + cr->set_source_rgb (0.9, 0.9, 0.); + cr->stroke (); + drawMarks(cr, chist, chromamax, w, ui, oi); + } + + if (needRed) { + drawCurve(cr, rh, rgbmax, w, h); + cr->set_source_rgb (1.0, 0.0, 0.0); + cr->stroke (); + drawMarks(cr, rh, rgbmax, w, ui, oi); + } + + if (needGreen) { + drawCurve(cr, gh, rgbmax, w, h); + cr->set_source_rgb (0.0, 1.0, 0.0); + cr->stroke (); + drawMarks(cr, gh, rgbmax, w, ui, oi); + } + + if (needBlue) { + drawCurve(cr, bh, rgbmax, w, h); + cr->set_source_rgb (0.0, 0.4, 1.0); + cr->stroke (); + drawMarks(cr, bh, rgbmax, w, ui, oi); + } + + } + + // Draw the frame's border + style->render_frame(cr, 0, 0, surface->get_width(), surface->get_height()); + + oldwidth = w; + oldheight = h; + + setDirty(false); +} + +void HistogramArea::on_realize () +{ + + Gtk::DrawingArea::on_realize(); + add_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK); +} + +void HistogramArea::drawCurve(Cairo::RefPtr &cr, + const LUTu & data, double scale, int hsize, int vsize) +{ + BENCHFUNMICRO + + cr->set_line_width(RTScalable::getScale()); + const float scalef = rtengine::max(scale, 0.001); // avoid division by zero and negative values + + std::vector iscaled(65536); + std::vector vals(65536); + const float scaleFactor = vsize / scalef; + if (drawMode == 2) { // scale x for double log-scale + const float mult2 = 1.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); +//#pragma omp parallel for + for (int i = 0; i < 65536; ++i) { + iscaled[i] = HistogramScaling::logMult (65535.f, i, mult2); + } + } else { + for (int i = 0; i < 65536; ++i) { + iscaled[i] = i; + } + } + if (drawMode > 0) { // scale y for single and double log-scale + const float mult1 = 1.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + vsize)); +#pragma omp parallel for + for (int i = 0; i < 65536; ++i) { + vals[i] = HistogramScaling::logMult(vsize, data[i] * scaleFactor, mult1); + } + } else { + for (int i = 0; i < 65536; ++i) { + vals[i] = data[i] * scaleFactor; + } + } + + for (int i = 0; i < 65536; i++) { + const double posX = padding + iscaled[i] * (hsize - padding * 2.f) / 65535.f; + const double posY = vsize - 2 + vals[i] * (4 - vsize) / vsize; + + cr->move_to (posX, vsize - 2); + cr->line_to (posX, posY); + } +} + +void HistogramArea::drawMarks(Cairo::RefPtr &cr, + const LUTu & data, double scale, int hsize, int & ui, int & oi) +{ + int s = 8 * RTScalable::getScale(); + + if(data[0] > scale) { + cr->rectangle(padding, (ui++)*s, s, s); + } + + if(data[65535] > scale) { + cr->rectangle(hsize - s - padding, (oi++)*s, s, s); + } + + cr->fill(); +} + +bool HistogramArea::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) +{ + + if (get_width() != oldwidth || get_height() != oldheight || isDirty ()) { + updateBackBuffer (); + } + + const Glib::RefPtr style = get_style_context(); + style->render_background(cr, 0, 0, get_width(), get_height()); + copySurface(cr, NULL); + style->render_frame (cr, 0, 0, get_width(), get_height()); + + return true; +} + +bool HistogramArea::on_button_press_event (GdkEventButton* event) +{ + isPressed = true; + movingPosition = event->x; + + if (event->type == GDK_2BUTTON_PRESS && event->button == 1) { + + drawMode = (drawMode + 1) % 3; + options.histogramDrawMode = (options.histogramDrawMode + 1) % 3; + + if (myDrawModeListener) { + myDrawModeListener->toggleButtonMode (); + } + + updateBackBuffer (); + queue_draw (); + } + + return true; +} + +bool HistogramArea::on_button_release_event (GdkEventButton* event) +{ + isPressed = false; + return true; +} + +bool HistogramArea::on_motion_notify_event (GdkEventMotion* event) +{ + if (isPressed) + { + double mod = 1 + (event->x - movingPosition) / get_width(); + + factor /= mod; + if (factor < 1.0) + factor = 1.0; + if (factor > 100.0) + factor = 100.0; + + sigFactorChanged.emit(factor); + + setDirty(true); + queue_draw (); + } + + return true; +} + +HistogramArea::type_signal_factor_changed HistogramArea::signal_factor_changed() +{ + return sigFactorChanged; +} diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index ec6c4125c6..ed19d39dd6 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -31,6 +31,7 @@ #include "../rtengine/LUT.h" #include "../rtengine/noncopyable.h" #include "../rtengine/opthelper.h" +#include "../rtengine/sleef.h" class HistogramArea; @@ -51,9 +52,24 @@ class HistogramScaling { public: float factor; - HistogramScaling() : factor(10.f) {} - float log (float vsize, float val) const; - float logMult (float vsize, float val, float mult) const; + HistogramScaling() : factor(10.f) {} // factor(10.f) can be tuned if necessary - higher is flatter curve + + float log(float vsize, float val) const + { + return vsize * xlogf(factor / (factor + val)) / xlogf(factor / (factor + vsize)); + } + + float logMult(float val, float mult) const + { + return xlogf(factor / (factor + val)) * mult; + } + +#ifdef __SSE2__ + vfloat logMult(vfloat val, vfloat mult) const + { + return xlogf(F2V(factor) / (F2V(factor) + val)) * mult; + } +#endif }; class HistogramRGBArea final : public Gtk::DrawingArea, public BackBuffer, private HistogramScaling, public rtengine::NonCopyable @@ -172,7 +188,7 @@ class HistogramArea final : public Gtk::DrawingArea, public BackBuffer, private type_signal_factor_changed signal_factor_changed(); private: - void drawCurve(Cairo::RefPtr &cr, const LUTu & data, double scale, int hsize, int vsize); + void drawCurve(Cairo::RefPtr &cr, const LUTu & data, float scale, float hsize, float vsize); void drawMarks(Cairo::RefPtr &cr, const LUTu & data, double scale, int hsize, int & ui, int & oi); Gtk::SizeRequestMode get_request_mode_vfunc () const override; void get_preferred_height_vfunc (int& minimum_height, int& natural_height) const override; From 69d64d067c2b3f76ea03f377a4a5627e54eed192 Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Wed, 9 Sep 2020 13:41:29 +0200 Subject: [PATCH 04/15] removed accidently added file --- rtgui/histogrampanel.cc.save-failed | 1093 --------------------------- 1 file changed, 1093 deletions(-) delete mode 100644 rtgui/histogrampanel.cc.save-failed diff --git a/rtgui/histogrampanel.cc.save-failed b/rtgui/histogrampanel.cc.save-failed deleted file mode 100644 index 25a8acc50b..0000000000 --- a/rtgui/histogrampanel.cc.save-failed +++ /dev/null @@ -1,1093 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#include "histogrampanel.h" -#include "multilangmgr.h" -#include "guiutils.h" -#include "options.h" -#include -#include -#include "../rtengine/LUT.h" -#include "rtimage.h" -#include "../rtengine/color.h" -#include "../rtengine/sleef.h" -#define BENCHMARK -#include "../rtengine/StopWatch.h" - -using namespace rtengine; - - -// -// -// HistogramPanel -HistogramPanel::HistogramPanel() : - pointer_moved_delayed_call( - [this](bool validPos, const Glib::ustring &profile, const Glib::ustring &profileW, int r, int g, int b) - { - if (!validPos) { - // do something to un-show vertical bars - histogramRGBArea->updateBackBuffer(-1, -1, -1); - } else { - // do something to show vertical bars - histogramRGBArea->updateBackBuffer(r, g, b, profile, profileW); - } - histogramRGBArea->queue_draw (); - }, - 50, - 100 - ) -{ - setExpandAlignProperties(this, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - set_name("HistogramPanel"); - - histogramArea = Gtk::manage (new HistogramArea (this)); - setExpandAlignProperties(histogramArea, true, true, Gtk::ALIGN_FILL, Gtk::ALIGN_FILL); - - histogramRGBArea = Gtk::manage (new HistogramRGBArea ()); - setExpandAlignProperties(histogramRGBArea, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_END); - histogramRGBArea->show(); - - // connecting the two childs - histogramArea->signal_factor_changed().connect( sigc::mem_fun(*histogramRGBArea, &HistogramRGBArea::factorChanged) ); - - gfxGrid = Gtk::manage (new Gtk::Grid ()); - gfxGrid->set_orientation(Gtk::ORIENTATION_VERTICAL); - gfxGrid->set_row_spacing(1); - gfxGrid->set_column_spacing(1); - histogramRGBArea->setParent(gfxGrid); - gfxGrid->add(*histogramArea); - - if (options.histogramBar) { - gfxGrid->add (*histogramRGBArea); - } - - redImage = new RTImage ("histogram-red-on-small.png"); - greenImage = new RTImage ("histogram-green-on-small.png"); - blueImage = new RTImage ("histogram-blue-on-small.png"); - valueImage = new RTImage ("histogram-silver-on-small.png"); - chroImage = new RTImage ("histogram-gold-on-small.png"); - rawImage = new RTImage ("histogram-bayer-on-small.png"); - barImage = new RTImage ("histogram-bar-on-small.png"); - - redImage_g = new RTImage ("histogram-red-off-small.png"); - greenImage_g = new RTImage ("histogram-green-off-small.png"); - blueImage_g = new RTImage ("histogram-blue-off-small.png"); - valueImage_g = new RTImage ("histogram-silver-off-small.png"); - chroImage_g = new RTImage ("histogram-gold-off-small.png"); - rawImage_g = new RTImage ("histogram-bayer-off-small.png"); - barImage_g = new RTImage ("histogram-bar-off-small.png"); - - mode0Image = new RTImage ("histogram-mode-linear-small.png"); - mode1Image = new RTImage ("histogram-mode-logx-small.png"); - mode2Image = new RTImage ("histogram-mode-logxy-small.png"); - - showRed = Gtk::manage (new Gtk::ToggleButton ()); - showGreen = Gtk::manage (new Gtk::ToggleButton ()); - showBlue = Gtk::manage (new Gtk::ToggleButton ()); - showValue = Gtk::manage (new Gtk::ToggleButton ()); - showChro = Gtk::manage (new Gtk::ToggleButton ()); - showRAW = Gtk::manage (new Gtk::ToggleButton ()); - showMode = Gtk::manage (new Gtk::Button ()); - showBAR = Gtk::manage (new Gtk::ToggleButton ()); - - showRed->set_name("histButton"); - showRed->set_can_focus(false); - showGreen->set_name("histButton"); - showGreen->set_can_focus(false); - showBlue->set_name("histButton"); - showBlue->set_can_focus(false); - showValue->set_name("histButton"); - showValue->set_can_focus(false); - showChro->set_name("histButton"); - showChro->set_can_focus(false); - showRAW->set_name("histButton"); - showRAW->set_can_focus(false); - showMode->set_name("histButton"); - showMode->set_can_focus(false); - showBAR->set_name("histButton"); - showBAR->set_can_focus(false); - - showRed->set_relief (Gtk::RELIEF_NONE); - showGreen->set_relief (Gtk::RELIEF_NONE); - showBlue->set_relief (Gtk::RELIEF_NONE); - showValue->set_relief (Gtk::RELIEF_NONE); - showChro->set_relief (Gtk::RELIEF_NONE); - showRAW->set_relief (Gtk::RELIEF_NONE); - showMode->set_relief (Gtk::RELIEF_NONE); - showBAR->set_relief (Gtk::RELIEF_NONE); - - showRed->set_tooltip_text (M("HISTOGRAM_TOOLTIP_R")); - showGreen->set_tooltip_text (M("HISTOGRAM_TOOLTIP_G")); - showBlue->set_tooltip_text (M("HISTOGRAM_TOOLTIP_B")); - showValue->set_tooltip_text (M("HISTOGRAM_TOOLTIP_L")); - showChro->set_tooltip_text (M("HISTOGRAM_TOOLTIP_CHRO")); - showRAW->set_tooltip_text (M("HISTOGRAM_TOOLTIP_RAW")); - showMode->set_tooltip_text (M("HISTOGRAM_TOOLTIP_MODE")); - showBAR->set_tooltip_text (M("HISTOGRAM_TOOLTIP_BAR")); - - buttonGrid = Gtk::manage (new Gtk::Grid ()); - buttonGrid->set_orientation(Gtk::ORIENTATION_VERTICAL); - showRed->set_active (options.histogramRed); - showGreen->set_active (options.histogramGreen); - showBlue->set_active (options.histogramBlue); - showValue->set_active (options.histogramLuma); - showChro->set_active (options.histogramChroma); - showRAW->set_active (options.histogramRAW); - // no showMode->set_active(), as it's not a ToggleButton - showBAR->set_active (options.histogramBar); - - showRed->set_image (showRed->get_active() ? *redImage : *redImage_g); - showGreen->set_image (showGreen->get_active() ? *greenImage : *greenImage_g); - showBlue->set_image (showBlue->get_active() ? *blueImage : *blueImage_g); - showValue->set_image (showValue->get_active() ? *valueImage : *valueImage_g); - showChro->set_image (showChro->get_active() ? *chroImage : *chroImage_g); - showRAW->set_image (showRAW->get_active() ? *rawImage : *rawImage_g); - if (options.histogramDrawMode == 0) - showMode->set_image(*mode0Image); - else if (options.histogramDrawMode == 1) - showMode->set_image(*mode1Image); - else - showMode->set_image(*mode2Image); - showBAR->set_image (showBAR->get_active() ? *barImage : *barImage_g); - - raw_toggled(); // Make sure the luma/chroma toggles are enabled or disabled - - setExpandAlignProperties(showRed , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showGreen, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showBlue , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showValue, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showChro , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showRAW , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showMode , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - setExpandAlignProperties(showBAR , false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER); - - showRed->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::red_toggled), showRed ); - showGreen->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::green_toggled), showGreen ); - showBlue->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::blue_toggled), showBlue ); - showValue->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::value_toggled), showValue ); - showChro->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::chro_toggled), showChro ); - showRAW->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::raw_toggled), showRAW ); - showMode->signal_released().connect( sigc::mem_fun(*this, &HistogramPanel::mode_released), showMode ); - showBAR->signal_toggled().connect( sigc::mem_fun(*this, &HistogramPanel::bar_toggled), showBAR ); - - buttonGrid->add (*showRed); - buttonGrid->add (*showGreen); - buttonGrid->add (*showBlue); - buttonGrid->add (*showValue); - buttonGrid->add (*showChro); - buttonGrid->add (*showRAW); - buttonGrid->add (*showMode); - buttonGrid->add (*showBAR); - - // Put the button vbox next to the window's border to be less disturbing - if (options.histogramPosition == 1) { - add (*buttonGrid); - add (*gfxGrid); - } else { - add (*gfxGrid); - add (*buttonGrid); - } - - show_all (); - - rconn = signal_size_allocate().connect( sigc::mem_fun(*this, &HistogramPanel::resized) ); -} - -HistogramPanel::~HistogramPanel () -{ - pointer_moved_delayed_call.cancel(); - - delete redImage; - delete greenImage; - delete blueImage; - delete valueImage; - delete chroImage; - delete rawImage; - delete mode0Image; - delete mode1Image; - delete mode2Image; - delete barImage; - - delete redImage_g; - delete greenImage_g; - delete blueImage_g; - delete valueImage_g; - delete chroImage_g; - delete rawImage_g; - delete barImage_g; - -} - -void HistogramPanel::resized (Gtk::Allocation& req) -{ - - histogramArea->updateBackBuffer (); - histogramArea->queue_draw (); - - // set histogramRGBArea invalid; - histogramRGBArea->updateBackBuffer(-1, -1, -1); - histogramRGBArea->queue_draw (); - - // Store current height of the histogram - options.histogramHeight = get_height(); - -} - -void HistogramPanel::red_toggled () -{ - showRed->set_image(showRed->get_active() ? *redImage : *redImage_g); - rgbv_toggled(); -} -void HistogramPanel::green_toggled () -{ - showGreen->set_image(showGreen->get_active() ? *greenImage : *greenImage_g); - rgbv_toggled(); -} -void HistogramPanel::blue_toggled () -{ - showBlue->set_image(showBlue->get_active() ? *blueImage : *blueImage_g); - rgbv_toggled(); -} -void HistogramPanel::value_toggled () -{ - removeIfThere(showValue, valueImage, false); - removeIfThere(showValue, valueImage_g, false); - showValue->set_image(showValue->get_active() ? *valueImage : *valueImage_g); - rgbv_toggled(); -} -void HistogramPanel::chro_toggled () -{ - removeIfThere(showChro, chroImage, false); - removeIfThere(showChro, chroImage_g, false); - showChro->set_image(showChro->get_active() ? *chroImage : *chroImage_g); - rgbv_toggled(); -} - -void HistogramPanel::raw_toggled () -{ - if (showRAW->get_active()) { - showRAW->set_image(*rawImage); - showValue->set_sensitive(false); - showChro->set_sensitive(false); - } else { - showRAW->set_image(*rawImage_g); - showValue->set_sensitive(true); - showChro->set_sensitive(true); - } - - rgbv_toggled(); -} - -void HistogramPanel::mode_released () -{ - options.histogramDrawMode = (options.histogramDrawMode + 1) % 3; - if (options.histogramDrawMode == 0) - showMode->set_image(*mode0Image); - else if (options.histogramDrawMode == 1) - showMode->set_image(*mode1Image); - else - showMode->set_image(*mode2Image); - rgbv_toggled(); -} - -void HistogramPanel::bar_toggled () -{ - showBAR->set_image(showBAR->get_active() ? *barImage : *barImage_g); - rgbv_toggled(); -} - -void HistogramPanel::rgbv_toggled () -{ - // Update Display - histogramArea->updateOptions (showRed->get_active(), showGreen->get_active(), showBlue->get_active(), showValue->get_active(), showChro->get_active(), showRAW->get_active(), options.histogramDrawMode); - histogramArea->queue_draw (); - - histogramRGBArea->updateOptions (showRed->get_active(), showGreen->get_active(), showBlue->get_active(), showValue->get_active(), showChro->get_active(), showRAW->get_active(), showBAR->get_active()); - histogramRGBArea->updateBackBuffer (0, 0, 0); - histogramRGBArea->queue_draw (); -} - -void HistogramPanel::setHistRGBInvalid () -{ - // do something to un-show vertical bars - histogramRGBArea->updateBackBuffer(-1, -1, -1); - histogramRGBArea->queue_draw (); -} - -void HistogramPanel::pointerMoved (bool validPos, const Glib::ustring &profile, const Glib::ustring &profileW, int x, int y, int r, int g, int b, bool isRaw) -{ - pointer_moved_delayed_call(validPos, profile, profileW, r, g, b); -} - -/* - * Move the vertical button bar to the right side - * only allowed values for align are Gtk::POS_LEFT and Gtk::POS_RIGHT - */ -void HistogramPanel::reorder (Gtk::PositionType align) -{ - if (align == Gtk::POS_LEFT) { - gfxGrid->reference(); - removeIfThere(this, gfxGrid, false); - add (*gfxGrid); - gfxGrid->unreference(); - } else { - buttonGrid->reference(); - removeIfThere(this, buttonGrid, false); - add (*buttonGrid); - buttonGrid->unreference(); - } -} - -// DrawModeListener interface: -void HistogramPanel::toggleButtonMode () -{ - if (options.histogramDrawMode == 0) - showMode->set_image(*mode0Image); - else if (options.histogramDrawMode == 1) - showMode->set_image(*mode1Image); - else - showMode->set_image(*mode2Image); -} - -// -// -// -// HistogramScaling -float HistogramScaling::log(float vsize, float val) const -{ - //double factor = 10.0; // can be tuned if necessary - higher is flatter curve - return vsize * xlogf(factor / (factor + val)) / xlogf(factor / (factor + vsize)); -} - -float HistogramScaling::logMult(float vsize, float val, float mult) const -{ - //double factor = 10.0; // can be tuned if necessary - higher is flatter curve - return vsize * xlogf(factor / (factor + val)) * mult; -} - - -// -// -// -// HistogramRGBArea -HistogramRGBArea::HistogramRGBArea () : - val(0), r(0), g(0), b(0), valid(false), - needRed(options.histogramRed), needGreen(options.histogramGreen), needBlue(options.histogramBlue), - needLuma(options.histogramLuma), needChroma(options.histogramChroma), rawMode(options.histogramRAW), - showMode(options.histogramBar), barDisplayed(options.histogramBar), parent(nullptr) -{ - get_style_context()->add_class("drawingarea"); - set_name("HistogramRGBArea"); - - harih = new HistogramRGBAreaIdleHelper; - harih->harea = this; - harih->destroyed = false; - harih->pending = 0; -} - -HistogramRGBArea::~HistogramRGBArea () -{ - idle_register.destroy(); - - if (harih->pending) { - harih->destroyed = true; - } else { - delete harih; - } -} - - -Gtk::SizeRequestMode HistogramRGBArea::get_request_mode_vfunc () const -{ - return Gtk::SIZE_REQUEST_HEIGHT_FOR_WIDTH; -} - -void HistogramRGBArea::get_preferred_height_vfunc (int &minimum_height, int &natural_height) const -{ - int minimumWidth = 0; - int naturalWidth = 0; - get_preferred_width_vfunc(minimumWidth, naturalWidth); - get_preferred_height_for_width_vfunc (minimumWidth, minimum_height, natural_height); -} - -void HistogramRGBArea::get_preferred_width_vfunc (int &minimum_width, int &natural_width) const -{ - int s = RTScalable::getScale(); - minimum_width = 60 * s; - natural_width = 200 * s; -} - -void HistogramRGBArea::get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const -{ - int bHeight = width / 30; - - int s = RTScalable::getScale(); - - if (bHeight > (10 * s)) { - bHeight = 10 * s; - } else if (bHeight < (5 * s)) { - bHeight = 5 * s; - } - - minimum_height = bHeight; - natural_height = bHeight; -} - -// unused? -void HistogramRGBArea::get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const -{ - get_preferred_width_vfunc (minimum_width, natural_width); -} - -bool HistogramRGBArea::getShow() -{ - return(showMode); -} - -void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustring &profile, const Glib::ustring &profileW) -{ - if (!get_realized () || !showMode || rawMode) { - return; - } - - // Mostly not necessary, but should be in some case - GThreadLock lock; // All GUI access from idle_add callbacks or separate thread HAVE to be protected - - Glib::RefPtr window = get_window(); - int winx, winy, winw, winh; - window->get_geometry(winx, winy, winw, winh); - - double s = RTScalable::getScale(); - - // This will create or update the size of the BackBuffer::surface - setDrawRectangle(Cairo::FORMAT_ARGB32, 0, 0, winw, winh, true); - - if (surface) { - Cairo::RefPtr cc = Cairo::Context::create(surface); - - cc->set_source_rgba (0., 0., 0., 0.); - cc->set_operator (Cairo::OPERATOR_CLEAR); - cc->paint (); - cc->set_operator (Cairo::OPERATOR_OVER); - - cc->set_antialias(Cairo::ANTIALIAS_NONE); - cc->set_line_width (1.0 * s); - - if ( r != -1 && g != -1 && b != -1 ) { - double xpos; - if (needRed) { - // Red - cc->set_source_rgb(1.0, 0.0, 0.0); - if (options.histogramDrawMode < 2) { - xpos = padding + r * (winw - padding * 2.0) / 255.0 + 0.5*s; - } else { - xpos = padding + HistogramScaling::log (255, r) * (winw - padding * 2.0) / 255.0 + 0.5*s; - } - cc->move_to(xpos, 0.0); - cc->line_to(xpos, winh - 0.0); - cc->stroke(); - } - - if (needGreen) { - // Green - cc->set_source_rgb(0.0, 1.0, 0.0); - if (options.histogramDrawMode < 2) { - xpos = padding + g * (winw - padding * 2.0) / 255.0 + 0.5*s; - } else { - xpos = padding + HistogramScaling::log (255, g) * (winw - padding * 2.0) / 255.0 + 0.5*s; - } - cc->move_to(xpos, 0.0); - cc->line_to(xpos, winh - 0.0); - cc->stroke(); - } - - if (needBlue) { - // Blue - cc->set_source_rgb(0.0, 0.4, 1.0); - if (options.histogramDrawMode < 2) { - xpos = padding + b * (winw - padding * 2.0) / 255.0 + 0.5*s; - } else { - xpos = padding + HistogramScaling::log (255, b) * (winw - padding * 2.0) / 255.0 + 0.5*s; - } - cc->move_to(xpos, 0.0); - cc->line_to(xpos, winh - 0.0); - cc->stroke(); - } - - if(needLuma || needChroma) { - float Lab_L, Lab_a, Lab_b; - rtengine::Color::rgb2lab01(profile, profileW, r / 255.f, g / 255.f, b / 255.f, Lab_L, Lab_a, Lab_b, options.rtSettings.HistogramWorking); - - if (needLuma) { - // Luma - cc->set_source_rgb(1.0, 1.0, 1.0); - if (options.histogramDrawMode < 2) { - xpos = padding + static_cast(Lab_L) * (winw - padding * 2.0) / 100.0 + 0.5*s; - } else { - xpos = padding + HistogramScaling::log(100, Lab_L) * (winw - padding * 2.0) / 100.0 + 0.5*s; - } - cc->move_to(xpos, 0.0); - cc->line_to(xpos, winh - 0.0); - cc->stroke(); - } - - if (needChroma) { - // Chroma - double chromaval = sqrt(Lab_a * Lab_a + Lab_b * Lab_b) / 1.8; - cc->set_source_rgb(0.9, 0.9, 0.0); - if (options.histogramDrawMode < 2) { - xpos = padding + chromaval * (winw - padding * 2.0) / 100.0 + 0.5*s; - } else { - xpos = padding + HistogramScaling::log(100, chromaval) * (winw - padding * 2.0) / 100.0 + 0.5*s; - } - cc->move_to(xpos, 0.0); - cc->line_to(xpos, winh - 0.0); - cc->stroke(); - } - } - } - } - - setDirty(false); -} - -void HistogramRGBArea::update (int valh, int rh, int gh, int bh) -{ - - if (valh) { - val = valh; - r = rh; - g = gh; - b = bh; - valid = true; - } else { - valid = false; - } - - harih->pending++; - - idle_register.add( - [this]() -> bool - { - if (harih->destroyed) { - if (harih->pending == 1) { - delete harih; - } else { - --harih->pending; - } - - return false; - } - - harih->harea->updateBackBuffer(-1, -1, -1); - harih->harea->queue_draw (); - - --harih->pending; - - return false; - } - ); -} - -void HistogramRGBArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, bool bar) -{ - - options.histogramRed = needRed = r; - options.histogramGreen = needGreen = g; - options.histogramBlue = needBlue = b; - options.histogramLuma = needLuma = l; - options.histogramChroma = needChroma = c; - options.histogramRAW = rawMode = raw; - options.histogramBar = showMode = bar; - - // Show/hide the RGB bar widget - if (bar && !barDisplayed) { - parent->add(*this); - barDisplayed = true; - } else if (!bar && barDisplayed) { - removeIfThere(parent, this, false); - barDisplayed = false; - } - -} - -void HistogramRGBArea::on_realize () -{ - - Gtk::DrawingArea::on_realize(); - add_events(Gdk::BUTTON_PRESS_MASK); -} - -bool HistogramRGBArea::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) -{ - - const Glib::RefPtr style = get_style_context(); - style->render_background(cr, 0, 0, get_width(), get_height()); - - // on_realize & updateBackBuffer have to be called before - if (surface) { - if (isDirty()) { // not sure this could happen... - updateBackBuffer(-1, -1, -1); - } - - copySurface(cr, NULL); - } - - style->render_frame (cr, 0, 0, get_width(), get_height()); - - return true; -} - -bool HistogramRGBArea::on_button_press_event (GdkEventButton* event) -{ - - if (event->type == GDK_2BUTTON_PRESS && event->button == 1) { - // do something? - } - - return true; -} - -void HistogramRGBArea::factorChanged (double newFactor) -{ - factor = newFactor; -} - -// -// -// -// HistogramArea -HistogramArea::HistogramArea (DrawModeListener *fml) : - valid(false), drawMode(options.histogramDrawMode), myDrawModeListener(fml), - oldwidth(-1), oldheight(-1), - needRed(options.histogramRed), needGreen(options.histogramGreen), needBlue(options.histogramBlue), - needLuma(options.histogramLuma), needChroma(options.histogramChroma), rawMode(options.histogramRAW), - isPressed(false), movingPosition(0.0) -{ - - rhist(65536); - ghist(65536); - bhist(65536); - lhist(256); - chist(256); - - get_style_context()->add_class("drawingarea"); - set_name("HistogramArea"); - - haih = new HistogramAreaIdleHelper; - haih->harea = this; - haih->destroyed = false; - haih->pending = 0; -} - -HistogramArea::~HistogramArea () -{ - idle_register.destroy(); - - if (haih->pending) { - haih->destroyed = true; - } else { - delete haih; - } -} - -Gtk::SizeRequestMode HistogramArea::get_request_mode_vfunc () const -{ - return Gtk::SIZE_REQUEST_CONSTANT_SIZE; -} - -void HistogramArea::get_preferred_height_vfunc (int &minimum_height, int &natural_height) const -{ - int s = (int)RTScalable::getScale(); - minimum_height = 100 * s; - natural_height = 200 * s; -} - -void HistogramArea::get_preferred_width_vfunc (int &minimum_width, int &natural_width) const -{ - - int s = (int)RTScalable::getScale(); - minimum_width = 200 * s; - natural_width = 400 * s; -} - -void HistogramArea::get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const -{ - - minimum_height = 0; - natural_height = 0; -} - -void HistogramArea::get_preferred_width_for_height_vfunc (int height, int &minimum_width, int &natural_width) const -{ - get_preferred_width_vfunc (minimum_width, natural_width); -} - -void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, bool raw, int mode) -{ - - options.histogramRed = needRed = r; - options.histogramGreen = needGreen = g; - options.histogramBlue = needBlue = b; - options.histogramLuma = needLuma = l; - options.histogramChroma = needChroma = c; - options.histogramRAW = rawMode = raw; - options.histogramDrawMode = drawMode = mode; - - updateBackBuffer (); -} - -void HistogramArea::update( - const LUTu& histRed, - const LUTu& histGreen, - const LUTu& histBlue, - const LUTu& histLuma, - const LUTu& histChroma, - const LUTu& histRedRaw, - const LUTu& histGreenRaw, - const LUTu& histBlueRaw -) -{ - if (histRed) { - rhist = histRed; - ghist = histGreen; - bhist = histBlue; - lhist = histLuma; - chist = histChroma; - rhistRaw = histRedRaw; - ghistRaw = histGreenRaw; - bhistRaw = histBlueRaw; - valid = true; - } else { - valid = false; - } - - haih->pending++; - - // Can be done outside of the GUI thread - idle_register.add( - [this]() -> bool - { - if (haih->destroyed) { - if (haih->pending == 1) { - delete haih; - } else { - --haih->pending; - } - - return false; - } - - haih->harea->setDirty(true); - haih->harea->updateBackBuffer(); - haih->harea->queue_draw(); - - --haih->pending; - - return false; - } - ); -} - -void HistogramArea::updateBackBuffer () -{ - - if (!get_realized ()) { - return; - } - - Glib::RefPtr window = get_window(); - int winx, winy, winw, winh; - window->get_geometry(winx, winy, winw, winh); - - // This will create or update the size of the BackBuffer::surface - setDrawRectangle(Cairo::FORMAT_ARGB32, 0, 0, winw, winh, true); - - Cairo::RefPtr cr = Cairo::Context::create(surface); - const Glib::RefPtr style = get_style_context(); - - double s = RTScalable::getScale(); - - // Setup drawing - cr->set_source_rgba (0., 0., 0., 0.); - cr->set_operator (Cairo::OPERATOR_CLEAR); - cr->paint (); - cr->set_operator (Cairo::OPERATOR_SOURCE); - - // Prepare drawing gridlines first - cr->set_source_rgba (1., 1., 1., 0.25); - cr->set_line_width (1.0 * s); - cr->set_antialias(Cairo::ANTIALIAS_NONE); - cr->set_line_join(Cairo::LINE_JOIN_MITER); - cr->set_line_cap(Cairo::LINE_CAP_BUTT); - std::valarray ch_ds (1); - ch_ds[0] = 4; - cr->set_dash (ch_ds, 0); - - // determine the number of h-gridlines based on current h - int nrOfHGridPartitions = (int)rtengine::min (16.0, pow (2.0, floor ((h - 100) / 250) + 2)); - int nrOfVGridPartitions = 8; // always show 8 stops (lines at 1,3,7,15,31,63,127) - - // draw vertical gridlines - for (int i = 0; i <= nrOfVGridPartitions; i++) { - double xpos = padding + 0.5; - if (options.histogramDrawMode < 2) { - xpos += (pow(2.0,i) - 1) * (w - padding * 2.0) / 255.0; - } else { - xpos += HistogramScaling::log (255, pow(2.0,i) - 1) * (w - padding * 2.0) / 255.0; - } - cr->move_to (xpos, 0.); - cr->line_to (xpos, h); - cr->stroke (); - } - - // draw horizontal gridlines - if (options.histogramDrawMode == 0) { - for (int i = 1; i < nrOfHGridPartitions; i++) { - cr->move_to (padding, i * (double)h / nrOfHGridPartitions + 0.5); - cr->line_to (w - padding, i * (double)h / nrOfHGridPartitions + 0.5); - cr->stroke (); - } - } else { - for (int i = 1; i < nrOfHGridPartitions; i++) { - cr->move_to (padding, h - HistogramScaling::log (h, i * (double)h / nrOfHGridPartitions) + 0.5); - cr->line_to (w - padding, h - HistogramScaling::log (h, i * (double)h / nrOfHGridPartitions) + 0.5); - cr->stroke (); - } - } - - cr->unset_dash(); - - if (valid) { - // For RAW mode use the other hists - LUTu& rh = rawMode ? rhistRaw : rhist; - LUTu& gh = rawMode ? ghistRaw : ghist; - LUTu& bh = rawMode ? bhistRaw : bhist; - - // Compute the highest point of the histogram for scaling - unsigned int rgbmax = 0; - unsigned int lumamax = 0; - unsigned int chromamax = 0; - - for (int i = 1; i < 65535; i++) { // Values at far left and right end are handled differently - if (needLuma && lhist[i] > lumamax) { - lumamax = lhist[i]; - } - - if (needChroma && chist[i] > chromamax) { - chromamax = chist[i]; - } - - if (needRed && rh[i] > rgbmax) { - rgbmax = rh[i]; - } - - if (needGreen && gh[i] > rgbmax) { - rgbmax = gh[i]; - } - - if (needBlue && bh[i] > rgbmax) { - rgbmax = bh[i]; - } - } - - cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL); - cr->set_line_width (1.0 * s); - cr->set_operator (Cairo::OPERATOR_OVER); - - int ui = 0, oi = 0; - - if (needLuma && !rawMode) { - drawCurve(cr, lhist, lumamax, w, h); - cr->set_source_rgb (0.7, 0.7, 0.7); - cr->stroke (); - drawMarks(cr, lhist, lumamax, w, ui, oi); - } - - if (needChroma && !rawMode) { - drawCurve(cr, chist, chromamax, w, h); - cr->set_source_rgb (0.9, 0.9, 0.); - cr->stroke (); - drawMarks(cr, chist, chromamax, w, ui, oi); - } - - if (needRed) { - drawCurve(cr, rh, rgbmax, w, h); - cr->set_source_rgb (1.0, 0.0, 0.0); - cr->stroke (); - drawMarks(cr, rh, rgbmax, w, ui, oi); - } - - if (needGreen) { - drawCurve(cr, gh, rgbmax, w, h); - cr->set_source_rgb (0.0, 1.0, 0.0); - cr->stroke (); - drawMarks(cr, gh, rgbmax, w, ui, oi); - } - - if (needBlue) { - drawCurve(cr, bh, rgbmax, w, h); - cr->set_source_rgb (0.0, 0.4, 1.0); - cr->stroke (); - drawMarks(cr, bh, rgbmax, w, ui, oi); - } - - } - - // Draw the frame's border - style->render_frame(cr, 0, 0, surface->get_width(), surface->get_height()); - - oldwidth = w; - oldheight = h; - - setDirty(false); -} - -void HistogramArea::on_realize () -{ - - Gtk::DrawingArea::on_realize(); - add_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK); -} - -void HistogramArea::drawCurve(Cairo::RefPtr &cr, - const LUTu & data, double scale, int hsize, int vsize) -{ - BENCHFUNMICRO - - cr->set_line_width(RTScalable::getScale()); - const float scalef = rtengine::max(scale, 0.001); // avoid division by zero and negative values - - std::vector iscaled(65536); - std::vector vals(65536); - const float scaleFactor = vsize / scalef; - if (drawMode == 2) { // scale x for double log-scale - const float mult2 = 1.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); -//#pragma omp parallel for - for (int i = 0; i < 65536; ++i) { - iscaled[i] = HistogramScaling::logMult (65535.f, i, mult2); - } - } else { - for (int i = 0; i < 65536; ++i) { - iscaled[i] = i; - } - } - if (drawMode > 0) { // scale y for single and double log-scale - const float mult1 = 1.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + vsize)); -#pragma omp parallel for - for (int i = 0; i < 65536; ++i) { - vals[i] = HistogramScaling::logMult(vsize, data[i] * scaleFactor, mult1); - } - } else { - for (int i = 0; i < 65536; ++i) { - vals[i] = data[i] * scaleFactor; - } - } - - for (int i = 0; i < 65536; i++) { - const double posX = padding + iscaled[i] * (hsize - padding * 2.f) / 65535.f; - const double posY = vsize - 2 + vals[i] * (4 - vsize) / vsize; - - cr->move_to (posX, vsize - 2); - cr->line_to (posX, posY); - } -} - -void HistogramArea::drawMarks(Cairo::RefPtr &cr, - const LUTu & data, double scale, int hsize, int & ui, int & oi) -{ - int s = 8 * RTScalable::getScale(); - - if(data[0] > scale) { - cr->rectangle(padding, (ui++)*s, s, s); - } - - if(data[65535] > scale) { - cr->rectangle(hsize - s - padding, (oi++)*s, s, s); - } - - cr->fill(); -} - -bool HistogramArea::on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) -{ - - if (get_width() != oldwidth || get_height() != oldheight || isDirty ()) { - updateBackBuffer (); - } - - const Glib::RefPtr style = get_style_context(); - style->render_background(cr, 0, 0, get_width(), get_height()); - copySurface(cr, NULL); - style->render_frame (cr, 0, 0, get_width(), get_height()); - - return true; -} - -bool HistogramArea::on_button_press_event (GdkEventButton* event) -{ - isPressed = true; - movingPosition = event->x; - - if (event->type == GDK_2BUTTON_PRESS && event->button == 1) { - - drawMode = (drawMode + 1) % 3; - options.histogramDrawMode = (options.histogramDrawMode + 1) % 3; - - if (myDrawModeListener) { - myDrawModeListener->toggleButtonMode (); - } - - updateBackBuffer (); - queue_draw (); - } - - return true; -} - -bool HistogramArea::on_button_release_event (GdkEventButton* event) -{ - isPressed = false; - return true; -} - -bool HistogramArea::on_motion_notify_event (GdkEventMotion* event) -{ - if (isPressed) - { - double mod = 1 + (event->x - movingPosition) / get_width(); - - factor /= mod; - if (factor < 1.0) - factor = 1.0; - if (factor > 100.0) - factor = 100.0; - - sigFactorChanged.emit(factor); - - setDirty(true); - queue_draw (); - } - - return true; -} - -HistogramArea::type_signal_factor_changed HistogramArea::signal_factor_changed() -{ - return sigFactorChanged; -} From 0fb8b98e6d27668a58f190ae5d2f13ec8d97bf3b Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Wed, 9 Sep 2020 19:03:42 +0200 Subject: [PATCH 05/15] Some modifications to increase the responsiveness of the histogram. Not drawing 0's helps a lot. --- rtengine/improccoordinator.cc | 1 - rtengine/rawimagesource.cc | 2 +- rtgui/histogrampanel.cc | 13 ++++++------- rtgui/histogrampanel.h | 2 +- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index cf0bc11b4f..79ce24f497 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1745,7 +1745,6 @@ void ImProcCoordinator::setScale(int prevscale) void ImProcCoordinator::updateLRGBHistograms() { - int x1, y1, x2, y2; params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2); diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index d209cab04a..8134a55dd7 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -3721,7 +3721,7 @@ void RawImageSource::getAutoExpHistogram (LUTu & histogram, int& histcompr) // Histogram MUST be 256 in size; gamma is applied, blackpoint and gain also void RawImageSource::getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw) -{ +{ // BENCHFUN histRedRaw.clear(); histGreenRaw.clear(); diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 0ff91b6d81..6bb2a4dd3b 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -785,6 +785,7 @@ void HistogramArea::update( void HistogramArea::updateBackBuffer () { + BENCHFUNMICRO if (!get_realized ()) { return; @@ -800,8 +801,6 @@ void HistogramArea::updateBackBuffer () Cairo::RefPtr cr = Cairo::Context::create(surface); const Glib::RefPtr style = get_style_context(); - double s = RTScalable::getScale(); - // Setup drawing cr->set_source_rgba (0., 0., 0., 0.); cr->set_operator (Cairo::OPERATOR_CLEAR); @@ -810,7 +809,7 @@ void HistogramArea::updateBackBuffer () // Prepare drawing gridlines first cr->set_source_rgba (1., 1., 1., 0.25); - cr->set_line_width (1.0 * s); + cr->set_line_width (RTScalable::getScale()); cr->set_antialias(Cairo::ANTIALIAS_NONE); cr->set_line_join(Cairo::LINE_JOIN_MITER); cr->set_line_cap(Cairo::LINE_CAP_BUTT); @@ -885,8 +884,6 @@ void HistogramArea::updateBackBuffer () } } - cr->set_antialias (Cairo::ANTIALIAS_SUBPIXEL); - cr->set_line_width (1.0 * s); cr->set_operator (Cairo::OPERATOR_OVER); int ui = 0, oi = 0; @@ -949,8 +946,6 @@ void HistogramArea::drawCurve(Cairo::RefPtr &cr, { BENCHFUNMICRO - cr->set_line_width(RTScalable::getScale()); - std::vector iscaled(65536); std::vector vals(65536); @@ -995,12 +990,16 @@ void HistogramArea::drawCurve(Cairo::RefPtr &cr, } for (int i = 0; i < 65536; i++) { + + if (vals[i] == 0.0) continue; + const double posX = padding + iscaled[i] * (hsize - padding * 2.f) / 65535.f; const double posY = vsize - 2 + vals[i] * (4 - vsize) / vsize; cr->move_to (posX, vsize - 2); cr->line_to (posX, posY); } + } void HistogramArea::drawMarks(Cairo::RefPtr &cr, diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index ed19d39dd6..9ba4734e36 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -148,7 +148,7 @@ class HistogramArea final : public Gtk::DrawingArea, public BackBuffer, private protected: LUTu rhist, ghist, bhist, lhist, chist; - LUTu rhistRaw, ghistRaw, bhistRaw, lhistRaw; //lhistRaw is unused? + LUTu rhistRaw, ghistRaw, bhistRaw; bool valid; int drawMode; From 56d6436360f17318ba8346662382ea2b599147cf Mon Sep 17 00:00:00 2001 From: Ingo Weyrich Date: Thu, 10 Sep 2020 19:36:02 +0200 Subject: [PATCH 06/15] further speedup for drawCurve() --- rtgui/histogrampanel.cc | 65 +++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 6bb2a4dd3b..e28f621b9e 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -949,57 +949,72 @@ void HistogramArea::drawCurve(Cairo::RefPtr &cr, std::vector iscaled(65536); std::vector vals(65536); - if (drawMode == 2) { // scale x for double log-scale - const float mult = 65535.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); + const float scalef = rtengine::max(scale, 0.001f); // avoid division by zero and negative values + const float scaleFactor = vsize / scalef; + if (drawMode > 0) { // scale y for single and double log-scale + const float mult = vsize / xlogf(HistogramScaling::factor / (HistogramScaling::factor + vsize)); #ifdef __SSE2__ + const vfloat scaleFactorv = F2V(scaleFactor); const vfloat multv = F2V(mult); - const vfloat fourv = F2V(4.f); - vfloat iv = _mm_setr_ps(0.f, 1.f, 2.f, 3.f); - for (int i = 0; i < 65536; i += 4, iv += fourv) { - STVFU(iscaled[i], HistogramScaling::logMult(iv, multv)); + for (int i = 0; i < 65536; i += 4) { + const vfloat val = _mm_cvtepi32_ps(_mm_loadu_si128((__m128i_u*)&data[i])); + if (_mm_movemask_ps(ZEROV - val)) { + STVFU(vals[i], HistogramScaling::logMult(val * scaleFactorv, multv)); + } else { + STVFU(vals[i], ZEROV); + } } #else for (int i = 0; i < 65536; ++i) { - iscaled[i] = HistogramScaling::logMult(i, mult); + if (data[i]) { + vals[i] = HistogramScaling::logMult(data[i] * scaleFactor, mult); + } else { + vals[i] = 0.f; + } } #endif } else { for (int i = 0; i < 65536; ++i) { - iscaled[i] = i; + vals[i] = data[i] * scaleFactor; } } - const float scalef = rtengine::max(scale, 0.001f); // avoid division by zero and negative values - const float scaleFactor = vsize / scalef; - if (drawMode > 0) { // scale y for single and double log-scale - const float mult = vsize / xlogf(HistogramScaling::factor / (HistogramScaling::factor + vsize)); + + if (drawMode == 2) { // scale x for double log-scale + const float mult = 65535.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); #ifdef __SSE2__ - const vfloat scaleFactorv = F2V(scaleFactor); const vfloat multv = F2V(mult); - for (int i = 0; i < 65536; i += 4) { - STVFU(vals[i], HistogramScaling::logMult(_mm_cvtepi32_ps(_mm_loadu_si128((__m128i_u*)&data[i])) * scaleFactorv, multv)); + const vfloat fourv = F2V(4.f); + vfloat iv = _mm_setr_ps(0.f, 1.f, 2.f, 3.f); + for (int i = 0; i < 65536; i += 4, iv += fourv) { + if (_mm_movemask_ps(ZEROV - LVFU(vals[i]))) { + STVFU(iscaled[i], HistogramScaling::logMult(iv, multv)); + } } #else for (int i = 0; i < 65536; ++i) { - vals[i] = HistogramScaling::logMult(data[i] * scaleFactor, mult); + if (vals[i] != 0.f) { + iscaled[i] = HistogramScaling::logMult(i, mult); + } } #endif } else { for (int i = 0; i < 65536; ++i) { - vals[i] = data[i] * scaleFactor; + iscaled[i] = i; } } for (int i = 0; i < 65536; i++) { + if (vals[i] == 0.f) { + continue; + } - if (vals[i] == 0.0) continue; - - const double posX = padding + iscaled[i] * (hsize - padding * 2.f) / 65535.f; - const double posY = vsize - 2 + vals[i] * (4 - vsize) / vsize; - - cr->move_to (posX, vsize - 2); - cr->line_to (posX, posY); + const double posY = vsize - 2 + vals[i] * ((4 - vsize) / vsize); +// remove me if (vsize - 2 - posY >= 1) { + const double posX = padding + iscaled[i] * ((hsize - padding * 2.f) / 65535.f); + cr->move_to (posX, vsize - 2); + cr->line_to (posX, posY); +// remove me } } - } void HistogramArea::drawMarks(Cairo::RefPtr &cr, From f7d36e312c70d16361acb11b357c5eb7f7010267 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Thu, 10 Sep 2020 21:07:44 +0200 Subject: [PATCH 07/15] Indicator lines for min/max levels. Proof of principle. --- rtgui/histogrampanel.cc | 46 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 6bb2a4dd3b..3ff201a40a 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -785,7 +785,7 @@ void HistogramArea::update( void HistogramArea::updateBackBuffer () { - BENCHFUNMICRO + //BENCHFUNMICRO if (!get_realized ()) { return; @@ -883,6 +883,20 @@ void HistogramArea::updateBackBuffer () rgbmax = bh[i]; } } + + int rgbFirst = -1, rgbLast = -1; + for (int i = 0; i < 65536; i++) { + if (needRed && rgbFirst == -1 && rh[i] != 0) rgbFirst = i; + if (needGreen && rgbFirst == -1 && gh[i] != 0) rgbFirst = i; + if (needBlue && rgbFirst == -1 && bh[i] != 0) rgbFirst = i; + if (rgbFirst != -1) break; + } + for (int i = 65535; i >= 0; i--) { + if (needRed && rgbLast == -1 && rh[i] != 0) rgbLast = i; + if (needGreen && rgbLast == -1 && gh[i] != 0) rgbLast = i; + if (needBlue && rgbLast == -1 && bh[i] != 0) rgbLast = i; + if (rgbLast != -1) break; + } cr->set_operator (Cairo::OPERATOR_OVER); @@ -922,6 +936,34 @@ void HistogramArea::updateBackBuffer () cr->stroke (); drawMarks(cr, bh, rgbmax, w, ui, oi); } + + if (rgbFirst != -1) { // Draw min/max marker lines + + float posX = static_cast(rgbFirst); + const float mult = 65535.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); + if (drawMode == 2) { + posX = HistogramScaling::logMult(posX, mult); + } + posX = posX * w / 65535.f + padding;// + 0.5; + cr->move_to (posX, 0); + cr->line_to (posX, h); + cr->set_source_rgba (1., 1., 1., 0.55); + cr->stroke(); + } + + if (rgbLast != -1) { // Draw min/max marker lines + + float posX = static_cast(rgbLast); + const float mult = 65535.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); + if (drawMode == 2) { + posX = HistogramScaling::logMult(posX, mult); + } + posX = posX * w / 65535.f + padding;// + 0.5; + cr->move_to (posX, 0); + cr->line_to (posX, h); + cr->set_source_rgba (1., 1., 1., 0.55); + cr->stroke(); + } } @@ -944,7 +986,7 @@ void HistogramArea::on_realize () void HistogramArea::drawCurve(Cairo::RefPtr &cr, const LUTu & data, float scale, float hsize, float vsize) { - BENCHFUNMICRO + //BENCHFUNMICRO std::vector iscaled(65536); std::vector vals(65536); From df60590d5bb1659096e4800e023defeebeebacee Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Tue, 29 Dec 2020 16:38:49 +0100 Subject: [PATCH 08/15] Rethought drawing raw and non-raw histogram. Removed padddding. Minor other changes. --- rtdata/themes/RawTherapee-GTK3-20_.css | 3 +- rtengine/rawimagesource.cc | 2 +- rtgui/histogrampanel.cc | 200 ++++++++++++------------- rtgui/histogrampanel.h | 10 +- 4 files changed, 106 insertions(+), 109 deletions(-) diff --git a/rtdata/themes/RawTherapee-GTK3-20_.css b/rtdata/themes/RawTherapee-GTK3-20_.css index f4f9ddb7fc..5c84d4ea3e 100644 --- a/rtdata/themes/RawTherapee-GTK3-20_.css +++ b/rtdata/themes/RawTherapee-GTK3-20_.css @@ -706,7 +706,8 @@ flowboxchild:selected { #HistogramArea, #HistogramRGBArea { - border-width: 0.083333333333333333em; + border: none; + /*border-width: 0.083333333333333333em;*/ } #histButton { diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index ff6e707233..5dde838a2a 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -3769,7 +3769,7 @@ void RawImageSource::getAutoExpHistogram (LUTu & histogram, int& histcompr) } } -// Histogram MUST be 256 in size; gamma is applied, blackpoint and gain also +// For histogram data gamma is applied, blackpoint and gain also void RawImageSource::getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw) { // BENCHFUN diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index b8abc5f460..025f9b0dd6 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -961,9 +961,9 @@ void HistogramRGBAreaHori::drawBar(Cairo::RefPtr cc, double valu { double pos; if (options.histogramDrawMode < 2) { - pos = padding + value * (winw - padding * 2.0) / max_value + 0.5 * scale; + pos = value * winw / max_value + 0.5 * scale; } else { - pos = padding + HistogramScaling::log (max_value, value) * (winw - padding * 2.0) / max_value + 0.5 * scale; + pos = HistogramScaling::log (max_value, value) * winw / max_value + 0.5 * scale; } cc->move_to(pos, 0.0); cc->line_to(pos, winh - 0.0); @@ -999,9 +999,9 @@ void HistogramRGBAreaVert::drawBar(Cairo::RefPtr cc, double valu { double pos; if (options.histogramDrawMode < 2 || options.histogramScopeType == ScopeType::PARADE || options.histogramScopeType == ScopeType::WAVEFORM) { - pos = padding + value * (winh - padding * 2.0 - 1) / max_value + 0.5 * scale; + pos = value * (winh - 1) / max_value + 0.5 * scale; } else { - pos = padding + HistogramScaling::log (max_value, value) * (winh - padding * 2.0) / max_value + 0.5 * scale; + pos = HistogramScaling::log (max_value, value) * winh / max_value + 0.5 * scale; } cc->move_to(0.0, winh - pos); cc->line_to(winw, winh - pos); @@ -1098,7 +1098,6 @@ void HistogramArea::get_preferred_height_vfunc (int &minimum_height, int &natura void HistogramArea::get_preferred_width_vfunc (int &minimum_width, int &natural_width) const { - int s = RTScalable::getScale(); minimum_width = 200 * s; natural_width = 400 * s; @@ -1106,7 +1105,6 @@ void HistogramArea::get_preferred_width_vfunc (int &minimum_width, int &natural_ void HistogramArea::get_preferred_height_for_width_vfunc (int width, int &minimum_height, int &natural_height) const { - minimum_height = 0; natural_height = 0; } @@ -1235,50 +1233,50 @@ void HistogramArea::updateBackBuffer () window->get_geometry(winx, winy, winw, winh); // This will create or update the size of the BackBuffer::surface - setDrawRectangle(Cairo::FORMAT_ARGB32, 0, 0, winw, winh, true); + setDrawRectangle(Cairo::FORMAT_ARGB32, 0, 0, winw, winh, true); // sets w and h in the BackBuffer Cairo::RefPtr cr = Cairo::Context::create(surface); const Glib::RefPtr style = get_style_context(); // Setup drawing - cr->set_source_rgba (0., 0., 0., 0.); - cr->set_operator (Cairo::OPERATOR_CLEAR); - cr->paint (); - cr->set_operator (Cairo::OPERATOR_SOURCE); + cr->set_source_rgba(0., 0., 0., 0.); + cr->set_operator(Cairo::OPERATOR_CLEAR); + cr->paint(); + cr->set_operator(Cairo::OPERATOR_SOURCE); // Prepare drawing gridlines first - cr->set_source_rgba (1., 1., 1., 0.25); + cr->set_source_rgba(1., 1., 1., 0.25); cr->set_line_width (RTScalable::getScale()); cr->set_antialias(Cairo::ANTIALIAS_NONE); cr->set_line_join(Cairo::LINE_JOIN_MITER); cr->set_line_cap(Cairo::LINE_CAP_BUTT); - std::valarray ch_ds (1); + std::valarray ch_ds(1); ch_ds[0] = 4; - cr->set_dash (ch_ds, 0); + cr->set_dash(ch_ds, 0); - // determine the number of h-gridlines based on current h + // determine the number of horiztonal gridlines based on current height int nrOfHGridPartitions = static_cast(rtengine::min (16.0, pow (2.0, floor ((h - 100) / 250) + 2))); - int nrOfVGridPartitions = 8; // always show 8 stops (lines at 1,3,7,15,31,63,127) + int nrOfVGridPartitions = 16; // always show 16 stops // draw vertical gridlines if (options.histogramScopeType == ScopeType::HISTOGRAM || options.histogramScopeType == ScopeType::HISTOGRAM_RAW) { + float xpos; for (int i = 0; i <= nrOfVGridPartitions; i++) { - double xpos = padding + 0.5; if (options.histogramDrawMode < 2) { - xpos += (pow(2.0,i) - 1) * (w - padding * 2.0) / 255.0; + xpos = (pow(2.0,i) - 1) / 65535.0 * (w - 1.0); } else { - xpos += HistogramScaling::log (255, pow(2.0,i) - 1) * (w - padding * 2.0) / 255.0; + xpos = HistogramScaling::log(65535.0, pow(2.0,i) - 1) * (w - 1.0); } - cr->move_to (xpos, 0.); - cr->line_to (xpos, h); - cr->stroke (); + cr->move_to(xpos + 1.0, 0); + cr->line_to(xpos + 1.0, h); + cr->stroke(); } } // draw horizontal gridlines - if (options.histogramScopeType == ScopeType::PARADE || options.histogramScopeType == ScopeType::WAVEFORM) { + /*if (options.histogramScopeType == ScopeType::PARADE || options.histogramScopeType == ScopeType::WAVEFORM) { for (int i = 0; i <= nrOfVGridPartitions; i++) { - const double ypos = h - padding - (pow(2.0,i) - 1) * (h - 2 * padding - 1) / 255.0; + const double ypos = h - (pow(2.0,i) - 1) * (h - 1) / 255.0; cr->move_to(0, ypos); cr->line_to(w, ypos); cr->stroke(); @@ -1287,17 +1285,17 @@ void HistogramArea::updateBackBuffer () // Vectorscope has no gridlines. } else if (options.histogramDrawMode == 0) { for (int i = 1; i < nrOfHGridPartitions; i++) { - cr->move_to (padding, i * static_cast(h) / nrOfHGridPartitions + 0.5); - cr->line_to (w - padding, i * static_cast(h) / nrOfHGridPartitions + 0.5); + cr->move_to (0, i * static_cast(h) / nrOfHGridPartitions + 0.5); + cr->line_to (w, i * static_cast(h) / nrOfHGridPartitions + 0.5); cr->stroke (); } } else { for (int i = 1; i < nrOfHGridPartitions; i++) { - cr->move_to (padding, h - HistogramScaling::log (h, i * static_cast(h) / nrOfHGridPartitions) + 0.5); - cr->line_to (w - padding, h - HistogramScaling::log (h, i * static_cast(h) / nrOfHGridPartitions) + 0.5); + cr->move_to (0, h - HistogramScaling::log (h, i * static_cast(h) / nrOfHGridPartitions) + 0.5); + cr->line_to (w, h - HistogramScaling::log (h, i * static_cast(h) / nrOfHGridPartitions) + 0.5); cr->stroke (); } - } + }*/ cr->unset_dash(); @@ -1336,6 +1334,7 @@ void HistogramArea::updateBackBuffer () } } + // Compute the first and last non-zero histogram bins int rgbFirst = -1, rgbLast = -1; for (int i = 0; i < 65536; i++) { if (needRed && rgbFirst == -1 && rh[i] != 0) rgbFirst = i; @@ -1351,71 +1350,84 @@ void HistogramArea::updateBackBuffer () } cr->set_operator (Cairo::OPERATOR_OVER); - + + if (rgbFirst != -1) { // Draw min/max marker lines + + float posX = static_cast(rgbFirst); + if (drawMode == 2) { + const float mult = 65535.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); + posX = HistogramScaling::logMult(posX, mult); + } + posX = posX * (w - 1.f) / 65535.f; + cr->move_to (posX + 1.f, 0); + cr->line_to (posX + 1.f, h); + cr->set_source_rgba (1., 1., 1., 0.55); + cr->stroke(); + } + + if (rgbLast != -1) { // Draw min/max marker lines + + float posX = static_cast(rgbLast); + if (drawMode == 2) { + const float mult = 65535.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); + posX = HistogramScaling::logMult(posX, mult); + } + posX = posX * (w - 1.f) / 65535.f; + cr->move_to (posX + 1.f, 0); + cr->line_to (posX + 1.f, h); + cr->set_source_rgba (1., 1., 1., 0.55); + cr->stroke(); + } + + // Draw EV0 line + float posX = 32768.f; // TODO: Link directly to bitdepth + if (drawMode == 2) { + const float mult = 65535.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); + posX = HistogramScaling::logMult(posX, mult); + } + posX = posX * (w - 1.f) / 65535.f; + cr->move_to (posX + 1.f, 0); + cr->line_to (posX + 1.f, h); + cr->set_source_rgba (1., 1., 1., 0.55); + cr->stroke(); + + // Draw all curves int ui = 0, oi = 0; if (needLuma && !rawMode) { - drawCurve(cr, lhist, lumamax, w, h); + drawCurve(cr, lhist, lumamax); cr->set_source_rgb (0.7, 0.7, 0.7); cr->stroke (); drawMarks(cr, lhist, lumamax, w, ui, oi); } if (needChroma && !rawMode) { - drawCurve(cr, chist, chromamax, w, h); + drawCurve(cr, chist, chromamax); cr->set_source_rgb (0.9, 0.9, 0.); cr->stroke (); drawMarks(cr, chist, chromamax, w, ui, oi); } if (needRed) { - drawCurve(cr, rh, rgbmax, w, h); + drawCurve(cr, rh, rgbmax); cr->set_source_rgb (1.0, 0.0, 0.0); cr->stroke (); drawMarks(cr, rh, rgbmax, w, ui, oi); } if (needGreen) { - drawCurve(cr, gh, rgbmax, w, h); + drawCurve(cr, gh, rgbmax); cr->set_source_rgb (0.0, 1.0, 0.0); cr->stroke (); drawMarks(cr, gh, rgbmax, w, ui, oi); } if (needBlue) { - drawCurve(cr, bh, rgbmax, w, h); + drawCurve(cr, bh, rgbmax); cr->set_source_rgb (0.0, 0.4, 1.0); cr->stroke (); drawMarks(cr, bh, rgbmax, w, ui, oi); } - - if (rgbFirst != -1) { // Draw min/max marker lines - - float posX = static_cast(rgbFirst); - const float mult = 65535.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); - if (drawMode == 2) { - posX = HistogramScaling::logMult(posX, mult); - } - posX = posX * w / 65535.f + padding;// + 0.5; - cr->move_to (posX, 0); - cr->line_to (posX, h); - cr->set_source_rgba (1., 1., 1., 0.55); - cr->stroke(); - } - - if (rgbLast != -1) { // Draw min/max marker lines - - float posX = static_cast(rgbLast); - const float mult = 65535.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); - if (drawMode == 2) { - posX = HistogramScaling::logMult(posX, mult); - } - posX = posX * w / 65535.f + padding;// + 0.5; - cr->move_to (posX, 0); - cr->line_to (posX, h); - cr->set_source_rgba (1., 1., 1., 0.55); - cr->stroke(); - } } else if (scopeType == ScopeType::PARADE && rwave.getWidth() > 0) { drawParade(cr, w, h); @@ -1425,9 +1437,6 @@ void HistogramArea::updateBackBuffer () drawVectorscope(cr, w, h); } - // Draw the frame's border - style->render_frame(cr, 0, 0, surface->get_width(), surface->get_height()); - oldwidth = w; oldheight = h; @@ -1454,30 +1463,25 @@ bool HistogramArea::updatePointer(int r, int g, int b, const Glib::ustring &prof void HistogramArea::on_realize () { - Gtk::DrawingArea::on_realize(); add_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK); } -void HistogramArea::drawCurve(Cairo::RefPtr &cr, - const LUTu & data, float scale, float hsize, float vsize) +void HistogramArea::drawCurve(Cairo::RefPtr &cr, const LUTu & data, float scale) { - //BENCHFUNMICRO - std::vector iscaled(65536); std::vector vals(65536); - const float scalef = rtengine::max(scale, 0.001f); // avoid division by zero and negative values - const float scaleFactor = vsize / scalef; + const float maxvalue = rtengine::max(scale, 0.001f); // avoid division by zero and negative values + if (drawMode > 0) { // scale y for single and double log-scale - const float mult = vsize / xlogf(HistogramScaling::factor / (HistogramScaling::factor + vsize)); + const float mult = (h - 1.0f) / xlogf(HistogramScaling::factor / (HistogramScaling::factor + maxvalue)); #ifdef __SSE2__ - const vfloat scaleFactorv = F2V(scaleFactor); const vfloat multv = F2V(mult); for (int i = 0; i < 65536; i += 4) { const vfloat val = _mm_cvtepi32_ps(_mm_loadu_si128((__m128i_u*)&data[i])); if (_mm_movemask_ps(ZEROV - val)) { - STVFU(vals[i], HistogramScaling::logMult(val * scaleFactorv, multv)); + STVFU(vals[i], HistogramScaling::logMult(val, multv)); } else { STVFU(vals[i], ZEROV); } @@ -1485,20 +1489,21 @@ void HistogramArea::drawCurve(Cairo::RefPtr &cr, #else for (int i = 0; i < 65536; ++i) { if (data[i]) { - vals[i] = HistogramScaling::logMult(data[i] * scaleFactor, mult); + vals[i] = HistogramScaling::logMult(data[i], mult); } else { vals[i] = 0.f; } } #endif } else { + const float mult = (h - 1.0f) / maxvalue; for (int i = 0; i < 65536; ++i) { - vals[i] = data[i] * scaleFactor; + vals[i] = data[i] * mult; } } if (drawMode == 2) { // scale x for double log-scale - const float mult = 65535.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); + const float mult = (w - 1.f) / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.f)); #ifdef __SSE2__ const vfloat multv = F2V(mult); const vfloat fourv = F2V(4.f); @@ -1516,22 +1521,19 @@ void HistogramArea::drawCurve(Cairo::RefPtr &cr, } #endif } else { + const float mult = (w - 1.f) / 65535.f; for (int i = 0; i < 65536; ++i) { - iscaled[i] = i; + iscaled[i] = i * mult; } } for (int i = 0; i < 65536; i++) { - if (vals[i] == 0.f) { + if (vals[i] == 0.f) continue; - } - - const double posY = vsize - 2 + vals[i] * ((4 - vsize) / vsize); -// remove me if (vsize - 2 - posY >= 1) { - const double posX = padding + iscaled[i] * ((hsize - padding * 2.f) / 65535.f); - cr->move_to (posX, vsize - 2); - cr->line_to (posX, posY); -// remove me } + const float posY = h - 1.f - vals[i]; + const float posX = 1.f + iscaled[i]; + cr->move_to(posX, h); + cr->line_to(posX, posY); } } @@ -1541,11 +1543,11 @@ void HistogramArea::drawMarks(Cairo::RefPtr &cr, int s = 8 * RTScalable::getScale(); if(data[0] > scale) { - cr->rectangle(padding, (ui++)*s, s, s); + cr->rectangle(0, (ui++)*s, s, s); } if(data[65535] > scale) { - cr->rectangle(hsize - s - padding, (oi++)*s, s, s); + cr->rectangle(hsize - s, (oi++)*s, s, s); } cr->fill(); @@ -1652,8 +1654,8 @@ void HistogramArea::drawParade(Cairo::RefPtr &cr, int w, int h) const double display_wave_width = static_cast(w) / buffers.size(); for (unsigned i = 0; i < buffers.size(); i++) { Cairo::RefPtr surface; - cr->translate(i * display_wave_width, padding); - cr->scale(display_wave_width / wave_width, (h - 2 * padding) / wave_height); + cr->translate(i * display_wave_width, 0); + cr->scale(display_wave_width / wave_width, h / wave_height); surface = Cairo::ImageSurface::create( buffers[i], Cairo::FORMAT_ARGB32, wave_width, wave_height, cairo_stride); cr->set_source(surface, 0, 0); @@ -1703,12 +1705,10 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in vect_buffer_dirty = false; } - const bool fit_width = - vect_width * (h - 2 * padding) > vect_height * (w - 2 * padding); - const float scope_scale = fit_width ? - (w - 2 * padding) / vect_width : (h - 2 * padding) / vect_height; + const bool fit_width = vect_width * h > vect_height * w; + const float scope_scale = fit_width ? w / vect_width : h / vect_height; const float scope_size = (vectorscope_scale > 0) ? - scope_scale * std::max(vect_width, vect_height) : std::min(w, h) - 2 * padding; + scope_scale * std::max(vect_width, vect_height) : std::min(w, h); const float o_x = (w - scope_scale * vect_width) / 2; const float o_y = (h - scope_scale * vect_height) / 2; const double s = RTScalable::getScale(); @@ -1899,8 +1899,8 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h Cairo::RefPtr surface; auto orig_matrix = cr->get_matrix(); - cr->translate(0, padding); - cr->scale(static_cast(w) / wave_width, (h - 2 * padding) / wave_height); + cr->translate(0, 0); + cr->scale(static_cast(w) / wave_width, h / wave_height); if (needLuma) { surface = Cairo::ImageSurface::create( wave_buffer_luma.data(), Cairo::FORMAT_ARGB32, wave_width, wave_height, cairo_stride); diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 4f1e34c43c..2eb704eb74 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -58,9 +58,9 @@ class HistogramScaling float factor; HistogramScaling() : factor(10.f) {} // factor(10.f) can be tuned if necessary - higher is flatter curve - float log(float vsize, float val) const + float log(float scale, float val) const { - return vsize * xlogf(factor / (factor + val)) / xlogf(factor / (factor + vsize)); + return xlogf(factor / (factor + val)) / xlogf(factor / (factor + scale)); } float logMult(float val, float mult) const @@ -100,8 +100,6 @@ class HistogramRGBArea : public Gtk::DrawingArea, public BackBuffer, protected H bool barDisplayed; Gtk::Grid* parent; - - double padding = 5.0; HistogramRGBAreaIdleHelper* harih; @@ -207,8 +205,6 @@ class HistogramArea final : public Gtk::DrawingArea, public BackBuffer, private bool isPressed; double movingPosition; bool needPointer; - - double padding = 5.0; HistogramAreaIdleHelper* haih; @@ -256,7 +252,7 @@ class HistogramArea final : public Gtk::DrawingArea, public BackBuffer, private type_signal_factor_changed signal_factor_changed(); private: - void drawCurve(Cairo::RefPtr &cr, const LUTu & data, float scale, float hsize, float vsize); + void drawCurve(Cairo::RefPtr &cr, const LUTu & data, float scale); void drawMarks(Cairo::RefPtr &cr, const LUTu & data, double scale, int hsize, int & ui, int & oi); void drawParade(Cairo::RefPtr &cr, int hsize, int vsize); void drawVectorscope(Cairo::RefPtr &cr, int hsize, int vsize); From a11dffd5cfb283dac3bd09cf8e56b85f1c358ccf Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Sat, 12 Jun 2021 12:33:54 +0200 Subject: [PATCH 09/15] Expose bitdepth to ImProcCoordinator --- rtengine/imagesource.h | 5 +++++ rtengine/improccoordinator.cc | 4 +++- rtengine/rawimage.h | 5 +++++ rtengine/rawimagesource.cc | 5 +++++ rtengine/rawimagesource.h | 2 ++ rtengine/stdimagesource.cc | 5 +++++ rtengine/stdimagesource.h | 2 ++ 7 files changed, 27 insertions(+), 1 deletion(-) diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index a1c3731f16..ebf9bc7c11 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -124,6 +124,11 @@ class ImageSource : public InitialImage virtual void WBauto(double &tempref, double &greenref, array2D &redloc, array2D &greenloc, array2D &blueloc, int bfw, int bfh, double &avg_rm, double &avg_gm, double &avg_bm, double &tempitc, double &greenitc, float &studgood, bool &twotimes, const procparams::WBParams & wbpar, int begx, int begy, int yEn, int xEn, int cx, int cy, const procparams::ColorManagementParams &cmp, const procparams::RAWParams &raw) = 0; virtual void getrgbloc(int begx, int begy, int yEn, int xEn, int cx, int cy, int bf_h, int bf_w) = 0; + virtual unsigned int getBitDepth() const + { + return 0; + } + virtual double getDefGain () const { return 1.0; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 6ce7e96c5f..002fcef146 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -105,7 +105,6 @@ ImProcCoordinator::ImProcCoordinator() : histGreen(65536), histGreenRaw(65536), histBlue(65536), histBlueRaw(65536), histLuma(65536), - histChroma(65536), histToneCurve(256), histToneCurveBW(256), @@ -117,6 +116,7 @@ ImProcCoordinator::ImProcCoordinator() : histCCAM(256), histClad(256), bcabhist(256), + histChroma(65536), histLRETI(256), @@ -1810,6 +1810,8 @@ void ImProcCoordinator::notifyHistogramChanged() bool ImProcCoordinator::updateLRGBHistograms() { + printf("%u bit image - update histogram\n",imgsrc->getBitDepth()); + if (!hist_lrgb_dirty) { return false; } diff --git a/rtengine/rawimage.h b/rtengine/rawimage.h index 871267dac5..3af2cebb2f 100644 --- a/rtengine/rawimage.h +++ b/rtengine/rawimage.h @@ -108,6 +108,11 @@ class RawImage: public DCraw { return fuji_width; } + + unsigned int get_bitdepth() const + { + return tiff_bps; + } float const * get_FloatRawImage() const { diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 5dde838a2a..1467c9fc96 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -517,6 +517,11 @@ int RawImageSource::getRotateDegree() const return ri->get_rotateDegree(); } +unsigned int RawImageSource::getBitDepth() const +{ + return ri->get_bitdepth(); +} + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void RawImageSource::transformRect (const PreviewProps &pp, int tran, int &ssx1, int &ssy1, int &width, int &height, int &fw) diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index b463ea7884..57f06587ce 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -168,6 +168,8 @@ class RawImageSource final : public ImageSource void getSize (const PreviewProps &pp, int& w, int& h) override; int getRotateDegree() const override; + unsigned int getBitDepth() const override; + ImageMatrices* getImageMatrices () override { return &imatrices; diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index 8cb8fa7925..fc0c1042f2 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -297,6 +297,11 @@ void StdImageSource::getSize (const PreviewProps &pp, int& w, int& h) h = pp.getHeight() / pp.getSkip() + (pp.getHeight() % pp.getSkip() > 0); } +unsigned int StdImageSource::getBitDepth() const +{ + return img->getBPS(); +} + void StdImageSource::getAutoExpHistogram (LUTu & histogram, int& histcompr) { if (img->getType() == sImage8) { diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 9b95fe34ea..de65002183 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -87,6 +87,8 @@ class StdImageSource : public ImageSource void getFullSize (int& w, int& h, int tr = TR_NONE) override; void getSize (const PreviewProps &pp, int& w, int& h) override; + unsigned int getBitDepth() const override; + ImageIO* getImageIO () { return img; From 3707d216d896b3b080960f649ec88adbb3d149d1 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Sat, 12 Jun 2021 14:31:31 +0200 Subject: [PATCH 10/15] Expose bitdepth to HistogramArea --- rtengine/improccoordinator.cc | 8 +++----- rtengine/rawimagesource.cc | 2 +- rtengine/rtengine.h | 2 ++ rtgui/editorpanel.cc | 7 +++++++ rtgui/editorpanel.h | 1 + rtgui/histogrampanel.cc | 7 +++++++ rtgui/histogrampanel.h | 7 +++++++ 7 files changed, 28 insertions(+), 6 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 002fcef146..387bd2cd0c 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1810,8 +1810,6 @@ void ImProcCoordinator::notifyHistogramChanged() bool ImProcCoordinator::updateLRGBHistograms() { - printf("%u bit image - update histogram\n",imgsrc->getBitDepth()); - if (!hist_lrgb_dirty) { return false; } @@ -1860,9 +1858,9 @@ bool ImProcCoordinator::updateLRGBHistograms() int ofs = (i * pW + x1) * 3; for (int j = x1; j < x2; j++) { - int r = workimg->data[ofs++] * 256; // scale up, because workimg is 8 bit - int g = workimg->data[ofs++] * 256; - int b = workimg->data[ofs++] * 256; + int r = workimg->data[ofs++];// * 256; // scale up, because workimg is 8 bit + int g = workimg->data[ofs++];// * 256; + int b = workimg->data[ofs++];// * 256; histRed[r]++; histGreen[g]++; diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 1467c9fc96..fc450d7d53 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -3776,7 +3776,7 @@ void RawImageSource::getAutoExpHistogram (LUTu & histogram, int& histcompr) // For histogram data gamma is applied, blackpoint and gain also void RawImageSource::getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw) -{ +{ // BENCHFUN histRedRaw.clear(); histGreenRaw.clear(); diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h index c4ffb91f75..0a9614e583 100644 --- a/rtengine/rtengine.h +++ b/rtengine/rtengine.h @@ -354,6 +354,8 @@ class HistogramListener virtual bool updateVectorscopeHS(void) const = 0; /** Returns if the listener wants the waveform to be updated. */ virtual bool updateWaveform(void) const = 0; + /** Set the bit depth of the image for the histogram binning */ + virtual void setBitDepth(unsigned int bitdepth) = 0; }; class HistogramObservable diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 34d6772061..5b218a7702 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -2305,6 +2305,13 @@ bool EditorPanel::updateWaveform(void) const || histogram_scope_type == ScopeType::NONE; } +void EditorPanel::setBitDepth(unsigned int bitdepth) +{ + if (histogramPanel) { + histogramPanel->setBitDepth(bitdepth); + } +} + void EditorPanel::scopeTypeChanged(ScopeType new_type) { histogram_scope_type = new_type; diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index a277ffd3a3..acd8a8b769 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -149,6 +149,7 @@ class EditorPanel final : bool updateVectorscopeHC(void) const override; bool updateVectorscopeHS(void) const override; bool updateWaveform(void) const override; + void setBitDepth(unsigned int bitdepth) override; // HistogramPanelListener void scopeTypeChanged(Options::ScopeType new_type) override; diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index 025f9b0dd6..ed69c268a3 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1114,6 +1114,11 @@ void HistogramArea::get_preferred_width_for_height_vfunc (int height, int &minim get_preferred_width_vfunc (minimum_width, natural_width); } +void HistogramArea::setBitDepth(unsigned int bitdepth) +{ + HistogramArea::bitdepth = bitdepth; +} + void HistogramArea::updateOptions (bool r, bool g, bool b, bool l, bool c, int mode, ScopeType type, bool pointer) { wave_buffer_dirty = wave_buffer_dirty || needRed != r || needGreen != g || needBlue != b; @@ -1254,6 +1259,8 @@ void HistogramArea::updateBackBuffer () ch_ds[0] = 4; cr->set_dash(ch_ds, 0); + printf("HistogramArea::setBitDepth -> %u\n",bitdepth); + // determine the number of horiztonal gridlines based on current height int nrOfHGridPartitions = static_cast(rtengine::min (16.0, pow (2.0, floor ((h - 100) / 250) + 2))); int nrOfVGridPartitions = 16; // always show 16 stops diff --git a/rtgui/histogrampanel.h b/rtgui/histogrampanel.h index 2eb704eb74..dc554153cc 100644 --- a/rtgui/histogrampanel.h +++ b/rtgui/histogrampanel.h @@ -206,6 +206,8 @@ class HistogramArea final : public Gtk::DrawingArea, public BackBuffer, private double movingPosition; bool needPointer; + unsigned int bitdepth; + HistogramAreaIdleHelper* haih; int pointer_red, pointer_green, pointer_blue; @@ -240,6 +242,7 @@ class HistogramArea final : public Gtk::DrawingArea, public BackBuffer, private ); void updateOptions (bool r, bool g, bool b, bool l, bool c, int mode, Options::ScopeType type, bool pointer); bool updatePending(); + void setBitDepth(unsigned int bitdepth); void on_realize() override; bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr) override; bool on_button_press_event (GdkEventButton* event) override; @@ -355,6 +358,10 @@ class HistogramPanel final : public Gtk::Grid, public PointerMotionListener, pub { histogramArea->update(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscopeHC, vectorscopeHS, waveformScale, waveformRed, waveformGreen, waveformBlue, waveformLuma); } + void setBitDepth(unsigned int bitdepth) + { + histogramArea->setBitDepth(bitdepth); + } // pointermotionlistener interface void pointerMoved (bool validPos, const Glib::ustring &profile, const Glib::ustring &profileW, int x, int y, int r, int g, int b, bool isRaw = false) override; From 65ff20a21574acf04a0fe82b6a11c34c73cc55ad Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Sat, 12 Jun 2021 15:04:17 +0200 Subject: [PATCH 11/15] Actually enable forwarding + verbose message --- rtengine/improccoordinator.cc | 8 ++++++++ rtgui/histogrampanel.cc | 2 -- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 387bd2cd0c..abc58486a0 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -313,6 +313,14 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } } + // Forward bit depth of image to the histogram + if (hListener) { + hListener->setBitDepth(imgsrc->getBitDepth()); + if (settings->verbose) { + printf("Image has a bit depth of %u bits\n",imgsrc->getBitDepth()); + } + } + if (((todo & ALL) == ALL) || (todo & M_MONITOR) || panningRelatedChange || (highDetailNeeded && options.prevdemo != PD_Sidecar)) { bwAutoR = bwAutoG = bwAutoB = -9000.f; diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index ed69c268a3..a635ad73d8 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1259,8 +1259,6 @@ void HistogramArea::updateBackBuffer () ch_ds[0] = 4; cr->set_dash(ch_ds, 0); - printf("HistogramArea::setBitDepth -> %u\n",bitdepth); - // determine the number of horiztonal gridlines based on current height int nrOfHGridPartitions = static_cast(rtengine::min (16.0, pow (2.0, floor ((h - 100) / 250) + 2))); int nrOfVGridPartitions = 16; // always show 16 stops From 20fe5cbc983a0a3573fe5b1fa4c4163993553064 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Sat, 12 Jun 2021 20:38:41 +0200 Subject: [PATCH 12/15] Make all histograms scale according to bitdepth --- rtengine/rawimagesource.cc | 9 ++--- rtgui/histogrampanel.cc | 73 ++++++++++++++++++++++++-------------- 2 files changed, 51 insertions(+), 31 deletions(-) diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index fc450d7d53..baf5676f9d 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -3782,9 +3782,10 @@ void RawImageSource::getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LU histGreenRaw.clear(); histBlueRaw.clear(); + const float maxrawvalue = static_cast(1 << getBitDepth()) - 1.f; const float maxWhite = rtengine::max(c_white[0], c_white[1], c_white[2], c_white[3]); - const float scale = maxWhite <= 1.f ? 65535.f : 1.f; // special case for float raw images in [0.0;1.0] range - const float multScale = maxWhite <= 1.f ? 1.f / 65535.f : 65535.f; + const float scale = maxWhite <= 1.f ? maxrawvalue : 1.f; // special case for float raw images in [0.0;1.0] range + const float multScale = maxWhite <= 1.f ? 1.f / maxrawvalue : maxrawvalue; const float mult[4] = { multScale / (c_white[0] - cblacksom[0]), multScale / (c_white[1] - cblacksom[1]), multScale / (c_white[2] - cblacksom[2]), @@ -3893,12 +3894,12 @@ void RawImageSource::getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LU } } // end of critical region } // end of parallel region - + const auto getidx = [&](int c, int i) -> int { float f = mult[c] * std::max(0.f, i - cblacksom[c]); - return f > 0.f ? (f < 1.f ? 1 : std::min(int(f), 65535)) : 0; + return f > 0.f ? (f < 1.f ? 1 : std::min(int(f), int(maxrawvalue))) : 0; }; for (int i = 0; i < histoSize; i++) { diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index a635ad73d8..fc43907c48 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1259,18 +1259,25 @@ void HistogramArea::updateBackBuffer () ch_ds[0] = 4; cr->set_dash(ch_ds, 0); - // determine the number of horiztonal gridlines based on current height + // determine the number of horizontal gridlines based on current height int nrOfHGridPartitions = static_cast(rtengine::min (16.0, pow (2.0, floor ((h - 100) / 250) + 2))); - int nrOfVGridPartitions = 16; // always show 16 stops + + // set up vertical grid based on image bitdepth + int nrOfVGridPartitions = bitdepth; + if (options.histogramScopeType == ScopeType::HISTOGRAM) { + nrOfVGridPartitions = 8; // Preview image is always 8-bit + } + int maxHValue = (1 << nrOfVGridPartitions) - 1; + float maxHValuef = static_cast(maxHValue); // draw vertical gridlines if (options.histogramScopeType == ScopeType::HISTOGRAM || options.histogramScopeType == ScopeType::HISTOGRAM_RAW) { float xpos; - for (int i = 0; i <= nrOfVGridPartitions; i++) { + for (int i = 0; i < nrOfVGridPartitions; i++) { if (options.histogramDrawMode < 2) { - xpos = (pow(2.0,i) - 1) / 65535.0 * (w - 1.0); + xpos = (pow(2.0,i) - 1) / maxHValuef * (w - 1.0); } else { - xpos = HistogramScaling::log(65535.0, pow(2.0,i) - 1) * (w - 1.0); + xpos = HistogramScaling::log(maxHValuef, pow(2.0,i) - 1) * (w - 1.0); } cr->move_to(xpos + 1.0, 0); cr->line_to(xpos + 1.0, h); @@ -1317,7 +1324,7 @@ void HistogramArea::updateBackBuffer () unsigned int lumamax = 0; unsigned int chromamax = 0; - for (int i = 1; i < 65535; i++) { // Values at far left and right end are handled differently + for (int i = 1; i < maxHValue; i++) { // Values at far left and right end are handled differently if (needLuma && lhist[i] > lumamax) { lumamax = lhist[i]; } @@ -1341,13 +1348,13 @@ void HistogramArea::updateBackBuffer () // Compute the first and last non-zero histogram bins int rgbFirst = -1, rgbLast = -1; - for (int i = 0; i < 65536; i++) { + for (int i = 0; i < maxHValue + 1; i++) { if (needRed && rgbFirst == -1 && rh[i] != 0) rgbFirst = i; if (needGreen && rgbFirst == -1 && gh[i] != 0) rgbFirst = i; if (needBlue && rgbFirst == -1 && bh[i] != 0) rgbFirst = i; if (rgbFirst != -1) break; } - for (int i = 65535; i >= 0; i--) { + for (int i = maxHValue + 1; i >= 0; i--) { if (needRed && rgbLast == -1 && rh[i] != 0) rgbLast = i; if (needGreen && rgbLast == -1 && gh[i] != 0) rgbLast = i; if (needBlue && rgbLast == -1 && bh[i] != 0) rgbLast = i; @@ -1360,10 +1367,10 @@ void HistogramArea::updateBackBuffer () float posX = static_cast(rgbFirst); if (drawMode == 2) { - const float mult = 65535.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); + const float mult = maxHValuef / xlogf(HistogramScaling::factor / (HistogramScaling::factor + maxHValuef)); posX = HistogramScaling::logMult(posX, mult); } - posX = posX * (w - 1.f) / 65535.f; + posX = posX * (w - 1.f) / maxHValuef; cr->move_to (posX + 1.f, 0); cr->line_to (posX + 1.f, h); cr->set_source_rgba (1., 1., 1., 0.55); @@ -1374,23 +1381,23 @@ void HistogramArea::updateBackBuffer () float posX = static_cast(rgbLast); if (drawMode == 2) { - const float mult = 65535.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); + const float mult = maxHValuef / xlogf(HistogramScaling::factor / (HistogramScaling::factor + maxHValuef)); posX = HistogramScaling::logMult(posX, mult); } - posX = posX * (w - 1.f) / 65535.f; + posX = posX * (w - 1.f) / maxHValuef; cr->move_to (posX + 1.f, 0); cr->line_to (posX + 1.f, h); cr->set_source_rgba (1., 1., 1., 0.55); cr->stroke(); } - // Draw EV0 line - float posX = 32768.f; // TODO: Link directly to bitdepth + // Draw EV0 line at -3 stops from maximum (cf. RawDigger) + float posX = static_cast(1 << (nrOfVGridPartitions - 3)) - 1.f; if (drawMode == 2) { - const float mult = 65535.f / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.0)); + const float mult = maxHValuef / xlogf(HistogramScaling::factor / (HistogramScaling::factor + maxHValuef)); posX = HistogramScaling::logMult(posX, mult); } - posX = posX * (w - 1.f) / 65535.f; + posX = posX * (w - 1.f) / maxHValuef; cr->move_to (posX + 1.f, 0); cr->line_to (posX + 1.f, h); cr->set_source_rgba (1., 1., 1., 0.55); @@ -1479,11 +1486,18 @@ void HistogramArea::drawCurve(Cairo::RefPtr &cr, const LUTu & da const float maxvalue = rtengine::max(scale, 0.001f); // avoid division by zero and negative values + // Limit the loop to the actual available data based on the image bit depth + int maxHValue = (1 << bitdepth) - 1; + if (options.histogramScopeType == ScopeType::HISTOGRAM) { + maxHValue = (1 << 8) - 1; // Preview image is always 8-bit + } + float maxHValuef = static_cast(maxHValue); + if (drawMode > 0) { // scale y for single and double log-scale const float mult = (h - 1.0f) / xlogf(HistogramScaling::factor / (HistogramScaling::factor + maxvalue)); #ifdef __SSE2__ const vfloat multv = F2V(mult); - for (int i = 0; i < 65536; i += 4) { + for (int i = 0; i <= maxHValue; i += 4) { const vfloat val = _mm_cvtepi32_ps(_mm_loadu_si128((__m128i_u*)&data[i])); if (_mm_movemask_ps(ZEROV - val)) { STVFU(vals[i], HistogramScaling::logMult(val, multv)); @@ -1492,7 +1506,7 @@ void HistogramArea::drawCurve(Cairo::RefPtr &cr, const LUTu & da } } #else - for (int i = 0; i < 65536; ++i) { + for (int i = 0; i <= maxHValue; ++i) { if (data[i]) { vals[i] = HistogramScaling::logMult(data[i], mult); } else { @@ -1502,37 +1516,37 @@ void HistogramArea::drawCurve(Cairo::RefPtr &cr, const LUTu & da #endif } else { const float mult = (h - 1.0f) / maxvalue; - for (int i = 0; i < 65536; ++i) { + for (int i = 0; i <= maxHValue; ++i) { vals[i] = data[i] * mult; } } if (drawMode == 2) { // scale x for double log-scale - const float mult = (w - 1.f) / xlogf(HistogramScaling::factor / (HistogramScaling::factor + 65535.f)); + const float mult = (w - 1.f) / xlogf(HistogramScaling::factor / (HistogramScaling::factor + static_cast(maxHValue))); #ifdef __SSE2__ const vfloat multv = F2V(mult); const vfloat fourv = F2V(4.f); vfloat iv = _mm_setr_ps(0.f, 1.f, 2.f, 3.f); - for (int i = 0; i < 65536; i += 4, iv += fourv) { + for (int i = 0; i <= maxHValue; i += 4, iv += fourv) { if (_mm_movemask_ps(ZEROV - LVFU(vals[i]))) { STVFU(iscaled[i], HistogramScaling::logMult(iv, multv)); } } #else - for (int i = 0; i < 65536; ++i) { + for (int i = 0; i <= maxHValue; ++i) { if (vals[i] != 0.f) { iscaled[i] = HistogramScaling::logMult(i, mult); } } #endif } else { - const float mult = (w - 1.f) / 65535.f; - for (int i = 0; i < 65536; ++i) { + const float mult = (w - 1.f) / static_cast(maxHValue); + for (int i = 0; i <= maxHValue; ++i) { iscaled[i] = i * mult; } } - for (int i = 0; i < 65536; i++) { + for (int i = 0; i <= maxHValue; i++) { if (vals[i] == 0.f) continue; const float posY = h - 1.f - vals[i]; @@ -1547,11 +1561,16 @@ void HistogramArea::drawMarks(Cairo::RefPtr &cr, { int s = 8 * RTScalable::getScale(); - if(data[0] > scale) { + if (data[0] > scale) { cr->rectangle(0, (ui++)*s, s, s); } - if(data[65535] > scale) { + int max = 1 << bitdepth; + if (options.histogramScopeType == ScopeType::HISTOGRAM) { + max = 1 << 8; // Preview image is always 8-bit + } + + if (data[max - 1] > scale) { cr->rectangle(hsize - s, (oi++)*s, s, s); } From 2e58bae1dbd8089ee07022af2b7a8b805027dd68 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Sat, 12 Jun 2021 20:56:33 +0200 Subject: [PATCH 13/15] Fix the L and chroma curves --- rtengine/improccoordinator.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index abc58486a0..397d29cc07 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -1838,7 +1838,7 @@ bool ImProcCoordinator::updateLRGBHistograms() for (int i = y1; i < y2; i++) for (int j = x1; j < x2; j++) { - histChroma[(int)(sqrtf(SQR(nprevl->a[i][j]) + SQR(nprevl->b[i][j])) * 1.3653333333f)]++; // = 65536/48000 + histChroma[(int)(sqrtf(SQR(nprevl->a[i][j]) + SQR(nprevl->b[i][j])) * 255.0/48000.0)]++; } } #ifdef _OPENMP @@ -1847,10 +1847,11 @@ bool ImProcCoordinator::updateLRGBHistograms() { histLuma.clear(); + double s = 0.0078125; // map L = [0..32768] to [0..255] for (int i = y1; i < y2; i++) for (int j = x1; j < x2; j++) { - histLuma[2 * (int)(nprevl->L[i][j])]++; // L = [0..32768] map to [0..65535] + histLuma[(int)(nprevl->L[i][j] * s)]++; } } #ifdef _OPENMP @@ -1866,9 +1867,9 @@ bool ImProcCoordinator::updateLRGBHistograms() int ofs = (i * pW + x1) * 3; for (int j = x1; j < x2; j++) { - int r = workimg->data[ofs++];// * 256; // scale up, because workimg is 8 bit - int g = workimg->data[ofs++];// * 256; - int b = workimg->data[ofs++];// * 256; + int r = workimg->data[ofs++]; + int g = workimg->data[ofs++]; + int b = workimg->data[ofs++]; histRed[r]++; histGreen[g]++; From 8116678459e7dd1abff28a8ea05573cbb2040ae4 Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Wed, 16 Jun 2021 20:52:35 +0200 Subject: [PATCH 14/15] Fix RGB bar readout in log-log mode, re-enable horizontal gridlines --- rtgui/histogrampanel.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index fc43907c48..af6655d7bb 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -963,7 +963,7 @@ void HistogramRGBAreaHori::drawBar(Cairo::RefPtr cc, double valu if (options.histogramDrawMode < 2) { pos = value * winw / max_value + 0.5 * scale; } else { - pos = HistogramScaling::log (max_value, value) * winw / max_value + 0.5 * scale; + pos = HistogramScaling::log (max_value, value) * winw + 0.5 * scale; } cc->move_to(pos, 0.0); cc->line_to(pos, winh - 0.0); @@ -1001,7 +1001,7 @@ void HistogramRGBAreaVert::drawBar(Cairo::RefPtr cc, double valu if (options.histogramDrawMode < 2 || options.histogramScopeType == ScopeType::PARADE || options.histogramScopeType == ScopeType::WAVEFORM) { pos = value * (winh - 1) / max_value + 0.5 * scale; } else { - pos = HistogramScaling::log (max_value, value) * winh / max_value + 0.5 * scale; + pos = HistogramScaling::log (max_value, value) * winh + 0.5 * scale; } cc->move_to(0.0, winh - pos); cc->line_to(winw, winh - pos); @@ -1286,7 +1286,7 @@ void HistogramArea::updateBackBuffer () } // draw horizontal gridlines - /*if (options.histogramScopeType == ScopeType::PARADE || options.histogramScopeType == ScopeType::WAVEFORM) { + if (options.histogramScopeType == ScopeType::PARADE || options.histogramScopeType == ScopeType::WAVEFORM) { for (int i = 0; i <= nrOfVGridPartitions; i++) { const double ypos = h - (pow(2.0,i) - 1) * (h - 1) / 255.0; cr->move_to(0, ypos); @@ -1307,7 +1307,7 @@ void HistogramArea::updateBackBuffer () cr->line_to (w, h - HistogramScaling::log (h, i * static_cast(h) / nrOfHGridPartitions) + 0.5); cr->stroke (); } - }*/ + } cr->unset_dash(); @@ -1522,7 +1522,7 @@ void HistogramArea::drawCurve(Cairo::RefPtr &cr, const LUTu & da } if (drawMode == 2) { // scale x for double log-scale - const float mult = (w - 1.f) / xlogf(HistogramScaling::factor / (HistogramScaling::factor + static_cast(maxHValue))); + const float mult = (w - 1.f) / xlogf(HistogramScaling::factor / (HistogramScaling::factor + maxHValuef)); #ifdef __SSE2__ const vfloat multv = F2V(mult); const vfloat fourv = F2V(4.f); @@ -1540,7 +1540,7 @@ void HistogramArea::drawCurve(Cairo::RefPtr &cr, const LUTu & da } #endif } else { - const float mult = (w - 1.f) / static_cast(maxHValue); + const float mult = (w - 1.f) / maxHValuef; for (int i = 0; i <= maxHValue; ++i) { iscaled[i] = i * mult; } From bc2e4cd31aea30229c7d04842d80c5bc2835628a Mon Sep 17 00:00:00 2001 From: Thanatomanic <6567747+Thanatomanic@users.noreply.github.com> Date: Wed, 16 Jun 2021 21:17:23 +0200 Subject: [PATCH 15/15] Fix scaling of waveform, parade and scopes - cast from integer to float/double --- rtgui/histogrampanel.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rtgui/histogrampanel.cc b/rtgui/histogrampanel.cc index af6655d7bb..b3a5ea542b 100644 --- a/rtgui/histogrampanel.cc +++ b/rtgui/histogrampanel.cc @@ -1679,7 +1679,7 @@ void HistogramArea::drawParade(Cairo::RefPtr &cr, int w, int h) for (unsigned i = 0; i < buffers.size(); i++) { Cairo::RefPtr surface; cr->translate(i * display_wave_width, 0); - cr->scale(display_wave_width / wave_width, h / wave_height); + cr->scale(display_wave_width / wave_width, static_cast(h) / wave_height); surface = Cairo::ImageSurface::create( buffers[i], Cairo::FORMAT_ARGB32, wave_width, wave_height, cairo_stride); cr->set_source(surface, 0, 0); @@ -1730,7 +1730,7 @@ void HistogramArea::drawVectorscope(Cairo::RefPtr &cr, int w, in } const bool fit_width = vect_width * h > vect_height * w; - const float scope_scale = fit_width ? w / vect_width : h / vect_height; + const float scope_scale = fit_width ? static_cast(w) / vect_width : static_cast(h) / vect_height; const float scope_size = (vectorscope_scale > 0) ? scope_scale * std::max(vect_width, vect_height) : std::min(w, h); const float o_x = (w - scope_scale * vect_width) / 2; @@ -1924,7 +1924,7 @@ void HistogramArea::drawWaveform(Cairo::RefPtr &cr, int w, int h Cairo::RefPtr surface; auto orig_matrix = cr->get_matrix(); cr->translate(0, 0); - cr->scale(static_cast(w) / wave_width, h / wave_height); + cr->scale(static_cast(w) / wave_width, static_cast(h) / wave_height); if (needLuma) { surface = Cairo::ImageSurface::create( wave_buffer_luma.data(), Cairo::FORMAT_ARGB32, wave_width, wave_height, cairo_stride);