add brightness and contrast (#396)
* 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 <finticemo@gmail.com> Co-authored-by: NRK <nrk@disroot.org> Reviewed-on: https://codeberg.org/nsxiv/nsxiv/pulls/396 Reviewed-by: NRK <nrk@disroot.org> Reviewed-by: TAAPArthur <taaparthur@noreply.codeberg.org> Co-authored-by: Berke Kocaoğlu <kberke@metu.edu.tr> Co-committed-by: Berke Kocaoğlu <kberke@metu.edu.tr>
This commit is contained in:
parent
9cb9a54944
commit
95bc9b463b
23
commands.c
23
commands.c
|
@ -222,15 +222,28 @@ bool cg_navigate_marked(arg_t n)
|
||||||
return navigate_to(new);
|
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 (!img_change_color_modifier(&img, d * (prefix > 0 ? prefix : 1), target))
|
||||||
|
return false;
|
||||||
if (mode == MODE_THUMB)
|
if (mode == MODE_THUMB)
|
||||||
tns.dirty = true;
|
tns.dirty = true;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
}
|
||||||
return false;
|
|
||||||
}
|
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)
|
bool ci_navigate(arg_t n)
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
/* global */
|
/* global */
|
||||||
bool cg_change_gamma(arg_t);
|
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_first(arg_t);
|
||||||
bool cg_mark_range(arg_t);
|
bool cg_mark_range(arg_t);
|
||||||
bool cg_n_or_last(arg_t);
|
bool cg_n_or_last(arg_t);
|
||||||
|
@ -47,6 +49,8 @@ bool ct_select(arg_t);
|
||||||
#ifdef INCLUDE_MAPPINGS_CONFIG
|
#ifdef INCLUDE_MAPPINGS_CONFIG
|
||||||
/* global */
|
/* global */
|
||||||
#define g_change_gamma { cg_change_gamma, MODE_ALL }
|
#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_first { cg_first, MODE_ALL }
|
||||||
#define g_mark_range { cg_mark_range, MODE_ALL }
|
#define g_mark_range { cg_mark_range, MODE_ALL }
|
||||||
#define g_n_or_last { cg_n_or_last, MODE_ALL }
|
#define g_n_or_last { cg_n_or_last, MODE_ALL }
|
||||||
|
|
13
config.def.h
13
config.def.h
|
@ -33,11 +33,14 @@ static const float zoom_levels[] = {
|
||||||
/* default slideshow delay (in sec, overwritten via -S option): */
|
/* default slideshow delay (in sec, overwritten via -S option): */
|
||||||
static const int SLIDESHOW_DELAY = 5;
|
static const int SLIDESHOW_DELAY = 5;
|
||||||
|
|
||||||
/* gamma correction: the user-visible ranges [-GAMMA_RANGE, 0] and
|
/* color correction: the user-visible ranges [-CC_STEPS, 0] and
|
||||||
* (0, GAMMA_RANGE] are mapped to the ranges [0, 1], and (1, GAMMA_MAX].
|
* (0, CC_STEPS] are mapped to the ranges [0, 1], and (1, *_MAX].
|
||||||
|
* Higher step count will have higher granulairy.
|
||||||
*/
|
*/
|
||||||
|
static const int CC_STEPS = 32;
|
||||||
static const double GAMMA_MAX = 10.0;
|
static const double GAMMA_MAX = 10.0;
|
||||||
static const int GAMMA_RANGE = 32;
|
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 */
|
/* command i_scroll pans image 1/PAN_FRACTION of screen width/height */
|
||||||
static const int PAN_FRACTION = 5;
|
static const int PAN_FRACTION = 5;
|
||||||
|
@ -118,6 +121,10 @@ static const keymap_t keys[] = {
|
||||||
{ 0, XK_braceleft, g_change_gamma, -1 },
|
{ 0, XK_braceleft, g_change_gamma, -1 },
|
||||||
{ 0, XK_braceright, g_change_gamma, +1 },
|
{ 0, XK_braceright, g_change_gamma, +1 },
|
||||||
{ ControlMask, XK_g, g_change_gamma, 0 },
|
{ 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_h, t_move_sel, DIR_LEFT },
|
||||||
{ 0, XK_Left, t_move_sel, DIR_LEFT },
|
{ 0, XK_Left, t_move_sel, DIR_LEFT },
|
||||||
|
|
20
etc/nsxiv.1
20
etc/nsxiv.1
|
@ -209,6 +209,26 @@ steps.
|
||||||
.TP
|
.TP
|
||||||
.B Ctrl-g
|
.B Ctrl-g
|
||||||
Reset gamma correction.
|
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
|
.SS Thumbnail mode
|
||||||
The following keyboard commands are only available in thumbnail mode:
|
The following keyboard commands are only available in thumbnail mode:
|
||||||
.TP
|
.TP
|
||||||
|
|
50
image.c
50
image.c
|
@ -90,7 +90,9 @@ void img_init(img_t *img, win_t *win)
|
||||||
|
|
||||||
img->cmod = imlib_create_color_modifier();
|
img->cmod = imlib_create_color_modifier();
|
||||||
imlib_context_set_color_modifier(img->cmod);
|
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.on = options->slideshow > 0;
|
||||||
img->ss.delay = options->slideshow > 0 ? options->slideshow : SLIDESHOW_DELAY * 10u;
|
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;
|
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
|
return offset + d * ((d <= 0 ? 1.0 : (max - 1.0)) / CC_STEPS);
|
||||||
* d = 0: reset gamma
|
}
|
||||||
* d > 0: increase gamma
|
|
||||||
*/
|
|
||||||
int gamma;
|
|
||||||
double range;
|
|
||||||
|
|
||||||
if (d == 0)
|
void img_update_color_modifiers(img_t *img)
|
||||||
gamma = 0;
|
{
|
||||||
else
|
assert(imlib_context_get_color_modifier() == img->cmod);
|
||||||
gamma = MIN(MAX(img->gamma + d, -GAMMA_RANGE), GAMMA_RANGE);
|
|
||||||
|
|
||||||
if (img->gamma != gamma) {
|
|
||||||
imlib_reset_color_modifier();
|
imlib_reset_color_modifier();
|
||||||
if (gamma) {
|
|
||||||
range = gamma <= 0 ? 1.0 : GAMMA_MAX - 1.0;
|
if (img->gamma != 0)
|
||||||
imlib_modify_color_modifier_gamma(1.0 + gamma * (range / GAMMA_RANGE));
|
imlib_modify_color_modifier_gamma(steps_to_range(img->gamma, GAMMA_MAX, 1.0));
|
||||||
}
|
if (img->brightness != 0)
|
||||||
img->gamma = gamma;
|
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;
|
img->dirty = true;
|
||||||
return true;
|
}
|
||||||
} else {
|
|
||||||
|
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;
|
return false;
|
||||||
}
|
|
||||||
|
*target = value;
|
||||||
|
img_update_color_modifiers(img);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool img_frame_goto(img_t *img, int n)
|
static bool img_frame_goto(img_t *img, int n)
|
||||||
|
|
4
main.c
4
main.c
|
@ -444,6 +444,10 @@ static void update_info(void)
|
||||||
}
|
}
|
||||||
if (img.gamma)
|
if (img.gamma)
|
||||||
bar_put(r, "G%+d" BAR_SEP, 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));
|
bar_put(r, "%3d%%" BAR_SEP, (int) (img.zoom * 100.0));
|
||||||
if (img.multi.cnt > 0) {
|
if (img.multi.cnt > 0) {
|
||||||
for (fn = 0, i = img.multi.cnt; i > 0; fn++, i /= 10);
|
for (fn = 0, i = img.multi.cnt; i > 0; fn++, i /= 10);
|
||||||
|
|
5
nsxiv.h
5
nsxiv.h
|
@ -181,6 +181,8 @@ struct img {
|
||||||
|
|
||||||
Imlib_Color_Modifier cmod;
|
Imlib_Color_Modifier cmod;
|
||||||
int gamma;
|
int gamma;
|
||||||
|
int brightness;
|
||||||
|
int contrast;
|
||||||
|
|
||||||
scalemode_t scalemode;
|
scalemode_t scalemode;
|
||||||
float zoom;
|
float zoom;
|
||||||
|
@ -212,7 +214,8 @@ bool img_pan_edge(img_t*, direction_t);
|
||||||
void img_rotate(img_t*, degree_t);
|
void img_rotate(img_t*, degree_t);
|
||||||
void img_flip(img_t*, flipdir_t);
|
void img_flip(img_t*, flipdir_t);
|
||||||
void img_toggle_antialias(img_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_navigate(img_t*, int);
|
||||||
bool img_frame_animate(img_t*);
|
bool img_frame_animate(img_t*);
|
||||||
Imlib_Image img_open(const fileinfo_t*);
|
Imlib_Image img_open(const fileinfo_t*);
|
||||||
|
|
Loading…
Reference in a new issue