From 95bc9b463b87236d30d86626e1052e6979d6510f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Berke=20Kocao=C4=9Flu?= Date: Thu, 22 Dec 2022 11:21:40 +0000 Subject: [PATCH] add brightness and contrast (#396) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Imlib2 supports modifying gamma, brightness and contrast directly while sxiv only supports gamma. Makes sense to extend it to brightness and contrast as well. * Since color corrections need to be aware of each other, they have been refactored into one centralized function. * This also makes the code more hackable as it makes it easier to add more color correction functions without them interfering with each other. Co-authored-by: 0ion9 Co-authored-by: NRK Reviewed-on: https://codeberg.org/nsxiv/nsxiv/pulls/396 Reviewed-by: NRK Reviewed-by: TAAPArthur Co-authored-by: Berke Kocaoğlu Co-committed-by: Berke Kocaoğlu --- commands.c | 27 ++++++++++++++++++++------- commands.h | 4 ++++ config.def.h | 15 +++++++++++---- etc/nsxiv.1 | 20 ++++++++++++++++++++ image.c | 52 +++++++++++++++++++++++++++++----------------------- main.c | 4 ++++ nsxiv.h | 5 ++++- 7 files changed, 92 insertions(+), 35 deletions(-) diff --git a/commands.c b/commands.c index 3cc921c..1ba0363 100644 --- a/commands.c +++ b/commands.c @@ -222,15 +222,28 @@ bool cg_navigate_marked(arg_t n) return navigate_to(new); } -bool cg_change_gamma(arg_t d) +static bool change_color_modifier(arg_t d, int *target) { - if (img_change_gamma(&img, d * (prefix > 0 ? prefix : 1))) { - if (mode == MODE_THUMB) - tns.dirty = true; - return true; - } else { + if (!img_change_color_modifier(&img, d * (prefix > 0 ? prefix : 1), target)) return false; - } + if (mode == MODE_THUMB) + tns.dirty = true; + return true; +} + +bool cg_change_gamma(arg_t d) +{ + return change_color_modifier(d, &img.gamma); +} + +bool cg_change_brightness(arg_t d) +{ + return change_color_modifier(d, &img.brightness); +} + +bool cg_change_contrast(arg_t d) +{ + return change_color_modifier(d, &img.contrast); } bool ci_navigate(arg_t n) diff --git a/commands.h b/commands.h index c4c3973..76b1330 100644 --- a/commands.h +++ b/commands.h @@ -4,6 +4,8 @@ /* global */ bool cg_change_gamma(arg_t); +bool cg_change_brightness(arg_t); +bool cg_change_contrast(arg_t); bool cg_first(arg_t); bool cg_mark_range(arg_t); bool cg_n_or_last(arg_t); @@ -47,6 +49,8 @@ bool ct_select(arg_t); #ifdef INCLUDE_MAPPINGS_CONFIG /* global */ #define g_change_gamma { cg_change_gamma, MODE_ALL } +#define g_change_brightness { cg_change_brightness, MODE_ALL } +#define g_change_contrast { cg_change_contrast, MODE_ALL } #define g_first { cg_first, MODE_ALL } #define g_mark_range { cg_mark_range, MODE_ALL } #define g_n_or_last { cg_n_or_last, MODE_ALL } diff --git a/config.def.h b/config.def.h index 00f1f22..198c696 100644 --- a/config.def.h +++ b/config.def.h @@ -33,11 +33,14 @@ static const float zoom_levels[] = { /* default slideshow delay (in sec, overwritten via -S option): */ static const int SLIDESHOW_DELAY = 5; -/* gamma correction: the user-visible ranges [-GAMMA_RANGE, 0] and - * (0, GAMMA_RANGE] are mapped to the ranges [0, 1], and (1, GAMMA_MAX]. +/* color correction: the user-visible ranges [-CC_STEPS, 0] and + * (0, CC_STEPS] are mapped to the ranges [0, 1], and (1, *_MAX]. + * Higher step count will have higher granulairy. */ -static const double GAMMA_MAX = 10.0; -static const int GAMMA_RANGE = 32; +static const int CC_STEPS = 32; +static const double GAMMA_MAX = 10.0; +static const double BRIGHTNESS_MAX = 2.0; +static const double CONTRAST_MAX = 4.0; /* command i_scroll pans image 1/PAN_FRACTION of screen width/height */ static const int PAN_FRACTION = 5; @@ -118,6 +121,10 @@ static const keymap_t keys[] = { { 0, XK_braceleft, g_change_gamma, -1 }, { 0, XK_braceright, g_change_gamma, +1 }, { ControlMask, XK_g, g_change_gamma, 0 }, + { ControlMask, XK_bracketright, g_change_brightness, +1 }, + { ControlMask, XK_bracketleft, g_change_brightness, -1 }, + { 0, XK_parenleft, g_change_contrast, -1 }, + { 0, XK_parenright, g_change_contrast, +1 }, { 0, XK_h, t_move_sel, DIR_LEFT }, { 0, XK_Left, t_move_sel, DIR_LEFT }, diff --git a/etc/nsxiv.1 b/etc/nsxiv.1 index 3109075..57a6c39 100644 --- a/etc/nsxiv.1 +++ b/etc/nsxiv.1 @@ -209,6 +209,26 @@ steps. .TP .B Ctrl-g Reset gamma correction. +.TP +.B [ +Decrease brightness correction by +.I count +steps. +.TP +.B ] +Increase brightness correction by +.I count +steps. +.TP +.B ( +Decrease contrast by +.I count +steps. +.TP +.B ) +Increase contrast by +.I count +steps. .SS Thumbnail mode The following keyboard commands are only available in thumbnail mode: .TP diff --git a/image.c b/image.c index 2da4817..418eb60 100644 --- a/image.c +++ b/image.c @@ -90,7 +90,9 @@ void img_init(img_t *img, win_t *win) img->cmod = imlib_create_color_modifier(); imlib_context_set_color_modifier(img->cmod); - img_change_gamma(img, options->gamma); + img->brightness = 0; + img->contrast = 0; + img_change_color_modifier(img, options->gamma, &img->gamma); img->ss.on = options->slideshow > 0; img->ss.delay = options->slideshow > 0 ? options->slideshow : SLIDESHOW_DELAY * 10u; @@ -840,32 +842,36 @@ void img_toggle_antialias(img_t *img) img->dirty = true; } -bool img_change_gamma(img_t *img, int d) +static double steps_to_range(int d, double max, double offset) { - /* d < 0: decrease gamma - * d = 0: reset gamma - * d > 0: increase gamma - */ - int gamma; - double range; + return offset + d * ((d <= 0 ? 1.0 : (max - 1.0)) / CC_STEPS); +} - if (d == 0) - gamma = 0; - else - gamma = MIN(MAX(img->gamma + d, -GAMMA_RANGE), GAMMA_RANGE); +void img_update_color_modifiers(img_t *img) +{ + assert(imlib_context_get_color_modifier() == img->cmod); + imlib_reset_color_modifier(); - if (img->gamma != gamma) { - imlib_reset_color_modifier(); - if (gamma) { - range = gamma <= 0 ? 1.0 : GAMMA_MAX - 1.0; - imlib_modify_color_modifier_gamma(1.0 + gamma * (range / GAMMA_RANGE)); - } - img->gamma = gamma; - img->dirty = true; - return true; - } else { + if (img->gamma != 0) + imlib_modify_color_modifier_gamma(steps_to_range(img->gamma, GAMMA_MAX, 1.0)); + if (img->brightness != 0) + imlib_modify_color_modifier_brightness(steps_to_range(img->brightness, BRIGHTNESS_MAX, 0.0)); + if (img->contrast != 0) + imlib_modify_color_modifier_contrast(steps_to_range(img->contrast, CONTRAST_MAX, 1.0)); + + img->dirty = true; +} + +bool img_change_color_modifier(img_t *img, int d, int *target) +{ + int value = d == 0 ? 0 : MIN(MAX(*target + d, -CC_STEPS), CC_STEPS); + + if (*target == value) return false; - } + + *target = value; + img_update_color_modifiers(img); + return true; } static bool img_frame_goto(img_t *img, int n) diff --git a/main.c b/main.c index 44f8eb9..8ee5b9d 100644 --- a/main.c +++ b/main.c @@ -444,6 +444,10 @@ static void update_info(void) } if (img.gamma) bar_put(r, "G%+d" BAR_SEP, img.gamma); + if (img.brightness) + bar_put(r, "B%+d" BAR_SEP, img.brightness); + if (img.contrast) + bar_put(r, "C%+d" BAR_SEP, img.contrast); bar_put(r, "%3d%%" BAR_SEP, (int) (img.zoom * 100.0)); if (img.multi.cnt > 0) { for (fn = 0, i = img.multi.cnt; i > 0; fn++, i /= 10); diff --git a/nsxiv.h b/nsxiv.h index 7bf7e25..33a2bde 100644 --- a/nsxiv.h +++ b/nsxiv.h @@ -181,6 +181,8 @@ struct img { Imlib_Color_Modifier cmod; int gamma; + int brightness; + int contrast; scalemode_t scalemode; float zoom; @@ -212,7 +214,8 @@ bool img_pan_edge(img_t*, direction_t); void img_rotate(img_t*, degree_t); void img_flip(img_t*, flipdir_t); void img_toggle_antialias(img_t*); -bool img_change_gamma(img_t*, int); +void img_update_color_modifiers(img_t*); +bool img_change_color_modifier(img_t*, int, int*); bool img_frame_navigate(img_t*, int); bool img_frame_animate(img_t*); Imlib_Image img_open(const fileinfo_t*);