app: resurrect the Iscissors tool to a zombie state

The interaction is fully restored, it's also ported to the new halt()
and commit() API of tools and semi-properly GEGLized: the gradient map
is now constructed on the fly using a GimpTileHandlerValidate
subclass.

The only problem is that it doesn't find any edges in the image and is
totally useless. Pushing anyway to put an end to the bitrot, any help
with debugging is greatly appreciated...
This commit is contained in:
Michael Natterer 2015-03-17 22:19:29 +01:00
parent 8c6e890835
commit d11f83a640
7 changed files with 538 additions and 323 deletions

View File

@ -192,6 +192,8 @@ libapptools_a_sources = \
gimptexttool-editor.h \
gimpthresholdtool.c \
gimpthresholdtool.h \
gimptilehandleriscissors.c \
gimptilehandleriscissors.h \
gimptool.c \
gimptool.h \
gimptool-progress.c \

View File

@ -183,9 +183,7 @@ gimp_tools_init (Gimp *gimp)
/* selection tools */
gimp_foreground_select_tool_register,
#if 0
gimp_iscissors_tool_register,
#endif
gimp_by_color_select_tool_register,
gimp_fuzzy_select_tool_register,
gimp_free_select_tool_register,

View File

@ -42,8 +42,6 @@
/* Livewire boundary implementation done by Laramie Leavitt */
#if 0
#include "config.h"
#include <stdlib.h>
@ -57,12 +55,6 @@
#include "tools-types.h"
#include "base/pixel-region.h"
#include "base/tile-manager.h"
#include "base/tile.h"
#include "paint-funcs/paint-funcs.h"
#include "gegl/gimp-gegl-utils.h"
#include "core/gimpchannel.h"
@ -80,17 +72,16 @@
#include "gimpiscissorsoptions.h"
#include "gimpiscissorstool.h"
#include "gimptilehandleriscissors.h"
#include "gimptoolcontrol.h"
#include "gimp-intl.h"
/* defines */
#define MAX_GRADIENT 179.606 /* == sqrt (127^2 + 127^2) */
#define GRADIENT_SEARCH 32 /* how far to look when snapping to an edge */
#define EXTEND_BY 0.2 /* proportion to expand cost map by */
#define FIXED 5 /* additional fixed size to expand cost map */
#define MIN_GRADIENT 63 /* gradients < this are directionless */
#define COST_WIDTH 2 /* number of bytes for each pixel in cost map */
@ -151,16 +142,18 @@ static gboolean gimp_iscissors_tool_key_press (GimpTool *tool,
GdkEventKey *kevent,
GimpDisplay *display);
static void gimp_iscissors_tool_apply (GimpIscissorsTool *iscissors,
GimpDisplay *display);
static void gimp_iscissors_tool_draw (GimpDrawTool *draw_tool);
static void gimp_iscissors_tool_halt (GimpIscissorsTool *iscissors,
GimpDisplay *display);
static void gimp_iscissors_tool_commit (GimpIscissorsTool *iscissors,
GimpDisplay *display);
static void iscissors_convert (GimpIscissorsTool *iscissors,
GimpDisplay *display);
static TileManager * gradient_map_new (GimpImage *image);
static GeglBuffer * gradient_map_new (GimpImage *image);
static void find_optimal_path (TileManager *gradient_map,
static void find_optimal_path (GeglBuffer *gradient_map,
GimpTempBuf *dp_buf,
gint x1,
gint y1,
@ -200,12 +193,6 @@ static GPtrArray * plot_pixels (GimpIscissorsTool *iscissors,
gint ye);
G_DEFINE_TYPE (GimpIscissorsTool, gimp_iscissors_tool,
GIMP_TYPE_SELECTION_TOOL)
#define parent_class gimp_iscissors_tool_parent_class
/* static variables */
/* where to move on a given link direction */
@ -231,39 +218,16 @@ static const gint move[8][2] =
* `---+---+---'
*/
/* temporary convolution buffers -- */
static guchar maxgrad_conv0[TILE_WIDTH * TILE_HEIGHT * 4] = "";
static guchar maxgrad_conv1[TILE_WIDTH * TILE_HEIGHT * 4] = "";
static guchar maxgrad_conv2[TILE_WIDTH * TILE_HEIGHT * 4] = "";
static const gfloat horz_deriv[9] =
{
1, 0, -1,
2, 0, -2,
1, 0, -1,
};
static const gfloat vert_deriv[9] =
{
1, 2, 1,
0, 0, 0,
-1, -2, -1,
};
static const gfloat blur_32[9] =
{
1, 1, 1,
1, 24, 1,
1, 1, 1,
};
static gfloat distance_weights[GRADIENT_SEARCH * GRADIENT_SEARCH];
static gint diagonal_weight[256];
static gint direction_value[256][4];
static Tile *cur_tile = NULL;
G_DEFINE_TYPE (GimpIscissorsTool, gimp_iscissors_tool,
GIMP_TYPE_SELECTION_TOOL)
#define parent_class gimp_iscissors_tool_parent_class
void
@ -374,50 +338,11 @@ gimp_iscissors_tool_control (GimpTool *tool,
break;
case GIMP_TOOL_ACTION_HALT:
/* Free and reset the curve list */
while (! g_queue_is_empty (iscissors->curves))
{
ICurve *curve = g_queue_pop_head (iscissors->curves);
gimp_iscissors_tool_halt (iscissors, display);
break;
if (curve->points)
g_ptr_array_free (curve->points, TRUE);
g_slice_free (ICurve, curve);
}
/* free mask */
if (iscissors->mask)
{
g_object_unref (iscissors->mask);
iscissors->mask = NULL;
}
/* free the gradient map */
if (iscissors->gradient_map)
{
/* release any tile we were using */
if (cur_tile)
{
tile_release (cur_tile, FALSE);
cur_tile = NULL;
}
tile_manager_unref (iscissors->gradient_map);
iscissors->gradient_map = NULL;
}
iscissors->curve1 = NULL;
iscissors->curve2 = NULL;
iscissors->first_point = TRUE;
iscissors->connected = FALSE;
iscissors->state = NO_ACTION;
/* Reset the dp buffers */
if (iscissors->dp_buf)
{
gimp_temp_buf_unref (iscissors->dp_buf);
iscissors->dp_buf = NULL;
}
case GIMP_TOOL_ACTION_COMMIT:
gimp_iscissors_tool_commit (iscissors, display);
break;
}
@ -481,7 +406,8 @@ gimp_iscissors_tool_button_press (GimpTool *tool,
iscissors->x,
iscissors->y))
{
gimp_iscissors_tool_apply (iscissors, display);
gimp_tool_control (tool, GIMP_TOOL_ACTION_COMMIT, display);
gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display);
}
else if (! iscissors->connected)
{
@ -1070,7 +996,8 @@ gimp_iscissors_tool_key_press (GimpTool *tool,
case GDK_KEY_ISO_Enter:
if (iscissors->connected && iscissors->mask)
{
gimp_iscissors_tool_apply (iscissors, display);
gimp_tool_control (tool, GIMP_TOOL_ACTION_COMMIT, display);
gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display);
return TRUE;
}
return FALSE;
@ -1085,27 +1012,69 @@ gimp_iscissors_tool_key_press (GimpTool *tool,
}
static void
gimp_iscissors_tool_apply (GimpIscissorsTool *iscissors,
GimpDisplay *display)
gimp_iscissors_tool_halt (GimpIscissorsTool *iscissors,
GimpDisplay *display)
{
/* Free and reset the curve list */
while (! g_queue_is_empty (iscissors->curves))
{
ICurve *curve = g_queue_pop_head (iscissors->curves);
if (curve->points)
g_ptr_array_free (curve->points, TRUE);
g_slice_free (ICurve, curve);
}
/* free mask */
if (iscissors->mask)
{
g_object_unref (iscissors->mask);
iscissors->mask = NULL;
}
/* free the gradient map */
if (iscissors->gradient_map)
{
g_object_unref (iscissors->gradient_map);
iscissors->gradient_map = NULL;
}
iscissors->curve1 = NULL;
iscissors->curve2 = NULL;
iscissors->first_point = TRUE;
iscissors->connected = FALSE;
iscissors->state = NO_ACTION;
/* Reset the dp buffers */
if (iscissors->dp_buf)
{
gimp_temp_buf_unref (iscissors->dp_buf);
iscissors->dp_buf = NULL;
}
}
static void
gimp_iscissors_tool_commit (GimpIscissorsTool *iscissors,
GimpDisplay *display)
{
GimpTool *tool = GIMP_TOOL (iscissors);
GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool);
GimpImage *image = gimp_display_get_image (display);
gimp_draw_tool_stop (GIMP_DRAW_TOOL (tool));
if (iscissors->connected && iscissors->mask)
{
gimp_channel_select_channel (gimp_image_get_mask (image),
tool->tool_info->blurb,
iscissors->mask,
0, 0,
options->operation,
options->feather,
options->feather_radius,
options->feather_radius);
gimp_channel_select_channel (gimp_image_get_mask (image),
tool->tool_info->blurb,
iscissors->mask,
0, 0,
options->operation,
options->feather,
options->feather_radius,
options->feather_radius);
gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display);
gimp_image_flush (image);
gimp_image_flush (image);
}
}
@ -1345,8 +1314,8 @@ calculate_curve (GimpIscissorsTool *iscissors,
/* Initialise the gradient map tile manager for this image if we
* don't already have one. */
if (!iscissors->gradient_map)
iscissors->gradient_map = gradient_map_new (image);
if (! iscissors->gradient_map)
iscissors->gradient_map = gradient_map_new (image);
/* allocate the dynamic programming array */
if (iscissors->dp_buf)
@ -1394,51 +1363,46 @@ calculate_curve (GimpIscissorsTool *iscissors,
/* badly need to get a replacement - this is _way_ too expensive */
static gboolean
gradient_map_value (TileManager *map,
gint x,
gint y,
guint8 *grad,
guint8 *dir)
gradient_map_value (GeglBuffer *map,
gint x,
gint y,
guint8 *grad,
guint8 *dir)
{
static gint cur_tilex;
static gint cur_tiley;
const guint8 *p;
const GeglRectangle *extents;
if (! cur_tile ||
x / TILE_WIDTH != cur_tilex ||
y / TILE_HEIGHT != cur_tiley)
extents = gegl_buffer_get_extent (map);
if (x >= extents->x &&
y >= extents->y &&
x < extents->width &&
y < extents->height)
{
if (cur_tile)
tile_release (cur_tile, FALSE);
guint8 sample[2];
cur_tile = tile_manager_get_tile (map, x, y, TRUE, FALSE);
gegl_buffer_sample (map, x, y, NULL, sample, NULL,
GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
if (!cur_tile)
return FALSE;
*grad = sample[0];
*dir = sample[1];
cur_tilex = x / TILE_WIDTH;
cur_tiley = y / TILE_HEIGHT;
return TRUE;
}
p = tile_data_pointer (cur_tile, x, y);
*grad = p[0];
*dir = p[1];
return TRUE;
return FALSE;
}
static gint
calculate_link (TileManager *gradient_map,
gint x,
gint y,
guint32 pixel,
gint link)
calculate_link (GeglBuffer *gradient_map,
gint x,
gint y,
guint32 pixel,
gint link)
{
gint value = 0;
guint8 grad1, dir1, grad2, dir2;
if (!gradient_map_value (gradient_map, x, y, &grad1, &dir1))
if (! gradient_map_value (gradient_map, x, y, &grad1, &dir1))
{
grad1 = 0;
dir1 = 255;
@ -1458,7 +1422,7 @@ calculate_link (TileManager *gradient_map,
x += (gint8)(pixel & 0xff);
y += (gint8)((pixel & 0xff00) >> 8);
if (!gradient_map_value (gradient_map, x, y, &grad2, &dir2))
if (! gradient_map_value (gradient_map, x, y, &grad2, &dir2))
{
grad2 = 0;
dir2 = 255;
@ -1521,7 +1485,7 @@ plot_pixels (GimpIscissorsTool *iscissors,
static void
find_optimal_path (TileManager *gradient_map,
find_optimal_path (GeglBuffer *gradient_map,
GimpTempBuf *dp_buf,
gint x1,
gint y1,
@ -1654,159 +1618,30 @@ find_optimal_path (TileManager *gradient_map,
}
}
/* Called to fill in a newly referenced tile in the gradient map */
static void
gradmap_tile_validate (TileManager *tm,
Tile *tile,
GimpImage *image)
{
GimpPickable *pickable;
const Babl *pickable_format;
GeglBuffer *src_buffer;
Tile *srctile;
PixelRegion srcPR;
PixelRegion destPR;
gint x, y;
gint dw, dh;
gint sw, sh;
gint i, j;
gint b;
gfloat gradient;
guint8 *tiledata;
guint8 *gradmap;
tile_manager_get_tile_coordinates (tm, tile, &x, &y);
dw = tile_ewidth (tile);
dh = tile_eheight (tile);
pickable = GIMP_PICKABLE (image);
gimp_pickable_flush (pickable);
/* get corresponding tile in the image */
src_buffer = gimp_pickable_get_buffer (pickable);
srctile = tile_manager_get_tile (gimp_gegl_buffer_get_tiles (src_buffer),
x, y, TRUE, FALSE);
if (! srctile)
return;
sw = tile_ewidth (srctile);
sh = tile_eheight (srctile);
pickable_format = gimp_pickable_get_format (pickable);
pixel_region_init_data (&srcPR,
tile_data_pointer (srctile, 0, 0),
babl_format_get_bytes_per_pixel (pickable_format),
babl_format_get_bytes_per_pixel (pickable_format) *
MIN (dw, sw),
0, 0, MIN (dw, sw), MIN (dh, sh));
/* XXX tile edges? */
/* Blur the source to get rid of noise */
pixel_region_init_data (&destPR, maxgrad_conv0, 4, TILE_WIDTH * 4,
0, 0, srcPR.w, srcPR.h);
convolve_region (&srcPR, &destPR, blur_32, 3, 32, GIMP_NORMAL_CONVOL, FALSE);
/* Use the blurred region as the new source pixel region */
pixel_region_init_data (&srcPR, maxgrad_conv0, 4, TILE_WIDTH * 4,
0, 0, srcPR.w, srcPR.h);
/* Get the horizontal derivative */
pixel_region_init_data (&destPR, maxgrad_conv1, 4, TILE_WIDTH * 4,
0, 0, srcPR.w, srcPR.h);
convolve_region (&srcPR, &destPR, horz_deriv, 3, 1, GIMP_NEGATIVE_CONVOL,
FALSE);
/* Get the vertical derivative */
pixel_region_init_data (&destPR, maxgrad_conv2, 4, TILE_WIDTH * 4,
0, 0, srcPR.w, srcPR.h);
convolve_region (&srcPR, &destPR, vert_deriv, 3, 1, GIMP_NEGATIVE_CONVOL,
FALSE);
/* calculate overall gradient */
tiledata = tile_data_pointer (tile, 0, 0);
for (i = 0; i < srcPR.h; i++)
{
const guint8 *datah = maxgrad_conv1 + srcPR.rowstride * i;
const guint8 *datav = maxgrad_conv2 + srcPR.rowstride * i;
gradmap = tiledata + tile_ewidth (tile) * COST_WIDTH * i;
for (j = 0; j < srcPR.w; j++)
{
gint8 hmax = datah[0] - 128;
gint8 vmax = datav[0] - 128;
for (b = 1; b < srcPR.bytes; b++)
{
if (abs (datah[b] - 128) > abs (hmax))
hmax = datah[b] - 128;
if (abs (datav[b] - 128) > abs (vmax))
vmax = datav[b] - 128;
}
if (i == 0 || j == 0 || i == srcPR.h-1 || j == srcPR.w-1)
{
gradmap[j * COST_WIDTH + 0] = 0;
gradmap[j * COST_WIDTH + 1] = 255;
goto contin;
}
/* 1 byte absolute magnitude first */
gradient = sqrt (SQR (hmax) + SQR (vmax));
gradmap[j * COST_WIDTH] = gradient * 255 / MAX_GRADIENT;
/* then 1 byte direction */
if (gradient > MIN_GRADIENT)
{
gfloat direction;
if (!hmax)
direction = (vmax > 0) ? G_PI_2 : -G_PI_2;
else
direction = atan ((gdouble) vmax / (gdouble) hmax);
/* Scale the direction from between 0 and 254,
* corresponding to -PI/2, PI/2 255 is reserved for
* d9irectionless pixels */
gradmap[j * COST_WIDTH + 1] =
(guint8) (254 * (direction + G_PI_2) / G_PI);
}
else
{
gradmap[j * COST_WIDTH + 1] = 255; /* reserved for weak gradient */
}
contin:
datah += srcPR.bytes;
datav += srcPR.bytes;
}
}
tile_release (srctile, FALSE);
}
static TileManager *
static GeglBuffer *
gradient_map_new (GimpImage *image)
{
TileManager *tm;
GeglBuffer *buffer;
GeglTileHandler *handler;
tm = tile_manager_new (gimp_image_get_width (image),
gimp_image_get_height (image),
sizeof (guint8) * COST_WIDTH);
buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
gimp_image_get_width (image),
gimp_image_get_height (image)),
babl_format_n (babl_type ("u8"), 2));
tile_manager_set_validate_proc (tm,
(TileValidateProc) gradmap_tile_validate,
image);
handler = gimp_tile_handler_iscissors_new (image);
return tm;
gimp_tile_handler_validate_assign (GIMP_TILE_HANDLER_VALIDATE (handler),
buffer);
gimp_tile_handler_validate_invalidate (GIMP_TILE_HANDLER_VALIDATE (handler),
0, 0,
gimp_image_get_width (image),
gimp_image_get_height (image));
g_object_unref (handler);
return buffer;
}
static void
@ -1815,14 +1650,12 @@ find_max_gradient (GimpIscissorsTool *iscissors,
gint *x,
gint *y)
{
PixelRegion srcPR;
gint radius;
gint i, j;
gint endx, endy;
gint cx, cy;
gint x1, y1, x2, y2;
gpointer pr;
gfloat max_gradient;
GeglBufferIterator *iter;
GeglRectangle *roi;
gint radius;
gint cx, cy;
gint x1, y1, x2, y2;
gfloat max_gradient;
/* Initialise the gradient map tile manager for this image if we
* don't already have one. */
@ -1844,29 +1677,30 @@ find_max_gradient (GimpIscissorsTool *iscissors,
*x = cx;
*y = cy;
/* Find the point of max gradient */
pixel_region_init (&srcPR, iscissors->gradient_map,
x1, y1, x2 - x1, y2 - y1, FALSE);
iter = gegl_buffer_iterator_new (iscissors->gradient_map,
GEGL_RECTANGLE (x1, y1, x2 - x1, y2 - y1),
0, NULL,
GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
roi = &iter->roi[0];
/* this iterates over 1, 2 or 4 tiles only */
for (pr = pixel_regions_register (1, &srcPR);
pr != NULL;
pr = pixel_regions_process (pr))
while (gegl_buffer_iterator_next (iter))
{
endx = srcPR.x + srcPR.w;
endy = srcPR.y + srcPR.h;
guint8 *data = iter->data[0];
gint endx = roi->x + roi->width;
gint endy = roi->y + roi->height;
gint i, j;
for (i = srcPR.y; i < endy; i++)
for (i = roi->y; i < endy; i++)
{
const guint8 *gradient = srcPR.data + srcPR.rowstride * (i - srcPR.y);
const guint8 *gradient = data + 2 * roi->width * (i - roi->y);
for (j = srcPR.x; j < endx; j++)
for (j = roi->x; j < endx; j++)
{
gfloat g = *gradient;
gradient += COST_WIDTH;
g *= distance_weights [(i-y1) * GRADIENT_SEARCH + (j-x1)];
g *= distance_weights [(i - y1) * GRADIENT_SEARCH + (j - x1)];
if (g > max_gradient)
{
@ -1879,5 +1713,3 @@ find_max_gradient (GimpIscissorsTool *iscissors,
}
}
}
#endif

View File

@ -15,8 +15,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if 0
#ifndef __GIMP_ISCISSORS_TOOL_H__
#define __GIMP_ISCISSORS_TOOL_H__
@ -86,7 +84,7 @@ struct _GimpIscissorsTool
/* XXX might be useful */
GimpChannel *mask; /* selection mask */
TileManager *gradient_map; /* lazily filled gradient map */
GeglBuffer *gradient_map; /* lazily filled gradient map */
};
struct _GimpIscissorsToolClass
@ -102,5 +100,3 @@ GType gimp_iscissors_tool_get_type (void) G_GNUC_CONST;
#endif /* __GIMP_ISCISSORS_TOOL_H__ */
#endif

View File

@ -0,0 +1,330 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <stdlib.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libgimpmath/gimpmath.h"
#include "tools-types.h"
#include "gegl/gimp-gegl-loops.h"
#include "core/gimpimage.h"
#include "core/gimppickable.h"
#include "gimptilehandleriscissors.h"
enum
{
PROP_0,
PROP_IMAGE
};
static void gimp_tile_handler_iscissors_finalize (GObject *object);
static void gimp_tile_handler_iscissors_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void gimp_tile_handler_iscissors_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void gimp_tile_handler_iscissors_validate (GimpTileHandlerValidate *validate,
const GeglRectangle *rect,
const Babl *format,
gpointer dest_buf,
gint dest_stride);
G_DEFINE_TYPE (GimpTileHandlerIscissors, gimp_tile_handler_iscissors,
GIMP_TYPE_TILE_HANDLER_VALIDATE)
#define parent_class gimp_tile_handler_iscissors_parent_class
static void
gimp_tile_handler_iscissors_class_init (GimpTileHandlerIscissorsClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GimpTileHandlerValidateClass *validate_class;
validate_class = GIMP_TILE_HANDLER_VALIDATE_CLASS (klass);
object_class->finalize = gimp_tile_handler_iscissors_finalize;
object_class->set_property = gimp_tile_handler_iscissors_set_property;
object_class->get_property = gimp_tile_handler_iscissors_get_property;
validate_class->validate = gimp_tile_handler_iscissors_validate;
g_object_class_install_property (object_class, PROP_IMAGE,
g_param_spec_object ("image", NULL, NULL,
GIMP_TYPE_IMAGE,
GIMP_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
}
static void
gimp_tile_handler_iscissors_init (GimpTileHandlerIscissors *iscissors)
{
}
static void
gimp_tile_handler_iscissors_finalize (GObject *object)
{
GimpTileHandlerIscissors *iscissors = GIMP_TILE_HANDLER_ISCISSORS (object);
if (iscissors->image)
{
g_object_unref (iscissors->image);
iscissors->image = NULL;
}
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gimp_tile_handler_iscissors_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
GimpTileHandlerIscissors *iscissors = GIMP_TILE_HANDLER_ISCISSORS (object);
switch (property_id)
{
case PROP_IMAGE:
iscissors->image = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
gimp_tile_handler_iscissors_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
GimpTileHandlerIscissors *iscissors = GIMP_TILE_HANDLER_ISCISSORS (object);
switch (property_id)
{
case PROP_IMAGE:
g_value_set_object (value, iscissors->image);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static const gfloat horz_deriv[9] =
{
1, 0, -1,
2, 0, -2,
1, 0, -1,
};
static const gfloat vert_deriv[9] =
{
1, 2, 1,
0, 0, 0,
-1, -2, -1,
};
static const gfloat blur_32[9] =
{
1, 1, 1,
1, 24, 1,
1, 1, 1,
};
#define MAX_GRADIENT 179.606 /* == sqrt (127^2 + 127^2) */
#define MIN_GRADIENT 63 /* gradients < this are directionless */
#define COST_WIDTH 2 /* number of bytes for each pixel in cost map */
static void
gimp_tile_handler_iscissors_validate (GimpTileHandlerValidate *validate,
const GeglRectangle *rect,
const Babl *format,
gpointer dest_buf,
gint dest_stride)
{
GimpTileHandlerIscissors *iscissors = GIMP_TILE_HANDLER_ISCISSORS (validate);
GeglBuffer *src;
GeglBuffer *temp0;
GeglBuffer *temp1;
GeglBuffer *temp2;
gint stride1;
gint stride2;
gint i, j;
/* temporary convolution buffers -- */
guchar *maxgrad_conv1;
guchar *maxgrad_conv2;
#if 0
g_printerr ("validating at %d %d %d %d\n",
rect->x,
rect->y,
rect->width,
rect->height);
#endif
gimp_pickable_flush (GIMP_PICKABLE (iscissors->image));
src = gimp_pickable_get_buffer (GIMP_PICKABLE (iscissors->image));
temp0 = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
rect->width,
rect->height),
babl_format ("R'G'B'A u8"));
temp1 = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
rect->width,
rect->height),
babl_format ("R'G'B'A u8"));
temp2 = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
rect->width,
rect->height),
babl_format ("R'G'B'A u8"));
/* XXX tile edges? */
/* Blur the source to get rid of noise */
gimp_gegl_convolve (src, rect,
temp0, GEGL_RECTANGLE (0, 0, rect->width, rect->height),
blur_32, 3, 32, GIMP_NORMAL_CONVOL, FALSE);
/* Use this blurred region as the new source */
/* Get the horizontal derivative */
gimp_gegl_convolve (temp0, GEGL_RECTANGLE (0, 0, rect->width, rect->height),
temp1, GEGL_RECTANGLE (0, 0, rect->width, rect->height),
horz_deriv, 3, 1, GIMP_NEGATIVE_CONVOL, FALSE);
/* Get the vertical derivative */
gimp_gegl_convolve (temp0, GEGL_RECTANGLE (0, 0, rect->width, rect->height),
temp2, GEGL_RECTANGLE (0, 0, rect->width, rect->height),
vert_deriv, 3, 1, GIMP_NEGATIVE_CONVOL, FALSE);
maxgrad_conv1 = gegl_buffer_linear_open (temp1,
GEGL_RECTANGLE (0, 0,
rect->width,
rect->height),
&stride1, NULL);
maxgrad_conv2 = gegl_buffer_linear_open (temp2,
GEGL_RECTANGLE (0, 0,
rect->width,
rect->height),
&stride2, NULL);
/* calculate overall gradient */
for (i = 0; i < rect->height; i++)
{
const guint8 *datah = maxgrad_conv1 + stride1 * i;
const guint8 *datav = maxgrad_conv2 + stride2 * i;
guint8 *gradmap = (guint8 *) dest_buf + dest_stride * i;
for (j = 0; j < rect->width; j++)
{
gint8 hmax = datah[0] - 128;
gint8 vmax = datav[0] - 128;
gfloat gradient;
gint b;
for (b = 1; b < 4; b++)
{
if (abs (datah[b] - 128) > abs (hmax))
hmax = datah[b] - 128;
if (abs (datav[b] - 128) > abs (vmax))
vmax = datav[b] - 128;
}
if (i == 0 || j == 0 || i == rect->height - 1 || j == rect->width - 1)
{
gradmap[j * COST_WIDTH + 0] = 0;
gradmap[j * COST_WIDTH + 1] = 255;
goto contin;
}
/* 1 byte absolute magnitude first */
gradient = sqrt (SQR (hmax) + SQR (vmax));
gradmap[j * COST_WIDTH] = gradient * 255 / MAX_GRADIENT;
/* then 1 byte direction */
if (gradient > MIN_GRADIENT)
{
gfloat direction;
if (! hmax)
direction = (vmax > 0) ? G_PI_2 : -G_PI_2;
else
direction = atan ((gdouble) vmax / (gdouble) hmax);
/* Scale the direction from between 0 and 254,
* corresponding to -PI/2, PI/2 255 is reserved for
* directionless pixels
*/
gradmap[j * COST_WIDTH + 1] =
(guint8) (254 * (direction + G_PI_2) / G_PI);
}
else
{
gradmap[j * COST_WIDTH + 1] = 255; /* reserved for weak gradient */
}
contin:
datah += 4;
datav += 4;
}
}
gegl_buffer_linear_close (temp1, maxgrad_conv1);
gegl_buffer_linear_close (temp2, maxgrad_conv2);
g_object_unref (temp0);
g_object_unref (temp1);
g_object_unref (temp2);
}
GeglTileHandler *
gimp_tile_handler_iscissors_new (GimpImage *image)
{
g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
return g_object_new (GIMP_TYPE_TILE_HANDLER_ISCISSORS,
"whole-tile", TRUE,
"image", image,
NULL);
}

View File

@ -0,0 +1,59 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GIMP_TILE_HANDLER_ISCISSORS_H__
#define __GIMP_TILE_HANDLER_ISCISSORS_H__
#include "gegl/gimptilehandlervalidate.h"
/***
* GimpTileHandlerIscissors is a GeglTileHandler that renders the
* Iscissors tool's gradmap.
*/
#define GIMP_TYPE_TILE_HANDLER_ISCISSORS (gimp_tile_handler_iscissors_get_type ())
#define GIMP_TILE_HANDLER_ISCISSORS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_TILE_HANDLER_ISCISSORS, GimpTileHandlerIscissors))
#define GIMP_TILE_HANDLER_ISCISSORS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_TILE_HANDLER_ISCISSORS, GimpTileHandlerIscissorsClass))
#define GIMP_IS_TILE_HANDLER_ISCISSORS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_TILE_HANDLER_ISCISSORS))
#define GIMP_IS_TILE_HANDLER_ISCISSORS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_TILE_HANDLER_ISCISSORS))
#define GIMP_TILE_HANDLER_ISCISSORS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_TILE_HANDLER_ISCISSORS, GimpTileHandlerIscissorsClass))
typedef struct _GimpTileHandlerIscissors GimpTileHandlerIscissors;
typedef struct _GimpTileHandlerIscissorsClass GimpTileHandlerIscissorsClass;
struct _GimpTileHandlerIscissors
{
GimpTileHandlerValidate parent_instance;
GimpImage *image;
};
struct _GimpTileHandlerIscissorsClass
{
GimpTileHandlerValidateClass parent_class;
};
GType gimp_tile_handler_iscissors_get_type (void) G_GNUC_CONST;
GeglTileHandler * gimp_tile_handler_iscissors_new (GimpImage *image);
#endif /* __GIMP_TILE_HANDLER_ISCISSORS_H__ */

View File

@ -574,9 +574,7 @@
<menuitem action="tools-foreground-select" />
<menuitem action="tools-fuzzy-select" />
<menuitem action="tools-by-color-select" />
<!--
<menuitem action="tools-iscissors" />
-->
</menu>
<menu action="tools-paint-menu" name="Paint Tools">
<menuitem action="tools-bucket-fill" />