gimpconvolve.c 10.3 KB
Newer Older
1
/* GIMP - The GNU Image Manipulation Program
Elliot Lee's avatar
Elliot Lee committed
2 3
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
4
 * This program is free software: you can redistribute it and/or modify
Elliot Lee's avatar
Elliot Lee committed
5
 * it under the terms of the GNU General Public License as published by
6
 * the Free Software Foundation; either version 3 of the License, or
Elliot Lee's avatar
Elliot Lee committed
7 8 9 10 11 12 13 14
 * (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
15
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
16
 */
Sven Neumann's avatar
Sven Neumann committed
17

18
#include "config.h"
19

20
#include <gdk-pixbuf/gdk-pixbuf.h>
21
#include <gegl.h>
22

23
#include "paint-types.h"
Sven Neumann's avatar
Sven Neumann committed
24

25
#include "gegl/gimp-gegl-loops.h"
26

27
#include "core/gimp.h"
28 29
#include "core/gimpbrush.h"
#include "core/gimpdrawable.h"
30
#include "core/gimpdynamics.h"
31
#include "core/gimpimage.h"
32
#include "core/gimppickable.h"
Jehan's avatar
Jehan committed
33
#include "core/gimpsymmetry.h"
34
#include "core/gimptempbuf.h"
35

36
#include "gimpconvolve.h"
37
#include "gimpconvolveoptions.h"
38

39
#include "gimp-intl.h"
40

41

42 43 44 45 46 47
#define FIELD_COLS    4
#define MIN_BLUR      64         /*  (8/9 original pixel)   */
#define MAX_BLUR      0.25       /*  (1/33 original pixel)  */
#define MIN_SHARPEN   -512
#define MAX_SHARPEN   -64

48

49 50 51
static void    gimp_convolve_paint            (GimpPaintCore    *paint_core,
                                               GimpDrawable     *drawable,
                                               GimpPaintOptions *paint_options,
Jehan's avatar
Jehan committed
52
                                               GimpSymmetry     *sym,
53 54 55 56 57
                                               GimpPaintState    paint_state,
                                               guint32           time);
static void    gimp_convolve_motion           (GimpPaintCore    *paint_core,
                                               GimpDrawable     *drawable,
                                               GimpPaintOptions *paint_options,
Jehan's avatar
Jehan committed
58
                                               GimpSymmetry     *sym);
59 60 61 62 63 64 65

static void    gimp_convolve_calculate_matrix (GimpConvolve     *convolve,
                                               GimpConvolveType  type,
                                               gint              radius_x,
                                               gint              radius_y,
                                               gdouble           rate);
static gdouble gimp_convolve_sum_matrix       (const gfloat     *matrix);
Elliot Lee's avatar
Elliot Lee committed
66

67

68
G_DEFINE_TYPE (GimpConvolve, gimp_convolve, GIMP_TYPE_BRUSH_CORE)
Elliot Lee's avatar
Elliot Lee committed
69

70

71 72 73 74
void
gimp_convolve_register (Gimp                      *gimp,
                        GimpPaintRegisterCallback  callback)
{
75 76 77
  (* callback) (gimp,
                GIMP_TYPE_CONVOLVE,
                GIMP_TYPE_CONVOLVE_OPTIONS,
78 79
                "gimp-convolve",
                _("Convolve"),
80
                "gimp-tool-blur");
81 82
}

83
static void
84
gimp_convolve_class_init (GimpConvolveClass *klass)
85
{
86
  GimpPaintCoreClass *paint_core_class = GIMP_PAINT_CORE_CLASS (klass);
Elliot Lee's avatar
Elliot Lee committed
87

88
  paint_core_class->paint = gimp_convolve_paint;
89
}
90

91
static void
92
gimp_convolve_init (GimpConvolve *convolve)
93
{
94 95 96 97 98 99
  gint i;

  for (i = 0; i < 9; i++)
    convolve->matrix[i] = 1.0;

  convolve->matrix_divisor = 9.0;
Elliot Lee's avatar
Elliot Lee committed
100 101
}

102
static void
103 104 105
gimp_convolve_paint (GimpPaintCore    *paint_core,
                     GimpDrawable     *drawable,
                     GimpPaintOptions *paint_options,
Jehan's avatar
Jehan committed
106
                     GimpSymmetry     *sym,
107 108
                     GimpPaintState    paint_state,
                     guint32           time)
Elliot Lee's avatar
Elliot Lee committed
109
{
110
  switch (paint_state)
Elliot Lee's avatar
Elliot Lee committed
111
    {
112
    case GIMP_PAINT_STATE_MOTION:
Jehan's avatar
Jehan committed
113
      gimp_convolve_motion (paint_core, drawable, paint_options, sym);
Elliot Lee's avatar
Elliot Lee committed
114
      break;
115 116 117

    default:
      break;
Elliot Lee's avatar
Elliot Lee committed
118 119 120
    }
}

Sven Neumann's avatar
Sven Neumann committed
121
static void
Michael Natterer's avatar
Michael Natterer committed
122 123
gimp_convolve_motion (GimpPaintCore    *paint_core,
                      GimpDrawable     *drawable,
124
                      GimpPaintOptions *paint_options,
Jehan's avatar
Jehan committed
125
                      GimpSymmetry     *sym)
Elliot Lee's avatar
Elliot Lee committed
126
{
127 128 129 130
  GimpConvolve        *convolve   = GIMP_CONVOLVE (paint_core);
  GimpBrushCore       *brush_core = GIMP_BRUSH_CORE (paint_core);
  GimpConvolveOptions *options    = GIMP_CONVOLVE_OPTIONS (paint_options);
  GimpContext         *context    = GIMP_CONTEXT (paint_options);
131
  GimpDynamics        *dynamics   = GIMP_BRUSH_CORE (paint_core)->dynamics;
132
  GimpImage           *image      = gimp_item_get_image (GIMP_ITEM (drawable));
133 134 135
  GeglBuffer          *paint_buffer;
  gint                 paint_buffer_x;
  gint                 paint_buffer_y;
136
  GimpTempBuf         *temp_buf;
137
  GeglBuffer          *convolve_buffer;
138
  gdouble              fade_point;
139 140
  gdouble              opacity;
  gdouble              rate;
Jehan's avatar
Jehan committed
141 142 143 144 145
  const GimpCoords    *coords;
  GeglNode            *op;
  gint                 paint_width, paint_height;
  gint                 n_strokes;
  gint                 i;
Michael Natterer's avatar
Michael Natterer committed
146

147 148
  fade_point = gimp_paint_options_get_fade (paint_options, image,
                                            paint_core->pixel_dist);
Elliot Lee's avatar
Elliot Lee committed
149

Jehan's avatar
Jehan committed
150
  coords = gimp_symmetry_get_origin (sym);
151 152 153 154 155
  opacity = gimp_dynamics_get_linear_value (dynamics,
                                            GIMP_DYNAMICS_OUTPUT_OPACITY,
                                            coords,
                                            paint_options,
                                            fade_point);
156
  if (opacity == 0.0)
157 158
    return;

Jehan's avatar
Jehan committed
159 160 161 162 163 164 165 166 167 168
  gimp_brush_core_eval_transform_dynamics (GIMP_BRUSH_CORE (paint_core),
                                           drawable,
                                           paint_options,
                                           coords);
  n_strokes = gimp_symmetry_get_size (sym);
  for (i = 0; i < n_strokes; i++)
    {
      coords = gimp_symmetry_get_coords (sym, i);

      paint_buffer = gimp_paint_core_get_paint_buffer (paint_core, drawable,
169
                                                       paint_options,
170
                                                       GIMP_LAYER_MODE_NORMAL,
171
                                                       coords,
Jehan's avatar
Jehan committed
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
                                                       &paint_buffer_x,
                                                       &paint_buffer_y,
                                                       &paint_width,
                                                       &paint_height);
      if (! paint_buffer)
        continue;

      op = gimp_symmetry_get_operation (sym, i,
                                        paint_width,
                                        paint_height);

      rate = (options->rate *
              gimp_dynamics_get_linear_value (dynamics,
                                              GIMP_DYNAMICS_OUTPUT_RATE,
                                              coords,
                                              paint_options,
                                              fade_point));

      gimp_convolve_calculate_matrix (convolve, options->type,
                                      gimp_brush_get_width  (brush_core->brush) / 2,
                                      gimp_brush_get_height (brush_core->brush) / 2,
                                      rate);

      /*  need a linear buffer for gimp_gegl_convolve()  */
      temp_buf = gimp_temp_buf_new (gegl_buffer_get_width  (paint_buffer),
                                    gegl_buffer_get_height (paint_buffer),
                                    gegl_buffer_get_format (paint_buffer));
      convolve_buffer = gimp_temp_buf_create_buffer (temp_buf);
      gimp_temp_buf_unref (temp_buf);

202 203 204 205 206 207 208 209 210
      gimp_gegl_buffer_copy (
        gimp_drawable_get_buffer (drawable),
        GEGL_RECTANGLE (paint_buffer_x,
                        paint_buffer_y,
                        gegl_buffer_get_width  (paint_buffer),
                        gegl_buffer_get_height (paint_buffer)),
        GEGL_ABYSS_NONE,
        convolve_buffer,
        GEGL_RECTANGLE (0, 0, 0, 0));
Jehan's avatar
Jehan committed
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232

      gimp_gegl_convolve (convolve_buffer,
                          GEGL_RECTANGLE (0, 0,
                                          gegl_buffer_get_width  (convolve_buffer),
                                          gegl_buffer_get_height (convolve_buffer)),
                          paint_buffer,
                          GEGL_RECTANGLE (0, 0,
                                          gegl_buffer_get_width  (paint_buffer),
                                          gegl_buffer_get_height (paint_buffer)),
                          convolve->matrix, 3, convolve->matrix_divisor,
                          GIMP_NORMAL_CONVOL, TRUE);

      g_object_unref (convolve_buffer);

      gimp_brush_core_replace_canvas (brush_core, drawable,
                                      coords,
                                      MIN (opacity, GIMP_OPACITY_OPAQUE),
                                      gimp_context_get_opacity (context),
                                      gimp_paint_options_get_brush_mode (paint_options),
                                      1.0,
                                      GIMP_PAINT_INCREMENTAL, op);
    }
Elliot Lee's avatar
Elliot Lee committed
233 234 235
}

static void
236 237
gimp_convolve_calculate_matrix (GimpConvolve    *convolve,
                                GimpConvolveType type,
238 239
                                gint             radius_x,
                                gint             radius_y,
240
                                gdouble          rate)
Elliot Lee's avatar
Elliot Lee committed
241 242
{
  /*  find percent of tool pressure  */
243 244 245 246 247 248
  const gdouble percent = MIN (rate / 100.0, 1.0);

  convolve->matrix[0] = (radius_x && radius_y) ? 1.0 : 0.0;
  convolve->matrix[1] = (radius_y)             ? 1.0 : 0.0;
  convolve->matrix[2] = (radius_x && radius_y) ? 1.0 : 0.0;
  convolve->matrix[3] = (radius_x)             ? 1.0 : 0.0;
Elliot Lee's avatar
Elliot Lee committed
249 250 251 252

  /*  get the appropriate convolution matrix and size and divisor  */
  switch (type)
    {
253
    case GIMP_CONVOLVE_BLUR:
254
      convolve->matrix[4] = MIN_BLUR + percent * (MAX_BLUR - MIN_BLUR);
Elliot Lee's avatar
Elliot Lee committed
255 256
      break;

257
    case GIMP_CONVOLVE_SHARPEN:
258
      convolve->matrix[4] = MIN_SHARPEN + percent * (MAX_SHARPEN - MIN_SHARPEN);
Elliot Lee's avatar
Elliot Lee committed
259 260 261
      break;
    }

262 263 264 265 266
  convolve->matrix[5] = (radius_x)             ? 1.0 : 0.0;
  convolve->matrix[6] = (radius_x && radius_y) ? 1.0 : 0.0;
  convolve->matrix[7] = (radius_y)             ? 1.0 : 0.0;
  convolve->matrix[8] = (radius_x && radius_y) ? 1.0 : 0.0;

267
  convolve->matrix_divisor = gimp_convolve_sum_matrix (convolve->matrix);
Elliot Lee's avatar
Elliot Lee committed
268 269
}

270
static gdouble
271
gimp_convolve_sum_matrix (const gfloat *matrix)
Elliot Lee's avatar
Elliot Lee committed
272
{
273
  gdouble sum = 0.0;
274
  gint    i;
Elliot Lee's avatar
Elliot Lee committed
275

276 277
  for (i = 0; i < 9; i++)
    sum += matrix[i];
Elliot Lee's avatar
Elliot Lee committed
278 279 280

  return sum;
}