From 9a06b5f61ed46e1d2e28a28d4af1c8aa7ed74f25 Mon Sep 17 00:00:00 2001 From: Sebastian Ramacher Date: Tue, 30 Sep 2014 19:45:07 +0200 Subject: [PATCH] Add option to ignore images while recoloring Ideally we would handle this differently. See the TODO entry in the render function. But the patch is a start. Thanks to carlos for the patch. Closes: #398 Signed-off-by: Sebastian Ramacher --- callbacks.c | 17 ++++++++++++ callbacks.h | 11 ++++++++ config.c | 2 ++ render.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++-- render.h | 13 +++++++++ zathura.c | 2 ++ 6 files changed, 122 insertions(+), 3 deletions(-) diff --git a/callbacks.c b/callbacks.c index f00667a..c6d0a83 100644 --- a/callbacks.c +++ b/callbacks.c @@ -510,6 +510,23 @@ cb_setting_recolor_keep_hue_change(girara_session_t* session, const char* name, } } +void +cb_setting_recolor_keep_reverse_video_change(girara_session_t* session, const char* name, + girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data)) +{ + g_return_if_fail(value != NULL); + g_return_if_fail(session != NULL); + g_return_if_fail(session->global.data != NULL); + g_return_if_fail(name != NULL); + zathura_t* zathura = session->global.data; + + const bool bool_value = *((bool*) value); + + if (zathura->sync.render_thread != NULL && zathura_renderer_recolor_reverse_video_enabled(zathura->sync.render_thread) != bool_value) { + zathura_renderer_enable_recolor_reverse_video(zathura->sync.render_thread, bool_value); + render_all(zathura); + } +} bool cb_unknown_command(girara_session_t* session, const char* input) diff --git a/callbacks.h b/callbacks.h index 04b1fa0..cfdd923 100644 --- a/callbacks.h +++ b/callbacks.h @@ -176,6 +176,17 @@ void cb_setting_recolor_change(girara_session_t* session, const char* name, void cb_setting_recolor_keep_hue_change(girara_session_t* session, const char* name, girara_setting_type_t type, void* value, void* data); +/** + * Emitted when the 'recolor-reverse-video' setting is changed + * + * @param session Girara session + * @param name Name of the setting ("recolor") + * @param type Type of the setting (BOOLEAN) + * @param value New value + * @param data Custom data + */ +void cb_setting_recolor_keep_reverse_video_change(girara_session_t* session, + const char* name, girara_setting_type_t type, void* value, void* data); /** * Unknown command handler which is used to handle the strict numeric goto diff --git a/config.c b/config.c index d298ddc..8d38287 100644 --- a/config.c +++ b/config.c @@ -186,6 +186,8 @@ config_load_default(zathura_t* zathura) bool_value = false; girara_setting_add(gsession, "recolor-keephue", &bool_value, BOOLEAN, false, _("When recoloring keep original hue and adjust lightness only"), cb_setting_recolor_keep_hue_change, NULL); bool_value = false; + girara_setting_add(gsession, "recolor-reverse-video", &bool_value, BOOLEAN, false, _("When recoloring keep original image colors"), cb_setting_recolor_keep_reverse_video_change, NULL); + bool_value = false; girara_setting_add(gsession, "scroll-wrap", &bool_value, BOOLEAN, false, _("Wrap scrolling"), NULL, NULL); bool_value = false; girara_setting_add(gsession, "scroll-page-aware", &bool_value, BOOLEAN, false, _("Page aware scrolling"), NULL, NULL); diff --git a/render.c b/render.c index 67193f3..e291289 100644 --- a/render.c +++ b/render.c @@ -43,6 +43,7 @@ typedef struct private_s { struct { bool enabled; bool hue; + bool reverse_video; GdkRGBA light; GdkRGBA dark; @@ -107,6 +108,7 @@ zathura_renderer_init(ZathuraRenderer* renderer) /* recolor */ priv->recolor.enabled = false; priv->recolor.hue = true; + priv->recolor.reverse_video = false; /* page cache */ priv->page_cache.size = 0; @@ -336,6 +338,21 @@ zathura_renderer_enable_recolor_hue(ZathuraRenderer* renderer, bool enable) GET_PRIVATE(renderer)->recolor.hue = enable; } +bool +zathura_renderer_recolor_reverse_video_enabled(ZathuraRenderer* renderer) +{ + g_return_val_if_fail(ZATHURA_IS_RENDERER(renderer), false); + + return GET_PRIVATE(renderer)->recolor.reverse_video; +} + +void +zathura_renderer_enable_recolor_reverse_video(ZathuraRenderer* renderer, bool enable) +{ + g_return_if_fail(ZATHURA_IS_RENDERER(renderer)); + + GET_PRIVATE(renderer)->recolor.reverse_video = enable; +} void zathura_renderer_set_recolor_colors(ZathuraRenderer* renderer, const GdkRGBA* light, const GdkRGBA* dark) @@ -563,8 +580,8 @@ colorumax(const double* h, double l, double l1, double l2) } static void -recolor(private_t* priv, unsigned int page_width, unsigned int page_height, - cairo_surface_t* surface) +recolor(private_t* priv, zathura_page_t* page, unsigned int page_width, + unsigned int page_height, cairo_surface_t* surface) { /* uses a representation of a rgb color as follows: - a lightness scalar (between 0,1), which is a weighted average of r, g, b, @@ -574,6 +591,12 @@ recolor(private_t* priv, unsigned int page_width, unsigned int page_height, in the boundary of the rgb cube. */ + /* TODO: split handling of image handling off + * Ideally we would create a mask surface for the location of the images and + * we would blit the the recolored and unmodified surfaces together to get the + * same effect. + */ + const int rowstride = cairo_image_surface_get_stride(surface); unsigned char* image = cairo_image_surface_get_data(surface); @@ -591,10 +614,54 @@ recolor(private_t* priv, unsigned int page_width, unsigned int page_height, rgb2.blue - rgb1.blue }; + girara_list_t* images = NULL; + girara_list_t* rectangles = NULL; + bool found_images = false; + + /* If in reverse video mode retrieve images */ + if (priv->recolor.reverse_video == true) { + images = zathura_page_images_get(page, NULL); + found_images = (images != NULL); + + rectangles = girara_list_new(); + if (rectangles == NULL) { + found_images = false; + girara_warning("Failed to retrieve images.\n"); + } + + if (found_images == true) { + /* Get images bounding boxes */ + GIRARA_LIST_FOREACH(images, zathura_image_t*, iter, image_it) + zathura_rectangle_t* rect = g_try_malloc(sizeof(zathura_rectangle_t)); + if (rect == NULL) { + break; + } + *rect = recalc_rectangle(page, image_it->position); + girara_list_append(rectangles, rect); + GIRARA_LIST_FOREACH_END(images, zathura_image_t*, iter, image_it); + } + } + for (unsigned int y = 0; y < page_height; y++) { unsigned char* data = image + y * rowstride; for (unsigned int x = 0; x < page_width; x++, data += 4) { + /* Check if the pixel belongs to an image when in reverse video mode*/ + if (priv->recolor.reverse_video == true && found_images == true){ + bool inside_image = false; + GIRARA_LIST_FOREACH(rectangles, zathura_rectangle_t*, iter, rect_it) + if (rect_it->x1 <= x && rect_it->x2 >= x && + rect_it->y1 <= y && rect_it->y2 >= y) { + inside_image = true; + break; + } + GIRARA_LIST_FOREACH_END(rectangles, zathura_rectangle_t*, iter, rect_it); + /* If it's inside and image don't recolor */ + if (inside_image == true) { + continue; + } + } + /* Careful. data color components blue, green, red. */ const double rgb[3] = { (double) data[2] / 256., @@ -640,6 +707,13 @@ recolor(private_t* priv, unsigned int page_width, unsigned int page_height, } } + if (images != NULL) { + girara_list_free(images); + } + if (rectangles != NULL) { + girara_list_free(rectangles); + } + #undef rgb1 #undef rgb2 } @@ -708,7 +782,7 @@ render(render_job_t* job, ZathuraRenderRequest* request, ZathuraRenderer* render /* recolor */ if (priv->recolor.enabled == true) { - recolor(priv, page_width, page_height, surface); + recolor(priv, page, page_width, page_height, surface); } emit_completed_signal_t* ecs = g_try_malloc0(sizeof(emit_completed_signal_t)); diff --git a/render.h b/render.h index 016c6b2..f2ecba2 100644 --- a/render.h +++ b/render.h @@ -71,6 +71,19 @@ bool zathura_renderer_recolor_hue_enabled(ZathuraRenderer* renderer); */ void zathura_renderer_enable_recolor_hue(ZathuraRenderer* renderer, bool enable); +/** + * Return whether images should be recolored while recoloring. + * @param renderer a renderer object + * @returns true if images should be recolored, false otherwise + */ +bool zathura_renderer_recolor_reverse_video_enabled(ZathuraRenderer* renderer); +/** + * Enable/disable recoloring of images while recoloring. + * @param renderer a renderer object + * @param enable or disable images recoloring + */ +void zathura_renderer_enable_recolor_reverse_video(ZathuraRenderer* renderer, + bool enable); /** * Set light and dark colors for recoloring. * @param renderer a renderer object diff --git a/zathura.c b/zathura.c index d0b2ae3..4501fff 100644 --- a/zathura.c +++ b/zathura.c @@ -744,6 +744,8 @@ document_open(zathura_t* zathura, const char* path, const char* password, zathura_renderer_enable_recolor(zathura->sync.render_thread, recolor); girara_setting_get(zathura->ui.session, "recolor-keephue", &recolor); zathura_renderer_enable_recolor_hue(zathura->sync.render_thread, recolor); + girara_setting_get(zathura->ui.session, "recolor-reverse-video", &recolor); + zathura_renderer_enable_recolor_reverse_video(zathura->sync.render_thread, recolor); /* get view port size */ GtkAdjustment* hadjustment = gtk_scrolled_window_get_hadjustment(