mirror of https://github.com/GNOME/gimp.git
added gimp_scan_convert_compose(), an alternative to
2005-08-06 Sven Neumann <sven@gimp.org> * app/core/gimpscanconvert.[ch]: added gimp_scan_convert_compose(), an alternative to gimp_scan_convert_render() that allows to compose strokes on a drawable. * app/tools/gimpforegroundselecttool.c: use the new function to get rid of temporary channels for applying the strokes. Also fixed calculation of stroke width from display scale.
This commit is contained in:
parent
39f4e7bdb3
commit
68f09c7cb6
12
ChangeLog
12
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
2005-08-06 Sven Neumann <sven@gimp.org>
|
||||
|
||||
* app/core/gimpscanconvert.[ch]: added gimp_scan_convert_compose(),
|
||||
an alternative to gimp_scan_convert_render() that allows to compose
|
||||
strokes on a drawable.
|
||||
|
||||
* app/tools/gimpforegroundselecttool.c: use the new function to
|
||||
get rid of temporary channels for applying the strokes. Also fixed
|
||||
calculation of stroke width from display scale.
|
||||
|
||||
2005-08-06 Michael Natterer <mitch@gimp.org>
|
||||
|
||||
* app/widgets/gimpuimanager.c (gimp_ui_manager_ui_popup): applied
|
||||
|
@ -7,7 +17,7 @@
|
|||
2005-08-06 Sven Neumann <sven@gimp.org>
|
||||
|
||||
* app/display/gimpdisplayshell-draw.c (gimp_display_shell_draw_pen):
|
||||
* app/tools/gimpforegroundselecttool.c: ccorrectly handle a stroke
|
||||
* app/tools/gimpforegroundselecttool.c: correctly handle a stroke
|
||||
consisting of just a single point.
|
||||
|
||||
2005-08-06 Sven Neumann <sven@gimp.org>
|
||||
|
|
|
@ -37,33 +37,35 @@
|
|||
|
||||
struct _GimpScanConvert
|
||||
{
|
||||
gdouble ratio_xy;
|
||||
gdouble ratio_xy;
|
||||
|
||||
/* stuff necessary for the _add_polygons API... :-/ */
|
||||
gboolean got_first;
|
||||
gboolean need_closing;
|
||||
GimpVector2 first;
|
||||
GimpVector2 prev;
|
||||
gboolean got_first;
|
||||
gboolean need_closing;
|
||||
GimpVector2 first;
|
||||
GimpVector2 prev;
|
||||
|
||||
gboolean have_open;
|
||||
guint num_nodes;
|
||||
ArtVpath *vpath;
|
||||
gboolean have_open;
|
||||
guint num_nodes;
|
||||
ArtVpath *vpath;
|
||||
|
||||
ArtSVP *svp; /* Sorted vector path
|
||||
ArtSVP *svp; /* Sorted vector path
|
||||
(extension no longer possible) */
|
||||
|
||||
/* stuff necessary for the rendering callback */
|
||||
guchar *buf;
|
||||
gint rowstride;
|
||||
gint x0, x1;
|
||||
gboolean antialias;
|
||||
gboolean value;
|
||||
GimpChannelOps op;
|
||||
guchar *buf;
|
||||
gint rowstride;
|
||||
gint x0, x1;
|
||||
gboolean antialias;
|
||||
gboolean value;
|
||||
};
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static void gimp_scan_convert_render_internal (GimpScanConvert *sc,
|
||||
GimpChannelOps op,
|
||||
TileManager *tile_manager,
|
||||
gint off_x,
|
||||
gint off_y,
|
||||
|
@ -72,11 +74,16 @@ static void gimp_scan_convert_render_internal (GimpScanConvert *sc,
|
|||
static void gimp_scan_convert_finish (GimpScanConvert *sc);
|
||||
static void gimp_scan_convert_close_add_points (GimpScanConvert *sc);
|
||||
|
||||
static void gimp_scan_convert_render_callback (gpointer user_data,
|
||||
gint y,
|
||||
gint start_value,
|
||||
ArtSVPRenderAAStep *steps,
|
||||
gint n_steps);
|
||||
static void gimp_scan_convert_render_callback (gpointer user_data,
|
||||
gint y,
|
||||
gint start_value,
|
||||
ArtSVPRenderAAStep *steps,
|
||||
gint n_steps);
|
||||
static void gimp_scan_convert_compose_callback (gpointer user_data,
|
||||
gint y,
|
||||
gint start_value,
|
||||
ArtSVPRenderAAStep *steps,
|
||||
gint n_steps);
|
||||
|
||||
/* public functions */
|
||||
|
||||
|
@ -448,7 +455,7 @@ gimp_scan_convert_render (GimpScanConvert *sc,
|
|||
g_return_if_fail (sc != NULL);
|
||||
g_return_if_fail (tile_manager != NULL);
|
||||
|
||||
gimp_scan_convert_render_internal (sc,
|
||||
gimp_scan_convert_render_internal (sc, GIMP_CHANNEL_OP_REPLACE,
|
||||
tile_manager, off_x, off_y,
|
||||
antialias, 255);
|
||||
}
|
||||
|
@ -463,13 +470,29 @@ gimp_scan_convert_render_value (GimpScanConvert *sc,
|
|||
g_return_if_fail (sc != NULL);
|
||||
g_return_if_fail (tile_manager != NULL);
|
||||
|
||||
gimp_scan_convert_render_internal (sc,
|
||||
gimp_scan_convert_render_internal (sc, GIMP_CHANNEL_OP_REPLACE,
|
||||
tile_manager, off_x, off_y,
|
||||
FALSE, value);
|
||||
}
|
||||
|
||||
void
|
||||
gimp_scan_convert_compose (GimpScanConvert *sc,
|
||||
GimpChannelOps op,
|
||||
TileManager *tile_manager,
|
||||
gint off_x,
|
||||
gint off_y)
|
||||
{
|
||||
g_return_if_fail (sc != NULL);
|
||||
g_return_if_fail (tile_manager != NULL);
|
||||
|
||||
gimp_scan_convert_render_internal (sc, op,
|
||||
tile_manager, off_x, off_y,
|
||||
FALSE, 255);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_scan_convert_render_internal (GimpScanConvert *sc,
|
||||
GimpChannelOps op,
|
||||
TileManager *tile_manager,
|
||||
gint off_x,
|
||||
gint off_y,
|
||||
|
@ -478,6 +501,7 @@ gimp_scan_convert_render_internal (GimpScanConvert *sc,
|
|||
{
|
||||
PixelRegion maskPR;
|
||||
gpointer pr;
|
||||
gpointer callback;
|
||||
|
||||
gimp_scan_convert_finish (sc);
|
||||
|
||||
|
@ -493,6 +517,11 @@ gimp_scan_convert_render_internal (GimpScanConvert *sc,
|
|||
|
||||
sc->antialias = antialias;
|
||||
sc->value = value;
|
||||
sc->op = op;
|
||||
|
||||
callback = (op == GIMP_CHANNEL_OP_REPLACE ?
|
||||
gimp_scan_convert_render_callback :
|
||||
gimp_scan_convert_compose_callback);
|
||||
|
||||
for (pr = pixel_regions_register (1, &maskPR);
|
||||
pr != NULL;
|
||||
|
@ -508,8 +537,7 @@ gimp_scan_convert_render_internal (GimpScanConvert *sc,
|
|||
off_y + maskPR.y,
|
||||
sc->x1,
|
||||
off_y + maskPR.y + maskPR.h,
|
||||
gimp_scan_convert_render_callback, sc);
|
||||
|
||||
callback, sc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -639,3 +667,87 @@ gimp_scan_convert_render_callback (gpointer user_data,
|
|||
#undef VALUE_TO_PIXEL
|
||||
}
|
||||
|
||||
static inline void
|
||||
compose (GimpChannelOps op,
|
||||
guchar *buf,
|
||||
guchar value,
|
||||
gint len)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case GIMP_CHANNEL_OP_ADD:
|
||||
if (value)
|
||||
memset (buf, value, len);
|
||||
break;
|
||||
case GIMP_CHANNEL_OP_SUBTRACT:
|
||||
if (value)
|
||||
memset (buf, 0, len);
|
||||
break;
|
||||
case GIMP_CHANNEL_OP_REPLACE:
|
||||
memset (buf, value, len);
|
||||
break;
|
||||
case GIMP_CHANNEL_OP_INTERSECT:
|
||||
do
|
||||
{
|
||||
if (*buf)
|
||||
*buf = value;
|
||||
buf++;
|
||||
}
|
||||
while (--len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_scan_convert_compose_callback (gpointer user_data,
|
||||
gint y,
|
||||
gint start_value,
|
||||
ArtSVPRenderAAStep *steps,
|
||||
gint n_steps)
|
||||
{
|
||||
GimpScanConvert *sc = user_data;
|
||||
gint cur_value = start_value;
|
||||
gint k, run_x0, run_x1;
|
||||
|
||||
#define VALUE_TO_PIXEL(x) (((x) & (1 << 23) ? 255 : 0))
|
||||
|
||||
if (n_steps > 0)
|
||||
{
|
||||
run_x1 = steps[0].x;
|
||||
|
||||
if (run_x1 > sc->x0)
|
||||
compose (sc->op, sc->buf,
|
||||
VALUE_TO_PIXEL (cur_value),
|
||||
run_x1 - sc->x0);
|
||||
|
||||
for (k = 0; k < n_steps - 1; k++)
|
||||
{
|
||||
cur_value += steps[k].delta;
|
||||
|
||||
run_x0 = run_x1;
|
||||
run_x1 = steps[k + 1].x;
|
||||
|
||||
if (run_x1 > run_x0)
|
||||
compose (sc->op, sc->buf + run_x0 - sc->x0,
|
||||
VALUE_TO_PIXEL (cur_value),
|
||||
run_x1 - run_x0);
|
||||
}
|
||||
|
||||
cur_value += steps[k].delta;
|
||||
|
||||
if (sc->x1 > run_x1)
|
||||
compose (sc->op, sc->buf + run_x1 - sc->x0,
|
||||
VALUE_TO_PIXEL (cur_value),
|
||||
sc->x1 - run_x1);
|
||||
}
|
||||
else
|
||||
{
|
||||
compose (sc->op, sc->buf,
|
||||
VALUE_TO_PIXEL (cur_value),
|
||||
sc->x1 - sc->x0);
|
||||
}
|
||||
|
||||
sc->buf += sc->rowstride;
|
||||
|
||||
#undef VALUE_TO_PIXEL
|
||||
}
|
||||
|
|
|
@ -87,5 +87,14 @@ void gimp_scan_convert_render_value (GimpScanConvert *sc,
|
|||
gint off_y,
|
||||
guchar value);
|
||||
|
||||
/* This is a variant of gimp_scan_convert_render() that composes the
|
||||
* (unaliased) scan conversion with the existing drawable content.
|
||||
*/
|
||||
void gimp_scan_convert_compose (GimpScanConvert *sc,
|
||||
GimpChannelOps op,
|
||||
TileManager *tile_manager,
|
||||
gint off_x,
|
||||
gint off_y);
|
||||
|
||||
|
||||
#endif /* __GIMP_SCAN_CONVERT_H__ */
|
||||
|
|
|
@ -106,11 +106,11 @@ static void gimp_foreground_select_tool_apply (GimpForegroundSelectTool *fg
|
|||
GimpDisplay *gdisp);
|
||||
|
||||
static void gimp_foreground_select_tool_stroke (GimpChannel *mask,
|
||||
GimpDisplay *gdisp,
|
||||
FgSelectStroke *stroke);
|
||||
|
||||
static void gimp_foreground_select_tool_push_stroke (GimpForegroundSelectTool *fg_select,
|
||||
GimpForegroundSelectOptions *options);
|
||||
static void gimp_foreground_select_tool_push_stroke (GimpForegroundSelectTool *fg_select,
|
||||
GimpDisplay *gdisp,
|
||||
GimpForegroundSelectOptions *options);
|
||||
|
||||
|
||||
static GimpFreeSelectToolClass *parent_class = NULL;
|
||||
|
@ -418,7 +418,7 @@ gimp_foreground_select_tool_button_release (GimpTool *tool,
|
|||
|
||||
gimp_tool_control_halt (tool->control);
|
||||
|
||||
gimp_foreground_select_tool_push_stroke (fg_select, options);
|
||||
gimp_foreground_select_tool_push_stroke (fg_select, gdisp, options);
|
||||
|
||||
gimp_foreground_select_tool_select (GIMP_FREE_SELECT_TOOL (tool), gdisp);
|
||||
}
|
||||
|
@ -524,15 +524,15 @@ gimp_foreground_select_tool_select (GimpFreeSelectTool *free_sel,
|
|||
0, 0, 127);
|
||||
gimp_scan_convert_free (scan_convert);
|
||||
|
||||
/* apply foreground and background markers */
|
||||
for (list = fg_select->strokes; list; list = list->next)
|
||||
gimp_foreground_select_tool_stroke (mask, list->data);
|
||||
|
||||
/* restrict working area to double the size of the bounding box */
|
||||
gimp_channel_bounds (mask, &x, &y, &x2, &y2);
|
||||
width = x2 - x;
|
||||
height = y2 - y;
|
||||
|
||||
/* apply foreground and background markers */
|
||||
for (list = fg_select->strokes; list; list = list->next)
|
||||
gimp_foreground_select_tool_stroke (mask, gdisp, list->data);
|
||||
|
||||
/* restrict working area to double the size of the bounding box */
|
||||
x = MAX (0, x - width / 2);
|
||||
y = MAX (0, y - height / 2);
|
||||
width = MIN (width * 2, gimp_item_width (GIMP_ITEM (mask)) - x);
|
||||
|
@ -627,20 +627,9 @@ gimp_foreground_select_tool_apply (GimpForegroundSelectTool *fg_select,
|
|||
|
||||
static void
|
||||
gimp_foreground_select_tool_stroke (GimpChannel *mask,
|
||||
GimpDisplay *gdisp,
|
||||
FgSelectStroke *stroke)
|
||||
{
|
||||
GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (gdisp->shell);
|
||||
GimpScanConvert *scan_convert = gimp_scan_convert_new ();
|
||||
GimpItem *item = GIMP_ITEM (mask);
|
||||
GimpChannel *channel = gimp_channel_new (gimp_item_get_image (item),
|
||||
gimp_item_width (item),
|
||||
gimp_item_height (item),
|
||||
"tmp", NULL);
|
||||
|
||||
/* FIXME: We should be able to get away w/o a temporary drawable
|
||||
* by doing some changes to GimpScanConvert.
|
||||
*/
|
||||
GimpScanConvert *scan_convert = gimp_scan_convert_new ();
|
||||
|
||||
if (stroke->num_points == 1)
|
||||
{
|
||||
|
@ -661,34 +650,31 @@ gimp_foreground_select_tool_stroke (GimpChannel *mask,
|
|||
}
|
||||
|
||||
gimp_scan_convert_stroke (scan_convert,
|
||||
SCALEFACTOR_Y (shell) * stroke->width,
|
||||
stroke->width,
|
||||
GIMP_JOIN_MITER, GIMP_CAP_ROUND, 10.0,
|
||||
0.0, NULL);
|
||||
gimp_scan_convert_render (scan_convert,
|
||||
gimp_drawable_data (GIMP_DRAWABLE (channel)),
|
||||
0, 0, FALSE);
|
||||
gimp_scan_convert_free (scan_convert);
|
||||
|
||||
gimp_channel_combine_mask (mask, channel,
|
||||
gimp_scan_convert_compose (scan_convert,
|
||||
stroke->background ?
|
||||
GIMP_CHANNEL_OP_SUBTRACT : GIMP_CHANNEL_OP_ADD,
|
||||
gimp_drawable_data (GIMP_DRAWABLE (mask)),
|
||||
0, 0);
|
||||
|
||||
g_object_unref (channel);
|
||||
gimp_scan_convert_free (scan_convert);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_foreground_select_tool_push_stroke (GimpForegroundSelectTool *fg_select,
|
||||
GimpDisplay *gdisp,
|
||||
GimpForegroundSelectOptions *options)
|
||||
{
|
||||
FgSelectStroke *stroke;
|
||||
GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (gdisp->shell);
|
||||
FgSelectStroke *stroke;
|
||||
|
||||
g_return_if_fail (fg_select->stroke != NULL);
|
||||
|
||||
stroke = g_new (FgSelectStroke, 1);
|
||||
|
||||
stroke->background = options->background;
|
||||
stroke->width = options->stroke_width;
|
||||
stroke->width = options->stroke_width / SCALEFACTOR_Y (shell);
|
||||
stroke->num_points = fg_select->stroke->len;
|
||||
stroke->points = (GimpVector2 *) g_array_free (fg_select->stroke, FALSE);
|
||||
|
||||
|
|
Loading…
Reference in New Issue