diff --git a/ChangeLog b/ChangeLog index f72dd395a8..b1844c3e75 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2001-10-30 Simon Budig + + * app/pdb/tools_cmds.c + * app/tools/gimperasertool.c + * app/tools/gimperasertool.h + * tools/pdbgen/pdb/tools.pdb + + Added a "color erase" feature to the eraser. This is ported from + the colortoalpha plugin and is utterly cool. + + The "Color Erase" Option should be disabled when the drawable + has no alpha channel, however, I have no idea how to do this. + 2001-10-29 Sven Neumann * app/base/temp-buf.c (temp_buf_to_gray): rewrote so gcc-3.0 doesn't diff --git a/app/paint/gimperaser.c b/app/paint/gimperaser.c index 554cd127c4..73402231eb 100644 --- a/app/paint/gimperaser.c +++ b/app/paint/gimperaser.c @@ -25,6 +25,7 @@ #include "tools-types.h" +#include "base/pixel-region.h" #include "base/temp-buf.h" #include "paint-funcs/paint-funcs.h" @@ -40,10 +41,14 @@ #include "libgimp/gimpintl.h" +#include "libgimpcolor/gimpcolor.h" +#include "libgimpcolor/gimprgb.h" + #define ERASER_DEFAULT_HARD FALSE #define ERASER_DEFAULT_INCREMENTAL FALSE #define ERASER_DEFAULT_ANTI_ERASE FALSE +#define ERASER_DEFAULT_COLOR_ERASE FALSE typedef struct _EraserOptions EraserOptions; @@ -59,6 +64,10 @@ struct _EraserOptions gboolean anti_erase; gboolean anti_erase_d; GtkWidget *anti_erase_w; + + gboolean color_erase; + gboolean color_erase_d; + GtkWidget *color_erase_w; }; @@ -78,16 +87,20 @@ static void gimp_eraser_tool_motion (GimpPaintTool *paint_tool, PaintPressureOptions *pressure_options, gboolean hard, gboolean incremental, - gboolean anti_erase); + gboolean anti_erase, + gboolean color_erase); static EraserOptions * gimp_eraser_tool_options_new (void); static void gimp_eraser_tool_options_reset (GimpToolOptions *tool_options); +static void gimp_eraser_tool_colortoalpha (GimpRGB *src, + const GimpRGB *color); /* local variables */ static gboolean non_gui_hard = ERASER_DEFAULT_HARD; static gboolean non_gui_incremental = ERASER_DEFAULT_INCREMENTAL; static gboolean non_gui_anti_erase = ERASER_DEFAULT_ANTI_ERASE; +static gboolean non_gui_color_erase = ERASER_DEFAULT_COLOR_ERASE; static EraserOptions *eraser_options = NULL; @@ -214,6 +227,7 @@ gimp_eraser_tool_paint (GimpPaintTool *paint_tool, gboolean hard; gboolean incremental; gboolean anti_erase; + gboolean color_erase; if (eraser_options) { @@ -221,6 +235,7 @@ gimp_eraser_tool_paint (GimpPaintTool *paint_tool, hard = eraser_options->hard; incremental = eraser_options->paint_options.incremental; anti_erase = eraser_options->anti_erase; + color_erase = eraser_options->color_erase; } else { @@ -228,6 +243,7 @@ gimp_eraser_tool_paint (GimpPaintTool *paint_tool, hard = non_gui_hard; incremental = non_gui_incremental; anti_erase = non_gui_anti_erase; + color_erase = non_gui_color_erase; } switch (state) @@ -241,7 +257,8 @@ gimp_eraser_tool_paint (GimpPaintTool *paint_tool, pressure_options, hard, incremental, - anti_erase); + anti_erase, + color_erase); break; case FINISH_PAINT: @@ -258,7 +275,8 @@ gimp_eraser_tool_motion (GimpPaintTool *paint_tool, PaintPressureOptions *pressure_options, gboolean hard, gboolean incremental, - gboolean anti_erase) + gboolean anti_erase, + gboolean color_erase) { GimpImage *gimage; GimpContext *context; @@ -266,6 +284,13 @@ gimp_eraser_tool_motion (GimpPaintTool *paint_tool, TempBuf *area; guchar col[MAX_CHANNELS]; gdouble scale; + TempBuf *orig; + gint x, y, x1, y1, x2, y2; + PixelRegion srcPR, destPR; + gpointer pr; + GimpRGB bgcolor, color; + guchar *s, *d; + if (! (gimage = gimp_drawable_gimage (drawable))) return; @@ -283,26 +308,119 @@ gimp_eraser_tool_motion (GimpPaintTool *paint_tool, if (! (area = gimp_paint_tool_get_paint_area (paint_tool, drawable, scale))) return; - /* set the alpha channel */ - col[area->bytes - 1] = OPAQUE_OPACITY; + if (anti_erase || !color_erase) + { + /* set the alpha channel */ + col[area->bytes - 1] = OPAQUE_OPACITY; - /* color the pixels */ - color_pixels (temp_buf_data (area), col, - area->width * area->height, area->bytes); + /* color the pixels */ + color_pixels (temp_buf_data (area), col, + area->width * area->height, area->bytes); - opacity = 255 * gimp_context_get_opacity (context); + opacity = 255 * gimp_context_get_opacity (context); - if (pressure_options->opacity) - opacity = opacity * 2.0 * paint_tool->curpressure; + if (pressure_options->opacity) + opacity = opacity * 2.0 * paint_tool->curpressure; - /* paste the newly painted canvas to the gimage which is being worked on */ - gimp_paint_tool_paste_canvas (paint_tool, drawable, - MIN (opacity, 255), - gimp_context_get_opacity (context) * 255, - anti_erase ? ANTI_ERASE_MODE : ERASE_MODE, - hard ? HARD : (pressure_options->pressure ? PRESSURE : SOFT), - scale, - incremental ? INCREMENTAL : CONSTANT); + /* paste the newly painted canvas to the gimage which is being + * worked on */ + gimp_paint_tool_paste_canvas (paint_tool, drawable, + MIN (opacity, 255), + gimp_context_get_opacity (context) * 255, + anti_erase ? (color_erase ? BEHIND_MODE : ANTI_ERASE_MODE ) : ERASE_MODE, + hard ? HARD : (pressure_options->pressure ? PRESSURE : SOFT), + scale, + incremental ? INCREMENTAL : CONSTANT); + } + else + { + /* This is Simons evil Eraser Hack. Code is borrowed from the + * colortoalpha plugin by Seth Burgess. Algorithm has been + * described on IRC by clahey. + */ +#warning "Simons evil Eraser Hack" + + gimp_rgb_set_uchar (&bgcolor, col[0], col[1], col[2]); + + if (!gimp_drawable_has_alpha (drawable)) + return; + + /* is this necessary? */ + x1 = CLAMP (area->x, 0, gimp_drawable_width (drawable)); + y1 = CLAMP (area->y, 0, gimp_drawable_height (drawable)); + x2 = CLAMP (area->x + area->width, + 0, gimp_drawable_width (drawable)); + y2 = CLAMP (area->y + area->height, + 0, gimp_drawable_height (drawable)); + + if (!(x2 - x1) || !(y2 - y1)) + return; + + /* get the original image */ + orig = gimp_paint_tool_get_orig_image (paint_tool, drawable, x1, y1, x2, y2); + + srcPR.bytes = orig->bytes; + srcPR.x = 0; srcPR.y = 0; + srcPR.w = x2 - x1; + srcPR.h = y2 - y1; + srcPR.rowstride = srcPR.bytes * orig->width; + srcPR.data = temp_buf_data (orig); + + /* configure the destination */ + destPR.bytes = area->bytes; + destPR.x = 0; destPR.y = 0; + destPR.w = srcPR.w; + destPR.h = srcPR.h; + destPR.rowstride = destPR.bytes * area->width; + destPR.data = temp_buf_data (area); + + /* I am not sure, if this really is necessary. + * Probably the orig Tempbuf has the same size as the area Tempbuf */ + pr = pixel_regions_register (2, &srcPR, &destPR); + + for (; pr != NULL; pr = pixel_regions_process (pr)) + { + s = srcPR.data; + d = destPR.data; + for (y = 0; y < destPR.h; y++) + { + for (x = 0; x < destPR.w; x++) + { + + gimp_rgba_set_uchar (&color, + s[x*srcPR.bytes ], + s[x*srcPR.bytes + 1], + s[x*srcPR.bytes + 2], + s[x*srcPR.bytes + 3]); + + gimp_eraser_tool_colortoalpha (&color, &bgcolor); + + gimp_rgba_get_uchar (&color, + &(d[x*destPR.bytes ]), + &(d[x*destPR.bytes + 1]), + &(d[x*destPR.bytes + 2]), + &(d[x*destPR.bytes + 3])); + } + + s += srcPR.rowstride; + d += destPR.rowstride; + } + } + + opacity = 255 * gimp_context_get_opacity (context); + + if (pressure_options->opacity) + opacity = opacity * 2.0 * paint_tool->curpressure; + + /* paste the newly painted canvas to the gimage which is + * being worked on */ + gimp_paint_tool_replace_canvas (paint_tool, drawable, + MIN (opacity, 255), + gimp_context_get_opacity (context) * 255, + hard ? HARD : (pressure_options->pressure ? PRESSURE : SOFT), + scale, + incremental ? INCREMENTAL : CONSTANT); + } } @@ -316,6 +434,7 @@ eraser_non_gui_default (GimpDrawable *drawable, gboolean hard = ERASER_DEFAULT_HARD; gboolean incremental = ERASER_DEFAULT_INCREMENTAL; gboolean anti_erase = ERASER_DEFAULT_ANTI_ERASE; + gboolean color_erase = ERASER_DEFAULT_COLOR_ERASE; EraserOptions *options = eraser_options; @@ -324,10 +443,11 @@ eraser_non_gui_default (GimpDrawable *drawable, hard = options->hard; incremental = options->paint_options.incremental; anti_erase = options->anti_erase; + color_erase = options->color_erase; } return eraser_non_gui (drawable, num_strokes, stroke_array, - hard, incremental, anti_erase); + hard, incremental, anti_erase, color_erase); } gboolean @@ -336,7 +456,8 @@ eraser_non_gui (GimpDrawable *drawable, gdouble *stroke_array, gint hard, gint incremental, - gboolean anti_erase) + gboolean anti_erase, + gboolean color_erase) { static GimpEraserTool *non_gui_eraser = NULL; @@ -357,6 +478,7 @@ eraser_non_gui (GimpDrawable *drawable, non_gui_hard = hard; non_gui_incremental = incremental; non_gui_anti_erase = anti_erase; + non_gui_color_erase = color_erase; paint_tool->startx = paint_tool->lastx = stroke_array[0]; paint_tool->starty = paint_tool->lasty = stroke_array[1]; @@ -398,6 +520,7 @@ gimp_eraser_tool_options_new (void) options->hard = options->hard_d = ERASER_DEFAULT_HARD; options->anti_erase = options->anti_erase_d = ERASER_DEFAULT_ANTI_ERASE; + options->color_erase = options->color_erase_d = ERASER_DEFAULT_COLOR_ERASE; /* the main vbox */ vbox = ((GimpToolOptions *) options)->main_vbox; @@ -422,6 +545,16 @@ gimp_eraser_tool_options_new (void) options->anti_erase_d); gtk_widget_show (options->anti_erase_w); + /* the color_erase toggle */ + options->color_erase_w = gtk_check_button_new_with_label (_("Color Erase")); + gtk_box_pack_start (GTK_BOX (vbox), options->color_erase_w, FALSE, FALSE, 0); + g_signal_connect (G_OBJECT (options->color_erase_w), "toggled", + G_CALLBACK (gimp_toggle_button_update), + &options->color_erase); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->color_erase_w), + options->color_erase_d); + gtk_widget_show (options->color_erase_w); + return options; } @@ -438,4 +571,71 @@ gimp_eraser_tool_options_reset (GimpToolOptions *tool_options) options->hard_d); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->anti_erase_w), options->anti_erase_d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->color_erase_w), + options->color_erase_d); } + + +static void +gimp_eraser_tool_colortoalpha (GimpRGB *src, + const GimpRGB *color) +{ + GimpRGB alpha; + + alpha.a = src->a; + + if (color->r < 0.0001) + alpha.r = src->r; + else if ( src->r > color->r ) + alpha.r = (src->r - color->r) / (1.0 - color->r); + else if (src->r < color->r) + alpha.r = (color->r - src->r) / color->r; + else alpha.r = 0.0; + + if (color->g < 0.0001) + alpha.g = src->g; + else if ( src->g > color->g ) + alpha.g = (src->g - color->g) / (1.0 - color->g); + else if ( src->g < color->g ) + alpha.g = (color->g - src->g) / (color->g); + else alpha.g = 0.0; + + if (color->b < 0.0001) + alpha.b = src->b; + else if ( src->b > color->b ) + alpha.b = (src->b - color->b) / (1.0 - color->b); + else if ( src->b < color->b ) + alpha.b = (color->b - src->b) / (color->b); + else alpha.b = 0.0; + + if ( alpha.r > alpha.g ) + { + if ( alpha.r > alpha.b ) + { + src->a = alpha.r; + } + else + { + src->a = alpha.b; + } + } + else if ( alpha.g > alpha.b ) + { + src->a = alpha.g; + } + else + { + src->a = alpha.b; + } + + if (src->a < 0.0001) + return; + + src->r = (src->r - color->r) / src->a + color->r; + src->g = (src->g - color->g) / src->a + color->g; + src->b = (src->b - color->b) / src->a + color->b; + + src->a *= alpha.a; +} + + diff --git a/app/paint/gimperaser.h b/app/paint/gimperaser.h index 98d8a2fc6a..84ac304a05 100644 --- a/app/paint/gimperaser.h +++ b/app/paint/gimperaser.h @@ -55,7 +55,8 @@ gboolean eraser_non_gui (GimpDrawable *drawable, gdouble *stroke_array, gint hardness, gint method, - gboolean anti_erase); + gboolean anti_erase, + gboolean color_erase); gboolean eraser_non_gui_default (GimpDrawable *paint_core, gint num_strokes, gdouble *stroke_array); diff --git a/app/pdb/tools_cmds.c b/app/pdb/tools_cmds.c index 5f7795bf74..adce4bb1aa 100644 --- a/app/pdb/tools_cmds.c +++ b/app/pdb/tools_cmds.c @@ -1148,7 +1148,7 @@ eraser_invoker (Gimp *gimp, success = FALSE; if (success) - success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE); + success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE, FALSE); return procedural_db_return_args (&eraser_proc, success); } diff --git a/app/tools/gimperasertool.c b/app/tools/gimperasertool.c index 554cd127c4..73402231eb 100644 --- a/app/tools/gimperasertool.c +++ b/app/tools/gimperasertool.c @@ -25,6 +25,7 @@ #include "tools-types.h" +#include "base/pixel-region.h" #include "base/temp-buf.h" #include "paint-funcs/paint-funcs.h" @@ -40,10 +41,14 @@ #include "libgimp/gimpintl.h" +#include "libgimpcolor/gimpcolor.h" +#include "libgimpcolor/gimprgb.h" + #define ERASER_DEFAULT_HARD FALSE #define ERASER_DEFAULT_INCREMENTAL FALSE #define ERASER_DEFAULT_ANTI_ERASE FALSE +#define ERASER_DEFAULT_COLOR_ERASE FALSE typedef struct _EraserOptions EraserOptions; @@ -59,6 +64,10 @@ struct _EraserOptions gboolean anti_erase; gboolean anti_erase_d; GtkWidget *anti_erase_w; + + gboolean color_erase; + gboolean color_erase_d; + GtkWidget *color_erase_w; }; @@ -78,16 +87,20 @@ static void gimp_eraser_tool_motion (GimpPaintTool *paint_tool, PaintPressureOptions *pressure_options, gboolean hard, gboolean incremental, - gboolean anti_erase); + gboolean anti_erase, + gboolean color_erase); static EraserOptions * gimp_eraser_tool_options_new (void); static void gimp_eraser_tool_options_reset (GimpToolOptions *tool_options); +static void gimp_eraser_tool_colortoalpha (GimpRGB *src, + const GimpRGB *color); /* local variables */ static gboolean non_gui_hard = ERASER_DEFAULT_HARD; static gboolean non_gui_incremental = ERASER_DEFAULT_INCREMENTAL; static gboolean non_gui_anti_erase = ERASER_DEFAULT_ANTI_ERASE; +static gboolean non_gui_color_erase = ERASER_DEFAULT_COLOR_ERASE; static EraserOptions *eraser_options = NULL; @@ -214,6 +227,7 @@ gimp_eraser_tool_paint (GimpPaintTool *paint_tool, gboolean hard; gboolean incremental; gboolean anti_erase; + gboolean color_erase; if (eraser_options) { @@ -221,6 +235,7 @@ gimp_eraser_tool_paint (GimpPaintTool *paint_tool, hard = eraser_options->hard; incremental = eraser_options->paint_options.incremental; anti_erase = eraser_options->anti_erase; + color_erase = eraser_options->color_erase; } else { @@ -228,6 +243,7 @@ gimp_eraser_tool_paint (GimpPaintTool *paint_tool, hard = non_gui_hard; incremental = non_gui_incremental; anti_erase = non_gui_anti_erase; + color_erase = non_gui_color_erase; } switch (state) @@ -241,7 +257,8 @@ gimp_eraser_tool_paint (GimpPaintTool *paint_tool, pressure_options, hard, incremental, - anti_erase); + anti_erase, + color_erase); break; case FINISH_PAINT: @@ -258,7 +275,8 @@ gimp_eraser_tool_motion (GimpPaintTool *paint_tool, PaintPressureOptions *pressure_options, gboolean hard, gboolean incremental, - gboolean anti_erase) + gboolean anti_erase, + gboolean color_erase) { GimpImage *gimage; GimpContext *context; @@ -266,6 +284,13 @@ gimp_eraser_tool_motion (GimpPaintTool *paint_tool, TempBuf *area; guchar col[MAX_CHANNELS]; gdouble scale; + TempBuf *orig; + gint x, y, x1, y1, x2, y2; + PixelRegion srcPR, destPR; + gpointer pr; + GimpRGB bgcolor, color; + guchar *s, *d; + if (! (gimage = gimp_drawable_gimage (drawable))) return; @@ -283,26 +308,119 @@ gimp_eraser_tool_motion (GimpPaintTool *paint_tool, if (! (area = gimp_paint_tool_get_paint_area (paint_tool, drawable, scale))) return; - /* set the alpha channel */ - col[area->bytes - 1] = OPAQUE_OPACITY; + if (anti_erase || !color_erase) + { + /* set the alpha channel */ + col[area->bytes - 1] = OPAQUE_OPACITY; - /* color the pixels */ - color_pixels (temp_buf_data (area), col, - area->width * area->height, area->bytes); + /* color the pixels */ + color_pixels (temp_buf_data (area), col, + area->width * area->height, area->bytes); - opacity = 255 * gimp_context_get_opacity (context); + opacity = 255 * gimp_context_get_opacity (context); - if (pressure_options->opacity) - opacity = opacity * 2.0 * paint_tool->curpressure; + if (pressure_options->opacity) + opacity = opacity * 2.0 * paint_tool->curpressure; - /* paste the newly painted canvas to the gimage which is being worked on */ - gimp_paint_tool_paste_canvas (paint_tool, drawable, - MIN (opacity, 255), - gimp_context_get_opacity (context) * 255, - anti_erase ? ANTI_ERASE_MODE : ERASE_MODE, - hard ? HARD : (pressure_options->pressure ? PRESSURE : SOFT), - scale, - incremental ? INCREMENTAL : CONSTANT); + /* paste the newly painted canvas to the gimage which is being + * worked on */ + gimp_paint_tool_paste_canvas (paint_tool, drawable, + MIN (opacity, 255), + gimp_context_get_opacity (context) * 255, + anti_erase ? (color_erase ? BEHIND_MODE : ANTI_ERASE_MODE ) : ERASE_MODE, + hard ? HARD : (pressure_options->pressure ? PRESSURE : SOFT), + scale, + incremental ? INCREMENTAL : CONSTANT); + } + else + { + /* This is Simons evil Eraser Hack. Code is borrowed from the + * colortoalpha plugin by Seth Burgess. Algorithm has been + * described on IRC by clahey. + */ +#warning "Simons evil Eraser Hack" + + gimp_rgb_set_uchar (&bgcolor, col[0], col[1], col[2]); + + if (!gimp_drawable_has_alpha (drawable)) + return; + + /* is this necessary? */ + x1 = CLAMP (area->x, 0, gimp_drawable_width (drawable)); + y1 = CLAMP (area->y, 0, gimp_drawable_height (drawable)); + x2 = CLAMP (area->x + area->width, + 0, gimp_drawable_width (drawable)); + y2 = CLAMP (area->y + area->height, + 0, gimp_drawable_height (drawable)); + + if (!(x2 - x1) || !(y2 - y1)) + return; + + /* get the original image */ + orig = gimp_paint_tool_get_orig_image (paint_tool, drawable, x1, y1, x2, y2); + + srcPR.bytes = orig->bytes; + srcPR.x = 0; srcPR.y = 0; + srcPR.w = x2 - x1; + srcPR.h = y2 - y1; + srcPR.rowstride = srcPR.bytes * orig->width; + srcPR.data = temp_buf_data (orig); + + /* configure the destination */ + destPR.bytes = area->bytes; + destPR.x = 0; destPR.y = 0; + destPR.w = srcPR.w; + destPR.h = srcPR.h; + destPR.rowstride = destPR.bytes * area->width; + destPR.data = temp_buf_data (area); + + /* I am not sure, if this really is necessary. + * Probably the orig Tempbuf has the same size as the area Tempbuf */ + pr = pixel_regions_register (2, &srcPR, &destPR); + + for (; pr != NULL; pr = pixel_regions_process (pr)) + { + s = srcPR.data; + d = destPR.data; + for (y = 0; y < destPR.h; y++) + { + for (x = 0; x < destPR.w; x++) + { + + gimp_rgba_set_uchar (&color, + s[x*srcPR.bytes ], + s[x*srcPR.bytes + 1], + s[x*srcPR.bytes + 2], + s[x*srcPR.bytes + 3]); + + gimp_eraser_tool_colortoalpha (&color, &bgcolor); + + gimp_rgba_get_uchar (&color, + &(d[x*destPR.bytes ]), + &(d[x*destPR.bytes + 1]), + &(d[x*destPR.bytes + 2]), + &(d[x*destPR.bytes + 3])); + } + + s += srcPR.rowstride; + d += destPR.rowstride; + } + } + + opacity = 255 * gimp_context_get_opacity (context); + + if (pressure_options->opacity) + opacity = opacity * 2.0 * paint_tool->curpressure; + + /* paste the newly painted canvas to the gimage which is + * being worked on */ + gimp_paint_tool_replace_canvas (paint_tool, drawable, + MIN (opacity, 255), + gimp_context_get_opacity (context) * 255, + hard ? HARD : (pressure_options->pressure ? PRESSURE : SOFT), + scale, + incremental ? INCREMENTAL : CONSTANT); + } } @@ -316,6 +434,7 @@ eraser_non_gui_default (GimpDrawable *drawable, gboolean hard = ERASER_DEFAULT_HARD; gboolean incremental = ERASER_DEFAULT_INCREMENTAL; gboolean anti_erase = ERASER_DEFAULT_ANTI_ERASE; + gboolean color_erase = ERASER_DEFAULT_COLOR_ERASE; EraserOptions *options = eraser_options; @@ -324,10 +443,11 @@ eraser_non_gui_default (GimpDrawable *drawable, hard = options->hard; incremental = options->paint_options.incremental; anti_erase = options->anti_erase; + color_erase = options->color_erase; } return eraser_non_gui (drawable, num_strokes, stroke_array, - hard, incremental, anti_erase); + hard, incremental, anti_erase, color_erase); } gboolean @@ -336,7 +456,8 @@ eraser_non_gui (GimpDrawable *drawable, gdouble *stroke_array, gint hard, gint incremental, - gboolean anti_erase) + gboolean anti_erase, + gboolean color_erase) { static GimpEraserTool *non_gui_eraser = NULL; @@ -357,6 +478,7 @@ eraser_non_gui (GimpDrawable *drawable, non_gui_hard = hard; non_gui_incremental = incremental; non_gui_anti_erase = anti_erase; + non_gui_color_erase = color_erase; paint_tool->startx = paint_tool->lastx = stroke_array[0]; paint_tool->starty = paint_tool->lasty = stroke_array[1]; @@ -398,6 +520,7 @@ gimp_eraser_tool_options_new (void) options->hard = options->hard_d = ERASER_DEFAULT_HARD; options->anti_erase = options->anti_erase_d = ERASER_DEFAULT_ANTI_ERASE; + options->color_erase = options->color_erase_d = ERASER_DEFAULT_COLOR_ERASE; /* the main vbox */ vbox = ((GimpToolOptions *) options)->main_vbox; @@ -422,6 +545,16 @@ gimp_eraser_tool_options_new (void) options->anti_erase_d); gtk_widget_show (options->anti_erase_w); + /* the color_erase toggle */ + options->color_erase_w = gtk_check_button_new_with_label (_("Color Erase")); + gtk_box_pack_start (GTK_BOX (vbox), options->color_erase_w, FALSE, FALSE, 0); + g_signal_connect (G_OBJECT (options->color_erase_w), "toggled", + G_CALLBACK (gimp_toggle_button_update), + &options->color_erase); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->color_erase_w), + options->color_erase_d); + gtk_widget_show (options->color_erase_w); + return options; } @@ -438,4 +571,71 @@ gimp_eraser_tool_options_reset (GimpToolOptions *tool_options) options->hard_d); gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->anti_erase_w), options->anti_erase_d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->color_erase_w), + options->color_erase_d); } + + +static void +gimp_eraser_tool_colortoalpha (GimpRGB *src, + const GimpRGB *color) +{ + GimpRGB alpha; + + alpha.a = src->a; + + if (color->r < 0.0001) + alpha.r = src->r; + else if ( src->r > color->r ) + alpha.r = (src->r - color->r) / (1.0 - color->r); + else if (src->r < color->r) + alpha.r = (color->r - src->r) / color->r; + else alpha.r = 0.0; + + if (color->g < 0.0001) + alpha.g = src->g; + else if ( src->g > color->g ) + alpha.g = (src->g - color->g) / (1.0 - color->g); + else if ( src->g < color->g ) + alpha.g = (color->g - src->g) / (color->g); + else alpha.g = 0.0; + + if (color->b < 0.0001) + alpha.b = src->b; + else if ( src->b > color->b ) + alpha.b = (src->b - color->b) / (1.0 - color->b); + else if ( src->b < color->b ) + alpha.b = (color->b - src->b) / (color->b); + else alpha.b = 0.0; + + if ( alpha.r > alpha.g ) + { + if ( alpha.r > alpha.b ) + { + src->a = alpha.r; + } + else + { + src->a = alpha.b; + } + } + else if ( alpha.g > alpha.b ) + { + src->a = alpha.g; + } + else + { + src->a = alpha.b; + } + + if (src->a < 0.0001) + return; + + src->r = (src->r - color->r) / src->a + color->r; + src->g = (src->g - color->g) / src->a + color->g; + src->b = (src->b - color->b) / src->a + color->b; + + src->a *= alpha.a; +} + + diff --git a/app/tools/gimperasertool.h b/app/tools/gimperasertool.h index 98d8a2fc6a..84ac304a05 100644 --- a/app/tools/gimperasertool.h +++ b/app/tools/gimperasertool.h @@ -55,7 +55,8 @@ gboolean eraser_non_gui (GimpDrawable *drawable, gdouble *stroke_array, gint hardness, gint method, - gboolean anti_erase); + gboolean anti_erase, + gboolean color_erase); gboolean eraser_non_gui_default (GimpDrawable *paint_core, gint num_strokes, gdouble *stroke_array); diff --git a/tools/pdbgen/pdb/misc_tools.pdb b/tools/pdbgen/pdb/misc_tools.pdb index 14b1bcfa5c..509f8eed23 100644 --- a/tools/pdbgen/pdb/misc_tools.pdb +++ b/tools/pdbgen/pdb/misc_tools.pdb @@ -491,7 +491,7 @@ HELP %invoke = ( headers => [ qw("tools/gimperasertool.h") ], code => <<'CODE' -success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE); +success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE, FALSE); CODE ); } @@ -521,7 +521,7 @@ HELP %invoke = ( headers => [ qw("tools/gimperasertool.h") ], code => <<'CODE' -success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE); +success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE, FALSE); CODE ); } diff --git a/tools/pdbgen/pdb/paint_tools.pdb b/tools/pdbgen/pdb/paint_tools.pdb index 14b1bcfa5c..509f8eed23 100644 --- a/tools/pdbgen/pdb/paint_tools.pdb +++ b/tools/pdbgen/pdb/paint_tools.pdb @@ -491,7 +491,7 @@ HELP %invoke = ( headers => [ qw("tools/gimperasertool.h") ], code => <<'CODE' -success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE); +success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE, FALSE); CODE ); } @@ -521,7 +521,7 @@ HELP %invoke = ( headers => [ qw("tools/gimperasertool.h") ], code => <<'CODE' -success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE); +success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE, FALSE); CODE ); } diff --git a/tools/pdbgen/pdb/tools.pdb b/tools/pdbgen/pdb/tools.pdb index 14b1bcfa5c..509f8eed23 100644 --- a/tools/pdbgen/pdb/tools.pdb +++ b/tools/pdbgen/pdb/tools.pdb @@ -491,7 +491,7 @@ HELP %invoke = ( headers => [ qw("tools/gimperasertool.h") ], code => <<'CODE' -success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE); +success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE, FALSE); CODE ); } @@ -521,7 +521,7 @@ HELP %invoke = ( headers => [ qw("tools/gimperasertool.h") ], code => <<'CODE' -success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE); +success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE, FALSE); CODE ); } diff --git a/tools/pdbgen/pdb/transform_tools.pdb b/tools/pdbgen/pdb/transform_tools.pdb index 14b1bcfa5c..509f8eed23 100644 --- a/tools/pdbgen/pdb/transform_tools.pdb +++ b/tools/pdbgen/pdb/transform_tools.pdb @@ -491,7 +491,7 @@ HELP %invoke = ( headers => [ qw("tools/gimperasertool.h") ], code => <<'CODE' -success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE); +success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE, FALSE); CODE ); } @@ -521,7 +521,7 @@ HELP %invoke = ( headers => [ qw("tools/gimperasertool.h") ], code => <<'CODE' -success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE); +success = eraser_non_gui (drawable, num_strokes, strokes, hardness, method, TRUE, FALSE); CODE ); }