mirror of https://github.com/GNOME/gimp.git
Partially implemented sample-merged healing.
This commit is contained in:
parent
2a97cb07c1
commit
02156f9a74
|
@ -0,0 +1,795 @@
|
|||
/* The GIMP -- an 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "libgimpbase/gimpbase.h"
|
||||
|
||||
#include "paint-types.h"
|
||||
|
||||
#include "paint-funcs/paint-funcs.h"
|
||||
|
||||
#include "base/pixel-region.h"
|
||||
#include "base/temp-buf.h"
|
||||
#include "base/tile-manager.h"
|
||||
|
||||
#include "core/gimpitem.h"
|
||||
#include "core/gimppickable.h"
|
||||
#include "core/gimpimage.h"
|
||||
#include "core/gimpdrawable.h"
|
||||
#include "core/gimppattern.h"
|
||||
|
||||
#include "gimpheal.h"
|
||||
#include "gimphealoptions.h"
|
||||
|
||||
#include "gimp-intl.h"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_SRC_DRAWABLE,
|
||||
PROP_SRC_X,
|
||||
PROP_SRC_Y
|
||||
};
|
||||
|
||||
static void gimp_heal_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void gimp_heal_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void gimp_heal_paint (GimpPaintCore *paint_core,
|
||||
GimpDrawable *drawable,
|
||||
GimpPaintOptions *paint_options,
|
||||
GimpPaintState paint_state,
|
||||
guint32 time);
|
||||
|
||||
static void gimp_heal_motion (GimpPaintCore *paint_core,
|
||||
GimpDrawable *drawable,
|
||||
GimpPaintOptions *paint_options);
|
||||
|
||||
static void gimp_heal_set_src_drawable (GimpHeal *heal,
|
||||
GimpDrawable *drawable);
|
||||
|
||||
G_DEFINE_TYPE (GimpHeal, gimp_heal, GIMP_TYPE_BRUSH_CORE)
|
||||
|
||||
void
|
||||
gimp_heal_register (Gimp *gimp,
|
||||
GimpPaintRegisterCallback callback)
|
||||
{
|
||||
(* callback) (gimp, /* gimp */
|
||||
GIMP_TYPE_HEAL, /* paint type */
|
||||
GIMP_TYPE_HEAL_OPTIONS, /* paint options type */
|
||||
"gimp-heal", /* identifier */
|
||||
_("Heal"), /* blurb */
|
||||
"gimp-tool-heal"); /* stock id */
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_class_init (GimpHealClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GimpPaintCoreClass *paint_core_class = GIMP_PAINT_CORE_CLASS (klass);
|
||||
GimpBrushCoreClass *brush_core_class = GIMP_BRUSH_CORE_CLASS (klass);
|
||||
|
||||
object_class->set_property = gimp_heal_set_property;
|
||||
object_class->get_property = gimp_heal_get_property;
|
||||
|
||||
paint_core_class->paint = gimp_heal_paint;
|
||||
|
||||
brush_core_class->handles_changing_brush = TRUE;
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SRC_DRAWABLE,
|
||||
g_param_spec_object ("src-drawable",
|
||||
NULL, NULL,
|
||||
GIMP_TYPE_DRAWABLE,
|
||||
GIMP_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SRC_X,
|
||||
g_param_spec_double ("src-x", NULL, NULL,
|
||||
0, GIMP_MAX_IMAGE_SIZE,
|
||||
0.0,
|
||||
GIMP_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (object_class, PROP_SRC_Y,
|
||||
g_param_spec_double ("src-y", NULL, NULL,
|
||||
0, GIMP_MAX_IMAGE_SIZE,
|
||||
0.0,
|
||||
GIMP_PARAM_READWRITE));
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_init (GimpHeal *heal)
|
||||
{
|
||||
heal->set_source = FALSE;
|
||||
|
||||
heal->src_drawable = NULL;
|
||||
heal->src_x = 0.0;
|
||||
heal->src_y = 0.0;
|
||||
|
||||
heal->orig_src_x = 0.0;
|
||||
heal->orig_src_y = 0.0;
|
||||
|
||||
heal->offset_x = 0.0;
|
||||
heal->offset_y = 0.0;
|
||||
heal->first_stroke = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GimpHeal *heal = GIMP_HEAL (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_SRC_DRAWABLE:
|
||||
gimp_heal_set_src_drawable (heal, g_value_get_object (value));
|
||||
break;
|
||||
case PROP_SRC_X:
|
||||
heal->src_x = g_value_get_double (value);
|
||||
break;
|
||||
case PROP_SRC_Y:
|
||||
heal->src_y = g_value_get_double (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GimpHeal *heal = GIMP_HEAL (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_SRC_DRAWABLE:
|
||||
g_value_set_object (value, heal->src_drawable);
|
||||
break;
|
||||
case PROP_SRC_X:
|
||||
g_value_set_int (value, heal->src_x);
|
||||
break;
|
||||
case PROP_SRC_Y:
|
||||
g_value_set_int (value, heal->src_y);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_paint (GimpPaintCore *paint_core,
|
||||
GimpDrawable *drawable,
|
||||
GimpPaintOptions *paint_options,
|
||||
GimpPaintState paint_state,
|
||||
guint32 time)
|
||||
{
|
||||
GimpHeal *heal = GIMP_HEAL (paint_core);
|
||||
GimpHealOptions *options = GIMP_HEAL_OPTIONS (paint_options);
|
||||
|
||||
/* gimp passes the current state of the painting system to the function */
|
||||
switch (paint_state)
|
||||
{
|
||||
case GIMP_PAINT_STATE_INIT:
|
||||
/* heal->set_source is set by gimphealtool when CTRL is pressed */
|
||||
if (heal->set_source)
|
||||
{
|
||||
/* defined later in this file, sets heal to the current drawable
|
||||
* and notifies heal that the drawable is ready */
|
||||
gimp_heal_set_src_drawable (heal, drawable);
|
||||
|
||||
/* get the current source coordinates from the paint core */
|
||||
heal->src_x = paint_core->cur_coords.x;
|
||||
heal->src_y = paint_core->cur_coords.y;
|
||||
|
||||
/* set first stroke to be true */
|
||||
heal->first_stroke = TRUE;
|
||||
}
|
||||
else if (options->align_mode == GIMP_HEAL_ALIGN_NO)
|
||||
{
|
||||
heal->orig_src_x = heal->src_x;
|
||||
heal->orig_src_y = heal->src_y;
|
||||
|
||||
heal->first_stroke = TRUE;
|
||||
}
|
||||
break;
|
||||
|
||||
case GIMP_PAINT_STATE_MOTION:
|
||||
if (heal->set_source)
|
||||
{
|
||||
/* if the control key is down, move the src and return */
|
||||
heal->src_x = paint_core->cur_coords.x;
|
||||
heal->src_y = paint_core->cur_coords.y;
|
||||
|
||||
heal->first_stroke = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* otherwise, update the target */
|
||||
|
||||
/* get the current destination from the paint core */
|
||||
gint dest_x = paint_core->cur_coords.x;
|
||||
gint dest_y = paint_core->cur_coords.y;
|
||||
|
||||
/* update the coordinates depending on the alignment mode */
|
||||
if (options->align_mode == GIMP_HEAL_ALIGN_FIXED)
|
||||
{
|
||||
heal->offset_x = heal->src_x - dest_x;
|
||||
heal->offset_y = heal->src_y - dest_y;
|
||||
}
|
||||
else if (heal->first_stroke)
|
||||
{
|
||||
heal->offset_x = heal->src_x - dest_x;
|
||||
heal->offset_y = heal->src_y - dest_y;
|
||||
|
||||
heal->first_stroke = FALSE;
|
||||
}
|
||||
|
||||
heal->src_x = dest_x + heal->offset_x;
|
||||
heal->src_y = dest_y + heal->offset_y;
|
||||
|
||||
/* defined later, does the actual healing */
|
||||
gimp_heal_motion (paint_core, drawable, paint_options);
|
||||
}
|
||||
break;
|
||||
|
||||
case GIMP_PAINT_STATE_FINISH:
|
||||
if ((options->align_mode == GIMP_HEAL_ALIGN_NO) && (! heal->first_stroke))
|
||||
{
|
||||
heal->src_x = heal->orig_src_x;
|
||||
heal->src_y = heal->orig_src_y;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* notify the brush that the src attributes have changed */
|
||||
g_object_notify (G_OBJECT (heal), "src-x");
|
||||
g_object_notify (G_OBJECT (heal), "src-y");
|
||||
}
|
||||
|
||||
/*
|
||||
* Substitute any zeros in the input PixelRegion for ones. This is needed by
|
||||
* the algorithm to avoid division by zero, and to get a more realistic image
|
||||
* since multiplying by zero is often incorrect (i.e., healing from a dark to
|
||||
* a light region will have incorrect spots of zero)
|
||||
*/
|
||||
static void
|
||||
gimp_heal_substitute_0_for_1 (PixelRegion *pr)
|
||||
{
|
||||
gint i, j, k;
|
||||
|
||||
gint height = pr->h;
|
||||
gint width = pr->w;
|
||||
gint depth = pr->bytes;
|
||||
|
||||
guchar *pr_data = pr->data;
|
||||
|
||||
guchar *p;
|
||||
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
p = pr_data;
|
||||
|
||||
for (j = 0; j < width; j++)
|
||||
{
|
||||
for (k = 0; k < depth; k++)
|
||||
{
|
||||
if (p[k] == 0)
|
||||
p[k] = 1;
|
||||
}
|
||||
|
||||
p += depth;
|
||||
}
|
||||
|
||||
pr_data += pr->rowstride;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Divide topPR by bottomPR and store the result as a double
|
||||
*/
|
||||
static void
|
||||
gimp_heal_divide (PixelRegion *topPR,
|
||||
PixelRegion *bottomPR,
|
||||
gdouble *result)
|
||||
{
|
||||
gint i, j, k;
|
||||
|
||||
gint height = topPR->h;
|
||||
gint width = topPR->w;
|
||||
gint depth = topPR->bytes;
|
||||
|
||||
guchar *t_data = topPR->data;
|
||||
guchar *b_data = bottomPR->data;
|
||||
|
||||
guchar *t;
|
||||
guchar *b;
|
||||
gdouble *r = result;
|
||||
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
t = t_data;
|
||||
b = b_data;
|
||||
|
||||
for (j = 0; j < width; j++)
|
||||
{
|
||||
for (k = 0; k < depth; k++)
|
||||
{
|
||||
r[k] = (gdouble) (t[k]) / (gdouble) (b[k]);
|
||||
}
|
||||
|
||||
t += depth;
|
||||
b += depth;
|
||||
r += depth;
|
||||
}
|
||||
|
||||
t_data += topPR->rowstride;
|
||||
b_data += bottomPR->rowstride;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* multiply first by secondPR and store the result as a PixelRegion
|
||||
*/
|
||||
static void
|
||||
gimp_heal_multiply (gdouble *first,
|
||||
PixelRegion *secondPR,
|
||||
PixelRegion *resultPR)
|
||||
{
|
||||
gint i, j, k;
|
||||
|
||||
gint height = secondPR->h;
|
||||
gint width = secondPR->w;
|
||||
gint depth = secondPR->bytes;
|
||||
|
||||
guchar *s_data = secondPR->data;
|
||||
guchar *r_data = resultPR->data;
|
||||
|
||||
gdouble *f = first;
|
||||
guchar *s;
|
||||
guchar *r;
|
||||
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
s = s_data;
|
||||
r = r_data;
|
||||
|
||||
for (j = 0; j < width; j++)
|
||||
{
|
||||
for (k = 0; k < depth; k++)
|
||||
{
|
||||
r[k] = (guchar) CLAMP0255 (ROUND (((gdouble) (f[k])) * ((gdouble) (s[k]))));
|
||||
}
|
||||
|
||||
f += depth;
|
||||
s += depth;
|
||||
r += depth;
|
||||
}
|
||||
|
||||
s_data += secondPR->rowstride;
|
||||
r_data += resultPR->rowstride;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform one iteration of the laplace solver for matrix. Store the result in
|
||||
* solution and return the cummulative error of the solution.
|
||||
*/
|
||||
gdouble
|
||||
gimp_heal_laplace_iteration (gdouble *matrix,
|
||||
gint height,
|
||||
gint depth,
|
||||
gint width,
|
||||
gdouble *solution)
|
||||
{
|
||||
gint rowstride = width * depth;
|
||||
gint i, j, k;
|
||||
gdouble err = 0.0;
|
||||
gdouble tmp, diff;
|
||||
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
for (j = 0; j < width; j++)
|
||||
{
|
||||
if ((i == 0) || (i == (height - 1)) || (j == 0) || (j == (height - 1)))
|
||||
/* do nothing at the boundary */
|
||||
for (k = 0; k < depth; k++)
|
||||
*(solution + k) = *(matrix + k);
|
||||
else
|
||||
{
|
||||
/* calculate the mean of four neighbours for all color channels */
|
||||
/* v[i][j] = 0.45 * (v[i][j-1]+v[i][j+1]+v[i-1][j]+v[i+1][j]) */
|
||||
for (k = 0; k < depth; k++)
|
||||
{
|
||||
tmp = *(solution + k);
|
||||
|
||||
*(solution + k) = 0.25 *
|
||||
( *(matrix - depth + k) /* west */
|
||||
+ *(matrix + depth + k) /* east */
|
||||
+ *(matrix - rowstride + k) /* north */
|
||||
+ *(matrix + rowstride + k)); /* south */
|
||||
|
||||
diff = *(solution + k) - tmp;
|
||||
err += diff*diff;
|
||||
}
|
||||
}
|
||||
|
||||
/* advance pointers to data */
|
||||
matrix += depth; solution += depth;
|
||||
}
|
||||
}
|
||||
|
||||
return sqrt (err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Solve the laplace equation for matrix and store the result in solution.
|
||||
*/
|
||||
void
|
||||
gimp_heal_laplace_loop (gdouble *matrix,
|
||||
gint height,
|
||||
gint depth,
|
||||
gint width,
|
||||
gdouble *solution)
|
||||
{
|
||||
#define EPSILON 0.0001
|
||||
#define MAX_ITER 500
|
||||
|
||||
gint num_iter = 0;
|
||||
gdouble err;
|
||||
|
||||
/* do one iteration and store the amount of error */
|
||||
err = gimp_heal_laplace_iteration (matrix, height, depth, width, solution);
|
||||
|
||||
/* copy solution to matrix */
|
||||
memcpy (matrix, solution, width * height * depth * sizeof(double));
|
||||
|
||||
/* repeat until convergence or max iterations */
|
||||
while (err > EPSILON)
|
||||
{
|
||||
err = gimp_heal_laplace_iteration (matrix, height, depth, width, solution);
|
||||
memcpy (matrix, solution, width * height * depth * sizeof(double));
|
||||
|
||||
num_iter++;
|
||||
|
||||
if (num_iter >= MAX_ITER)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The healing brush algorithm. Heal tempPR and store the result in srcPR.
|
||||
* Algorithm Design:
|
||||
* T. Georgiev, "Image Reconstruction Invariant to Relighting", EUROGRAPHICS
|
||||
* 2005, http://www.tgeorgiev.net/
|
||||
*/
|
||||
PixelRegion *
|
||||
gimp_heal_region (PixelRegion *tempPR,
|
||||
PixelRegion *srcPR)
|
||||
{
|
||||
gdouble *i_1 = g_malloc (tempPR->h * tempPR->bytes * tempPR->w * sizeof (gdouble));
|
||||
gdouble *i_2 = g_malloc (tempPR->h * tempPR->bytes * tempPR->w * sizeof (gdouble));
|
||||
|
||||
/* substitute 0's for 1's for the division and multiplication operations that
|
||||
* come later */
|
||||
gimp_heal_substitute_0_for_1 (srcPR);
|
||||
|
||||
/* divide tempPR by srcPR and store the result as a double in i_1 */
|
||||
gimp_heal_divide (tempPR, srcPR, i_1);
|
||||
|
||||
/* FIXME: is a faster implementation needed? */
|
||||
gimp_heal_laplace_loop (i_1, tempPR->h, tempPR->bytes, tempPR->w, i_2);
|
||||
|
||||
/* multiply a double by srcPR and store in tempPR */
|
||||
gimp_heal_multiply (i_2, srcPR, tempPR);
|
||||
|
||||
g_free (i_1);
|
||||
g_free (i_2);
|
||||
|
||||
return tempPR;
|
||||
}
|
||||
|
||||
void print_uchar_matrix (guchar *matrix, gint width, gint height, gint depth, gint rowstride)
|
||||
{
|
||||
gint i,j;
|
||||
|
||||
guchar *temp;
|
||||
|
||||
for (i = 0; i < height; i++)
|
||||
{
|
||||
temp = matrix;
|
||||
for (j = 0; j < width; j++)
|
||||
{
|
||||
printf("%d\t", *temp);
|
||||
temp += depth;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
matrix += rowstride;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_motion (GimpPaintCore *paint_core,
|
||||
GimpDrawable *drawable,
|
||||
GimpPaintOptions *paint_options)
|
||||
{
|
||||
GimpHeal *heal = GIMP_HEAL (paint_core);
|
||||
GimpHealOptions *options = GIMP_HEAL_OPTIONS (paint_options);
|
||||
GimpContext *context = GIMP_CONTEXT (paint_options);
|
||||
GimpPressureOptions *pressure_options = paint_options->pressure_options;
|
||||
GimpImage *image;
|
||||
GimpImage *src_image = NULL;
|
||||
GimpPickable *src_pickable = NULL;
|
||||
TileManager *src_tiles;
|
||||
TempBuf *area;
|
||||
TempBuf *temp;
|
||||
gdouble opacity;
|
||||
PixelRegion tempPR;
|
||||
PixelRegion srcPR;
|
||||
PixelRegion destPR;
|
||||
gint offset_x;
|
||||
gint offset_y;
|
||||
|
||||
/* FIXME: Why doesn't the sample merged option work? It is set up exactly as
|
||||
* in the clone tool, but nothing gets displayed properly.
|
||||
*
|
||||
* Currently merged is disabled in gimphealtool.c. If you want to try
|
||||
* and get it working, enable it there.
|
||||
*/
|
||||
|
||||
image = gimp_item_get_image (GIMP_ITEM (drawable));
|
||||
|
||||
/* FIXME: This test expects a GimpImageType variable, not GimpImage */
|
||||
if (GIMP_IMAGE_TYPE_IS_INDEXED (image))
|
||||
{
|
||||
g_message (_("Indexed images are not currently supported."));
|
||||
return;
|
||||
}
|
||||
|
||||
opacity = gimp_paint_options_get_fade (paint_options, image, paint_core->pixel_dist);
|
||||
|
||||
if (opacity == 0.0)
|
||||
return;
|
||||
|
||||
if (! heal->src_drawable)
|
||||
return;
|
||||
|
||||
/* prepare the regions to get data from */
|
||||
src_pickable = GIMP_PICKABLE (heal->src_drawable);
|
||||
src_image = gimp_pickable_get_image (src_pickable);
|
||||
|
||||
/* make local copies */
|
||||
offset_x = heal->offset_x;
|
||||
offset_y = heal->offset_y;
|
||||
|
||||
/* adjust offsets and pickable if we are merging layers */
|
||||
if (options->sample_merged)
|
||||
{
|
||||
gint off_x, off_y;
|
||||
|
||||
src_pickable = GIMP_PICKABLE (src_image->projection);
|
||||
|
||||
gimp_item_offsets (GIMP_ITEM (heal->src_drawable), &off_x, &off_y);
|
||||
|
||||
offset_x += off_x;
|
||||
offset_y += off_y;
|
||||
}
|
||||
|
||||
gimp_pickable_flush (src_pickable);
|
||||
|
||||
area = gimp_paint_core_get_paint_area (paint_core, drawable, paint_options);
|
||||
if (!area)
|
||||
return;
|
||||
|
||||
/* clear the area where we want to paint */
|
||||
temp_buf_data_clear (area);
|
||||
|
||||
/* get the source tiles */
|
||||
src_tiles = gimp_pickable_get_tiles (src_pickable);
|
||||
|
||||
/* FIXME: the area under the cursor and the source area should be x% larger
|
||||
* than the brush size so that we have seamless blending. Otherwise the brush
|
||||
* must be a lot bigger than the area to heal in order to get good results.
|
||||
* Having the user pick such a large brush is perhaps counter-intutitive? */
|
||||
|
||||
/* Get the area underneath the cursor */
|
||||
{
|
||||
TempBuf *orig;
|
||||
gint x1, x2, y1, y2;
|
||||
|
||||
x1 = CLAMP (area->x,
|
||||
0, tile_manager_width (src_tiles));
|
||||
y1 = CLAMP (area->y,
|
||||
0, tile_manager_height (src_tiles));
|
||||
x2 = CLAMP (area->x + area->width,
|
||||
0, tile_manager_width (src_tiles));
|
||||
y2 = CLAMP (area->y + area->height,
|
||||
0, tile_manager_height (src_tiles));
|
||||
|
||||
if (! (x2 - x1) || (! (y2 - y1)))
|
||||
return;
|
||||
|
||||
/* get the original image data */
|
||||
if (options->sample_merged)
|
||||
orig = gimp_paint_core_get_orig_proj (paint_core,
|
||||
src_pickable,
|
||||
x1, y1, x2, y2);
|
||||
else
|
||||
orig = gimp_paint_core_get_orig_image (paint_core,
|
||||
GIMP_DRAWABLE (src_pickable),
|
||||
x1, y1, x2, y2);
|
||||
|
||||
pixel_region_init_temp_buf (&srcPR, orig, 0, 0, x2 - x1, y2 - y1);
|
||||
}
|
||||
|
||||
temp = temp_buf_new (srcPR.w, srcPR.h, srcPR.bytes, 0, 0, NULL);
|
||||
|
||||
pixel_region_init_temp_buf (&tempPR, temp, 0, 0, srcPR.w, srcPR.h);
|
||||
|
||||
copy_region (&srcPR, &tempPR);
|
||||
|
||||
/* now tempPR holds the data under the cursor */
|
||||
|
||||
/* get a copy of the location we will sample from */
|
||||
{
|
||||
TempBuf *orig;
|
||||
gint x1, x2, y1, y2;
|
||||
|
||||
x1 = CLAMP (area->x + offset_x,
|
||||
0, tile_manager_width (src_tiles));
|
||||
y1 = CLAMP (area->y + offset_y,
|
||||
0, tile_manager_height (src_tiles));
|
||||
x2 = CLAMP (area->x + offset_x + area->width,
|
||||
0, tile_manager_width (src_tiles));
|
||||
y2 = CLAMP (area->y + offset_y + area->height,
|
||||
0, tile_manager_height (src_tiles));
|
||||
|
||||
if (! (x2 - x1) || (! (y2 - y1)))
|
||||
return;
|
||||
|
||||
/* if we have a different source and destination image */
|
||||
if (( options->sample_merged && (src_image != image)) ||
|
||||
(! options->sample_merged && (heal->src_drawable != drawable)))
|
||||
{
|
||||
/* FIXME: Here we need to initialize srcPR using data from the other
|
||||
* image. */
|
||||
g_message (_("Healing between images is not currently supported."));
|
||||
return;
|
||||
}
|
||||
/* if we don't have a different source and destination image */
|
||||
else
|
||||
{
|
||||
if (options->sample_merged)
|
||||
orig = gimp_paint_core_get_orig_proj (paint_core,
|
||||
src_pickable,
|
||||
x1, y1, x2, y2);
|
||||
else
|
||||
orig = gimp_paint_core_get_orig_image (paint_core,
|
||||
GIMP_DRAWABLE (src_pickable),
|
||||
x1, y1, x2, y2);
|
||||
|
||||
pixel_region_init_temp_buf (&srcPR, orig, 0, 0, x2 - x1, y2 - y1);
|
||||
}
|
||||
|
||||
/* set the proper offset */
|
||||
offset_x = x1 - (area->x + offset_x);
|
||||
offset_y = y1 - (area->y + offset_y);
|
||||
}
|
||||
|
||||
/* now srcPR holds the source area to sample from */
|
||||
|
||||
/* get the destination to paint to */
|
||||
pixel_region_init_temp_buf (&destPR, area, offset_x, offset_y, srcPR.w, srcPR.h);
|
||||
|
||||
/* FIXME: Can we ensure that this is true in the code above?
|
||||
* Is it already guaranteed to be true before we get here? */
|
||||
/* check that srcPR, tempPR, and destPR are the same size */
|
||||
if ((srcPR.w != tempPR.w ) || (srcPR.w != destPR.w ) ||
|
||||
(srcPR.h != tempPR.h ) || (srcPR.h != destPR.h ))
|
||||
{
|
||||
g_message (_("Source and destination regions are not the same size."));
|
||||
return;
|
||||
}
|
||||
|
||||
/* heal tempPR using srcPR */
|
||||
gimp_heal_region (&tempPR, &srcPR);
|
||||
|
||||
/* re-initialize tempPR so that it can be used within copy_region */
|
||||
pixel_region_init_data (&tempPR, tempPR.data, tempPR.bytes, tempPR.rowstride,
|
||||
0, 0, tempPR.w, tempPR.h);
|
||||
|
||||
/* add an alpha region to the area if necessary */
|
||||
if (! gimp_drawable_has_alpha (drawable))
|
||||
add_alpha_region (&tempPR, &destPR);
|
||||
else
|
||||
copy_region (&tempPR, &destPR);
|
||||
|
||||
if (pressure_options->opacity)
|
||||
opacity *= PRESSURE_SCALE * paint_core->cur_coords.pressure;
|
||||
|
||||
gimp_brush_core_replace_canvas (GIMP_BRUSH_CORE (paint_core),
|
||||
drawable,
|
||||
MIN (opacity, GIMP_OPACITY_OPAQUE),
|
||||
gimp_context_get_opacity (context),
|
||||
gimp_paint_options_get_brush_mode (paint_options),
|
||||
GIMP_PAINT_CONSTANT);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_src_drawable_removed (GimpDrawable *drawable,
|
||||
GimpHeal *heal)
|
||||
{
|
||||
/* set the drawable to NULL */
|
||||
if (drawable == heal->src_drawable)
|
||||
{
|
||||
heal->src_drawable = NULL;
|
||||
}
|
||||
|
||||
/* disconnect the signal handler for this function */
|
||||
g_signal_handlers_disconnect_by_func (drawable,
|
||||
gimp_heal_src_drawable_removed,
|
||||
heal);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_set_src_drawable (GimpHeal *heal,
|
||||
GimpDrawable *drawable)
|
||||
{
|
||||
/* check if we already have a drawable */
|
||||
if (heal->src_drawable == drawable)
|
||||
return;
|
||||
|
||||
/* remove the current signal handler */
|
||||
if (heal->src_drawable)
|
||||
g_signal_handlers_disconnect_by_func (heal->src_drawable,
|
||||
gimp_heal_src_drawable_removed,
|
||||
heal);
|
||||
|
||||
/* set the drawable */
|
||||
heal->src_drawable = drawable;
|
||||
|
||||
/* connect the signal handler that handles the "remove" signal */
|
||||
if (heal->src_drawable)
|
||||
g_signal_connect (heal->src_drawable, "removed",
|
||||
G_CALLBACK (gimp_heal_src_drawable_removed),
|
||||
heal);
|
||||
|
||||
/* notify heal that the source drawable is set */
|
||||
g_object_notify (G_OBJECT (heal), "src-drawable");
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/* The GIMP -- an 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GIMP_HEAL_H__
|
||||
#define __GIMP_HEAL_H__
|
||||
|
||||
#include "gimpbrushcore.h"
|
||||
|
||||
#define GIMP_TYPE_HEAL (gimp_heal_get_type ())
|
||||
#define GIMP_HEAL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_HEAL, GimpHeal))
|
||||
#define GIMP_HEAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_HEAL, GimpHealClass))
|
||||
#define GIMP_IS_HEAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_HEAL))
|
||||
#define GIMP_IS_HEAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_HEAL))
|
||||
#define GIMP_HEAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_HEAL, GimpHealClass))
|
||||
|
||||
typedef struct _GimpHeal GimpHeal;
|
||||
typedef struct _GimpHealClass GimpHealClass;
|
||||
|
||||
struct _GimpHeal
|
||||
{
|
||||
GimpBrushCore parent_instance;
|
||||
|
||||
gboolean set_source;
|
||||
|
||||
GimpDrawable *src_drawable;
|
||||
gdouble src_x;
|
||||
gdouble src_y;
|
||||
|
||||
gdouble orig_src_x;
|
||||
gdouble orig_src_y;
|
||||
|
||||
gdouble offset_x;
|
||||
gdouble offset_y;
|
||||
gboolean first_stroke;
|
||||
};
|
||||
|
||||
struct _GimpHealClass
|
||||
{
|
||||
GimpBrushCoreClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
void gimp_heal_register (Gimp *gimp,
|
||||
GimpPaintRegisterCallback callback);
|
||||
|
||||
GType gimp_heal_get_type (void) G_GNUC_CONST;
|
||||
|
||||
|
||||
#endif /* __GIMP_HEAL_H__ */
|
|
@ -0,0 +1,114 @@
|
|||
/* The GIMP -- an 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "libgimpconfig/gimpconfig.h"
|
||||
|
||||
#include "paint-types.h"
|
||||
#include "gimphealoptions.h"
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_ALIGN_MODE,
|
||||
PROP_SAMPLE_MERGED
|
||||
};
|
||||
|
||||
static void gimp_heal_options_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void gimp_heal_options_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
G_DEFINE_TYPE (GimpHealOptions, gimp_heal_options, GIMP_TYPE_PAINT_OPTIONS)
|
||||
|
||||
static void
|
||||
gimp_heal_options_class_init (GimpHealOptionsClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->set_property = gimp_heal_options_set_property;
|
||||
object_class->get_property = gimp_heal_options_get_property;
|
||||
|
||||
GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_ALIGN_MODE,
|
||||
"align-mode", NULL,
|
||||
GIMP_TYPE_HEAL_ALIGN_MODE,
|
||||
GIMP_HEAL_ALIGN_NO,
|
||||
GIMP_PARAM_STATIC_STRINGS);
|
||||
|
||||
GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_SAMPLE_MERGED,
|
||||
"sample-merged", NULL,
|
||||
FALSE,
|
||||
GIMP_PARAM_STATIC_STRINGS);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_options_init (GimpHealOptions *options)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_options_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GimpHealOptions *options = GIMP_HEAL_OPTIONS (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_ALIGN_MODE:
|
||||
options->align_mode = g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_SAMPLE_MERGED:
|
||||
options->sample_merged = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_options_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GimpHealOptions *options = GIMP_HEAL_OPTIONS (object);
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_ALIGN_MODE:
|
||||
g_value_set_enum (value, options->align_mode);
|
||||
break;
|
||||
case PROP_SAMPLE_MERGED:
|
||||
g_value_set_boolean (value, options->sample_merged);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/* The GIMP -- an 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GIMP_HEAL_OPTIONS_H__
|
||||
#define __GIMP_HEAL_OPTIONS_H__
|
||||
|
||||
|
||||
#include "gimppaintoptions.h"
|
||||
|
||||
|
||||
#define GIMP_TYPE_HEAL_OPTIONS (gimp_heal_options_get_type ())
|
||||
#define GIMP_HEAL_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_HEAL_OPTIONS, GimpHealOptions))
|
||||
#define GIMP_HEAL_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_HEAL_OPTIONS, GimpHealOptionsClass))
|
||||
#define GIMP_IS_HEAL_OPTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_HEAL_OPTIONS))
|
||||
#define GIMP_IS_HEAL_OPTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_HEAL_OPTIONS))
|
||||
#define GIMP_HEAL_OPTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_HEAL_OPTIONS, GimpHealOptionsClass))
|
||||
|
||||
|
||||
typedef struct _GimpHealOptions GimpHealOptions;
|
||||
typedef struct _GimpPaintOptionsClass GimpHealOptionsClass;
|
||||
|
||||
struct _GimpHealOptions
|
||||
{
|
||||
GimpPaintOptions paint_options;
|
||||
|
||||
GimpHealAlignMode align_mode;
|
||||
gboolean sample_merged;
|
||||
};
|
||||
|
||||
|
||||
GType gimp_heal_options_get_type (void) G_GNUC_CONST;
|
||||
|
||||
#endif /* __GIMP_HEAL_OPTIONS_H__ */
|
|
@ -0,0 +1,492 @@
|
|||
/* The GIMP -- an 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libgimpwidgets/gimpwidgets.h"
|
||||
|
||||
#include "tools-types.h"
|
||||
|
||||
#include "core/gimpchannel.h"
|
||||
#include "core/gimpimage.h"
|
||||
#include "core/gimppickable.h"
|
||||
#include "core/gimptoolinfo.h"
|
||||
|
||||
#include "paint/gimpheal.h"
|
||||
#include "paint/gimphealoptions.h"
|
||||
|
||||
#include "widgets/gimphelp-ids.h"
|
||||
#include "widgets/gimpviewablebox.h"
|
||||
#include "widgets/gimpwidgets-utils.h"
|
||||
|
||||
#include "display/gimpdisplay.h"
|
||||
|
||||
#include "gimphealtool.h"
|
||||
#include "gimppaintoptions-gui.h"
|
||||
#include "gimptoolcontrol.h"
|
||||
|
||||
#include "gimp-intl.h"
|
||||
|
||||
#define TARGET_WIDTH 15
|
||||
#define TARGET_HEIGHT 15
|
||||
|
||||
static gboolean gimp_heal_tool_has_display (GimpTool *tool,
|
||||
GimpDisplay *display);
|
||||
static GimpDisplay *gimp_heal_tool_has_image (GimpTool *tool,
|
||||
GimpImage *image);
|
||||
|
||||
static void gimp_heal_tool_button_press (GimpTool *tool,
|
||||
GimpCoords *coords,
|
||||
guint32 time,
|
||||
GdkModifierType state,
|
||||
GimpDisplay *display);
|
||||
|
||||
static void gimp_heal_tool_control (GimpTool *tool,
|
||||
GimpToolAction action,
|
||||
GimpDisplay *display);
|
||||
|
||||
static void gimp_heal_tool_motion (GimpTool *tool,
|
||||
GimpCoords *coords,
|
||||
guint32 time,
|
||||
GdkModifierType state,
|
||||
GimpDisplay *display);
|
||||
|
||||
static void gimp_heal_tool_cursor_update (GimpTool *tool,
|
||||
GimpCoords *coords,
|
||||
GdkModifierType state,
|
||||
GimpDisplay *display);
|
||||
|
||||
static void gimp_heal_tool_oper_update (GimpTool *tool,
|
||||
GimpCoords *coords,
|
||||
GdkModifierType state,
|
||||
gboolean proximity,
|
||||
GimpDisplay *display);
|
||||
|
||||
static void gimp_heal_tool_draw (GimpDrawTool *draw_tool);
|
||||
|
||||
static GtkWidget *gimp_heal_options_gui (GimpToolOptions *tool_options);
|
||||
|
||||
G_DEFINE_TYPE (GimpHealTool, gimp_heal_tool, GIMP_TYPE_PAINT_TOOL)
|
||||
|
||||
void
|
||||
gimp_heal_tool_register (GimpToolRegisterCallback callback,
|
||||
gpointer data)
|
||||
{
|
||||
(* callback) (GIMP_TYPE_HEAL_TOOL, /* tool type */
|
||||
GIMP_TYPE_HEAL_OPTIONS, /* tool option type */
|
||||
gimp_heal_options_gui, /* options gui */
|
||||
GIMP_PAINT_OPTIONS_CONTEXT_MASK, /* context properties */
|
||||
"gimp-heal-tool", /* identifier */
|
||||
_("Heal"), /* blurb */
|
||||
_("Heal image irregularities"), /* help */
|
||||
N_("_Heal"), /* menu path */
|
||||
"H", /* menu accelerator */
|
||||
NULL, /* help domain */
|
||||
GIMP_HELP_TOOL_HEAL, /* help data */
|
||||
GIMP_STOCK_TOOL_HEAL, /* stock id */
|
||||
data); /* register */
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_tool_class_init (GimpHealToolClass *klass)
|
||||
{
|
||||
/* get parent classes where we override methods */
|
||||
GimpToolClass *tool_class = GIMP_TOOL_CLASS (klass);
|
||||
GimpDrawToolClass *draw_tool_class = GIMP_DRAW_TOOL_CLASS (klass);
|
||||
|
||||
/* override the methods */
|
||||
tool_class->has_display = gimp_heal_tool_has_display;
|
||||
tool_class->has_image = gimp_heal_tool_has_image;
|
||||
tool_class->control = gimp_heal_tool_control;
|
||||
tool_class->button_press = gimp_heal_tool_button_press;
|
||||
tool_class->motion = gimp_heal_tool_motion;
|
||||
tool_class->cursor_update = gimp_heal_tool_cursor_update;
|
||||
tool_class->oper_update = gimp_heal_tool_oper_update;
|
||||
|
||||
draw_tool_class->draw = gimp_heal_tool_draw;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_tool_init (GimpHealTool *heal)
|
||||
{
|
||||
GimpTool *tool = GIMP_TOOL (heal);
|
||||
GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool);
|
||||
|
||||
gimp_tool_control_set_tool_cursor (tool->control,
|
||||
GIMP_TOOL_CURSOR_HEAL);
|
||||
|
||||
paint_tool->status = _("Click to heal.");
|
||||
paint_tool->status_ctrl = _("%s to set a new heal source");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gimp_heal_tool_has_display (GimpTool *tool,
|
||||
GimpDisplay *display)
|
||||
{
|
||||
GimpHealTool *heal_tool = GIMP_HEAL_TOOL (tool);
|
||||
|
||||
return (display == heal_tool->src_display ||
|
||||
GIMP_TOOL_CLASS (gimp_heal_tool_parent_class)->has_display (tool, display));
|
||||
}
|
||||
|
||||
static GimpDisplay *
|
||||
gimp_heal_tool_has_image (GimpTool *tool,
|
||||
GimpImage *image)
|
||||
{
|
||||
GimpHealTool *heal_tool = GIMP_HEAL_TOOL (tool);
|
||||
GimpDisplay *display;
|
||||
|
||||
display = GIMP_TOOL_CLASS (gimp_heal_tool_parent_class)->has_image (tool, image);
|
||||
|
||||
if (! display && heal_tool->src_display)
|
||||
{
|
||||
if (image && heal_tool->src_display->image == image)
|
||||
display = heal_tool->src_display;
|
||||
|
||||
/* NULL image means any display */
|
||||
if (! image)
|
||||
display = heal_tool->src_display;
|
||||
}
|
||||
|
||||
return display;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_tool_control (GimpTool *tool,
|
||||
GimpToolAction action,
|
||||
GimpDisplay *display)
|
||||
{
|
||||
GimpHealTool *heal_tool = GIMP_HEAL_TOOL (tool);
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case GIMP_TOOL_ACTION_PAUSE:
|
||||
case GIMP_TOOL_ACTION_RESUME:
|
||||
break;
|
||||
|
||||
case GIMP_TOOL_ACTION_HALT:
|
||||
heal_tool->src_display = NULL;
|
||||
g_object_set (GIMP_PAINT_TOOL (tool)->core,
|
||||
"src-drawable", NULL,
|
||||
NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
GIMP_TOOL_CLASS (gimp_heal_tool_parent_class)->control (tool, action, display);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gimp_heal_tool_button_press (GimpTool *tool,
|
||||
GimpCoords *coords,
|
||||
guint32 time,
|
||||
GdkModifierType state,
|
||||
GimpDisplay *display)
|
||||
{
|
||||
GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool);
|
||||
GimpHealTool *heal_tool = GIMP_HEAL_TOOL (tool);
|
||||
GimpHeal *heal = GIMP_HEAL (paint_tool->core);
|
||||
GimpHealOptions *options;
|
||||
|
||||
options = GIMP_HEAL_OPTIONS (tool->tool_info->tool_options);
|
||||
|
||||
/* pause the tool before drawing */
|
||||
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
|
||||
|
||||
/* use_saved_proj tells whether we keep the unmodified pixel projection
|
||||
* around. in this case no. */
|
||||
paint_tool->core->use_saved_proj = FALSE;
|
||||
|
||||
/* state holds a set of bit-flags to indicate the state of modifier keys and
|
||||
* mouse buttons in various event types. Typical modifier keys are Shift,
|
||||
* Control, Meta, Super, Hyper, Alt, Compose, Apple, CapsLock or ShiftLock.
|
||||
* Part of gtk -> GdkModifierType */
|
||||
if ((state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == GDK_CONTROL_MASK)
|
||||
/* we enter here only if CTRL is pressed */
|
||||
{
|
||||
/* mark that the source display has been set. defined in gimpheal.h */
|
||||
heal->set_source = TRUE;
|
||||
|
||||
/* if currently active display != the heal tools source display */
|
||||
if (display != heal_tool->src_display)
|
||||
{
|
||||
/* check if the heal tools src display has been previously set */
|
||||
if (heal_tool->src_display)
|
||||
/* if so remove the pointer to the display */
|
||||
g_object_remove_weak_pointer (G_OBJECT (heal_tool->src_display),
|
||||
(gpointer *) &heal_tool->src_display);
|
||||
|
||||
/* set the heal tools source display to the currently active
|
||||
* display */
|
||||
heal_tool->src_display = display;
|
||||
|
||||
/* add a pointer to the display */
|
||||
g_object_add_weak_pointer (G_OBJECT (display),
|
||||
(gpointer *) &heal_tool->src_display);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* note that the source is not being set */
|
||||
heal->set_source = FALSE;
|
||||
|
||||
if ((options->sample_merged) && (display == heal_tool->src_display))
|
||||
{
|
||||
/* keep unmodified projection around */
|
||||
paint_tool->core->use_saved_proj = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* chain up to call the parents functions */
|
||||
GIMP_TOOL_CLASS (gimp_heal_tool_parent_class)->button_press (tool, coords,
|
||||
time, state,
|
||||
display);
|
||||
|
||||
/* set the tool display's source position to match the current heal
|
||||
* implementation source position */
|
||||
heal_tool->src_x = heal->src_x;
|
||||
heal_tool->src_y = heal->src_y;
|
||||
|
||||
/* resume drawing */
|
||||
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_tool_motion (GimpTool *tool,
|
||||
GimpCoords *coords,
|
||||
guint32 time,
|
||||
GdkModifierType state,
|
||||
GimpDisplay *display)
|
||||
{
|
||||
GimpHealTool *heal_tool = GIMP_HEAL_TOOL (tool);
|
||||
GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool);
|
||||
GimpHeal *heal = GIMP_HEAL (paint_tool->core);
|
||||
|
||||
/* pause drawing */
|
||||
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
|
||||
|
||||
/* check if CTRL is pressed */
|
||||
if ((state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == GDK_CONTROL_MASK)
|
||||
/* if yes the source has been set */
|
||||
heal->set_source = TRUE;
|
||||
else
|
||||
/* if no the source has not been set */
|
||||
heal->set_source = FALSE;
|
||||
|
||||
/* chain up to the parent classes motion function */
|
||||
GIMP_TOOL_CLASS (gimp_heal_tool_parent_class)->motion (tool, coords, time,
|
||||
state, display);
|
||||
|
||||
/* set the tool display's source to be the same as the heal implementation
|
||||
* source */
|
||||
heal_tool->src_x = heal->src_x;
|
||||
heal_tool->src_y = heal->src_y;
|
||||
|
||||
/* resume drawing */
|
||||
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_tool_cursor_update (GimpTool *tool,
|
||||
GimpCoords *coords,
|
||||
GdkModifierType state,
|
||||
GimpDisplay *display)
|
||||
{
|
||||
GimpHealOptions *options;
|
||||
GimpCursorType cursor = GIMP_CURSOR_MOUSE;
|
||||
GimpCursorModifier modifier = GIMP_CURSOR_MODIFIER_NONE;
|
||||
|
||||
options = GIMP_HEAL_OPTIONS (tool->tool_info->tool_options);
|
||||
|
||||
/* if the cursor is in an active area */
|
||||
if (gimp_image_coords_in_active_pickable (display->image, coords,
|
||||
FALSE, TRUE))
|
||||
{
|
||||
/* set the cursor to the normal cursor */
|
||||
cursor = GIMP_CURSOR_MOUSE;
|
||||
}
|
||||
|
||||
/* if CTRL is pressed, change cursor to cross-hair */
|
||||
if ((state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK)) == GDK_CONTROL_MASK)
|
||||
{
|
||||
cursor = GIMP_CURSOR_CROSSHAIR_SMALL;
|
||||
}
|
||||
/* otherwise, let the cursor now that we can't paint */
|
||||
else if (! GIMP_HEAL (GIMP_PAINT_TOOL (tool)->core)->src_drawable)
|
||||
{
|
||||
modifier = GIMP_CURSOR_MODIFIER_BAD;
|
||||
}
|
||||
|
||||
/* set the cursor and the modifier cursor */
|
||||
gimp_tool_control_set_cursor (tool->control, cursor);
|
||||
gimp_tool_control_set_cursor_modifier (tool->control, modifier);
|
||||
|
||||
/* chain up to the parent class */
|
||||
GIMP_TOOL_CLASS (gimp_heal_tool_parent_class)->cursor_update (tool, coords,
|
||||
state, display);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_tool_oper_update (GimpTool *tool,
|
||||
GimpCoords *coords,
|
||||
GdkModifierType state,
|
||||
gboolean proximity,
|
||||
GimpDisplay *display)
|
||||
{
|
||||
GimpHealTool *heal_tool = GIMP_HEAL_TOOL (tool);
|
||||
GimpHealOptions *options;
|
||||
|
||||
options = GIMP_HEAL_OPTIONS (tool->tool_info->tool_options);
|
||||
|
||||
if (proximity)
|
||||
{
|
||||
GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool);
|
||||
|
||||
paint_tool->status_ctrl = _("%s to set a new heal source");
|
||||
}
|
||||
|
||||
/* chain up to the parent class */
|
||||
GIMP_TOOL_CLASS (gimp_heal_tool_parent_class)->oper_update (tool, coords,
|
||||
state, proximity,
|
||||
display);
|
||||
|
||||
if (proximity)
|
||||
{
|
||||
GimpHeal *heal = GIMP_HEAL (GIMP_PAINT_TOOL (tool)->core);
|
||||
|
||||
if (heal->src_drawable == NULL)
|
||||
{
|
||||
if (state & GDK_CONTROL_MASK)
|
||||
/* if we haven't set the source drawable yet, make a notice to do so */
|
||||
gimp_tool_replace_status (tool, display,
|
||||
_("Ctrl-Click to set a heal source."));
|
||||
else
|
||||
{
|
||||
gchar *status;
|
||||
status = g_strdup_printf (_("%s%sClick to set a heal source."),
|
||||
gimp_get_mod_name_control (),
|
||||
gimp_get_mod_separator ());
|
||||
gimp_tool_replace_status (tool, display, status);
|
||||
g_free (status);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* pause drawing */
|
||||
gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
|
||||
|
||||
/* set the tool source to match the implementation source */
|
||||
heal_tool->src_x = heal->src_x;
|
||||
heal_tool->src_y = heal->src_y;
|
||||
|
||||
if (! heal->first_stroke)
|
||||
{
|
||||
/* set the coordinates based on the alignment type */
|
||||
if (options->align_mode == GIMP_HEAL_ALIGN_YES)
|
||||
{
|
||||
heal_tool->src_x = coords->x + heal->offset_x;
|
||||
heal_tool->src_y = coords->y + heal->offset_y;
|
||||
}
|
||||
}
|
||||
|
||||
/* resume drawing */
|
||||
gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_heal_tool_draw (GimpDrawTool *draw_tool)
|
||||
{
|
||||
GimpTool *tool = GIMP_TOOL (draw_tool);
|
||||
GimpHealTool *heal_tool = GIMP_HEAL_TOOL (draw_tool);
|
||||
GimpHeal *heal = GIMP_HEAL (GIMP_PAINT_TOOL (tool)->core);
|
||||
GimpHealOptions *options;
|
||||
|
||||
options = GIMP_HEAL_OPTIONS (tool->tool_info->tool_options);
|
||||
|
||||
/* If we have a source drawable and display we can do the drawing */
|
||||
if ((heal->src_drawable) && (heal_tool->src_display))
|
||||
{
|
||||
/* make a temporary display and keep track of offsets */
|
||||
GimpDisplay *tmp_display;
|
||||
gint off_x;
|
||||
gint off_y;
|
||||
|
||||
/* gimp_item_offsets reveals the X and Y offsets of the first parameter.
|
||||
* this gets the location of the drawable. */
|
||||
gimp_item_offsets (GIMP_ITEM (heal->src_drawable), &off_x, &off_y);
|
||||
|
||||
/* store the display for later */
|
||||
tmp_display = draw_tool->display;
|
||||
|
||||
/* set the display */
|
||||
draw_tool->display = heal_tool->src_display;
|
||||
|
||||
/* convenience function to simplify drawing */
|
||||
gimp_draw_tool_draw_handle (draw_tool,
|
||||
GIMP_HANDLE_CROSS,
|
||||
heal_tool->src_x + off_x,
|
||||
heal_tool->src_y + off_y,
|
||||
TARGET_WIDTH, TARGET_HEIGHT,
|
||||
GTK_ANCHOR_CENTER,
|
||||
FALSE);
|
||||
|
||||
/* restore settings after drawing */
|
||||
draw_tool->display = tmp_display;
|
||||
}
|
||||
|
||||
/* chain up to the parent draw function */
|
||||
GIMP_DRAW_TOOL_CLASS (gimp_heal_tool_parent_class)->draw (draw_tool);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
gimp_heal_options_gui (GimpToolOptions *tool_options)
|
||||
{
|
||||
GObject *config;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *button;
|
||||
GtkWidget *table;
|
||||
GtkWidget *combo;
|
||||
|
||||
config = G_OBJECT (tool_options);
|
||||
|
||||
vbox = gimp_paint_options_gui (tool_options);
|
||||
|
||||
/* create and attach the sample merged checkbox */
|
||||
button = gimp_prop_check_button_new (config, "sample-merged",
|
||||
_("Sample merged"));
|
||||
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
|
||||
gtk_widget_show (button);
|
||||
|
||||
/* create and attach the alignment options to a table */
|
||||
table = gtk_table_new (1, 2, FALSE);
|
||||
gtk_table_set_col_spacings (GTK_TABLE (table), 2);
|
||||
gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, FALSE, 0);
|
||||
gtk_widget_show (table);
|
||||
|
||||
combo = gimp_prop_enum_combo_box_new (config, "align-mode", 0, 0);
|
||||
gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
|
||||
_("Alignment:"), 0.0, 0.5,
|
||||
combo, 1, FALSE);
|
||||
|
||||
return vbox;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/* The GIMP -- an 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 2 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GIMP_HEAL_TOOL_H__
|
||||
#define __GIMP_HEAL_TOOL_H__
|
||||
|
||||
#include "gimppainttool.h"
|
||||
|
||||
#define GIMP_TYPE_HEAL_TOOL (gimp_heal_tool_get_type ())
|
||||
#define GIMP_HEAL_TOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_HEAL_TOOL, GimpHealTool))
|
||||
#define GIMP_HEAL_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_HEAL_TOOL, GimpHealToolClass))
|
||||
#define GIMP_IS_HEAL_TOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_HEAL_TOOL))
|
||||
#define GIMP_IS_HEAL_TOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_HEAL_TOOL))
|
||||
#define GIMP_HEAL_TOOL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_HEAL_TOOL, GimpHealToolClass))
|
||||
|
||||
typedef struct _GimpHealTool GimpHealTool;
|
||||
typedef struct _GimpHealToolClass GimpHealToolClass;
|
||||
|
||||
struct _GimpHealTool
|
||||
{
|
||||
GimpPaintTool parent_instance;
|
||||
|
||||
GimpDisplay *src_display; /* Detail about the source location to paint from */
|
||||
gint src_x;
|
||||
gint src_y;
|
||||
};
|
||||
|
||||
struct _GimpHealToolClass
|
||||
{
|
||||
GimpPaintToolClass parent_class;
|
||||
};
|
||||
|
||||
|
||||
void gimp_heal_tool_register (GimpToolRegisterCallback callback,
|
||||
gpointer data);
|
||||
|
||||
GType gimp_heal_tool_get_type (void) G_GNUC_CONST;
|
||||
|
||||
#endif /* __GIMP_HEAL_TOOL_H__ */
|
Binary file not shown.
After Width: | Height: | Size: 1020 B |
|
@ -0,0 +1,14 @@
|
|||
#define tool_heal_mask_width 32
|
||||
#define tool_heal_mask_height 32
|
||||
static unsigned char tool_heal_mask_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x04,
|
||||
0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0xa0, 0x0d, 0x00, 0x00, 0x78, 0x05,
|
||||
0x00, 0x00, 0xbd, 0x55, 0x00, 0x00, 0xd8, 0x58, 0x00, 0x00, 0x80, 0x37,
|
||||
0x00, 0x00, 0xcc, 0x37, 0x00, 0x00, 0xc0, 0x7b, 0x00, 0x00, 0x12, 0x59,
|
||||
0x00, 0x00, 0x2a, 0x0b, 0x00, 0x00, 0xf8, 0x09, 0x00, 0x00, 0xc0, 0x01,
|
||||
0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x60, 0x04 };
|
|
@ -0,0 +1,14 @@
|
|||
#define tool_heal_width 32
|
||||
#define tool_heal_height 32
|
||||
static unsigned char tool_heal_bits[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x04,
|
||||
0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x40, 0x01,
|
||||
0x00, 0x00, 0x21, 0x44, 0x00, 0x00, 0x10, 0x48, 0x00, 0x00, 0x00, 0x30,
|
||||
0x00, 0x00, 0x4c, 0x32, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x02, 0x48,
|
||||
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x80, 0x01,
|
||||
0x00, 0x00, 0x10, 0x06, 0x00, 0x00, 0x60, 0x04 };
|
Loading…
Reference in New Issue