Skip to content
Closed
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 @@ -3173,6 +3173,13 @@
<shortdescription>height of color balance rgb graph in per cent</shortdescription>
<longdescription>height of color balance rgb graph in per cent</longdescription>
</dtconfig>
<dtconfig>
<name>plugins/darkroom/toneequal/graphheight</name>
<type min="200" max="400">int</type>
<default>300</default>
<shortdescription>height of tone equalizer graph in per cent</shortdescription>
<longdescription>height of tone equalizer graph in per cent</longdescription>
</dtconfig>
<dtconfig>
<name>plugins/darkroom/histogram/mode</name>
<type>
Expand Down
136 changes: 90 additions & 46 deletions src/common/luminance_mask.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ typedef enum dt_iop_luminance_mask_method_t
DT_TONEEQ_LIGHTNESS, // $DESCRIPTION: "HSL lightness"
DT_TONEEQ_VALUE, // $DESCRIPTION: "HSV value / RGB max"
DT_TONEEQ_NORM_1, // $DESCRIPTION: "RGB sum"
DT_TONEEQ_NORM_2, // $DESCRIPTION: "RGB euclidean norm")
DT_TONEEQ_NORM_2, // $DESCRIPTION: "RGB euclidean norm"
DT_TONEEQ_NORM_POWER, // $DESCRIPTION: "RGB power norm"
DT_TONEEQ_GEOMEAN, // $DESCRIPTION: "RGB geometric mean"
DT_TONEEQ_LAST
DT_TONEEQ_REC709W, // $DESCRIPTION: "Rec. 709 weights"
DT_TONEEQ_CUSTOM, // $DESCRIPTION: "Custom"
DT_TONEEQ_LAST,
} dt_iop_luminance_mask_method_t;

/**
Expand Down Expand Up @@ -78,11 +80,9 @@ static float linear_contrast(const float pixel, const float fulcrum, const float

DT_OMP_DECLARE_SIMD(aligned(image, luminance:64) uniform(image, luminance))
__DT_CLONE_TARGETS__
static void pixel_rgb_mean(const float *const restrict image,
static float pixel_rgb_mean(const float *const restrict image,
float *const restrict luminance,
const size_t k,
const float exposure_boost,
const float fulcrum, const float contrast_boost)
const size_t k)
{
// mean(RGB) is the intensity

Expand All @@ -92,67 +92,59 @@ static void pixel_rgb_mean(const float *const restrict image,
for(int c = 0; c < 3; ++c)
lum += image[k + c];

luminance[k / 4] = linear_contrast(exposure_boost * lum / 3.0f, fulcrum, contrast_boost);
return lum / 3.0f;
}


DT_OMP_DECLARE_SIMD(aligned(image, luminance:64) uniform(image, luminance))
__DT_CLONE_TARGETS__
static void pixel_rgb_value(const float *const restrict image,
static float pixel_rgb_value(const float *const restrict image,
float *const restrict luminance,
const size_t k,
const float exposure_boost,
const float fulcrum, const float contrast_boost)
const size_t k)
{
// max(RGB) is equivalent to HSV value

const float lum = exposure_boost * MAX(MAX(image[k], image[k + 1]), image[k + 2]);
luminance[k / 4] = linear_contrast(lum, fulcrum, contrast_boost);
const float lum = MAX(MAX(image[k], image[k + 1]), image[k + 2]);
return lum;
}


DT_OMP_DECLARE_SIMD(aligned(image, luminance:64) uniform(image, luminance))
__DT_CLONE_TARGETS__
static void pixel_rgb_lightness(const float *const restrict image,
static float pixel_rgb_lightness(const float *const restrict image,
float *const restrict luminance,
const size_t k,
const float exposure_boost,
const float fulcrum, const float contrast_boost)
const size_t k)
{
// (max(RGB) + min(RGB)) / 2 is equivalent to HSL lightness

const float max_rgb = MAX(MAX(image[k], image[k + 1]), image[k + 2]);
const float min_rgb = MIN(MIN(image[k], image[k + 1]), image[k + 2]);
luminance[k / 4] = linear_contrast(exposure_boost * (max_rgb + min_rgb) / 2.0f, fulcrum, contrast_boost);
return (max_rgb + min_rgb) / 2.0f;
}

DT_OMP_DECLARE_SIMD(aligned(image, luminance:64) uniform(image, luminance))
__DT_CLONE_TARGETS__
static void pixel_rgb_norm_1(const float *const restrict image,
static float pixel_rgb_norm_1(const float *const restrict image,
float *const restrict luminance,
const size_t k,
const float exposure_boost,
const float fulcrum, const float contrast_boost)
const size_t k)
{
// vector norm L1

float lum = 0.0f;

DT_OMP_SIMD(reduction(+:lum) aligned(image:64))
for(int c = 0; c < 3; ++c)
lum += fabsf(image[k + c]);
DT_OMP_SIMD(reduction(+:lum) aligned(image:64))
for(int c = 0; c < 3; ++c)
lum += fabsf(image[k + c]);

luminance[k / 4] = linear_contrast(exposure_boost * lum, fulcrum, contrast_boost);
return lum;
}


DT_OMP_DECLARE_SIMD(aligned(image, luminance:64) uniform(image, luminance))
__DT_CLONE_TARGETS__
static void pixel_rgb_norm_2(const float *const restrict image,
static float pixel_rgb_norm_2(const float *const restrict image,
float *const restrict luminance,
const size_t k,
const float exposure_boost,
const float fulcrum, const float contrast_boost)
const size_t k)
{
// vector norm L2 : euclidean norm

Expand All @@ -162,17 +154,15 @@ static void pixel_rgb_norm_2(const float *const restrict image,
for(int c = 0; c < 3; ++c)
result += image[k + c] * image[k + c];

luminance[k / 4] = linear_contrast(exposure_boost * sqrtf(result), fulcrum, contrast_boost);
return sqrtf(result);
}


DT_OMP_DECLARE_SIMD(aligned(image, luminance:64) uniform(image, luminance))
__DT_CLONE_TARGETS__
static void pixel_rgb_norm_power(const float *const restrict image,
static float pixel_rgb_norm_power(const float *const restrict image,
float *const restrict luminance,
const size_t k,
const float exposure_boost,
const float fulcrum, const float contrast_boost)
const size_t k)
{
// weird norm sort of perceptual. This is black magic really, but it looks good.

Expand All @@ -189,16 +179,14 @@ static void pixel_rgb_norm_power(const float *const restrict image,
denominator += RGB_square;
}

luminance[k / 4] = linear_contrast(exposure_boost * numerator / denominator, fulcrum, contrast_boost);
return numerator / denominator;
}

DT_OMP_DECLARE_SIMD(aligned(image, luminance:64) uniform(image, luminance))
__DT_CLONE_TARGETS__
static void pixel_rgb_geomean(const float *const restrict image,
static float pixel_rgb_geomean(const float *const restrict image,
float *const restrict luminance,
const size_t k,
const float exposure_boost,
const float fulcrum, const float contrast_boost)
const size_t k)
{
// geometric_mean(RGB). Kind of interesting for saturated colours (maps them to shadows)

Expand All @@ -210,7 +198,35 @@ static void pixel_rgb_geomean(const float *const restrict image,
lum *= fabsf(image[k + c]);
}

luminance[k / 4] = linear_contrast(exposure_boost * powf(lum, 1.0f / 3.0f), fulcrum, contrast_boost);
return powf(lum, 1.0f / 3.0f);
}

DT_OMP_DECLARE_SIMD(aligned(image, luminance:64) uniform(image, luminance))
__DT_CLONE_TARGETS__
static float pixel_rgb_r709w(const float *const restrict image,
float *const restrict luminance,
const size_t k)
{
// Rec. 709 weights. Green has more influence than red and blue.

const float lum = 0.2126 * image[k] + 0.7152 * image[k + 1] + 0.0722 * image[k + 2];
return lum;
}


DT_OMP_DECLARE_SIMD(aligned(image, luminance:64) uniform(image, luminance))
__DT_CLONE_TARGETS__
static float pixel_rgb_custom(const float *const restrict image,
float *const restrict luminance,
const size_t k,
const float r_weight,
const float g_weight,
const float b_weight)
{
// User can mix the greyscale image using sliders.

const float lum = MAX(MIN_FLOAT, r_weight * image[k] + g_weight * image[k + 1] + b_weight * image[k + 2]);
return lum;
}


Expand All @@ -221,11 +237,16 @@ static void pixel_rgb_geomean(const float *const restrict image,
#define LOOP(fn) \
{ \
_Pragma ("omp parallel for simd default(none) schedule(static) \
dt_omp_firstprivate(num_elem, in, out, exposure_boost, fulcrum, contrast_boost)\
dt_omp_firstprivate(num_elem, in, out, exposure_boost, fulcrum, contrast_boost, r_weight, g_weight, b_weight)\
reduction(min:min_lum) reduction(max:max_lum) \
aligned(in, out:64)" ) \
for(size_t k = 0; k < num_elem; k += 4) \
{ \
fn(in, out, k, exposure_boost, fulcrum, contrast_boost); \
const float lum = COMPUTE_LUM(fn); \
const float lum_boosted = linear_contrast(exposure_boost * lum, fulcrum, contrast_boost); \
min_lum = MIN(min_lum, lum_boosted); \
max_lum = MAX(max_lum, lum_boosted); \
out[k / 4] = lum_boosted; \
} \
break; \
}
Expand All @@ -234,7 +255,11 @@ static void pixel_rgb_geomean(const float *const restrict image,
{ \
for(size_t k = 0; k < num_elem; k += 4) \
{ \
fn(in, out, k, exposure_boost, fulcrum, contrast_boost); \
const float lum = COMPUTE_LUM(fn); \
const float lum_boosted = linear_contrast(exposure_boost * lum, fulcrum, contrast_boost); \
min_lum = MIN(min_lum, lum_boosted); \
max_lum = MAX(max_lum, lum_boosted); \
out[k / 4] = lum_boosted; \
} \
break; \
}
Expand All @@ -249,11 +274,20 @@ static inline void luminance_mask(const float *const restrict in,
const dt_iop_luminance_mask_method_t method,
const float exposure_boost,
const float fulcrum,
const float contrast_boost)
const float contrast_boost,
const float r_weight,
const float g_weight,
const float b_weight,
float *image_min_ev,
float *image_max_ev)
{
const size_t num_elem = width * height * 4;
float min_lum = INFINITY;
float max_lum = -INFINITY;

switch(method)
{
#define COMPUTE_LUM(fn) fn(in, out, k)
case DT_TONEEQ_MEAN:
LOOP(pixel_rgb_mean);

Expand All @@ -275,11 +309,21 @@ static inline void luminance_mask(const float *const restrict in,
case DT_TONEEQ_GEOMEAN:
LOOP(pixel_rgb_geomean);

case DT_TONEEQ_REC709W:
LOOP(pixel_rgb_r709w);

#undef COMPUTE_LUM
#define COMPUTE_LUM(fn) fn(in, out, k, r_weight, g_weight, b_weight)
case DT_TONEEQ_CUSTOM:
LOOP(pixel_rgb_custom);

default:
break;
}
}

*image_min_ev = log2f(min_lum);
*image_max_ev = log2f(max_lum);
}

// clang-format off
// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
Expand Down
22 changes: 22 additions & 0 deletions src/dtgtk/paint.c
Original file line number Diff line number Diff line change
Expand Up @@ -1174,6 +1174,28 @@ void dtgtk_cairo_paint_linear_scale(cairo_t *cr, const gint x, const gint y, con
FINISH
}

void dtgtk_cairo_paint_linear_scale_ignore_border(cairo_t *cr, const gint x, const gint y, const gint w, const gint h, const gint flags, void *data)
{
PREAMBLE(1, 1, 0, 0)

// Main line with reduced slope
cairo_move_to(cr, 0.0, 0.7);
cairo_line_to(cr, 1.0, 0.3);
cairo_stroke(cr);

// Small marks at edges to indicate "ignore border"
cairo_save(cr);
cairo_set_line_width(cr, 0.15);
cairo_move_to(cr, 0.0, 0.85);
cairo_line_to(cr, 0.0, 0.55);
cairo_move_to(cr, 1.0, 0.45);
cairo_line_to(cr, 1.0, 0.15);
cairo_stroke(cr);
cairo_restore(cr);

FINISH
}

void dtgtk_cairo_paint_logarithmic_scale(cairo_t *cr, const gint x, const gint y, const gint w, const gint h, gint flags, void *data)
{
PREAMBLE(1, 1, 0, 0)
Expand Down
2 changes: 2 additions & 0 deletions src/dtgtk/paint.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ void dtgtk_cairo_paint_waveform_scope(cairo_t *cr, gint x, gint y, gint w, gint
void dtgtk_cairo_paint_vectorscope(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data);
/** paint linear scale icon */
void dtgtk_cairo_paint_linear_scale(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data);
/** paint linear scale ignore border icon */
void dtgtk_cairo_paint_linear_scale_ignore_border(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data);
/** paint logarithmic scale icon */
void dtgtk_cairo_paint_logarithmic_scale(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data);
/** paint waveform overlaid icon */
Expand Down
44 changes: 44 additions & 0 deletions src/gui/draw.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,50 @@ static inline void dt_draw_grid(cairo_t *cr,
}
}

static inline void dt_draw_grid_xy(cairo_t *cr,
const int num_x,
const int num_y,
const int left,
const int top,
const int right,
const int bottom,
const gboolean border_left,
const gboolean border_top,
const gboolean border_right,
const gboolean border_bottom)
{
float width = right - left;
float height = bottom - top;

// Draw vertical lines (num_x divisions)
const int k_min_x = border_left ? 0 : 1;
const int k_max_x = border_right ? num_x : num_x - 1;

for(int k = k_min_x; k <= k_max_x; k++)
{
dt_draw_line(cr,
left + k / (float)num_x * width,
top,
left + k / (float)num_x * width,
bottom);
cairo_stroke(cr);
}

// Draw horizontal lines (num_y divisions)
const int k_min_y = border_top ? 0 : 1;
const int k_max_y = border_bottom ? num_y : num_y - 1;

for(int k = k_min_y; k <= k_max_y; k++)
{
dt_draw_line(cr,
left,
top + k / (float)num_y * height,
right,
top + k / (float)num_y * height);
cairo_stroke(cr);
}
}

static inline float dt_curve_to_mouse(const float x,
const float zoom_factor,
const float offset)
Expand Down
Loading
Loading