~ubuntu-branches/ubuntu/jaunty/gimp/jaunty-security

« back to all changes in this revision

Viewing changes to plug-ins/common/convmatrix.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Holbach
  • Date: 2007-05-02 16:33:03 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070502163303-bvzhjzbpw8qglc4y
Tags: 2.3.16-1ubuntu1
* Resynchronized with Debian, remaining Ubuntu changes:
  - debian/rules: i18n magic.
* debian/control.in:
  - Maintainer: Ubuntu Core Developers <ubuntu-devel@lists.ubuntu.com>
* debian/patches/02_help-message.patch,
  debian/patches/03_gimp.desktop.in.in.patch,
  debian/patches/10_dont_show_wizard.patch: updated.
* debian/patches/04_composite-signedness.patch,
  debian/patches/05_add-letter-spacing.patch: dropped, used upstream.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
 *
22
22
 *
23
23
 * CHANGELOG:
24
 
 * v0.13        15.12.2000
25
 
 *      Made the PDB interface actually work.   (Simon Budig <simon@gimp.org>)
26
 
 *
27
 
 * v0.12        15.9.1997
28
 
 *      Got rid of the unportable snprintf. Also made some _tiny_ GUI fixes.
29
 
 *
30
 
 * v0.11        20.7.1997
31
 
 *      Negative values in the matrix are now abs'ed when used to weight
 
24
 * v0.14        21.09.2006                   (gg <gg at catking the net>)
 
25
 *      Replace numerical consts by named const, much variable renaming for maintainability
 
26
 *      Generalisation of code w.r.t. matrix dimension with aim to support 7x7
 
27
 *      Some minor bug fixes.
 
28
 *
 
29
 * v0.13        15.12.2000
 
30
 *      Made the PDB interface actually work.   (Simon Budig <simon@gimp.org>)
 
31
 *
 
32
 * v0.12        15.9.1997
 
33
 *      Got rid of the unportable snprintf. Also made some _tiny_ GUI fixes.
 
34
 *
 
35
 * v0.11        20.7.1997
 
36
 *      Negative values in the matrix are now abs'ed when used to weight
32
37
 *      alpha. Embossing effects should work properly now. Also fixed a
33
38
 *      totally idiotic bug with embossing.
34
39
 *
35
 
 * v0.1         2.7.1997
36
 
 *      Initial release. Works... kinda.
 
40
 * v0.1         2.7.1997
 
41
 *      Initial release. Works... kinda.
37
42
 *
38
43
 *
39
44
 * TODO:
41
46
 * - remove channels selector (that's what the channels dialog is for)
42
47
 * - remove idiotic slowdowns
43
48
 * - clean up code
44
 
 * - preview
45
49
 * - optimize properly
46
50
 * - save & load matrices
47
51
 * - spiffy frontend for designing matrices
54
58
#include "config.h"
55
59
 
56
60
#include <stdlib.h>
57
 
#include <stdio.h>
58
 
#include <time.h>
59
61
#include <string.h>
60
 
#include <sys/types.h>
61
 
#ifdef HAVE_UNISTD_H
62
 
#include <unistd.h>
63
 
#endif
64
 
 
65
 
#include <gtk/gtk.h>
66
62
 
67
63
#include <libgimp/gimp.h>
68
64
#include <libgimp/gimpui.h>
70
66
#include "libgimp/stdplugins-intl.h"
71
67
 
72
68
 
 
69
#define PLUG_IN_PROC   "plug-in-convmatrix"
 
70
#define PLUG_IN_BINARY "convmatrix"
73
71
#define RESPONSE_RESET 1
74
72
 
 
73
 
 
74
#define BIG_MATRIX  /* toggle for 11x11 matrix code experimental*/
 
75
#undef BIG_MATRIX
 
76
 
 
77
 
 
78
#ifndef BIG_MATRIX
 
79
#define MATRIX_SIZE   (5)
 
80
#else
 
81
#define MATRIX_SIZE   (11)
 
82
#endif
 
83
 
 
84
#define HALF_WINDOW   (MATRIX_SIZE/2)
 
85
#define MATRIX_CELLS  (MATRIX_SIZE*MATRIX_SIZE)
 
86
#define DEST_ROWS     (MATRIX_SIZE/2 + 1)
 
87
#define CHANNELS      (5)
 
88
#define BORDER_MODES  (3)
 
89
 
 
90
 
 
91
 
75
92
typedef enum
76
93
{
77
94
  EXTEND,
78
95
  WRAP,
79
 
  CLEAR,
80
 
  MIRROR
 
96
  CLEAR
81
97
} BorderMode;
82
98
 
83
 
static GimpDrawable *drawable;
84
 
 
85
99
static gchar * const channel_labels[] =
86
100
{
87
101
  N_("Gr_ey"),
101
115
/* Declare local functions. */
102
116
static void query (void);
103
117
static void run   (const gchar      *name,
104
 
                   gint              nparams,
105
 
                   const GimpParam  *param,
106
 
                   gint             *nreturn_vals,
107
 
                   GimpParam       **return_vals);
108
 
 
109
 
static gboolean  dialog       (void);
110
 
 
111
 
static void      convmatrix   (void);
112
 
static void      check_config (void);
113
 
 
114
 
 
115
 
GimpPlugInInfo PLUG_IN_INFO =
 
118
                   gint              nparams,
 
119
                   const GimpParam  *param,
 
120
                   gint             *nreturn_vals,
 
121
                   GimpParam       **return_vals);
 
122
 
 
123
static gboolean  convolve_image_dialog (GimpDrawable  *drawable);
 
124
 
 
125
static void      convolve_image        (GimpDrawable  *drawable,
 
126
                                        GimpPreview   *preview);
 
127
 
 
128
static void      check_config          (GimpDrawable  *drawable);
 
129
 
 
130
static gfloat    convolve_pixel        (guchar       **src_row,
 
131
                                        gint           x_offset,
 
132
                                        gint           channel,
 
133
                                        GimpDrawable  *drawable);
 
134
 
 
135
const GimpPlugInInfo PLUG_IN_INFO =
116
136
{
117
137
  NULL,   /* init_proc  */
118
138
  NULL,   /* quit_proc  */
120
140
  run,    /* run_proc   */
121
141
};
122
142
 
123
 
static gint     bytes;
124
143
static gboolean run_flag = FALSE;
125
144
 
126
145
typedef struct
127
146
{
128
 
  gfloat     matrix[5][5];
 
147
  gfloat     matrix[MATRIX_SIZE][MATRIX_SIZE];
129
148
  gfloat     divisor;
130
149
  gfloat     offset;
131
 
  gint       alpha_alg;
 
150
  gint       alpha_weighting;
132
151
  BorderMode bmode;
133
 
  gint       channels[5];
134
 
  gint       autoset;
135
 
} config;
 
152
  gboolean   channels[CHANNELS];
 
153
  gboolean   autoset;
 
154
} config_struct;
136
155
 
137
 
static const config default_config =
 
156
#ifndef BIG_MATRIX
 
157
static const config_struct default_config =
138
158
{
139
159
  {
140
160
    { 0.0, 0.0, 0.0, 0.0, 0.0 },
147
167
  0,                 /* offset */
148
168
  1,                 /* Alpha-handling algorithm */
149
169
  CLEAR,             /* border-mode */
150
 
  { 1, 1, 1, 1, 1 }, /* Channels mask */
151
 
  0                  /* autoset */
152
 
};
153
 
 
154
 
static config my_config;
 
170
  { TRUE, TRUE, TRUE, TRUE, TRUE }, /* Channels mask */
 
171
  FALSE,              /* autoset */
 
172
};
 
173
 
 
174
#else
 
175
 
 
176
static const config_struct default_config =
 
177
{
 
178
  {
 
179
    { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  },
 
180
    { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  },
 
181
    { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  },
 
182
    { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  },
 
183
    { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  },
 
184
    { 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0  },
 
185
    { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  },
 
186
    { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  },
 
187
    { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  },
 
188
    { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  },
 
189
    { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0  }
 
190
  },                 /* matrix */
 
191
  1,                 /* divisor */
 
192
  0,                 /* offset */
 
193
  1,                 /* Alpha-handling algorithm */
 
194
  CLEAR,             /* border-mode */
 
195
  { TRUE, TRUE, TRUE, TRUE, TRUE }, /* Channels mask */
 
196
  FALSE,              /* autoset */
 
197
};
 
198
 
 
199
#endif
 
200
 
 
201
 
 
202
static config_struct config;
155
203
 
156
204
struct
157
205
{
158
 
  GtkWidget *matrix[5][5];
 
206
  GtkWidget *matrix[MATRIX_SIZE][MATRIX_SIZE];
159
207
  GtkWidget *divisor;
160
208
  GtkWidget *offset;
161
 
  GtkWidget *alpha_alg;
162
 
  GtkWidget *bmode[3];
163
 
  GtkWidget *channels[5];
 
209
  GtkWidget *alpha_weighting;
 
210
  GtkWidget *bmode[BORDER_MODES];
 
211
  GtkWidget *channels[CHANNELS];
164
212
  GtkWidget *autoset;
165
 
} my_widgets;
 
213
} widget_set;
166
214
 
167
215
 
168
216
MAIN ()
170
218
static void
171
219
query (void)
172
220
{
173
 
  static GimpParamDef args[] =
 
221
  static const GimpParamDef args[] =
174
222
  {
175
 
    { GIMP_PDB_INT32,    "run_mode", "Interactive, non-interactive" },
176
 
    { GIMP_PDB_IMAGE,    "image",    "Input image (unused)" },
177
 
    { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
178
 
    { GIMP_PDB_INT32, "argc_matrix", "The number of elements in the following array. Should be always 25." },
179
 
    { GIMP_PDB_FLOATARRAY, "matrix", "The 5x5 convolution matrix" },
180
 
    { GIMP_PDB_INT32, "alpha_alg", "Enable weighting by alpha channel" },
181
 
    { GIMP_PDB_FLOAT, "divisor", "Divisor" },
182
 
    { GIMP_PDB_FLOAT, "offset", "Offset" },
 
223
    { GIMP_PDB_INT32,      "run-mode",    "Interactive, non-interactive" },
 
224
    { GIMP_PDB_IMAGE,      "image",       "Input image (unused)" },
 
225
    { GIMP_PDB_DRAWABLE,   "drawable",    "Input drawable" },
 
226
    { GIMP_PDB_INT32,      "argc-matrix", "The number of elements in the following array. Should be always 25." },
 
227
    { GIMP_PDB_FLOATARRAY, "matrix",      "The 5x5 convolution matrix" },
 
228
    { GIMP_PDB_INT32,      "alpha-alg",   "Enable weighting by alpha channel" },
 
229
    { GIMP_PDB_FLOAT,      "divisor",     "Divisor" },
 
230
    { GIMP_PDB_FLOAT,      "offset",      "Offset" },
183
231
 
184
 
    { GIMP_PDB_INT32, "argc_channels", "The number of elements in following array. Should be always 5." },
185
 
    { GIMP_PDB_INT32ARRAY, "channels", "Mask of the channels to be filtered" },
186
 
    { GIMP_PDB_INT32, "bmode", "Mode for treating image borders" }
 
232
    { GIMP_PDB_INT32,      "argc-channels", "The number of elements in following array. Should be always 5." },
 
233
    { GIMP_PDB_INT32ARRAY, "channels",      "Mask of the channels to be filtered" },
 
234
    { GIMP_PDB_INT32,      "bmode",         "Mode for treating image borders" },
187
235
  };
188
236
 
189
 
  gimp_install_procedure ("plug_in_convmatrix",
190
 
                          "A generic 5x5 convolution matrix",
191
 
                          "",
192
 
                          "Lauri Alanko",
193
 
                          "Lauri Alanko",
194
 
                          "1997",
195
 
                          N_("_Convolution Matrix..."),
196
 
                          "RGB*, GRAY*",
197
 
                          GIMP_PLUGIN,
198
 
                          G_N_ELEMENTS (args), 0,
199
 
                          args, NULL);
 
237
  gimp_install_procedure (PLUG_IN_PROC,
 
238
                          N_("Apply a generic 5x5 convolution matrix"),
 
239
                          "",
 
240
                          "Lauri Alanko",
 
241
                          "Lauri Alanko",
 
242
                          "1997",
 
243
                          N_("_Convolution Matrix..."),
 
244
                          "RGB*, GRAY*",
 
245
                          GIMP_PLUGIN,
 
246
                          G_N_ELEMENTS (args), 0,
 
247
                          args, NULL);
200
248
 
201
 
  gimp_plugin_menu_register ("plug_in_convmatrix", "<Image>/Filters/Generic");
 
249
  gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/Filters/Generic");
202
250
}
203
251
 
204
252
static void
208
256
     gint             *nreturn_vals,
209
257
     GimpParam       **return_vals)
210
258
{
211
 
  static GimpParam  values[1];
212
 
  GimpRunMode       run_mode;
213
 
  GimpPDBStatusType status = GIMP_PDB_SUCCESS;
214
 
  gint              x, y;
 
259
  static GimpParam   values[1];
 
260
  GimpRunMode        run_mode;
 
261
  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
 
262
  gint               x, y;
 
263
  GimpDrawable      *drawable;
215
264
 
216
265
  INIT_I18N ();
217
266
 
223
272
  /*  Get the specified drawable  */
224
273
  drawable = gimp_drawable_get (param[2].data.d_drawable);
225
274
 
226
 
  /*  The plug-in is not able to handle images smaller than 3 pixels  */
 
275
  /*  The plug-in is not able to handle images smaller than 3x3 pixels  */
227
276
  if (drawable->width < 3 || drawable->height < 3)
228
277
    {
229
 
      g_message (_("Convolution Matrix does not work on layers "
230
 
                   "smaller than 3 pixels."));
 
278
      g_message (_("Convolution does not work on layers "
 
279
                   "smaller than 3x3 pixels."));
231
280
      status = GIMP_PDB_EXECUTION_ERROR;
232
281
      values[0].type = GIMP_PDB_STATUS;
233
282
      values[0].data.d_status = status;
234
283
      return;
235
284
    }
236
285
 
237
 
  my_config = default_config;
 
286
  config = default_config;
238
287
  if (run_mode == GIMP_RUN_NONINTERACTIVE)
239
288
    {
240
 
      if (nparams != 11)
 
289
      if ((nparams != 11) && (nparams != 12))
241
290
        {
242
291
          status = GIMP_PDB_CALLING_ERROR;
243
292
        }
244
293
      else
245
 
        {
246
 
          if (param[3].data.d_int32 != 25)
247
 
            {
248
 
              status = GIMP_PDB_CALLING_ERROR;
249
 
            }
250
 
          else
251
 
            {
252
 
              for (y = 0; y < 5; y++)
253
 
                for (x = 0; x < 5; x++)
254
 
                  my_config.matrix[x][y]=param[4].data.d_floatarray[y*5+x];
255
 
            }
256
 
 
257
 
          my_config.alpha_alg = param[5].data.d_int32;
258
 
          my_config.divisor   = param[6].data.d_float;
259
 
          my_config.offset    = param[7].data.d_float;
260
 
 
261
 
 
262
 
          if (param[8].data.d_int32 != 5)
263
 
            {
264
 
              status = GIMP_PDB_CALLING_ERROR;
265
 
            }
266
 
          else
267
 
            {
268
 
              for (y = 0; y < 5; y++)
269
 
                my_config.channels[y] = param[9].data.d_int32array[y];
270
 
            }
271
 
 
272
 
          my_config.bmode     = param[10].data.d_int32;
273
 
 
274
 
          check_config ();
275
 
        }
 
294
        {
 
295
          if (param[3].data.d_int32 != MATRIX_CELLS)
 
296
            {
 
297
              status = GIMP_PDB_CALLING_ERROR;
 
298
            }
 
299
          else
 
300
            {
 
301
              for (y = 0; y < MATRIX_SIZE; y++)
 
302
                for (x = 0; x < MATRIX_SIZE; x++)
 
303
                  config.matrix[x][y]
 
304
                    = param[4].data.d_floatarray[x * MATRIX_SIZE + y];
 
305
            }
 
306
 
 
307
          config.alpha_weighting = param[5].data.d_int32;
 
308
          config.divisor   = param[6].data.d_float;
 
309
          config.offset    = param[7].data.d_float;
 
310
 
 
311
          if (param[8].data.d_int32 != CHANNELS)
 
312
            {
 
313
              status = GIMP_PDB_CALLING_ERROR;
 
314
            }
 
315
          else
 
316
            {
 
317
              for (y = 0; y < CHANNELS; y++)
 
318
                config.channels[y] = param[9].data.d_int32array[y];
 
319
            }
 
320
 
 
321
          config.bmode     = param[10].data.d_int32;
 
322
 
 
323
          check_config (drawable);
 
324
        }
276
325
    }
277
326
  else
278
327
    {
279
 
      gimp_get_data ("plug_in_convmatrix", &my_config);
 
328
      gimp_get_data (PLUG_IN_PROC, &config);
280
329
 
281
330
      if (run_mode == GIMP_RUN_INTERACTIVE)
282
 
        {
283
 
          /*  Oh boy. We get to do a dialog box, because we can't really
284
 
           *  expect the user to set us up with the right values using gdb.
285
 
           */
286
 
          check_config ();
 
331
        {
 
332
          /*  Oh boy. We get to do a dialog box, because we can't really
 
333
           *  expect the user to set us up with the right values using gdb.
 
334
           */
 
335
          check_config (drawable);
287
336
 
288
 
          if (! dialog ())
289
 
            {
290
 
              /* The dialog was closed, or something similarly evil happened. */
291
 
              status = GIMP_PDB_EXECUTION_ERROR;
292
 
            }
293
 
        }
 
337
          if (! convolve_image_dialog (drawable))
 
338
            {
 
339
              /* The dialog was closed, or something similarly evil happened. */
 
340
              status = GIMP_PDB_EXECUTION_ERROR;
 
341
            }
 
342
        }
294
343
    }
295
344
 
296
345
  if (status == GIMP_PDB_SUCCESS)
297
346
    {
298
347
      /*  Make sure that the drawable is gray or RGB color  */
299
348
      if (gimp_drawable_is_rgb (drawable->drawable_id) ||
300
 
          gimp_drawable_is_gray (drawable->drawable_id))
301
 
        {
302
 
          gimp_progress_init (_("Applying convolution"));
303
 
          gimp_tile_cache_ntiles (2 * (drawable->width /
304
 
                                       gimp_tile_width () + 1));
305
 
 
306
 
          convmatrix ();
307
 
 
308
 
          if (run_mode != GIMP_RUN_NONINTERACTIVE)
309
 
            gimp_displays_flush ();
310
 
 
311
 
          if (run_mode == GIMP_RUN_INTERACTIVE)
312
 
            gimp_set_data ("plug_in_convmatrix",
313
 
                           &my_config, sizeof (my_config));
314
 
        }
 
349
          gimp_drawable_is_gray (drawable->drawable_id))
 
350
        {
 
351
          gimp_progress_init (_("Applying convolution"));
 
352
          gimp_tile_cache_ntiles (2 * (drawable->width /
 
353
                                  gimp_tile_width () + 1));
 
354
          convolve_image (drawable, NULL);
 
355
 
 
356
          if (run_mode != GIMP_RUN_NONINTERACTIVE)
 
357
            gimp_displays_flush ();
 
358
 
 
359
          if (run_mode == GIMP_RUN_INTERACTIVE)
 
360
            gimp_set_data (PLUG_IN_PROC, &config, sizeof (config));
 
361
        }
315
362
      else
316
 
        {
317
 
          status = GIMP_PDB_EXECUTION_ERROR;
318
 
        }
 
363
        {
 
364
          status = GIMP_PDB_EXECUTION_ERROR;
 
365
        }
319
366
 
320
367
      gimp_drawable_detach (drawable);
321
368
    }
326
373
 
327
374
 
328
375
/*  A generic wrapper to gimp_pixel_rgn_get_row which handles unlimited
329
 
 *  wrapping or gives you transparent regions outside the image
 
376
 *  wrapping or gives the transparent regions outside the image
 
377
 *  fills additional bytes before and after image row to provide border modes.
330
378
 */
331
379
 
332
380
static void
333
381
my_get_row (GimpPixelRgn *PR,
334
 
            guchar       *dest,
335
 
            gint          x,
336
 
            gint          y,
337
 
            gint          w)
 
382
            guchar       *dest,
 
383
            gint          x,
 
384
            gint          y,
 
385
            gint          w)
338
386
{
339
 
  gint width, height, bytes;
 
387
  gint width, height, bpp;
340
388
  gint i;
341
389
 
342
390
  width  = PR->drawable->width;
343
391
  height = PR->drawable->height;
344
 
  bytes  = PR->drawable->bpp;
 
392
  bpp  = PR->drawable->bpp;
345
393
 
346
394
  /* Y-wrappings */
347
 
 
348
 
  switch (my_config.bmode)
 
395
  switch (config.bmode)
349
396
    {
350
397
    case WRAP:
351
398
      /* Wrapped, so we get the proper row from the other side */
352
399
      while (y < 0) /* This is the _sure_ way to wrap. :) */
353
 
        y += height;
 
400
        y += height;
354
401
      while (y >= height)
355
 
        y -= height;
 
402
        y -= height;
356
403
      break;
357
404
 
358
405
    case CLEAR:
359
406
      /* Beyond borders, so set full transparent. */
360
407
      if (y < 0 || y >= height)
361
 
        {
362
 
          memset (dest, 0, w * bytes);
363
 
          return; /* Done, so back. */
364
 
        }
365
 
    case MIRROR:
366
 
      /* The border lines are _not_ duplicated in the mirror image */
367
 
      /* is this right? */
368
 
      while (y < 0 || y >= height)
369
 
        {
370
 
          if (y < 0)
371
 
            y = -y; /* y=-y-1 */
372
 
          if (y >= height)
373
 
            y = 2 * height - y - 2; /* y=2*height-y-1 */
374
 
        }
375
 
      break;
 
408
        {
 
409
          memset (dest, 0, w * bpp);
 
410
          return; /* Done, so back. */
 
411
        }
376
412
 
377
413
    case EXTEND:
378
414
      y = CLAMP (y , 0 , height - 1);
379
415
      break;
380
416
    }
381
417
 
382
 
  switch (my_config.bmode)
 
418
 
 
419
  /* X-wrappings */
 
420
  switch (config.bmode)
383
421
    {
384
422
    case CLEAR:
385
423
      if (x < 0)
386
 
        {
387
 
          i = MIN (w, -x);
388
 
          memset (dest, 0, i * bytes);
389
 
          dest += i * bytes;
390
 
          w -= i;
391
 
          x += i;
392
 
        }
393
 
      if (w)
394
 
        {
395
 
          i = MIN (w, width);
396
 
          gimp_pixel_rgn_get_row (PR, dest, x, y, i);
397
 
          dest += i * bytes;
398
 
          w -= i;
399
 
          x += i;
400
 
        }
401
 
      if (w)
402
 
        memset (dest, 0, w * bytes);
 
424
        {
 
425
          i = MIN (w, -x);
 
426
          memset (dest, 0, i * bpp);
 
427
          dest += i * bpp;
 
428
          w -= i;
 
429
          x += i;
 
430
        }
 
431
      if (w)
 
432
        {
 
433
          i = MIN (w, width);
 
434
          gimp_pixel_rgn_get_row (PR, dest, x, y, i);
 
435
          dest += i * bpp;
 
436
          w -= i;
 
437
          x += i;
 
438
        }
 
439
      if (w)
 
440
        memset (dest, 0, w * bpp);
403
441
      break;
404
442
 
405
443
    case WRAP:
406
444
      while (x < 0)
407
 
        x += width;
 
445
        x += width;
408
446
      i = MIN (w, width - x);
409
447
      gimp_pixel_rgn_get_row (PR, dest, x, y, i);
410
448
      w -= i;
411
 
      dest += i * bytes;
 
449
      dest += i * bpp;
412
450
      x = 0;
413
451
      while (w)
414
 
        {
415
 
          i = MIN (w, width);
416
 
          gimp_pixel_rgn_get_row (PR, dest, x, y, i);
417
 
          w -= i;
418
 
          dest += i * bytes;
419
 
        }
 
452
        {
 
453
          i = MIN (w, width);
 
454
          gimp_pixel_rgn_get_row (PR, dest, x, y, i);
 
455
          w -= i;
 
456
          dest += i * bpp;
 
457
        }
420
458
      break;
421
459
 
422
460
    case EXTEND:
423
461
      if (x < 0)
424
 
        {
425
 
          gimp_pixel_rgn_get_pixel (PR, dest, 0, y);
426
 
          x++;
427
 
          w--;
428
 
          dest += bytes;
 
462
        {
 
463
          gimp_pixel_rgn_get_pixel (PR, dest, 0, y);
 
464
          x++;
 
465
          w--;
 
466
          dest += bpp;
429
467
 
430
 
          while (x < 0 && w)
431
 
            {
432
 
              for (i = 0; i < bytes; i++)
433
 
                {
434
 
                  *dest = *(dest - bytes);
435
 
                  dest++;
436
 
                }
437
 
              x++;
438
 
              w--;
439
 
            }
440
 
        }
 
468
          while (x < 0 && w)
 
469
            {
 
470
              for (i = 0; i < bpp; i++)
 
471
                {
 
472
                  *dest = *(dest - bpp);
 
473
                  dest++;
 
474
                }
 
475
              x++;
 
476
              w--;
 
477
            }
 
478
        }
441
479
      if (w && width - x > 0)
442
 
        {
443
 
          i = MIN (w, width - x);
444
 
          gimp_pixel_rgn_get_row (PR, dest, x, y, i);
445
 
          w -= i;
446
 
          dest += i * bytes;
447
 
        }
 
480
        {
 
481
          i = MIN (w, width - x);
 
482
          gimp_pixel_rgn_get_row (PR, dest, x, y, i);
 
483
          w -= i;
 
484
          dest += i * bpp;
 
485
        }
448
486
      while (w)
449
 
        {
450
 
          for (i = 0; i < bytes; i++)
451
 
            {
452
 
              *dest= *(dest - bytes);
453
 
              dest++;
454
 
            }
455
 
          x++;
456
 
          w--;
457
 
        }
 
487
        {
 
488
          for (i = 0; i < bpp; i++)
 
489
            {
 
490
              *dest= *(dest - bpp);
 
491
              dest++;
 
492
            }
 
493
          x++;
 
494
          w--;
 
495
        }
458
496
      break;
459
497
 
460
 
    case MIRROR: /* Not yet handled */
461
 
      break;
462
498
    }
463
499
}
464
500
 
465
501
static gfloat
466
 
calcmatrix (guchar **srcrow,
467
 
            gint     xoff,
468
 
            gint     i)
 
502
convolve_pixel (guchar       **src_row,
 
503
                gint           x_offset,
 
504
                gint           channel,
 
505
                GimpDrawable  *drawable)
469
506
{
470
 
  static gfloat matrixsum = 0;
471
 
  static gint bytes       = 0;
 
507
  static gfloat matrixsum = 0; /* FIXME: this certainly breaks the preview */
 
508
  static gint bpp         = 0;
472
509
 
473
 
  gfloat sum      = 0;
474
 
  gfloat alphasum = 0;
 
510
  gfloat sum              = 0;
 
511
  gfloat alphasum         = 0;
475
512
  gfloat temp;
476
513
  gint   x, y;
 
514
  gint   alpha_channel;
477
515
 
478
 
  if (!bytes)
 
516
  if (!bpp)
479
517
    {
480
 
      bytes = drawable->bpp;
481
 
      for (y = 0; y < 5; y++)
482
 
        for (x = 0; x < 5; x++)
483
 
          {
484
 
            temp = my_config.matrix[x][y];
485
 
            matrixsum += ABS (temp);
486
 
          }
 
518
      bpp = drawable->bpp;
 
519
 
 
520
      for (y = 0; y < MATRIX_SIZE; y++)
 
521
        for (x = 0; x < MATRIX_SIZE; x++)
 
522
          {
 
523
            temp = config.matrix[x][y];
 
524
            matrixsum += ABS (config.matrix[x][y]);
 
525
          }
487
526
    }
488
 
  for (y = 0; y < 5; y++)
489
 
    for (x = 0; x < 5; x++)
 
527
 
 
528
  alpha_channel = bpp - 1;
 
529
 
 
530
  for (y = 0; y < MATRIX_SIZE; y++)
 
531
    for (x = 0; x < MATRIX_SIZE; x++)
490
532
      {
491
 
        temp = my_config.matrix[x][y];
492
 
        if (i != (bytes - 1) && my_config.alpha_alg == 1)
493
 
          {
494
 
            temp *= srcrow[y][xoff + x * bytes +bytes - 1 - i];
495
 
            alphasum += ABS (temp);
496
 
          }
497
 
        temp *= srcrow[y][xoff + x * bytes];
498
 
        sum += temp;
 
533
        temp = config.matrix[x][y];
 
534
 
 
535
        if (channel != alpha_channel && config.alpha_weighting == 1)
 
536
          {
 
537
            temp *= src_row[y][x_offset + x * bpp + alpha_channel - channel];
 
538
            alphasum += ABS (temp);
 
539
          }
 
540
 
 
541
        temp *= src_row[y][x_offset + x * bpp];
 
542
        sum += temp;
499
543
      }
500
 
  sum /= my_config.divisor;
501
 
  if (i != (bytes - 1) && my_config.alpha_alg == 1)
 
544
 
 
545
  sum /= config.divisor;
 
546
 
 
547
  if (channel != alpha_channel && config.alpha_weighting == 1)
502
548
    {
503
549
      if (alphasum != 0)
504
 
        sum = sum * matrixsum / alphasum;
 
550
        sum = sum * matrixsum / alphasum;
505
551
      else
506
 
        sum = 0;
507
 
      /* sum = srcrow[2][xoff + 2 * bytes] * my_config.matrix[2][2];*/
 
552
        sum = 0;
508
553
    }
509
 
  sum += my_config.offset;
 
554
 
 
555
  sum += config.offset;
510
556
 
511
557
  return sum;
512
558
}
513
559
 
514
560
static void
515
 
convmatrix (void)
 
561
convolve_image (GimpDrawable *drawable,
 
562
                GimpPreview  *preview)
516
563
{
517
564
  GimpPixelRgn  srcPR, destPR;
518
565
  gint          width, height, row, col;
519
 
  gint          w, h, i;
520
 
  gint          sx1, sy1, sx2, sy2;
 
566
  gint          src_w, src_row_w, src_h, i;
 
567
  gint          src_x1, src_y1, src_x2, src_y2;
521
568
  gint          x1, x2, y1, y2;
522
 
  guchar       *destrow[3];
523
 
  guchar       *srcrow[5];
524
 
  guchar       *temprow;
 
569
  guchar       *dest_row[DEST_ROWS];
 
570
  guchar       *src_row[MATRIX_SIZE];
 
571
  guchar       *tmp_row;
525
572
  gfloat        sum;
526
 
  gint          xoff;
527
 
  gint          chanmask[4];
 
573
  gint          x_offset;
 
574
  gboolean      chanmask[CHANNELS-1];
 
575
  gint          bpp,channel,alpha_channel;
528
576
 
529
577
  /* Get the input area. This is the bounding box of the selection in
530
578
   *  the image (or the entire image if there is no selection). Only
532
580
   *  need to be done for correct operation. (It simply makes it go
533
581
   *  faster, since fewer pixels need to be operated on).
534
582
   */
535
 
  gimp_drawable_mask_bounds (drawable->drawable_id, &sx1, &sy1, &sx2, &sy2);
536
 
  w = sx2 - sx1;
537
 
  h = sy2 - sy1;
 
583
  if (preview)
 
584
    {
 
585
      gimp_preview_get_position (preview, &src_x1, &src_y1);
 
586
      gimp_preview_get_size (preview, &src_w, &src_h);
 
587
      src_x2 = src_x1 + src_w;
 
588
      src_y2 = src_y1 + src_h;
 
589
    }
 
590
  else
 
591
    {
 
592
      gimp_drawable_mask_bounds (drawable->drawable_id,
 
593
                                 &src_x1, &src_y1, &src_x2, &src_y2);
 
594
      src_w = src_x2 - src_x1;
 
595
      src_h = src_y2 - src_y1;
 
596
    }
538
597
 
539
598
  /* Get the size of the input image. (This will/must be the same
540
599
   *  as the size of the output image.
541
600
   */
542
601
  width  = drawable->width;
543
602
  height = drawable->height;
544
 
  bytes  = drawable->bpp;
 
603
  bpp  = drawable->bpp;
 
604
  alpha_channel = bpp - 1;
545
605
 
546
606
  if (gimp_drawable_is_rgb (drawable->drawable_id))
547
 
    for (i = 0; i <3; i++)
548
 
      chanmask[i] = my_config.channels[i + 1];
 
607
    {
 
608
      for (i = 0; i <CHANNELS; i++)
 
609
        chanmask[i] = config.channels[i + 1];
 
610
    }
549
611
  else /* Grayscale */
550
 
    chanmask[0] = my_config.channels[0];
 
612
    chanmask[0] = config.channels[0];
551
613
 
552
614
  if (gimp_drawable_has_alpha (drawable->drawable_id))
553
 
    chanmask[bytes - 1] = my_config.channels[4];
554
 
 
555
 
  for (i = 0; i < 5; i++)
556
 
    srcrow[i] = g_new (guchar, (w + 4) * bytes);
557
 
  for (i = 0; i < 3; i++)
558
 
    destrow[i]= g_new (guchar, w * bytes);
 
615
    chanmask[alpha_channel] = config.channels[alpha_channel];
 
616
 
 
617
  src_row_w = src_w + HALF_WINDOW + HALF_WINDOW;
 
618
 
 
619
  for (i = 0; i < MATRIX_SIZE; i++)
 
620
    src_row[i] = g_new (guchar, src_row_w * bpp);
 
621
 
 
622
  for (i = 0; i < DEST_ROWS; i++)
 
623
    dest_row[i]= g_new (guchar, src_w * bpp);
559
624
 
560
625
  /*  initialize the pixel regions  */
561
 
  x1 = MAX (sx1 - 2, 0);
562
 
  y1 = MAX (sy1 - 2, 0);
563
 
  x2 = MIN (sx2 + 2, width);
564
 
  y2 = MIN (sy2 + 2, height);
 
626
  x1 = MAX (src_x1 - HALF_WINDOW, 0);
 
627
  y1 = MAX (src_y1 - HALF_WINDOW, 0);
 
628
  x2 = MIN (src_x2 + HALF_WINDOW, width);
 
629
  y2 = MIN (src_y2 + HALF_WINDOW, height);
565
630
  gimp_pixel_rgn_init (&srcPR, drawable,
566
631
                       x1, y1, x2 - x1, y2 - y1, FALSE, FALSE);
567
 
  gimp_pixel_rgn_init (&destPR, drawable, sx1, sy1, w, h, TRUE, TRUE);
 
632
  gimp_pixel_rgn_init (&destPR, drawable,
 
633
                       src_x1, src_y1, src_w, src_h,
 
634
                       preview == NULL, TRUE);
568
635
 
569
636
  /* initialize source arrays */
570
 
  for (i = 0; i < 5; i++)
571
 
    my_get_row (&srcPR, srcrow[i], sx1 - 2, sy1 + i - 2, w + 4);
572
 
 
573
 
  for (row = sy1; row < sy2; row++)
574
 
    {
575
 
      xoff = 0;
576
 
 
577
 
      for (col = sx1; col < sx2; col++)
578
 
        for (i = 0; i < bytes; i++)
579
 
          {
580
 
            if (chanmask[i] <= 0)
581
 
              sum = srcrow[2][xoff + 2 * bytes];
582
 
            else
583
 
              sum = calcmatrix(srcrow, xoff, i);
584
 
 
585
 
            destrow[2][xoff]= (guchar) CLAMP (sum, 0, 255);
586
 
            xoff++;
587
 
          }
588
 
 
589
 
      if (row > sy1 + 1)
590
 
        gimp_pixel_rgn_set_row (&destPR, destrow[0], sx1, row - 2, w);
591
 
 
592
 
      temprow = destrow[0];
593
 
      destrow[0] = destrow[1];
594
 
      destrow[1] = destrow[2];
595
 
      destrow[2] = temprow;
596
 
      temprow = srcrow[0];
597
 
 
598
 
      for (i = 0; i < 4; i++)
599
 
        srcrow[i] = srcrow[i + 1];
600
 
 
601
 
      srcrow[4] = temprow;
602
 
      my_get_row (&srcPR, srcrow[4], sx1 - 2, row + 3, w + 4);
603
 
 
604
 
      if (row % 10 == 0)
605
 
        gimp_progress_update ((double) (row - sy1) / h);
606
 
    }
607
 
 
608
 
  /* put the final rows in the buffer in place */
609
 
  if (h < 3)
610
 
    gimp_pixel_rgn_set_row (&destPR, destrow[2], sx1, row - 3, w);
611
 
  if (h > 1)
612
 
    gimp_pixel_rgn_set_row (&destPR, destrow[0], sx1, row - 2, w);
613
 
  if (h > 2)
614
 
    gimp_pixel_rgn_set_row (&destPR, destrow[1], sx1, row - 1, w);
615
 
 
616
 
  /*  update the timred region  */
617
 
  gimp_drawable_flush (drawable);
618
 
  gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
619
 
  gimp_drawable_update (drawable->drawable_id, sx1, sy1, sx2 - sx1, sy2 - sy1);
 
637
  for (i = 0; i < MATRIX_SIZE; i++)
 
638
    my_get_row (&srcPR, src_row[i], src_x1 - HALF_WINDOW,
 
639
                src_y1 - HALF_WINDOW + i , src_row_w);
 
640
 
 
641
  for (row = src_y1; row < src_y2; row++)
 
642
    {
 
643
      x_offset = 0;
 
644
 
 
645
      for (col = src_x1; col < src_x2; col++)
 
646
        for (channel = 0; channel < bpp; channel++)
 
647
          {
 
648
            if (chanmask[channel])
 
649
              sum = convolve_pixel(src_row, x_offset, channel, drawable);
 
650
            else
 
651
              sum = src_row[HALF_WINDOW][x_offset + HALF_WINDOW * bpp];  /* copy unmodified px */
 
652
 
 
653
            dest_row[HALF_WINDOW][x_offset] = (guchar) CLAMP (sum, 0, 255);
 
654
            x_offset++;
 
655
          }
 
656
 
 
657
      if (row >= src_y1 + HALF_WINDOW)
 
658
        gimp_pixel_rgn_set_row (&destPR, dest_row[0], src_x1, row - HALF_WINDOW, src_w);
 
659
 
 
660
      if (row < src_y2 - 1)
 
661
        {
 
662
          tmp_row = dest_row[0];
 
663
          for (i = 0; i < DEST_ROWS - 1; i++)
 
664
            dest_row[i] = dest_row[i + 1];
 
665
 
 
666
          dest_row[DEST_ROWS - 1] = tmp_row;
 
667
 
 
668
          tmp_row = src_row[0];
 
669
          for (i = 0; i < MATRIX_SIZE - 1; i++)
 
670
            src_row[i] = src_row[i + 1];
 
671
          src_row[MATRIX_SIZE-1] = tmp_row;
 
672
 
 
673
          my_get_row (&srcPR, src_row[MATRIX_SIZE - 1],
 
674
                      src_x1 - HALF_WINDOW, row + HALF_WINDOW + 1, src_row_w);
 
675
        }
 
676
 
 
677
      if ((row % 10 == 0) && !preview)
 
678
        gimp_progress_update ((double) (row - src_y1) / src_h);
 
679
    }
 
680
 
 
681
  /* put the remaining rows in the buffer in place */
 
682
  for (i = 1; i <  DEST_ROWS; i++)
 
683
    gimp_pixel_rgn_set_row (&destPR, dest_row[i],
 
684
                            src_x1, src_y2 + i - 1 - HALF_WINDOW, src_w);
 
685
 
 
686
 
 
687
  /*  update the region  */
 
688
  if (preview)
 
689
    {
 
690
      gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview),
 
691
                                         &destPR);
 
692
    }
 
693
  else
 
694
    {
 
695
      gimp_drawable_flush (drawable);
 
696
      gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
 
697
      gimp_drawable_update (drawable->drawable_id, src_x1, src_y1, src_x2 - src_x1, src_y2 - src_y1);
 
698
    }
 
699
  for (i = 0; i < MATRIX_SIZE; i++)
 
700
    g_free (src_row[i]);
 
701
  for (i = 0; i < DEST_ROWS; i++)
 
702
    g_free (dest_row[i]);
620
703
}
621
704
 
622
705
/***************************************************
625
708
 
626
709
static void
627
710
fprint (gfloat  f,
628
 
        gchar  *buffer,
 
711
        gchar  *buffer,
629
712
        gsize   len)
630
713
{
631
 
  gint i, t;
 
714
  guint i, t;
632
715
 
633
716
  g_snprintf (buffer, len, "%.7f", f);
634
717
  buffer[len - 1] = '\0';
635
718
 
636
 
  for (t = 0; t < len - 1 && buffer[t] != '.'; t++);
 
719
  for (t = 0; t < len - 1 && buffer[t] != '.'; t++)
 
720
      ;
637
721
 
638
722
  i = t + 1;
639
723
 
640
724
  while (buffer[i] != '\0')
641
725
    {
642
726
      if (buffer[i] != '0')
643
 
        t = i + 1;
 
727
        t = i + 1;
644
728
 
645
729
      i++;
646
730
    }
654
738
  gint  x, y;
655
739
  gchar buffer[12];
656
740
 
657
 
  for (y = 0; y < 5; y++)
658
 
    for (x = 0; x < 5; x++)
 
741
  for (y = 0; y < MATRIX_SIZE; y++)
 
742
    for (x = 0; x < MATRIX_SIZE; x++)
659
743
      {
660
 
        fprint (my_config.matrix[x][y], buffer, sizeof (buffer));
661
 
        gtk_entry_set_text (GTK_ENTRY (my_widgets.matrix[x][y]), buffer);
 
744
        fprint (config.matrix[x][y], buffer, sizeof (buffer));
 
745
        gtk_entry_set_text (GTK_ENTRY (widget_set.matrix[x][y]), buffer);
662
746
      }
663
747
}
664
748
 
667
751
{
668
752
  gint i;
669
753
 
670
 
  for (i = 0; i < 5; i++)
671
 
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (my_widgets.channels[i]),
672
 
                                  my_config.channels[i] > 0);
 
754
  for (i = 0; i < CHANNELS; i++)
 
755
    if (widget_set.channels[i])
 
756
      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget_set.channels[i]),
 
757
                                    config.channels[i]);
673
758
}
674
759
 
675
760
static void
676
761
redraw_autoset (void)
677
762
{
678
 
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (my_widgets.autoset),
679
 
                                my_config.autoset);
 
763
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget_set.autoset),
 
764
                                config.autoset);
680
765
}
681
766
 
682
767
static void
683
 
redraw_alpha_alg (void)
 
768
redraw_alpha_weighting (void)
684
769
{
685
 
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (my_widgets.alpha_alg),
686
 
                                my_config.alpha_alg > 0);
 
770
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget_set.alpha_weighting),
 
771
                                config.alpha_weighting > 0);
687
772
}
688
773
 
689
774
static void
691
776
{
692
777
  gchar buffer[12];
693
778
 
694
 
  fprint (my_config.divisor, buffer, sizeof (buffer));
695
 
  gtk_entry_set_text (GTK_ENTRY (my_widgets.divisor), buffer);
 
779
  fprint (config.divisor, buffer, sizeof (buffer));
 
780
  gtk_entry_set_text (GTK_ENTRY (widget_set.divisor), buffer);
696
781
 
697
 
  fprint (my_config.offset, buffer, sizeof (buffer));
698
 
  gtk_entry_set_text (GTK_ENTRY (my_widgets.offset), buffer);
 
782
  fprint (config.offset, buffer, sizeof (buffer));
 
783
  gtk_entry_set_text (GTK_ENTRY (widget_set.offset), buffer);
699
784
}
700
785
 
701
786
static void
702
787
redraw_bmode (void)
703
788
{
704
789
  gtk_toggle_button_set_active
705
 
    (GTK_TOGGLE_BUTTON (my_widgets.bmode[my_config.bmode]), TRUE);
 
790
    (GTK_TOGGLE_BUTTON (widget_set.bmode[config.bmode]), TRUE);
706
791
}
707
792
 
708
793
static void
711
796
  redraw_matrix ();
712
797
  redraw_off_and_div ();
713
798
  redraw_autoset ();
714
 
  redraw_alpha_alg ();
 
799
  redraw_alpha_weighting ();
715
800
  redraw_bmode ();
716
801
  redraw_channels ();
717
802
}
723
808
  gboolean  valid = FALSE;
724
809
  gfloat    sum   = 0.0;
725
810
 
726
 
  for (y = 0; y < 5; y++)
727
 
    for (x = 0; x < 5; x++)
 
811
  for (y = 0; y < MATRIX_SIZE; y++)
 
812
    for (x = 0; x < MATRIX_SIZE; x++)
728
813
      {
729
 
        sum += my_config.matrix[x][y];
730
 
        if (my_config.matrix[x][y] != 0.0)
731
 
          valid = TRUE;
 
814
        sum += config.matrix[x][y];
 
815
        if (config.matrix[x][y] != 0.0)
 
816
          valid = TRUE;
732
817
      }
733
818
 
734
 
  if (my_config.autoset)
 
819
  if (config.autoset)
735
820
    {
736
821
      if (sum > 0)
737
 
        {
738
 
          my_config.offset = 0;
739
 
          my_config.divisor = sum;
740
 
        }
 
822
        {
 
823
          config.offset = 0;
 
824
          config.divisor = sum;
 
825
        }
741
826
      else if (sum < 0)
742
 
        {
743
 
          my_config.offset = 255;
744
 
          my_config.divisor = -sum;
745
 
        }
 
827
        {
 
828
          config.offset = 255;
 
829
          config.divisor = -sum;
 
830
        }
746
831
      else
747
 
        {
748
 
          my_config.offset = 128;
749
 
          /* The sum is 0, so this is probably some sort of
750
 
           * embossing filter. Should divisor be autoset to 1
751
 
           * or left undefined, ie. for the user to define? */
752
 
          my_config.divisor = 1;
753
 
        }
 
832
        {
 
833
          config.offset = 128;
 
834
          /* The sum is 0, so this is probably some sort of
 
835
           * embossing filter. Should divisor be autoset to 1
 
836
           * or left undefined, ie. for the user to define? */
 
837
          config.divisor = 1;
 
838
        }
754
839
      redraw_off_and_div ();
755
840
    }
756
 
  /* gtk_widget_set_sensitive(my_widgets.ok,valid); */
757
841
}
758
842
 
759
843
static void
760
 
response_callback (GtkWidget *widget,
761
 
                   gint       response_id,
762
 
                   gpointer   data)
 
844
response_callback (GtkWidget    *widget,
 
845
                   gint          response_id,
 
846
                   GimpDrawable *drawable)
763
847
{
764
848
  switch (response_id)
765
849
    {
766
850
    case RESPONSE_RESET:
767
 
      my_config = default_config;
768
 
      check_config ();
 
851
      config = default_config;
 
852
      check_config (drawable);
769
853
      redraw_all ();
770
854
      break;
771
855
 
780
864
 
781
865
/* Checks that the configuration is valid for the image type */
782
866
static void
783
 
check_config (void)
 
867
check_config (GimpDrawable *drawable)
784
868
{
785
869
  gint i;
786
870
 
787
 
  for (i = 0; i < 5; i++)
788
 
    if (my_config.channels[i] < 0)
789
 
      my_config.channels[i] = 0;
790
 
 
791
 
  if (gimp_drawable_is_rgb (drawable->drawable_id))
792
 
    my_config.channels[0] = -1;
793
 
  else if (gimp_drawable_is_gray (drawable->drawable_id))
794
 
    for (i = 1; i < 4; i++)
795
 
      my_config.channels[i] = -1;
 
871
  for (i = 0; i < CHANNELS; i++)
 
872
    config.channels[i] = FALSE;
 
873
  config.alpha_weighting = 0;
796
874
 
797
875
  if (!gimp_drawable_has_alpha (drawable->drawable_id))
798
876
    {
799
 
      my_config.channels[4] = -1;
800
 
      my_config.alpha_alg   = -1;
801
 
      my_config.bmode       = EXTEND;
 
877
      config.alpha_weighting   = -1;
 
878
      config.bmode       = EXTEND;
802
879
    }
803
880
}
804
881
 
805
882
static void
806
883
entry_callback (GtkWidget *widget,
807
 
                gpointer   data)
 
884
                gpointer   data)
808
885
{
809
886
  gfloat *value = (gfloat *) data;
810
887
 
811
888
  *value = atof (gtk_entry_get_text (GTK_ENTRY (widget)));
812
889
 
813
 
#if 0
814
 
  check_matrix ();
815
 
#else
816
 
  if (widget == my_widgets.divisor)
 
890
  if (widget == widget_set.divisor)
817
891
    gtk_dialog_set_response_sensitive (GTK_DIALOG (gtk_widget_get_toplevel (widget)),
818
 
                                       GTK_RESPONSE_OK, (*value != 0.0));
819
 
  else if (widget != my_widgets.offset)
 
892
                                       GTK_RESPONSE_OK,
 
893
                                       (*value != 0.0));
 
894
  else if (widget != widget_set.offset)
820
895
    check_matrix ();
821
 
#endif
822
896
}
823
897
 
 
898
 
824
899
static void
825
900
my_toggle_callback (GtkWidget *widget,
826
 
                    gpointer   data)
 
901
                    gboolean  *data)
827
902
{
828
903
  gint val = GTK_TOGGLE_BUTTON (widget)->active;
829
904
 
830
 
  if (val)
831
 
    *(gint *) data = TRUE;
832
 
  else
833
 
    *(gint *) data = FALSE;
 
905
  *data = val;
834
906
 
835
 
  if (widget == my_widgets.alpha_alg)
 
907
  if (widget == widget_set.alpha_weighting)
836
908
    {
837
 
      gtk_widget_set_sensitive (my_widgets.bmode[CLEAR], val);
838
 
      if (val == 0 && my_config.bmode == CLEAR)
839
 
        {
840
 
          my_config.bmode = EXTEND;
841
 
          redraw_bmode ();
842
 
        }
 
909
      gtk_widget_set_sensitive (widget_set.bmode[CLEAR], val);
 
910
      if (val == 0 && config.bmode == CLEAR)
 
911
        {
 
912
          config.bmode = EXTEND;
 
913
          redraw_bmode ();
 
914
        }
843
915
    }
844
 
  else if (widget == my_widgets.autoset)
 
916
  else if (widget == widget_set.autoset)
845
917
    {
846
 
      gtk_widget_set_sensitive (my_widgets.divisor, !val);
847
 
      gtk_widget_set_sensitive (my_widgets.offset, !val);
 
918
      gtk_widget_set_sensitive (widget_set.divisor, !val);
 
919
      gtk_widget_set_sensitive (widget_set.offset, !val);
848
920
      check_matrix ();
849
921
    }
850
922
}
851
923
 
852
924
static void
853
925
my_bmode_callback (GtkWidget *widget,
854
 
                   gpointer   data)
 
926
                   gpointer   data)
855
927
{
856
 
  my_config.bmode = GPOINTER_TO_INT (data) - 1;
 
928
  config.bmode = GPOINTER_TO_INT (data) - 1;
857
929
}
858
930
 
859
931
static gboolean
860
 
dialog (void)
 
932
convolve_image_dialog (GimpDrawable *drawable)
861
933
{
862
 
  GtkWidget *dlg;
 
934
  GtkWidget *dialog;
 
935
  GtkWidget *main_vbox;
 
936
  GtkWidget *preview;
863
937
  GtkWidget *main_hbox;
864
938
  GtkWidget *table;
865
939
  GtkWidget *label;
872
946
  gint       x, y, i;
873
947
  GSList    *group;
874
948
 
875
 
  gimp_ui_init ("convmatrix", FALSE);
876
 
 
877
 
  dlg = gimp_dialog_new (_("Convolution Matrix"), "convmatrix",
878
 
                         NULL, 0,
879
 
                         gimp_standard_help_func, "plug-in-convmatrix",
880
 
 
881
 
                         GIMP_STOCK_RESET, RESPONSE_RESET,
882
 
                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
883
 
                         GTK_STOCK_OK,     GTK_RESPONSE_OK,
884
 
 
885
 
                         NULL);
886
 
 
887
 
  g_signal_connect (dlg, "response",
888
 
                    G_CALLBACK (response_callback),
889
 
                    NULL);
890
 
  g_signal_connect (dlg, "destroy",
891
 
                    G_CALLBACK (gtk_main_quit),
892
 
                    NULL);
 
949
  gimp_ui_init (PLUG_IN_BINARY, FALSE);
 
950
 
 
951
  dialog = gimp_dialog_new (_("Convolution Matrix"), PLUG_IN_BINARY,
 
952
                            NULL, 0,
 
953
                            gimp_standard_help_func, PLUG_IN_PROC,
 
954
 
 
955
                            GIMP_STOCK_RESET, RESPONSE_RESET,
 
956
                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 
957
                            GTK_STOCK_OK,     GTK_RESPONSE_OK,
 
958
 
 
959
                            NULL);
 
960
 
 
961
  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
 
962
                                           RESPONSE_RESET,
 
963
                                           GTK_RESPONSE_OK,
 
964
                                           GTK_RESPONSE_CANCEL,
 
965
                                           -1);
 
966
 
 
967
  gimp_window_set_transient (GTK_WINDOW (dialog));
 
968
 
 
969
  main_vbox = gtk_vbox_new (FALSE, 12);
 
970
  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
 
971
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox);
 
972
  gtk_widget_show (main_vbox);
 
973
 
 
974
  preview = gimp_drawable_preview_new (drawable, NULL);
 
975
  gtk_box_pack_start_defaults (GTK_BOX (main_vbox), preview);
 
976
  gtk_widget_show (preview);
 
977
  g_signal_connect_swapped (preview, "invalidated",
 
978
                            G_CALLBACK (convolve_image),
 
979
                            drawable);
893
980
 
894
981
  main_hbox = gtk_hbox_new (FALSE, 12);
895
 
  gtk_container_set_border_width (GTK_CONTAINER (main_hbox), 12);
896
 
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), main_hbox,
897
 
                      TRUE, TRUE, 0);
 
982
  gtk_box_pack_start (GTK_BOX (main_vbox), main_hbox, FALSE, FALSE, 0);
 
983
  gtk_widget_show (main_hbox),
898
984
 
899
985
  vbox = gtk_vbox_new (FALSE, 12);
900
986
  gtk_box_pack_start (GTK_BOX (main_hbox), vbox, TRUE, TRUE, 0);
905
991
  inbox = gtk_vbox_new (FALSE, 12);
906
992
  gtk_container_add (GTK_CONTAINER (frame), inbox);
907
993
 
908
 
  table = gtk_table_new (5, 5, FALSE);
 
994
  table = gtk_table_new (MATRIX_SIZE, MATRIX_SIZE, FALSE);
909
995
  gtk_table_set_row_spacings (GTK_TABLE (table), 4);
910
996
  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
911
997
  gtk_box_pack_start (GTK_BOX (inbox), table, TRUE, TRUE, 0);
912
998
 
913
 
  for (y = 0; y < 5; y++)
914
 
    for (x = 0; x < 5; x++)
 
999
  for (y = 0; y < MATRIX_SIZE; y++)
 
1000
    for (x = 0; x < MATRIX_SIZE; x++)
915
1001
      {
916
 
        my_widgets.matrix[x][y] = entry = gtk_entry_new ();
917
 
        gtk_widget_set_size_request (entry, 40, -1);
918
 
        gtk_table_attach (GTK_TABLE (table), entry, x, x+1, y, y+1,
919
 
                          GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
920
 
        gtk_widget_show (entry);
 
1002
        widget_set.matrix[x][y] = entry = gtk_entry_new ();
 
1003
        gtk_widget_set_size_request (entry, 40, -1);
 
1004
        gtk_table_attach (GTK_TABLE (table), entry, x, x+1, y, y+1,
 
1005
                          GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
 
1006
        gtk_widget_show (entry);
921
1007
 
922
 
        g_signal_connect (entry, "changed",
 
1008
        g_signal_connect (entry, "changed",
923
1009
                          G_CALLBACK (entry_callback),
924
 
                          &my_config.matrix[x][y]);
 
1010
                          &config.matrix[x][y]);
 
1011
        g_signal_connect_swapped (entry, "changed",
 
1012
                                  G_CALLBACK (gimp_preview_invalidate),
 
1013
                                  preview);
925
1014
      }
926
1015
 
927
1016
  gtk_widget_show (table);
929
1018
  box = gtk_hbox_new (FALSE, 6);
930
1019
  gtk_box_pack_start (GTK_BOX (inbox), box, FALSE, FALSE, 0);
931
1020
 
 
1021
 
932
1022
  table = gtk_table_new (1, 2, FALSE);
933
1023
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
934
1024
  gtk_box_pack_start (GTK_BOX (box), table, TRUE, FALSE, 0);
938
1028
  gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1);
939
1029
  gtk_widget_show (label);
940
1030
 
941
 
  my_widgets.divisor = entry = gtk_entry_new ();
 
1031
  widget_set.divisor = entry = gtk_entry_new ();
942
1032
  gtk_widget_set_size_request (entry, 40, -1);
943
1033
  gtk_table_attach_defaults (GTK_TABLE (table), entry, 1, 2, 0, 1);
944
1034
  gtk_widget_show (entry);
946
1036
 
947
1037
  g_signal_connect (entry, "changed",
948
1038
                    G_CALLBACK (entry_callback),
949
 
                    &my_config.divisor);
 
1039
                    &config.divisor);
 
1040
  g_signal_connect_swapped (entry, "changed",
 
1041
                            G_CALLBACK (gimp_preview_invalidate),
 
1042
                            preview);
950
1043
 
951
1044
  gtk_widget_show (table);
952
1045
 
 
1046
 
 
1047
 
953
1048
  table = gtk_table_new (1, 2, FALSE);
954
1049
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
955
1050
  gtk_box_pack_start (GTK_BOX (box), table, TRUE, FALSE, 0);
959
1054
  gtk_table_attach_defaults (GTK_TABLE (table), label, 0, 1, 0, 1);
960
1055
  gtk_widget_show (label);
961
1056
 
962
 
  my_widgets.offset = entry = gtk_entry_new ();
 
1057
  widget_set.offset = entry = gtk_entry_new ();
963
1058
  gtk_widget_set_size_request (entry, 40, -1);
964
1059
  gtk_table_attach_defaults (GTK_TABLE (table), entry, 1, 2, 0, 1);
965
1060
  gtk_widget_show (entry);
967
1062
 
968
1063
  g_signal_connect (entry, "changed",
969
1064
                    G_CALLBACK (entry_callback),
970
 
                    &my_config.offset);
 
1065
                    &config.offset);
 
1066
  g_signal_connect_swapped (entry, "changed",
 
1067
                            G_CALLBACK (gimp_preview_invalidate),
 
1068
                            preview);
971
1069
 
972
1070
  gtk_widget_show (table);
973
1071
 
979
1077
  box = gtk_vbox_new (FALSE, 6);
980
1078
  gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 0);
981
1079
 
982
 
  my_widgets.autoset = button =
983
 
    gtk_check_button_new_with_mnemonic (_("A_utomatic"));
 
1080
  widget_set.autoset = button =
 
1081
    gtk_check_button_new_with_mnemonic (_("N_ormalise"));
984
1082
  gtk_box_pack_start (GTK_BOX (box), button, TRUE, FALSE, 0);
985
1083
  gtk_widget_show (button);
986
1084
 
987
1085
  g_signal_connect (button, "toggled",
988
1086
                    G_CALLBACK (my_toggle_callback),
989
 
                    &my_config.autoset);
 
1087
                    &config.autoset);
 
1088
  g_signal_connect_swapped (button, "toggled",
 
1089
                            G_CALLBACK (gimp_preview_invalidate),
 
1090
                            preview);
990
1091
 
991
 
  my_widgets.alpha_alg = button =
 
1092
  widget_set.alpha_weighting = button =
992
1093
    gtk_check_button_new_with_mnemonic (_("A_lpha-weighting"));
993
 
  if (my_config.alpha_alg == -1)
 
1094
  if (config.alpha_weighting == -1)
994
1095
    gtk_widget_set_sensitive (button, FALSE);
995
1096
  gtk_box_pack_start (GTK_BOX (box), button, TRUE, FALSE, 0);
996
1097
  gtk_widget_show (button);
997
1098
 
998
1099
  g_signal_connect (button, "toggled",
999
1100
                    G_CALLBACK (my_toggle_callback),
1000
 
                    &my_config.alpha_alg);
 
1101
                    &config.alpha_weighting);
 
1102
  g_signal_connect_swapped (button, "toggled",
 
1103
                            G_CALLBACK (gimp_preview_invalidate),
 
1104
                            preview);
1001
1105
 
1002
1106
  gtk_widget_show (box);
1003
1107
  gtk_widget_show (vbox);
1013
1117
 
1014
1118
  group = NULL;
1015
1119
 
1016
 
  for (i = 0; i < 3; i++)
 
1120
  for (i = 0; i < BORDER_MODES; i++)
1017
1121
    {
1018
 
      my_widgets.bmode[i] = button =
1019
 
        gtk_radio_button_new_with_mnemonic (group, gettext (bmode_labels[i]));
 
1122
      widget_set.bmode[i] = button =
 
1123
        gtk_radio_button_new_with_mnemonic (group, gettext (bmode_labels[i]));
1020
1124
      group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
1021
1125
      gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
1022
1126
      gtk_widget_show (button);
1024
1128
      g_signal_connect (button, "toggled",
1025
1129
                        G_CALLBACK (my_bmode_callback),
1026
1130
                        GINT_TO_POINTER (i + 1));
 
1131
      g_signal_connect_swapped (button, "toggled",
 
1132
                                G_CALLBACK (gimp_preview_invalidate),
 
1133
                                preview);
1027
1134
    }
1028
1135
 
1029
1136
  gtk_widget_show (box);
1035
1142
  box = gtk_vbox_new (FALSE, 2);
1036
1143
  gtk_container_add (GTK_CONTAINER (frame), box);
1037
1144
 
1038
 
  for (i = 0; i < 5; i++)
 
1145
  for (i = 0; i < CHANNELS; i++)
1039
1146
    {
1040
 
      my_widgets.channels[i] = button =
1041
 
        gtk_check_button_new_with_mnemonic (gettext (channel_labels[i]));
1042
 
 
1043
 
      if (my_config.channels[i] < 0)
1044
 
        gtk_widget_set_sensitive (button, FALSE);
1045
 
 
1046
 
      gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
1047
 
      gtk_widget_show (button);
1048
 
 
1049
 
      g_signal_connect (button, "toggled",
1050
 
                        G_CALLBACK (my_toggle_callback),
1051
 
                        &my_config.channels[i]);
 
1147
      if ((gimp_drawable_is_gray (drawable->drawable_id) && i==0) ||
 
1148
          (gimp_drawable_is_rgb  (drawable->drawable_id) && i>=1 && i<=3) ||
 
1149
          (gimp_drawable_has_alpha (drawable->drawable_id) && i==4))
 
1150
        {
 
1151
          widget_set.channels[i] = button =
 
1152
            gtk_check_button_new_with_mnemonic (gettext (channel_labels[i]));
 
1153
 
 
1154
          gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
 
1155
          gtk_widget_show (button);
 
1156
 
 
1157
          g_signal_connect (button, "toggled",
 
1158
                            G_CALLBACK (my_toggle_callback),
 
1159
                            &config.channels[i]);
 
1160
          g_signal_connect_swapped (button, "toggled",
 
1161
                                    G_CALLBACK (gimp_preview_invalidate),
 
1162
                                    preview);
 
1163
        }
 
1164
      else
 
1165
        {
 
1166
          widget_set.channels[i] = NULL;
 
1167
        }
1052
1168
    }
1053
1169
 
1054
1170
  gtk_widget_show (box);
1056
1172
 
1057
1173
  gtk_widget_show (inbox);
1058
1174
 
1059
 
  gtk_widget_show (main_hbox);
 
1175
  g_signal_connect (dialog, "response",
 
1176
                    G_CALLBACK (response_callback),
 
1177
                    drawable);
 
1178
  g_signal_connect (dialog, "destroy",
 
1179
                    G_CALLBACK (gtk_main_quit),
 
1180
                    NULL);
1060
1181
 
1061
 
  gtk_widget_show (dlg);
 
1182
  gtk_widget_show (dialog);
1062
1183
  redraw_all ();
1063
1184
 
1064
 
  gtk_widget_set_sensitive (my_widgets.bmode[CLEAR],
1065
 
                            (my_config.alpha_alg > 0));
 
1185
  gtk_widget_set_sensitive (widget_set.bmode[CLEAR],
 
1186
                            (config.alpha_weighting > 0));
1066
1187
 
1067
1188
  gtk_main ();
1068
1189