Skip to content

Commit 43d94ab

Browse files
committed
waveform scope: add option for luma display
In waveform scope can now either show RGB channels or luma. When luma option is on, make the RGB channel buttons insensitive. Note that this is luma (Y') not relative luminance (Y). Until add an option to display linearized RGB data, it doesn't make sense to show linearized Y, not least as the jump from seeing non-linear RGB channels to linearized relative luminance is disconcerting. Calculate either RGB channels or luma waveform, not both. This makes sure that RGB waveform calc is as fast as it was before luminance calculation added. Luma calculation is ~15% faster than RGB calculation. This does require reprocessing the pixelpipe when turn on/off the luma option. Future improvements could be: - Add option to show linearized waveform (and rgb parade) data - When linearized option is on, show luminance rather than luma - Add option to show luma/luminance in addition to RGB channels in RGB parade mode - Show luma/luminance in histogram Also: - Rename vs_prof parameter to profile in non-vectorscope _process() functions. The vs_prof name was a result of copying the name from vectorscope process. - Update some comments and general tidying.
1 parent fbd6a7a commit 43d94ab

7 files changed

Lines changed: 193 additions & 82 deletions

File tree

data/darktableconfig.xml.in

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3362,6 +3362,13 @@
33623362
<shortdescription/>
33633363
<longdescription/>
33643364
</dtconfig>
3365+
<dtconfig>
3366+
<name>plugins/darkroom/histogram/show_luma</name>
3367+
<type>bool</type>
3368+
<default>false</default>
3369+
<shortdescription/>
3370+
<longdescription/>
3371+
</dtconfig>
33653372
<dtconfig>
33663373
<name>plugins/darkroom/histogram/vectorscope/harmony_type</name>
33673374
<type>

data/themes/darktable.css

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,11 @@ dialog .sidebar row:selected:hover label,
745745
background-color: alpha(@graph_blue, 0.2);
746746
}
747747

748+
#luma-channel-button
749+
{
750+
background-color: alpha(white, 0.2);
751+
}
752+
748753
/* set now them active state */
749754
#red-channel-button:checked
750755
{
@@ -761,6 +766,11 @@ dialog .sidebar row:selected:hover label,
761766
background-color: alpha(@graph_blue, 0.66);
762767
}
763768

769+
#luma-channel-button:checked
770+
{
771+
background-color: alpha(white, 0.66);
772+
}
773+
764774
/* set now hover state */
765775
#red-channel-button:hover
766776
{
@@ -777,6 +787,27 @@ dialog .sidebar row:selected:hover label,
777787
background-color: alpha(@graph_blue, 0.5);
778788
}
779789

790+
#luma-channel-button:hover
791+
{
792+
background-color: alpha(white, 0.5);
793+
}
794+
795+
/* inactive state */
796+
#red-channel-button:disabled
797+
{
798+
background-color: alpha(@graph_red, 0.1);
799+
}
800+
801+
#green-channel-button:disabled
802+
{
803+
background-color: alpha(@graph_green, 0.1);
804+
}
805+
806+
#blue-channel-button:disabled
807+
{
808+
background-color: alpha(@graph_blue, 0.1);
809+
}
810+
780811
/*------------------
781812
- Dialog windows -
782813
------------------*/

src/libs/histogram.c

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,11 @@ static void _lib_histogram_get_sector_angles(dt_lib_module_t *self,
4141
float *angles,
4242
int *n);
4343

44-
static const gchar *rgb_names[DT_SCOPES_RGB_N] =
44+
static const gchar *channel_names[DT_SCOPES_CHANNEL_N] =
4545
{ N_("red"),
4646
N_("green"),
47-
N_("blue")
47+
N_("blue"),
48+
N_("luma")
4849
};
4950

5051
const char *name(dt_lib_module_t *self)
@@ -442,7 +443,7 @@ static void _mode_toggle(GtkWidget *button, dt_scopes_t *s)
442443
lib_histogram_update_tooltip(s);
443444

444445
dt_scopes_call(prior_mode, mode_leave);
445-
gtk_widget_set_visible(s->button_box_rgb,
446+
gtk_widget_set_visible(s->button_box_channels,
446447
dt_scopes_func_exists(s->cur_mode, draw_scope_channels));
447448
dt_scopes_call(s->cur_mode, update_buttons);
448449
dt_scopes_call(s->cur_mode, mode_enter);
@@ -457,16 +458,23 @@ static void _mode_toggle(GtkWidget *button, dt_scopes_t *s)
457458

458459
static void _channel_toggle(GtkWidget *button, dt_scopes_t *s)
459460
{
460-
for(int i = 0; i < DT_SCOPES_RGB_N; i++)
461-
if(s->channel_buttons[i] == button)
461+
for(int i = 0; i < DT_SCOPES_CHANNEL_N; i++)
462+
if(s->channel_btns[i] == button)
462463
{
463464
char conf[48];
464465
g_snprintf(conf, sizeof(conf),
465-
"plugins/darkroom/histogram/show_%s", rgb_names[i]);
466+
"plugins/darkroom/histogram/show_%s", channel_names[i]);
466467
s->channels[i]
467468
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
468469
dt_conf_set_bool(conf, s->channels[i]);
469-
dt_scopes_refresh(s);
470+
if(i == DT_SCOPES_CHANNEL_LUMA)
471+
{
472+
for(int ch = 0; ch <= DT_SCOPES_CHANNEL_BLUE; ch++)
473+
gtk_widget_set_sensitive(s->channel_btns[ch], !s->channels[i]);
474+
dt_scopes_reprocess();
475+
}
476+
else
477+
dt_scopes_refresh(s);
470478
}
471479
}
472480

@@ -537,7 +545,7 @@ static void _eventbox_enter_notify_callback(GtkEventControllerMotion *controller
537545
if(s->cur_mode != &s->modes[i])
538546
dt_scopes_call(&s->modes[i], mode_leave);
539547
dt_scopes_call(s->cur_mode, mode_enter);
540-
gtk_widget_set_visible(s->button_box_rgb,
548+
gtk_widget_set_visible(s->button_box_channels,
541549
dt_scopes_func_exists(s->cur_mode, draw_scope_channels));
542550
gtk_widget_show(s->button_box_left);
543551
gtk_widget_show(s->button_box_right);
@@ -675,12 +683,14 @@ void gui_init(dt_lib_module_t *self)
675683

676684
dt_pthread_mutex_init(&s->lock, NULL);
677685

678-
s->channels[DT_SCOPES_RGB_RED]
686+
s->channels[DT_SCOPES_CHANNEL_RED]
679687
= dt_conf_get_bool("plugins/darkroom/histogram/show_red");
680-
s->channels[DT_SCOPES_RGB_GREEN]
688+
s->channels[DT_SCOPES_CHANNEL_GREEN]
681689
= dt_conf_get_bool("plugins/darkroom/histogram/show_green");
682-
s->channels[DT_SCOPES_RGB_BLUE]
690+
s->channels[DT_SCOPES_CHANNEL_BLUE]
683691
= dt_conf_get_bool("plugins/darkroom/histogram/show_blue");
692+
s->channels[DT_SCOPES_CHANNEL_LUMA]
693+
= dt_conf_get_bool("plugins/darkroom/histogram/show_luma");
684694

685695
// proxy functions and data so that pixelpipe or tether can
686696
// provide data for a histogram
@@ -804,28 +814,35 @@ void gui_init(dt_lib_module_t *self)
804814
GDK_KEY_H, GDK_CONTROL_MASK | GDK_SHIFT_MASK);
805815

806816
// RGB channel buttons
807-
s->button_box_rgb = dt_gui_hbox();
808-
gtk_widget_set_valign(s->button_box_rgb, GTK_ALIGN_CENTER);
809-
gtk_widget_set_halign(s->button_box_rgb, GTK_ALIGN_CENTER);
810-
// red/green/blue channel on/off
811-
for(int i=DT_SCOPES_RGB_RED; i < DT_SCOPES_RGB_N; i++)
817+
s->button_box_channels = dt_gui_hbox();
818+
gtk_widget_set_valign(s->button_box_channels, GTK_ALIGN_CENTER);
819+
gtk_widget_set_halign(s->button_box_channels, GTK_ALIGN_CENTER);
820+
// red/green/blue/luma on/off
821+
for(int i=DT_SCOPES_CHANNEL_RED; i < DT_SCOPES_CHANNEL_N; i++)
812822
{
813-
g_autofree char *name = g_strdup_printf("%s-channel-button", rgb_names[i]);
814-
g_autofree char *tip = g_strdup_printf(_("toggle %s channel"), _(rgb_names[i]));
823+
g_autofree char *name = g_strdup_printf("%s-channel-button", channel_names[i]);
824+
g_autofree char *tip = g_strdup_printf(_("toggle %s channel"), _(channel_names[i]));
815825
GtkWidget *btn = dtgtk_togglebutton_new(dtgtk_cairo_paint_color,
816826
CPF_NONE, NULL);
817827
dt_gui_add_class(btn, "rgb_toggle");
818828
gtk_widget_set_name(btn, name);
819829
gtk_widget_set_tooltip_text(btn, tip);
820830
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(btn),
821831
s->channels[i]);
822-
dt_action_define(dark, N_("toggle colors"), rgb_names[i], btn, &dt_action_def_toggle);
823-
dt_gui_box_add(s->button_box_rgb, btn);
832+
if(i <= DT_SCOPES_CHANNEL_BLUE)
833+
gtk_widget_set_sensitive(btn, !s->channels[DT_SCOPES_CHANNEL_LUMA]);
834+
dt_action_define(dark, N_("toggle colors"), channel_names[i], btn, &dt_action_def_toggle);
824835
g_signal_connect(G_OBJECT(btn), "toggled", G_CALLBACK(_channel_toggle), s);
825-
s->channel_buttons[i] = btn;
836+
s->channel_btns[i] = btn;
826837
}
827-
// RGB channels are always rightmost
828-
dt_gui_box_add(s->button_box_right, s->button_box_rgb);
838+
// luma is always leftmost
839+
dt_gui_box_add(s->button_box_channels,
840+
s->channel_btns[DT_SCOPES_CHANNEL_LUMA],
841+
s->channel_btns[DT_SCOPES_CHANNEL_RED],
842+
s->channel_btns[DT_SCOPES_CHANNEL_GREEN],
843+
s->channel_btns[DT_SCOPES_CHANNEL_BLUE]);
844+
// channels are always rightmost
845+
dt_gui_box_add(s->button_box_right, s->button_box_channels);
829846

830847
for(dt_scopes_mode_type_t i = 0; i < DT_SCOPES_MODE_N; i++)
831848
{

src/libs/scopes.h

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,16 @@ typedef enum dt_scopes_highlight_t
4343
DT_SCOPES_HIGHLIGHT_EXPOSURE
4444
} dt_scopes_highlight_t;
4545

46-
typedef enum dt_scopes_rgb_t
46+
typedef enum dt_scopes_channels_t
4747
{
48-
DT_SCOPES_RGB_RED = 0,
49-
DT_SCOPES_RGB_GREEN,
50-
DT_SCOPES_RGB_BLUE,
51-
DT_SCOPES_RGB_N // needs to be the last one
52-
} dt_scopes_rgb_t;
48+
DT_SCOPES_CHANNEL_RED = 0,
49+
DT_SCOPES_CHANNEL_GREEN,
50+
DT_SCOPES_CHANNEL_BLUE,
51+
DT_SCOPES_CHANNEL_LUMA,
52+
DT_SCOPES_CHANNEL_N // needs to be the last one
53+
} dt_scopes_channels_t;
5354

54-
typedef gboolean scopes_channels_t[DT_SCOPES_RGB_N];
55+
typedef gboolean dt_scopes_channels_list_t[DT_SCOPES_CHANNEL_N];
5556

5657
struct dt_scopes_t;
5758
struct dt_scopes_mode_t;
@@ -66,7 +67,7 @@ typedef struct dt_scopes_functions_t
6667
const float *const input,
6768
// FIXME: should ROI by dt_histogram_roi_t or another type?
6869
dt_histogram_roi_t *const roi,
69-
const dt_iop_order_iccprofile_info_t *vs_prof);
70+
const dt_iop_order_iccprofile_info_t *profile);
7071
// FIXME: do want a proper clear function or just tag as not up to date?
7172
void (*clear)(struct dt_scopes_mode_t *const self);
7273
void (*draw_bkgd)(const struct dt_scopes_mode_t *const self,
@@ -90,7 +91,7 @@ typedef struct dt_scopes_functions_t
9091
cairo_t *cr,
9192
const int width,
9293
const int height,
93-
const scopes_channels_t channels);
94+
const dt_scopes_channels_list_t channels);
9495
// FIXME: rename to something more sensible
9596
dt_scopes_highlight_t (*get_highlight)(const struct dt_scopes_mode_t *const self,
9697
const double posx,
@@ -140,16 +141,16 @@ typedef struct dt_scopes_t
140141
dt_scopes_mode_t modes[DT_SCOPES_MODE_N]; // all available modes
141142
int update_counter; // most recent pixelpipe vs mode data
142143
dt_scopes_highlight_t highlight; // depends on mouse position
143-
scopes_channels_t channels; // display state chosen by RGB buttons
144+
dt_scopes_channels_list_t channels; // RGB & luma display state
144145
gboolean dragging; // to block motion handling during drag
145146
gdouble last_offset_x, last_offset_y; // for drag handling
146147
// UI elements
147148
GtkWidget *overlay; // GtkOverlay -- scope and buttons
148149
GtkWidget *button_box_left; // GtkBox -- scope mode buttons
149150
GtkWidget *button_box_split; // GtkBox -- option buttons for left scope
150151
GtkWidget *button_box_right; // GtkBox -- option buttons for main scope
151-
GtkWidget *button_box_rgb; // GtkBox -- RGB channels buttons
152-
GtkWidget *channel_buttons[DT_SCOPES_RGB_N]; // Array of GtkToggleButton -- RGB channels
152+
GtkWidget *button_box_channels; // GtkBox -- RGB & luma buttons
153+
GtkWidget *channel_btns[DT_SCOPES_CHANNEL_N]; // Array of GtkToggleButton -- channels
153154
GtkWidget *scope_draw; // GtkDrawingArea -- scope & resize
154155
// for access to data during process/draw
155156
dt_pthread_mutex_t lock;

src/libs/scopes/histogram.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ const char* _hist_name(const dt_scopes_mode_t *const self)
5353
static void _hist_process(dt_scopes_mode_t *const self,
5454
const float *const input,
5555
dt_histogram_roi_t *const roi,
56-
const dt_iop_order_iccprofile_info_t *vs_prof)
56+
const dt_iop_order_iccprofile_info_t *profile)
5757
{
5858
dt_scopes_hist_t *const d = self->data;
5959
dt_dev_histogram_collection_params_t histogram_params = { 0 };
@@ -126,7 +126,7 @@ static void _hist_draw(const dt_scopes_mode_t *const self,
126126
cairo_t *cr,
127127
const int width,
128128
const int height,
129-
const scopes_channels_t channels)
129+
const dt_scopes_channels_list_t channels)
130130
{
131131
const dt_scopes_hist_t *const d = self->data;
132132

@@ -146,7 +146,7 @@ static void _hist_draw(const dt_scopes_mode_t *const self,
146146
cairo_scale(cr, width / 255.0, -(height - 10) / hist_max);
147147
cairo_set_operator(cr, CAIRO_OPERATOR_ADD);
148148
cairo_set_line_width(cr, DT_PIXEL_APPLY_DPI(1.));
149-
for(int k = 0; k < DT_SCOPES_RGB_N; k++)
149+
for(int k = 0; k <= DT_SCOPES_CHANNEL_BLUE; k++)
150150
if(channels[k])
151151
{
152152
// FIXME: this is the last place in dt these are used -- if can

src/libs/scopes/split.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ const char* _split_name(const dt_scopes_mode_t *const self)
3333
static void _split_process(dt_scopes_mode_t *const self,
3434
const float *const input,
3535
dt_histogram_roi_t *const roi,
36-
const dt_iop_order_iccprofile_info_t *vs_prof)
36+
const dt_iop_order_iccprofile_info_t *profile)
3737
{
3838
dt_scopes_split_t *const d = self->data;
39-
dt_scopes_call(d->left, process, input, roi, vs_prof);
40-
dt_scopes_call(d->right, process, input, roi, vs_prof);
39+
dt_scopes_call(d->left, process, input, roi, profile);
40+
dt_scopes_call(d->right, process, input, roi, profile);
4141
self->update_counter = self->scopes->update_counter;
4242
}
4343

@@ -90,7 +90,7 @@ static void _split_draw(const dt_scopes_mode_t *const self,
9090
cairo_t *cr,
9191
const int width,
9292
const int height,
93-
const scopes_channels_t channels)
93+
const dt_scopes_channels_list_t channels)
9494
{
9595
const dt_scopes_split_t *const d = self->data;
9696
const int half_width = width / 2;
@@ -225,7 +225,7 @@ static void _responsive_buttons(dt_scopes_t *const s)
225225

226226
const int mode_btns_hori = DT_SCOPES_MODE_N;
227227
const int opt_btns_wave = 1; // FIXME: change this if there are more
228-
const int opt_btns_hori = DT_SCOPES_RGB_N + opt_btns_wave;
228+
const int opt_btns_hori = DT_SCOPES_CHANNEL_N + opt_btns_wave;
229229
const int opt_btns_vert = 1 + opt_btns_wave;
230230
const int estd_margin = 6; // for both boxes and buttons
231231
const double estd_btn_width = min_w + estd_margin;
@@ -247,7 +247,7 @@ static void _responsive_buttons(dt_scopes_t *const s)
247247
// compact layout should show all buttons without overlap on the
248248
// smallest panel width and scope height
249249
gtk_orientable_set_orientation(GTK_ORIENTABLE(s->button_box_left), orient_btn_left);
250-
gtk_orientable_set_orientation(GTK_ORIENTABLE(s->button_box_rgb), orient_btn_rgb);
250+
gtk_orientable_set_orientation(GTK_ORIENTABLE(s->button_box_channels), orient_btn_rgb);
251251
}
252252

253253
static void _reparent(GtkWidget *src, GtkWidget *dest, GtkWidget *child)
@@ -279,7 +279,7 @@ static void _split_mode_enter(dt_scopes_mode_t *const self)
279279
d->left->options_box);
280280
if(d->left->functions->draw_scope_channels)
281281
_reparent(self->scopes->button_box_right, self->scopes->button_box_split,
282-
self->scopes->button_box_rgb);
282+
self->scopes->button_box_channels);
283283
gtk_widget_show_all(self->scopes->button_box_split);
284284
}
285285

@@ -293,11 +293,11 @@ static void _split_mode_leave(const dt_scopes_mode_t *const self)
293293
d->left->options_box);
294294
if(d->left->functions->draw_scope_channels)
295295
_reparent(self->scopes->button_box_split, self->scopes->button_box_right,
296-
self->scopes->button_box_rgb);
296+
self->scopes->button_box_channels);
297297
gtk_widget_hide(self->scopes->button_box_split);
298298
gtk_orientable_set_orientation(GTK_ORIENTABLE(self->scopes->button_box_left),
299299
GTK_ORIENTATION_HORIZONTAL);
300-
gtk_orientable_set_orientation(GTK_ORIENTABLE(self->scopes->button_box_rgb),
300+
gtk_orientable_set_orientation(GTK_ORIENTABLE(self->scopes->button_box_channels),
301301
GTK_ORIENTATION_HORIZONTAL);
302302
}
303303

0 commit comments

Comments
 (0)