app/pdb/tools_cmds.c app/tools/gimperasertool.c app/tools/gimperasertool.h
2001-10-30 Simon Budig <simon@gimp.org> * 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.
This commit is contained in:
13
ChangeLog
13
ChangeLog
@ -1,3 +1,16 @@
|
||||
2001-10-30 Simon Budig <simon@gimp.org>
|
||||
|
||||
* 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 <sven@gimp.org>
|
||||
|
||||
* app/base/temp-buf.c (temp_buf_to_gray): rewrote so gcc-3.0 doesn't
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user