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