Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions data/darktableconfig.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -3362,6 +3362,13 @@
<shortdescription/>
<longdescription/>
</dtconfig>
<dtconfig>
<name>plugins/darkroom/histogram/show_luma</name>
<type>bool</type>
<default>false</default>
<shortdescription/>
<longdescription/>
</dtconfig>
<dtconfig>
<name>plugins/darkroom/histogram/vectorscope/harmony_type</name>
<type>
Expand Down
32 changes: 32 additions & 0 deletions data/themes/darktable.css
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ Why that? Just because it's a developer choice and most classes use underscore i
@define-color graph_red rgb(237,30,20);
@define-color graph_green rgb(28,235,26);
@define-color graph_blue rgb(14,14,233);
@define-color graph_white @grey_95;

@define-color colorlabel_red rgb(230,0,0);
@define-color colorlabel_green rgb(0,230,0);
Expand Down Expand Up @@ -745,6 +746,11 @@ dialog .sidebar row:selected:hover label,
background-color: alpha(@graph_blue, 0.2);
}

#luma-toggle-button
{
background-color: alpha(white, 0.2);
}

/* set now them active state */
#red-channel-button:checked
{
Expand All @@ -761,6 +767,11 @@ dialog .sidebar row:selected:hover label,
background-color: alpha(@graph_blue, 0.66);
}

#luma-toggle-button:checked
{
background-color: alpha(white, 0.66);
}

/* set now hover state */
#red-channel-button:hover
{
Expand All @@ -777,6 +788,27 @@ dialog .sidebar row:selected:hover label,
background-color: alpha(@graph_blue, 0.5);
}

#luma-toggle-button:hover
{
background-color: alpha(white, 0.5);
}

/* inactive state */
#red-channel-button:disabled
{
background-color: alpha(@graph_red, 0.1);
}

#green-channel-button:disabled
{
background-color: alpha(@graph_green, 0.1);
}

#blue-channel-button:disabled
{
background-color: alpha(@graph_blue, 0.1);
}

/*------------------
- Dialog windows -
------------------*/
Expand Down
2 changes: 2 additions & 0 deletions src/bauhaus/bauhaus.c
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,8 @@ void dt_bauhaus_load_theme()
&bh->graph_colors[1]);
gtk_style_context_lookup_color(ctx, "graph_blue",
&bh->graph_colors[2]);
gtk_style_context_lookup_color(ctx, "graph_white",
&bh->graph_colors[3]);
gtk_style_context_lookup_color(ctx, "colorlabel_red",
&bh->colorlabels[DT_COLORLABELS_RED]);
gtk_style_context_lookup_color(ctx, "colorlabel_yellow",
Expand Down
2 changes: 1 addition & 1 deletion src/bauhaus/bauhaus.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ typedef struct dt_bauhaus_t

// colors for graphs
GdkRGBA graph_bg, graph_exterior, graph_border, graph_fg, graph_grid, graph_fg_active, graph_overlay, inset_histogram;
GdkRGBA graph_colors[3]; // primaries
GdkRGBA graph_colors[4]; // additive primaries and luma white
GdkRGBA colorlabels[DT_COLORLABELS_LAST];
} dt_bauhaus_t;

Expand Down
60 changes: 48 additions & 12 deletions src/common/histogram.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
This file is part of darktable,
Copyright (C) 2014-2023 darktable developers.
Copyright (C) 2014-2026 darktable developers.

darktable is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -70,6 +70,28 @@ static inline void _bin_raw(const dt_dev_histogram_collection_params_t *const pa

//------------------------------------------------------------------------------

static inline void _bin_luma(const dt_dev_histogram_collection_params_t *const params,
const void *const restrict pixel,
uint32_t *const restrict histogram,
const int j,
const dt_iop_order_iccprofile_info_t *const profile)
{
const dt_histogram_roi_t *roi = params->roi;
float *in = (float *)pixel + 4 * (roi->width * j + roi->crop_x);
const float max_bin = params->bins_count - 1;

for(int i = 0; i < roi->width - roi->crop_right - roi->crop_x; i++)
{
const float luma = profile->matrix_in[1][0] * in[i*4]
+ profile->matrix_in[1][1] * in[i*4+1]
+ profile->matrix_in[1][2] * in[i*4+2];
const size_t bin = CLAMP(max_bin * luma, 0.0f, max_bin);
histogram[bin]++;
}
}

//------------------------------------------------------------------------------

static inline void _bin_rgb(const dt_dev_histogram_collection_params_t *const params,
const void *const restrict pixel,
uint32_t *const restrict histogram,
Expand Down Expand Up @@ -225,15 +247,23 @@ void dt_histogram_helper(dt_dev_histogram_collection_params_t *histogram_params,
break;

case IOP_CS_RGB:
histogram_stats->ch = 3u;
if(compensate_middle_grey && profile_info)
// for rgbcurve (compensated)
if(histogram_stats->ch == 1u)
// for histogram utility module
_hist_worker(histogram_params, histogram_stats, pixel, histogram,
_bin_rgb_compensated, profile_info);
_bin_luma, profile_info);
else
// used by levels, rgbcurve (uncompensated), rgblevels
_hist_worker(histogram_params, histogram_stats, pixel, histogram,
_bin_rgb, profile_info);
{
histogram_stats->ch = 3u;
if(compensate_middle_grey && profile_info)
// for rgbcurve (compensated)
_hist_worker(histogram_params, histogram_stats, pixel, histogram,
_bin_rgb_compensated, profile_info);
else
// used by levels, rgbcurve (uncompensated), rgblevels, and
// histogram utility module
_hist_worker(histogram_params, histogram_stats, pixel, histogram,
_bin_rgb, profile_info);
}
break;

case IOP_CS_LAB:
Expand All @@ -257,7 +287,7 @@ void dt_histogram_helper(dt_dev_histogram_collection_params_t *histogram_params,
if(*histogram && histogram_max)
{
// RGB, Lab, and LCh
if(cst == IOP_CS_RGB || IOP_CS_LAB)
if(cst == IOP_CS_RGB || cst == IOP_CS_LAB)
{
uint32_t *hist = *histogram;

Expand All @@ -271,9 +301,15 @@ void dt_histogram_helper(dt_dev_histogram_collection_params_t *histogram_params,
m[2] = hist[2];
}

for(int k = 4; k < 4 * histogram_stats->bins_count; k += 4)
for_each_channel(ch,aligned(hist:64) aligned(m:16))
m[ch] = MAX(m[ch], hist[k+ch]);
// intentionally skip first bucket to show bit more y-axis range
// for underexposed images
if(histogram_stats->ch == 1u)
for(int k = 1; k < histogram_stats->bins_count; k++)
m[0] = MAX(m[0], hist[k]);
else
for(int k = 4; k < 4 * histogram_stats->bins_count; k += 4)
for_each_channel(ch,aligned(hist:64) aligned(m:16))
m[ch] = MAX(m[ch], hist[k+ch]);
}
else
// raw max not implemented, as is only seen in exposure
Expand Down
2 changes: 1 addition & 1 deletion src/develop/pixelpipe.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ typedef struct dt_dev_histogram_stats_t
size_t buf_size;
/** count of pixels sampled during histogram capture. */
uint32_t pixels;
/** count of channels: 1 for RAW, 3 for rgb/Lab. */
/** count of channels: 1 for RAW/luma, 3 for rgb/Lab. */
uint32_t ch;
} dt_dev_histogram_stats_t;

Expand Down
47 changes: 25 additions & 22 deletions src/libs/histogram.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ static void _lib_histogram_get_sector_angles(dt_lib_module_t *self,
float *angles,
int *n);

static const gchar *rgb_names[DT_SCOPES_RGB_N] =
static const gchar *channel_names[DT_SCOPES_CH_N] =
{ N_("red"),
N_("green"),
N_("blue")
N_("blue"),
};

const char *name(dt_lib_module_t *self)
Expand Down Expand Up @@ -442,7 +442,7 @@ static void _mode_toggle(GtkWidget *button, dt_scopes_t *s)
lib_histogram_update_tooltip(s);

dt_scopes_call(prior_mode, mode_leave);
gtk_widget_set_visible(s->button_box_rgb,
gtk_widget_set_visible(s->button_box_channels,
dt_scopes_func_exists(s->cur_mode, draw_scope_channels));
dt_scopes_call(s->cur_mode, update_buttons);
dt_scopes_call(s->cur_mode, mode_enter);
Expand All @@ -457,12 +457,12 @@ static void _mode_toggle(GtkWidget *button, dt_scopes_t *s)

static void _channel_toggle(GtkWidget *button, dt_scopes_t *s)
{
for(int i = 0; i < DT_SCOPES_RGB_N; i++)
if(s->channel_buttons[i] == button)
for(int i = 0; i < DT_SCOPES_CH_N; i++)
if(s->channel_btns[i] == button)
{
char conf[48];
g_snprintf(conf, sizeof(conf),
"plugins/darkroom/histogram/show_%s", rgb_names[i]);
"plugins/darkroom/histogram/show_%s", channel_names[i]);
s->channels[i]
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
dt_conf_set_bool(conf, s->channels[i]);
Expand Down Expand Up @@ -537,7 +537,7 @@ static void _eventbox_enter_notify_callback(GtkEventControllerMotion *controller
if(s->cur_mode != &s->modes[i])
dt_scopes_call(&s->modes[i], mode_leave);
dt_scopes_call(s->cur_mode, mode_enter);
gtk_widget_set_visible(s->button_box_rgb,
gtk_widget_set_visible(s->button_box_channels,
dt_scopes_func_exists(s->cur_mode, draw_scope_channels));
gtk_widget_show(s->button_box_left);
gtk_widget_show(s->button_box_right);
Expand Down Expand Up @@ -675,11 +675,11 @@ void gui_init(dt_lib_module_t *self)

dt_pthread_mutex_init(&s->lock, NULL);

s->channels[DT_SCOPES_RGB_RED]
s->channels[DT_SCOPES_CH_RED]
= dt_conf_get_bool("plugins/darkroom/histogram/show_red");
s->channels[DT_SCOPES_RGB_GREEN]
s->channels[DT_SCOPES_CH_GREEN]
= dt_conf_get_bool("plugins/darkroom/histogram/show_green");
s->channels[DT_SCOPES_RGB_BLUE]
s->channels[DT_SCOPES_CH_BLUE]
= dt_conf_get_bool("plugins/darkroom/histogram/show_blue");

// proxy functions and data so that pixelpipe or tether can
Expand Down Expand Up @@ -804,28 +804,31 @@ void gui_init(dt_lib_module_t *self)
GDK_KEY_H, GDK_CONTROL_MASK | GDK_SHIFT_MASK);

// RGB channel buttons
s->button_box_rgb = dt_gui_hbox();
gtk_widget_set_valign(s->button_box_rgb, GTK_ALIGN_CENTER);
gtk_widget_set_halign(s->button_box_rgb, GTK_ALIGN_CENTER);
// red/green/blue channel on/off
for(int i=DT_SCOPES_RGB_RED; i < DT_SCOPES_RGB_N; i++)
s->button_box_channels = dt_gui_hbox();
gtk_widget_set_valign(s->button_box_channels, GTK_ALIGN_CENTER);
gtk_widget_set_halign(s->button_box_channels, GTK_ALIGN_CENTER);
// red/green/blue on/off
for(int i=DT_SCOPES_CH_RED; i < DT_SCOPES_CH_N; i++)
{
g_autofree char *name = g_strdup_printf("%s-channel-button", rgb_names[i]);
g_autofree char *tip = g_strdup_printf(_("toggle %s channel"), _(rgb_names[i]));
g_autofree char *name = g_strdup_printf("%s-channel-button", channel_names[i]);
g_autofree char *tip = g_strdup_printf(_("toggle %s channel"), _(channel_names[i]));
GtkWidget *btn = dtgtk_togglebutton_new(dtgtk_cairo_paint_color,
CPF_NONE, NULL);
dt_gui_add_class(btn, "rgb_toggle");
gtk_widget_set_name(btn, name);
gtk_widget_set_tooltip_text(btn, tip);
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(btn),
s->channels[i]);
dt_action_define(dark, N_("toggle colors"), rgb_names[i], btn, &dt_action_def_toggle);
dt_gui_box_add(s->button_box_rgb, btn);
dt_action_define(dark, N_("toggle colors"), channel_names[i], btn, &dt_action_def_toggle);
g_signal_connect(G_OBJECT(btn), "toggled", G_CALLBACK(_channel_toggle), s);
s->channel_buttons[i] = btn;
s->channel_btns[i] = btn;
}
// RGB channels are always rightmost
dt_gui_box_add(s->button_box_right, s->button_box_rgb);
dt_gui_box_add(s->button_box_channels,
s->channel_btns[DT_SCOPES_CH_RED],
s->channel_btns[DT_SCOPES_CH_GREEN],
s->channel_btns[DT_SCOPES_CH_BLUE]);
// channels are always rightmost
dt_gui_box_add(s->button_box_right, s->button_box_channels);

for(dt_scopes_mode_type_t i = 0; i < DT_SCOPES_MODE_N; i++)
{
Expand Down
24 changes: 12 additions & 12 deletions src/libs/scopes.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ typedef enum dt_scopes_highlight_t
DT_SCOPES_HIGHLIGHT_EXPOSURE
} dt_scopes_highlight_t;

typedef enum dt_scopes_rgb_t
typedef enum dt_scopes_channels_t
{
DT_SCOPES_RGB_RED = 0,
DT_SCOPES_RGB_GREEN,
DT_SCOPES_RGB_BLUE,
DT_SCOPES_RGB_N // needs to be the last one
} dt_scopes_rgb_t;
DT_SCOPES_CH_RED = 0,
DT_SCOPES_CH_GREEN,
DT_SCOPES_CH_BLUE,
DT_SCOPES_CH_N // needs to be the last one
} dt_scopes_channels_t;

typedef gboolean scopes_channels_t[DT_SCOPES_RGB_N];
typedef gboolean dt_scopes_channels_list_t[DT_SCOPES_CH_N];

struct dt_scopes_t;
struct dt_scopes_mode_t;
Expand All @@ -66,7 +66,7 @@ typedef struct dt_scopes_functions_t
const float *const input,
// FIXME: should ROI by dt_histogram_roi_t or another type?
dt_histogram_roi_t *const roi,
const dt_iop_order_iccprofile_info_t *vs_prof);
const dt_iop_order_iccprofile_info_t *profile);
// FIXME: do want a proper clear function or just tag as not up to date?
void (*clear)(struct dt_scopes_mode_t *const self);
void (*draw_bkgd)(const struct dt_scopes_mode_t *const self,
Expand All @@ -90,7 +90,7 @@ typedef struct dt_scopes_functions_t
cairo_t *cr,
const int width,
const int height,
const scopes_channels_t channels);
const dt_scopes_channels_list_t channels);
// FIXME: rename to something more sensible
dt_scopes_highlight_t (*get_highlight)(const struct dt_scopes_mode_t *const self,
const double posx,
Expand Down Expand Up @@ -140,16 +140,16 @@ typedef struct dt_scopes_t
dt_scopes_mode_t modes[DT_SCOPES_MODE_N]; // all available modes
int update_counter; // most recent pixelpipe vs mode data
dt_scopes_highlight_t highlight; // depends on mouse position
scopes_channels_t channels; // display state chosen by RGB buttons
dt_scopes_channels_list_t channels; // RGB channels to display
gboolean dragging; // to block motion handling during drag
gdouble last_offset_x, last_offset_y; // for drag handling
// UI elements
GtkWidget *overlay; // GtkOverlay -- scope and buttons
GtkWidget *button_box_left; // GtkBox -- scope mode buttons
GtkWidget *button_box_split; // GtkBox -- option buttons for left scope
GtkWidget *button_box_right; // GtkBox -- option buttons for main scope
GtkWidget *button_box_rgb; // GtkBox -- RGB channels buttons
GtkWidget *channel_buttons[DT_SCOPES_RGB_N]; // Array of GtkToggleButton -- RGB channels
GtkWidget *button_box_channels; // GtkBox -- RGB channel buttons
GtkWidget *channel_btns[DT_SCOPES_CH_N]; // Array of GtkToggleButton -- channels
GtkWidget *scope_draw; // GtkDrawingArea -- scope & resize
// for access to data during process/draw
dt_pthread_mutex_t lock;
Expand Down
Loading