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:
		
							
								
								
									
										27
									
								
								commands.c
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								commands.c
									
									
									
									
									
								
							| @@ -222,15 +222,28 @@ bool cg_navigate_marked(arg_t n) | |||||||
| 	return navigate_to(new); | 	return navigate_to(new); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static bool change_color_modifier(arg_t d, int *target) | ||||||
|  | { | ||||||
|  | 	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) | bool cg_change_gamma(arg_t d) | ||||||
| { | { | ||||||
| 	if (img_change_gamma(&img, d * (prefix > 0 ? prefix : 1))) { | 	return change_color_modifier(d, &img.gamma); | ||||||
| 		if (mode == MODE_THUMB) | } | ||||||
| 			tns.dirty = true; |  | ||||||
| 		return true; | bool cg_change_brightness(arg_t d) | ||||||
| 	} else { | { | ||||||
| 		return false; | 	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 } | ||||||
|   | |||||||
							
								
								
									
										15
									
								
								config.def.h
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								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 double GAMMA_MAX   = 10.0; | static const int    CC_STEPS        = 32; | ||||||
| static const int    GAMMA_RANGE = 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 */ | /* 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 | ||||||
|   | |||||||
							
								
								
									
										52
									
								
								image.c
									
									
									
									
									
								
							
							
						
						
									
										52
									
								
								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); | 	imlib_reset_color_modifier(); | ||||||
|  |  | ||||||
| 	if (img->gamma != gamma) { | 	if (img->gamma != 0) | ||||||
| 		imlib_reset_color_modifier(); | 		imlib_modify_color_modifier_gamma(steps_to_range(img->gamma, GAMMA_MAX, 1.0)); | ||||||
| 		if (gamma) { | 	if (img->brightness != 0) | ||||||
| 			range = gamma <= 0 ? 1.0 : GAMMA_MAX - 1.0; | 		imlib_modify_color_modifier_brightness(steps_to_range(img->brightness, BRIGHTNESS_MAX, 0.0)); | ||||||
| 			imlib_modify_color_modifier_gamma(1.0 + gamma * (range / GAMMA_RANGE)); | 	if (img->contrast != 0) | ||||||
| 		} | 		imlib_modify_color_modifier_contrast(steps_to_range(img->contrast, CONTRAST_MAX, 1.0)); | ||||||
| 		img->gamma = gamma; |  | ||||||
| 		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*); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user