diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am index 802f96c..b369bed 100644 --- a/src/bin/Makefile.am +++ b/src/bin/Makefile.am @@ -30,6 +30,7 @@ ephoto_SOURCES = \ ephoto_hsv.c \ ephoto_ipc.c \ ephoto_main.c \ + ephoto_red_eye.c \ ephoto_thumb.c \ ephoto_thumb_browser.c \ ephoto_single_browser.c \ diff --git a/src/bin/ephoto.h b/src/bin/ephoto.h index 0375768..cf7170b 100644 --- a/src/bin/ephoto.h +++ b/src/bin/ephoto.h @@ -127,6 +127,8 @@ void ephoto_hsv_add(Evas_Object *main, Evas_Object *parent, Evas_Object *image); void ephoto_color_add(Evas_Object *main, Evas_Object *parent, Evas_Object *image); +void ephoto_red_eye_add(Evas_Object *main, Evas_Object *parent, + Evas_Object *image); void ephoto_filter_blur(Evas_Object *main, Evas_Object *image); void ephoto_filter_sharpen(Evas_Object *main, Evas_Object *image); void ephoto_filter_black_and_white(Evas_Object *main, Evas_Object *image); diff --git a/src/bin/ephoto_red_eye.c b/src/bin/ephoto_red_eye.c new file mode 100644 index 0000000..93dfbfb --- /dev/null +++ b/src/bin/ephoto_red_eye.c @@ -0,0 +1,254 @@ +#include "ephoto.h" + +typedef struct _Ephoto_Reye Ephoto_Reye; +struct _Ephoto_Reye +{ + Evas_Object *main; + Evas_Object *parent; + Evas_Object *image; + Evas_Object *editor; + Evas_Object *rslider; + Eina_List *handlers; + int rad; + int w, h; + unsigned int *original_im_data; + unsigned int *edited_im_data; +}; + +static int +_normalize_color(int color) +{ + if (color < 0) + return 0; + else if (color > 255) + return 255; + else + return color; +} + +static int +_mul_color_alpha(int color, int alpha) +{ + if (alpha > 0 && alpha < 255) + return color * (255 / alpha); + else + return color; +} + +static int +_demul_color_alpha(int color, int alpha) +{ + if (alpha > 0 && alpha < 255) + return (color * alpha) / 255; + else + return color; +} + +static void +_reye_clicked(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, + void *event_data EINA_UNUSED) +{ + Ephoto_Reye *er = data; + unsigned int *im_data, *im_data_new, *p1, *p2; + int x, y, imx, imy, xpos, ypos, xadj, yadj; + int a, r, g, b; + + evas_pointer_canvas_xy_get(evas_object_evas_get(er->image), &xpos, &ypos); + evas_object_geometry_get(er->image, &imx, &imy, 0, 0); + + xadj = (xpos-imx)-(er->rad/2); + yadj = (ypos-imy)-(er->rad/2); + + if (xadj < 0) xadj = 0; + if (yadj < 0) yadj = 0; + + im_data = malloc(sizeof(unsigned int) * er->w * er->h); + if (er->edited_im_data) + memcpy(im_data, er->edited_im_data, + sizeof(unsigned int) * er->w * er->h); + else + memcpy(im_data, er->original_im_data, + sizeof(unsigned int) * er->w * er->h); + + im_data_new = malloc(sizeof(unsigned int) * er->w * er->h); + + for (y = 0; y < er->h; y++) + { + p1 = im_data + (y * er->w); + p2 = im_data_new + (y * er->w); + for (x = 0; x < er->w; x++) + { + b = (int) ((*p1) & 0xff); + g = (int) ((*p1 >> 8) & 0xff); + r = (int) ((*p1 >> 16) & 0xff); + a = (int) ((*p1 >> 24) & 0xff); + b = _mul_color_alpha(b, a); + g = _mul_color_alpha(g, a); + r = _mul_color_alpha(r, a); + if (y >= yadj && y <= yadj+er->rad) + { + if (x >= xadj && x <= xadj+er->rad) + r = (int) ((g+b)/2); + } + b = _normalize_color(b); + g = _normalize_color(g); + r = _normalize_color(r); + b = _demul_color_alpha(b, a); + g = _demul_color_alpha(g, a); + r = _demul_color_alpha(r, a); + *p2 = (a << 24) | (r << 16) | (g << 8) | b; + p2++; + p1++; + } + } + er->edited_im_data = im_data_new; + ephoto_single_browser_image_data_update(er->main, er->image, EINA_FALSE, + im_data_new, er->w, er->h); + free(im_data); +} + +static void +_radius_slider_changed(void *data, Evas_Object *obj, void *event_info EINA_UNUSED) +{ + Ephoto_Reye *er = data; + + er->rad = elm_slider_value_get(obj); +} + +static Eina_Bool +_reye_reset(void *data, int type EINA_UNUSED, + void *event_info EINA_UNUSED) +{ + Ephoto_Reye *er = data; + + elm_slider_value_set(er->rslider, 15); + er->rad = 15; + + ephoto_single_browser_image_data_update(er->main, er->image, EINA_FALSE, + er->original_im_data, er->w, er->h); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_reye_apply(void *data, int type EINA_UNUSED, + void *event_info EINA_UNUSED) +{ + Ephoto_Reye *er = data; + unsigned int *image_data; + int w, h; + + image_data = + evas_object_image_data_get(elm_image_object_get(er->image), + EINA_FALSE); + evas_object_image_size_get(elm_image_object_get(er->image), &w, &h); + ephoto_single_browser_image_data_update(er->main, er->image, EINA_TRUE, + image_data, w, h); + ephoto_editor_del(er->editor); + + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +_reye_cancel(void *data, int type EINA_UNUSED, + void *event_info EINA_UNUSED) +{ + Ephoto_Reye *er = data; + + elm_slider_value_set(er->rslider, 15); + er->rad = 15; + + ephoto_single_browser_image_data_update(er->main, er->image, EINA_FALSE, + er->original_im_data, er->w, er->h); + ephoto_single_browser_cancel_editing(er->main, er->image); + ephoto_editor_del(er->editor); + + return ECORE_CALLBACK_PASS_ON; +} + +static void +_editor_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, + void *event_info EINA_UNUSED) +{ + Ephoto_Reye *er = data; + Ecore_Event_Handler *handler; + + evas_object_event_callback_del(er->image, EVAS_CALLBACK_MOUSE_UP, _reye_clicked); + EINA_LIST_FREE(er->handlers, handler) + ecore_event_handler_del(handler); + free(er->original_im_data); + free(er); +} + +void +ephoto_red_eye_add(Evas_Object *main, Evas_Object *parent, Evas_Object *image) +{ + Evas_Object *slider, *label; + Ephoto_Reye *er; + unsigned int *im_data; + + EINA_SAFETY_ON_NULL_GOTO(image, error); + + er = calloc(1, sizeof(Ephoto_Reye)); + EINA_SAFETY_ON_NULL_GOTO(er, error); + + er->rad = 15; + er->main = main; + er->parent = parent; + er->image = image; + im_data = + evas_object_image_data_get(elm_image_object_get(er->image), + EINA_FALSE); + evas_object_image_size_get(elm_image_object_get(er->image), &er->w, + &er->h); + er->original_im_data = malloc(sizeof(unsigned int) * er->w * er->h); + memcpy(er->original_im_data, im_data, + sizeof(unsigned int) * er->w * er->h); + + evas_object_event_callback_add(er->image, EVAS_CALLBACK_MOUSE_UP, + _reye_clicked, er); + + er->editor = ephoto_editor_add(parent, _("Red Eye Removal"), + "ereye", er); + evas_object_event_callback_add(er->editor, EVAS_CALLBACK_DEL, _editor_del, + er); + + slider = elm_slider_add(er->editor); + elm_object_text_set(slider, _("Radius")); + elm_slider_min_max_set(slider, 5, 50); + elm_slider_step_set(slider, 1); + elm_slider_value_set(slider, 15); + elm_slider_unit_format_set(slider, "%1.0f"); + evas_object_size_hint_weight_set(slider, EVAS_HINT_EXPAND, EVAS_HINT_FILL); + evas_object_size_hint_align_set(slider, EVAS_HINT_FILL, 0.5); + evas_object_smart_callback_add(slider, "delay,changed", + _radius_slider_changed, er); + elm_box_pack_start(er->editor, slider); + evas_object_show(slider); + er->rslider = slider; + + label = elm_label_add(er->editor); + elm_object_text_set(label, _("Click on an eye")); + evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, EVAS_HINT_FILL); + evas_object_size_hint_align_set(label, EVAS_HINT_FILL, 0.5); + elm_box_pack_start(er->editor, label); + evas_object_show(label); + + er->handlers = + eina_list_append(er->handlers, + ecore_event_handler_add(EPHOTO_EVENT_EDITOR_RESET, + _reye_reset, er)); + er->handlers = + eina_list_append(er->handlers, + ecore_event_handler_add(EPHOTO_EVENT_EDITOR_APPLY, + _reye_apply, er)); + er->handlers = + eina_list_append(er->handlers, + ecore_event_handler_add(EPHOTO_EVENT_EDITOR_CANCEL, + _reye_cancel, er)); + + return; + + error: + return; +} diff --git a/src/bin/ephoto_single_browser.c b/src/bin/ephoto_single_browser.c index 9cf5493..4c7a846 100644 --- a/src/bin/ephoto_single_browser.c +++ b/src/bin/ephoto_single_browser.c @@ -148,6 +148,8 @@ _scroller_mouse_up_cb(void *data, Evas *e EINA_UNUSED, Ephoto_Single_Browser *sb = data; Evas_Event_Mouse_Up *ev = event_info; + if (sb->editing) + return; if (ev->button == 3) { _edit_menu(sb); @@ -1193,6 +1195,23 @@ _go_color(void *data, Evas_Object *obj EINA_UNUSED, } } +static void +_go_reye(void *data, Evas_Object *obj EINA_UNUSED, + void *event_info EINA_UNUSED) +{ + Ephoto_Single_Browser *sb = data; + + if (sb->viewer) + { + sb->editing = EINA_TRUE; + if (sb->botbox) + evas_object_hide(sb->botbox); + Ephoto_Viewer *v = evas_object_data_get(sb->viewer, "viewer"); + + ephoto_red_eye_add(sb->main, sb->mhbox, v->image); + } +} + static void _go_auto_eq(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) @@ -1377,6 +1396,8 @@ _add_edit_menu_items(Ephoto_Single_Browser *sb, Evas_Object *menu) _("Brightness/Contrast/Gamma"), _go_bcg, sb); elm_menu_item_add(menu, menu_itt, "insert-image", _("Hue/Saturation/Value"), _go_hsv, sb); + elm_menu_item_add(menu, menu_itt, "insert-image", _("Red Eye Removal"), + _go_reye, sb); elm_menu_item_add(menu, menu_itt, "insert-image", _("Color Levels"), _go_color, sb); diff --git a/src/bin/ephoto_thumb_browser.c b/src/bin/ephoto_thumb_browser.c index 42ebf1a..b22efd9 100644 --- a/src/bin/ephoto_thumb_browser.c +++ b/src/bin/ephoto_thumb_browser.c @@ -2808,7 +2808,7 @@ ephoto_thumb_browser_add(Ephoto *ephoto, Evas_Object *parent) { elm_object_part_content_set(but, "icon", ic); elm_object_tooltip_text_set(but, _("Zoom In")); - elm_object_tooltip_orient_set(but, ELM_TOOLTIP_ORIENT_CENTER); + elm_object_tooltip_orient_set(but, ELM_TOOLTIP_ORIENT_TOP); } evas_object_smart_callback_add(but, "clicked", _zoom_in, tb); elm_box_pack_end(hbox, but); @@ -2826,7 +2826,7 @@ ephoto_thumb_browser_add(Ephoto *ephoto, Evas_Object *parent) { elm_object_part_content_set(but, "icon", ic); elm_object_tooltip_text_set(but, _("Zoom Out")); - elm_object_tooltip_orient_set(but, ELM_TOOLTIP_ORIENT_CENTER); + elm_object_tooltip_orient_set(but, ELM_TOOLTIP_ORIENT_TOP); } evas_object_smart_callback_add(but, "clicked", _zoom_out, tb); elm_box_pack_end(hbox, but);