Add H-S and H-C vectorscopes
This commit is contained in:
@@ -249,7 +249,7 @@ HISTOGRAM_TOOLTIP_L;Show/Hide CIELab luminance histogram.
|
||||
HISTOGRAM_TOOLTIP_MODE;Toggle between linear, log-linear and log-log scaling of the histogram.
|
||||
HISTOGRAM_TOOLTIP_R;Show/Hide red histogram.
|
||||
HISTOGRAM_TOOLTIP_RAW;Show/Hide raw histogram.
|
||||
HISTOGRAM_TOOLTIP_TYPE;Toggle between histogram and waveform.
|
||||
HISTOGRAM_TOOLTIP_TYPE;Toggle between histogram, waveform, Hue-Saturation vectorscope, and Hue-Chroma vectorscope.
|
||||
HISTORY_CHANGED;Changed
|
||||
HISTORY_CUSTOMCURVE;Custom curve
|
||||
HISTORY_FROMCLIPBOARD;From clipboard
|
||||
|
||||
@@ -1643,6 +1643,9 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange)
|
||||
if (hListener->updateHistogram()) {
|
||||
updateLRGBHistograms();
|
||||
}
|
||||
if (hListener->updateVectorscope()) {
|
||||
updateVectorscope();
|
||||
}
|
||||
if (hListener->updateWaveform()) {
|
||||
updateWaveforms();
|
||||
}
|
||||
@@ -1765,6 +1768,8 @@ void ImProcCoordinator::notifyHistogramChanged()
|
||||
histBlueRaw,
|
||||
histChroma,
|
||||
histLRETI,
|
||||
vectorscopeScale,
|
||||
vectorscope,
|
||||
waveformScale,
|
||||
waveformWidth,
|
||||
waveformRed.get(),
|
||||
@@ -1835,6 +1840,55 @@ void ImProcCoordinator::updateLRGBHistograms()
|
||||
|
||||
}
|
||||
|
||||
void ImProcCoordinator::updateVectorscope()
|
||||
{
|
||||
if (!workimg) {
|
||||
return;
|
||||
}
|
||||
|
||||
int x1, y1, x2, y2;
|
||||
params->crop.mapToResized(pW, pH, scale, x1, x2, y1, y2);
|
||||
|
||||
constexpr int size = HistogramListener::vectorscope_size;
|
||||
memset(vectorscope, 0, size * size * sizeof(vectorscope[0][0]));
|
||||
|
||||
for (int i = y1; i < y2; i++) {
|
||||
int ofs = (i * pW + x1) * 3;
|
||||
|
||||
for (int j = x1; j < x2; j++) {
|
||||
switch (hListener->vectorscopeType()) {
|
||||
case 0: {
|
||||
// HS
|
||||
int r = 256 * workimg->data[ofs++];
|
||||
int g = 256 * workimg->data[ofs++];
|
||||
int b = 256 * workimg->data[ofs++];
|
||||
float h, s, l;
|
||||
Color::rgb2hsl(r, g, b, h, s, l);
|
||||
const int col = s * cos(2 * RT_PI * h) * (size / 2) + size / 2;
|
||||
const int row = s * sin(2 * RT_PI * h) * (size / 2) + size / 2;
|
||||
if (col >= 0 && col < size && row >= 0 && row < size) {
|
||||
vectorscope[row][col]++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: {
|
||||
// CH
|
||||
const int col = (size / 96000.0) * nprevl->a[i][j] + size / 2;
|
||||
const int row = (size / 96000.0) * nprevl->b[i][j] + size / 2;
|
||||
|
||||
if (col >= 0 && col < size && row >= 0 && row < size) {
|
||||
vectorscope[row][col]++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vectorscopeScale = workimg->getWidth() * workimg->getHeight();
|
||||
}
|
||||
|
||||
void ImProcCoordinator::updateWaveforms()
|
||||
{
|
||||
if (!workimg) {
|
||||
@@ -2314,7 +2368,7 @@ void ImProcCoordinator::setHighQualComputed()
|
||||
highQualityComputed = true;
|
||||
}
|
||||
|
||||
void ImProcCoordinator::updateWaveform()
|
||||
void ImProcCoordinator::requestUpdateWaveform()
|
||||
{
|
||||
if (hListener) {
|
||||
updateWaveforms();
|
||||
@@ -2322,7 +2376,7 @@ void ImProcCoordinator::updateWaveform()
|
||||
}
|
||||
}
|
||||
|
||||
void ImProcCoordinator::updateHistogram()
|
||||
void ImProcCoordinator::requestUpdateHistogram()
|
||||
{
|
||||
if (hListener) {
|
||||
updateLRGBHistograms();
|
||||
@@ -2330,4 +2384,12 @@ void ImProcCoordinator::updateHistogram()
|
||||
}
|
||||
}
|
||||
|
||||
void ImProcCoordinator::requestUpdateVectorscope()
|
||||
{
|
||||
if (hListener) {
|
||||
updateVectorscope();
|
||||
notifyHistogramChanged();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -126,6 +126,8 @@ protected:
|
||||
LUTu histBlue, histBlueRaw;
|
||||
LUTu histLuma, histToneCurve, histToneCurveBW, histLCurve, histCCurve;
|
||||
LUTu histLLCurve, histLCAM, histCCAM, histClad, bcabhist, histChroma, histLRETI;
|
||||
int vectorscopeScale;
|
||||
int vectorscope[HistogramListener::vectorscope_size][HistogramListener::vectorscope_size];
|
||||
/// Waveform's intensity. Same as height of reference image.
|
||||
int waveformScale;
|
||||
int waveformWidth;
|
||||
@@ -202,6 +204,7 @@ protected:
|
||||
void notifyHistogramChanged();
|
||||
void reallocAll();
|
||||
void updateLRGBHistograms();
|
||||
void updateVectorscope();
|
||||
void updateWaveforms();
|
||||
void setScale(int prevscale);
|
||||
void updatePreviewImage (int todo, bool panningRelatedChange);
|
||||
@@ -560,8 +563,9 @@ public:
|
||||
|
||||
} denoiseInfoStore;
|
||||
|
||||
void updateHistogram() override;
|
||||
void updateWaveform() override;
|
||||
void requestUpdateHistogram() override;
|
||||
void requestUpdateVectorscope() override;
|
||||
void requestUpdateWaveform() override;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -308,6 +308,8 @@ class HistogramObservable;
|
||||
class HistogramListener
|
||||
{
|
||||
public:
|
||||
static constexpr int vectorscope_size = 128;
|
||||
|
||||
virtual ~HistogramListener() = default;
|
||||
/** This member function is called when the histogram of the final image has changed.
|
||||
* @param histRed is the array of size 256 containing the histogram of the red channel
|
||||
@@ -330,6 +332,8 @@ public:
|
||||
const LUTu& histBlueRaw,
|
||||
const LUTu& histChroma,
|
||||
const LUTu& histLRETI,
|
||||
int vectorscopeScale,
|
||||
const int vectorscope[vectorscope_size][vectorscope_size],
|
||||
int waveformScale,
|
||||
int waveformWidth,
|
||||
const int waveformRed[][256],
|
||||
@@ -340,17 +344,23 @@ public:
|
||||
virtual void setObservable(HistogramObservable* observable) = 0;
|
||||
/** Returns if the listener wants the histogram to be updated. */
|
||||
virtual bool updateHistogram(void) = 0;
|
||||
/** Returns if the listener wants the vectorscope to be updated. */
|
||||
virtual bool updateVectorscope(void) = 0;
|
||||
/** Returns if the listener wants the waveform to be updated. */
|
||||
virtual bool updateWaveform(void) = 0;
|
||||
/** Returns the vectorscope type: 0 for H-S and 1 for H-C. */
|
||||
virtual int vectorscopeType(void) = 0;
|
||||
};
|
||||
|
||||
class HistogramObservable
|
||||
{
|
||||
public:
|
||||
/** Tells the observable to update the histogram data. */
|
||||
virtual void updateHistogram() = 0;
|
||||
virtual void requestUpdateHistogram() = 0;
|
||||
/** Tells the observable to update the vectorscope data. */
|
||||
virtual void requestUpdateVectorscope() = 0;
|
||||
/** Tells the observable to update the waveform data. */
|
||||
virtual void updateWaveform() = 0;
|
||||
virtual void requestUpdateWaveform() = 0;
|
||||
};
|
||||
|
||||
/** This listener is used when the auto exposure has been recomputed (e.g. when the clipping ratio changed). */
|
||||
|
||||
@@ -2247,6 +2247,8 @@ void EditorPanel::histogramChanged(
|
||||
const LUTu& histBlueRaw,
|
||||
const LUTu& histChroma,
|
||||
const LUTu& histLRETI,
|
||||
int vectorscopeScale,
|
||||
const int vectorscope[HistogramListener::vectorscope_size][HistogramListener::vectorscope_size],
|
||||
int waveformScale,
|
||||
int waveformWidth,
|
||||
const int waveformRed[][256],
|
||||
@@ -2255,7 +2257,7 @@ void EditorPanel::histogramChanged(
|
||||
)
|
||||
{
|
||||
if (histogramPanel) {
|
||||
histogramPanel->histogramChanged(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, waveformScale, waveformWidth, waveformRed, waveformGreen, waveformBlue);
|
||||
histogramPanel->histogramChanged(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscope, waveformScale, waveformWidth, waveformRed, waveformGreen, waveformBlue);
|
||||
}
|
||||
|
||||
tpc->updateCurveBackgroundHistogram(histToneCurve, histLCurve, histCCurve, histLCAM, histCCAM, histRed, histGreen, histBlue, histLuma, histLRETI);
|
||||
@@ -2272,12 +2274,32 @@ bool EditorPanel::updateHistogram(void)
|
||||
|| histogram_scope_type == HistogramPanelListener::NONE;
|
||||
}
|
||||
|
||||
bool EditorPanel::updateVectorscope(void)
|
||||
{
|
||||
return
|
||||
histogram_scope_type == HistogramPanelListener::VECTORSCOPE_HS
|
||||
|| histogram_scope_type == HistogramPanelListener::VECTORSCOPE_CH
|
||||
|| histogram_scope_type == HistogramPanelListener::NONE;
|
||||
}
|
||||
|
||||
bool EditorPanel::updateWaveform(void)
|
||||
{
|
||||
return histogram_scope_type == HistogramPanelListener::WAVEFORM
|
||||
|| histogram_scope_type == HistogramPanelListener::NONE;
|
||||
}
|
||||
|
||||
int EditorPanel::vectorscopeType(void)
|
||||
{
|
||||
switch (histogram_scope_type) {
|
||||
case HistogramPanelListener::VECTORSCOPE_HS:
|
||||
return 0;
|
||||
case HistogramPanelListener::VECTORSCOPE_CH:
|
||||
return 1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void EditorPanel::scopeTypeChanged(ScopeType new_type)
|
||||
{
|
||||
histogram_scope_type = new_type;
|
||||
@@ -2289,9 +2311,13 @@ void EditorPanel::scopeTypeChanged(ScopeType new_type)
|
||||
// Make sure the new scope is updated since we only actively update the
|
||||
// current scope.
|
||||
if (new_type == HistogramPanelListener::HISTOGRAM) {
|
||||
histogram_observable->updateHistogram();
|
||||
histogram_observable->requestUpdateHistogram();
|
||||
} else if (new_type == HistogramPanelListener::VECTORSCOPE_HS) {
|
||||
histogram_observable->requestUpdateVectorscope();
|
||||
} else if (new_type == HistogramPanelListener::VECTORSCOPE_CH) {
|
||||
histogram_observable->requestUpdateVectorscope();
|
||||
} else if (new_type == HistogramPanelListener::WAVEFORM) {
|
||||
histogram_observable->updateWaveform();
|
||||
histogram_observable->requestUpdateWaveform();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -128,6 +128,8 @@ public:
|
||||
const LUTu& histBlueRaw,
|
||||
const LUTu& histChroma,
|
||||
const LUTu& histLRETI,
|
||||
int vectorscopeScale,
|
||||
const int vectorscope[HistogramListener::vectorscope_size][HistogramListener::vectorscope_size],
|
||||
int waveformScale,
|
||||
int waveformWidth,
|
||||
const int waveformRed[][256],
|
||||
@@ -136,7 +138,9 @@ public:
|
||||
) override;
|
||||
void setObservable(rtengine::HistogramObservable* observable) override;
|
||||
bool updateHistogram(void) override;
|
||||
bool updateVectorscope(void) override;
|
||||
bool updateWaveform(void) override;
|
||||
int vectorscopeType(void) override;
|
||||
|
||||
// HistogramPanelListener
|
||||
void scopeTypeChanged(ScopeType new_type) override;
|
||||
|
||||
@@ -163,8 +163,12 @@ HistogramPanel::HistogramPanel () : panel_listener(nullptr)
|
||||
showMode->set_image(*mode2Image);
|
||||
if (options.histogramScopeType == 0) {
|
||||
// TODO: scopeType->set_image(*histImage);
|
||||
} else {
|
||||
} else if (options.histogramScopeType == 1) {
|
||||
// TODO: scopeType->set_image(*waveImage);
|
||||
} else if (options.histogramScopeType == 2) {
|
||||
// TODO: scopeType->set_image(*vectHsImage);
|
||||
} else if (options.histogramScopeType == 3) {
|
||||
// TODO: scopeType->set_image(*vectHcImage);
|
||||
}
|
||||
showBAR->set_image (showBAR->get_active() ? *barImage : *barImage_g);
|
||||
|
||||
@@ -254,7 +258,7 @@ void HistogramPanel::showRGBBar()
|
||||
|
||||
gfxGrid->attach_next_to(*histogramRGBArea, *histogramArea, pos);
|
||||
setHistRGBInvalid();
|
||||
histogramRGBArea->setShow(true);
|
||||
histogramRGBArea->setShow(options.histogramScopeType < 2);
|
||||
}
|
||||
|
||||
void HistogramPanel::resized (Gtk::Allocation& req)
|
||||
@@ -331,12 +335,16 @@ void HistogramPanel::mode_released ()
|
||||
|
||||
void HistogramPanel::type_pressed()
|
||||
{
|
||||
constexpr int TYPE_COUNT = 2; // Histogram and waveform.
|
||||
constexpr int TYPE_COUNT = 4; // Histogram, waveform, and 2 vectorscopes.
|
||||
options.histogramScopeType = (options.histogramScopeType + 1) % TYPE_COUNT;
|
||||
if (options.histogramScopeType == 0) {
|
||||
// TODO: showMode->set_image(*histImage);
|
||||
} else {
|
||||
} else if (options.histogramScopeType == 1) {
|
||||
// TODO: showMode->set_image(*waveImage);
|
||||
} else if (options.histogramScopeType == 2) {
|
||||
// TODO: showMode->set_image(*vectHsImage);
|
||||
} else if (options.histogramScopeType == 3) {
|
||||
// TODO: showMode->set_image(*vectHcImage);
|
||||
}
|
||||
type_changed();
|
||||
rgbv_toggled();
|
||||
@@ -350,6 +358,9 @@ void HistogramPanel::type_changed()
|
||||
}
|
||||
|
||||
if (options.histogramScopeType == 0) {
|
||||
showRed->set_sensitive();
|
||||
showGreen->set_sensitive();
|
||||
showBlue->set_sensitive();
|
||||
showValue->set_sensitive(!showRAW->get_active());
|
||||
showChro->set_sensitive(!showRAW->get_active());
|
||||
showRAW->set_sensitive();
|
||||
@@ -359,7 +370,10 @@ void HistogramPanel::type_changed()
|
||||
updateHistAreaOptions();
|
||||
panel_listener->scopeTypeChanged(HistogramPanelListener::HISTOGRAM);
|
||||
}
|
||||
} else {
|
||||
} else if (options.histogramScopeType == 1) {
|
||||
showRed->set_sensitive();
|
||||
showGreen->set_sensitive();
|
||||
showBlue->set_sensitive();
|
||||
showValue->set_sensitive(false);
|
||||
showChro->set_sensitive(false);
|
||||
showRAW->set_sensitive(false);
|
||||
@@ -369,6 +383,28 @@ void HistogramPanel::type_changed()
|
||||
updateHistAreaOptions();
|
||||
panel_listener->scopeTypeChanged(HistogramPanelListener::WAVEFORM);
|
||||
}
|
||||
} else {
|
||||
showRed->set_sensitive(false);
|
||||
showGreen->set_sensitive(false);
|
||||
showBlue->set_sensitive(false);
|
||||
showValue->set_sensitive(false);
|
||||
showChro->set_sensitive(false);
|
||||
showRAW->set_sensitive(false);
|
||||
showMode->set_sensitive(false);
|
||||
histogramRGBArea = histogramRGBAreaHori.get();
|
||||
if (panel_listener) {
|
||||
updateHistAreaOptions();
|
||||
HistogramPanelListener::ScopeType type;
|
||||
switch (options.histogramScopeType) {
|
||||
case 2:
|
||||
type = HistogramPanelListener::VECTORSCOPE_HS;
|
||||
break;
|
||||
case 3:
|
||||
type = HistogramPanelListener::VECTORSCOPE_CH;
|
||||
break;
|
||||
}
|
||||
panel_listener->scopeTypeChanged(type);
|
||||
}
|
||||
}
|
||||
|
||||
if (showBAR->get_active()) {
|
||||
@@ -395,7 +431,7 @@ void HistogramPanel::rgbv_toggled ()
|
||||
histogramArea->updateBackBuffer ();
|
||||
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->updateOptions (showRed->get_active(), showGreen->get_active(), showBlue->get_active(), showValue->get_active(), showChro->get_active(), showRAW->get_active(), showBAR->get_active() && options.histogramScopeType < 2);
|
||||
histogramRGBArea->updateBackBuffer (0, 0, 0);
|
||||
histogramRGBArea->queue_draw ();
|
||||
}
|
||||
@@ -458,8 +494,14 @@ void HistogramPanel::setPanelListener(HistogramPanelListener* listener)
|
||||
HistogramPanelListener::ScopeType type;
|
||||
if (options.histogramScopeType == 0) {
|
||||
type = HistogramPanelListener::HISTOGRAM;
|
||||
} else {
|
||||
} else if (options.histogramScopeType == 1) {
|
||||
type = HistogramPanelListener::WAVEFORM;
|
||||
} else if (options.histogramScopeType == 2) {
|
||||
type = HistogramPanelListener::VECTORSCOPE_HS;
|
||||
} else if (options.histogramScopeType == 3) {
|
||||
type = HistogramPanelListener::VECTORSCOPE_CH;
|
||||
} else {
|
||||
type = HistogramPanelListener::NONE;
|
||||
}
|
||||
listener->scopeTypeChanged(type);
|
||||
}
|
||||
@@ -616,7 +658,7 @@ void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustrin
|
||||
drawBar(cc, b, 255.0, winw, winh, s);
|
||||
}
|
||||
|
||||
if((needLuma || needChroma) && options.histogramScopeType != 1) {
|
||||
if((needLuma || needChroma) && options.histogramScopeType == 0) {
|
||||
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);
|
||||
|
||||
@@ -828,6 +870,9 @@ HistogramArea::HistogramArea (DrawModeListener *fml) :
|
||||
lhist(256);
|
||||
chist(256);
|
||||
|
||||
const int vect_size = VECTORSCOPE_SIZE * Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, VECTORSCOPE_SIZE);
|
||||
vect_buffer.reset(new unsigned char[vect_size]);
|
||||
|
||||
get_style_context()->add_class("drawingarea");
|
||||
set_name("HistogramArea");
|
||||
|
||||
@@ -904,6 +949,8 @@ void HistogramArea::update(
|
||||
const LUTu& histRedRaw,
|
||||
const LUTu& histGreenRaw,
|
||||
const LUTu& histBlueRaw,
|
||||
int vectorscopeScale,
|
||||
const int vectorscope[VECTORSCOPE_SIZE][VECTORSCOPE_SIZE],
|
||||
int waveformScale,
|
||||
int waveformWidth,
|
||||
const int waveformRed[][256],
|
||||
@@ -936,6 +983,11 @@ void HistogramArea::update(
|
||||
memcpy(gw, waveformGreen, 256 * waveformWidth * sizeof(gw[0][0]));
|
||||
memcpy(bw, waveformBlue, 256 * waveformWidth * sizeof(bw[0][0]));
|
||||
wave_buffer_dirty = true;
|
||||
} else if (scopeType >= 2) {
|
||||
vectorscope_scale = vectorscopeScale;
|
||||
memcpy(vect, vectorscope, VECTORSCOPE_SIZE * VECTORSCOPE_SIZE *
|
||||
sizeof(vect[0][0]));
|
||||
vect_buffer_dirty = true;
|
||||
}
|
||||
valid = true;
|
||||
} else {
|
||||
@@ -1009,7 +1061,7 @@ void HistogramArea::updateBackBuffer ()
|
||||
int nrOfVGridPartitions = 8; // always show 8 stops (lines at 1,3,7,15,31,63,127)
|
||||
|
||||
// draw vertical gridlines
|
||||
if (options.histogramScopeType != 1) {
|
||||
if (options.histogramScopeType == 0) {
|
||||
for (int i = 0; i <= nrOfVGridPartitions; i++) {
|
||||
double xpos = padding + 0.5;
|
||||
if (options.histogramDrawMode < 2) {
|
||||
@@ -1031,6 +1083,8 @@ void HistogramArea::updateBackBuffer ()
|
||||
cr->line_to(w, ypos);
|
||||
cr->stroke();
|
||||
}
|
||||
} else if (options.histogramScopeType >= 2) {
|
||||
// Vectorscope has no gridlines.
|
||||
} else if (options.histogramDrawMode == 0) {
|
||||
for (int i = 1; i < nrOfHGridPartitions; i++) {
|
||||
cr->move_to (padding, i * (double)h / nrOfHGridPartitions + 0.5);
|
||||
@@ -1156,6 +1210,8 @@ void HistogramArea::updateBackBuffer ()
|
||||
|
||||
} else if (scopeType == 1 && waveform_width > 0) {
|
||||
drawWaveform(cr, w, h);
|
||||
} else if (scopeType >= 2) {
|
||||
drawVectorscope(cr, w, h);
|
||||
}
|
||||
|
||||
// Draw the frame's border
|
||||
@@ -1220,6 +1276,107 @@ void HistogramArea::drawMarks(Cairo::RefPtr<Cairo::Context> &cr,
|
||||
cr->fill();
|
||||
}
|
||||
|
||||
void HistogramArea::drawVectorscope(Cairo::RefPtr<Cairo::Context> &cr, int w, int h)
|
||||
{
|
||||
// Arbitrary scale factor multiplied by vectorscope area and divided by
|
||||
// current scale.
|
||||
const float scale = 16.f * VECTORSCOPE_SIZE * VECTORSCOPE_SIZE / vectorscope_scale;
|
||||
|
||||
// See Cairo documentation on stride.
|
||||
const int cairo_stride = Cairo::ImageSurface::format_stride_for_width(Cairo::FORMAT_ARGB32, VECTORSCOPE_SIZE);
|
||||
|
||||
if (vect_buffer_dirty && vectorscope_scale > 0) {
|
||||
// TODO: Optimize.
|
||||
for (int u = 0; u < VECTORSCOPE_SIZE; u++) {
|
||||
for (int v = 0; v < VECTORSCOPE_SIZE; v++) {
|
||||
const unsigned char value = LIM<float>(scale * vect[u][v], 0, 0xff);
|
||||
*(uint32_t*)&(vect_buffer[(VECTORSCOPE_SIZE - 1 - u) * cairo_stride + v * 4]) =
|
||||
value | (value << 8) | (value << 16) | (value << 24);
|
||||
}
|
||||
}
|
||||
|
||||
vect_buffer_dirty = false;
|
||||
}
|
||||
|
||||
const float scope_size = min<float>(w, h) - 2 * padding;
|
||||
const float o_x = (w - scope_size) / 2;
|
||||
const float o_y = (h - scope_size) / 2;
|
||||
const double s = RTScalable::getScale();
|
||||
auto orig_matrix = cr->get_matrix();
|
||||
const double line_spacing = 4.0 * s;
|
||||
const double line_length = scope_size / 2.0 - 2.0 * line_spacing;
|
||||
std::valarray<double> ch_ds(1);
|
||||
|
||||
cr->translate(w / 2.0, h / 2.0);
|
||||
cr->set_source_rgba (1., 1., 1., 0.25);
|
||||
cr->set_line_width (1.0 * s);
|
||||
cr->set_antialias(Cairo::ANTIALIAS_SUBPIXEL);
|
||||
ch_ds[0] = 4;
|
||||
|
||||
if (scopeType == 2) { // Hue-Saturation.
|
||||
// RYGCBM lines.
|
||||
for (int i = 0; i < 6; i++) {
|
||||
cr->move_to(line_spacing, 0);
|
||||
cr->line_to(line_spacing + line_length, 0);
|
||||
cr->rotate_degrees(60);
|
||||
}
|
||||
cr->stroke();
|
||||
// 100% saturation circle.
|
||||
cr->arc(0, 0, scope_size / 2.0, 0, 2 * RT_PI);
|
||||
cr->stroke();
|
||||
// 25%, 50%, and 75% saturation.
|
||||
cr->set_dash(ch_ds, 0);
|
||||
for (int i = 1; i < 4; i++) {
|
||||
cr->arc(0, 0, i * scope_size / 8.0, 0, 2 * RT_PI);
|
||||
cr->stroke();
|
||||
}
|
||||
// HSV skin tone line derived from -I axis of YIQ.
|
||||
cr->rotate(-0.134900 * RT_PI);
|
||||
cr->move_to(line_spacing, 0);
|
||||
cr->line_to(line_spacing + line_length, 0);
|
||||
cr->stroke();
|
||||
cr->unset_dash();
|
||||
} else if (scopeType == 3) { // Hue-Chroma.
|
||||
// a and b axes.
|
||||
cr->move_to(0, line_spacing);
|
||||
cr->line_to(0, line_spacing + line_length);
|
||||
cr->move_to(0, -line_spacing);
|
||||
cr->line_to(0, -line_spacing - line_length);
|
||||
cr->move_to(line_spacing, 0);
|
||||
cr->line_to(line_spacing + line_length, 0);
|
||||
cr->move_to(-line_spacing, 0);
|
||||
cr->line_to(-line_spacing - line_length, 0);
|
||||
cr->stroke();
|
||||
// 25%, 50%, 75%, and 100% of standard chroma range.
|
||||
cr->set_dash(ch_ds, 0);
|
||||
for (int i = 1; i <= 4; i++) {
|
||||
cr->arc(0, 0, i * scope_size / 8.0, 0, 2 * RT_PI);
|
||||
cr->stroke();
|
||||
}
|
||||
// CIELAB skin tone line, approximated by 50% saturation and
|
||||
// value along the HSV skin tone line.
|
||||
cr->rotate(-0.321713 * RT_PI);
|
||||
cr->move_to(line_spacing, 0);
|
||||
cr->line_to(line_spacing + line_length, 0);
|
||||
cr->stroke();
|
||||
cr->unset_dash();
|
||||
}
|
||||
cr->set_matrix(orig_matrix);
|
||||
|
||||
// Vectorscope trace.
|
||||
if (vectorscope_scale > 0) {
|
||||
Cairo::RefPtr<Cairo::ImageSurface> surface = Cairo::ImageSurface::create(
|
||||
vect_buffer.get(), Cairo::FORMAT_ARGB32, VECTORSCOPE_SIZE, VECTORSCOPE_SIZE, cairo_stride);
|
||||
cr->translate(o_x, o_y);
|
||||
cr->scale(scope_size / VECTORSCOPE_SIZE, scope_size / VECTORSCOPE_SIZE);
|
||||
cr->set_source(surface, 0, 0);
|
||||
cr->set_operator(Cairo::OPERATOR_OVER);
|
||||
cr->paint();
|
||||
surface->finish();
|
||||
cr->set_matrix(orig_matrix);
|
||||
}
|
||||
}
|
||||
|
||||
void HistogramArea::drawWaveform(Cairo::RefPtr<Cairo::Context> &cr, int w, int h)
|
||||
{
|
||||
// Arbitrary scale factor divided by current scale.
|
||||
@@ -1310,7 +1467,7 @@ bool HistogramArea::on_button_release_event (GdkEventButton* event)
|
||||
|
||||
bool HistogramArea::on_motion_notify_event (GdkEventMotion* event)
|
||||
{
|
||||
if (drawMode == 0 || scopeType == 1) {
|
||||
if (drawMode == 0 || scopeType >= 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,11 @@
|
||||
|
||||
class HistogramArea;
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr int VECTORSCOPE_SIZE = 128;
|
||||
}
|
||||
|
||||
struct HistogramAreaIdleHelper {
|
||||
HistogramArea* harea;
|
||||
bool destroyed;
|
||||
@@ -156,6 +161,10 @@ private:
|
||||
protected:
|
||||
LUTu rhist, ghist, bhist, lhist, chist;
|
||||
LUTu rhistRaw, ghistRaw, bhistRaw, lhistRaw; //lhistRaw is unused?
|
||||
int vectorscope_scale;
|
||||
int vect[VECTORSCOPE_SIZE][VECTORSCOPE_SIZE];
|
||||
std::unique_ptr<unsigned char[]> vect_buffer;
|
||||
bool vect_buffer_dirty;
|
||||
int waveform_scale;
|
||||
int waveform_width;
|
||||
std::unique_ptr<int[][256]> rwave, gwave, bwave;
|
||||
@@ -191,6 +200,8 @@ public:
|
||||
const LUTu& histRedRaw,
|
||||
const LUTu& histGreenRaw,
|
||||
const LUTu& histBlueRaw,
|
||||
int vectorscopeScale,
|
||||
const int vectorscope[VECTORSCOPE_SIZE][VECTORSCOPE_SIZE],
|
||||
int waveformScale,
|
||||
int waveformWidth,
|
||||
const int waveformRed[][256],
|
||||
@@ -208,6 +219,7 @@ public:
|
||||
private:
|
||||
void drawCurve(Cairo::RefPtr<Cairo::Context> &cr, const LUTu & data, double scale, int hsize, int vsize);
|
||||
void drawMarks(Cairo::RefPtr<Cairo::Context> &cr, const LUTu & data, double scale, int hsize, int & ui, int & oi);
|
||||
void drawVectorscope(Cairo::RefPtr<Cairo::Context> &cr, int hsize, int vsize);
|
||||
void drawWaveform(Cairo::RefPtr<Cairo::Context> &cr, int hsize, int vsize);
|
||||
Gtk::SizeRequestMode get_request_mode_vfunc () const override;
|
||||
void get_preferred_height_vfunc (int& minimum_height, int& natural_height) const override;
|
||||
@@ -219,7 +231,7 @@ private:
|
||||
class HistogramPanelListener
|
||||
{
|
||||
public:
|
||||
enum ScopeType {HISTOGRAM, WAVEFORM, NONE};
|
||||
enum ScopeType {HISTOGRAM, VECTORSCOPE_CH, VECTORSCOPE_HS, WAVEFORM, NONE};
|
||||
|
||||
virtual void scopeTypeChanged(ScopeType new_type) = 0;
|
||||
};
|
||||
@@ -286,6 +298,8 @@ public:
|
||||
const LUTu& histRedRaw,
|
||||
const LUTu& histGreenRaw,
|
||||
const LUTu& histBlueRaw,
|
||||
int vectorscopeScale,
|
||||
const int vectorscope[VECTORSCOPE_SIZE][VECTORSCOPE_SIZE],
|
||||
int waveformScale,
|
||||
int waveformWidth,
|
||||
const int waveformRed[][256],
|
||||
@@ -293,7 +307,7 @@ public:
|
||||
const int waveformBlue[][256]
|
||||
)
|
||||
{
|
||||
histogramArea->update(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, waveformScale, waveformWidth, waveformRed, waveformGreen, waveformBlue);
|
||||
histogramArea->update(histRed, histGreen, histBlue, histLuma, histChroma, histRedRaw, histGreenRaw, histBlueRaw, vectorscopeScale, vectorscope, waveformScale, waveformWidth, waveformRed, waveformGreen, waveformBlue);
|
||||
}
|
||||
// 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;
|
||||
|
||||
Reference in New Issue
Block a user