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

« back to all changes in this revision

Viewing changes to plug-ins/common/sel_gauss.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:
4
4
 *
5
5
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
6
6
 * Copyright (C) 1999 Thom van Os <thom@vanos.com>
 
7
 * Copyright (C) 2006 Loren Merritt
7
8
 *
8
9
 * This program is free software; you can redistribute it and/or modify
9
10
 * it under the terms of the GNU General Public License as published by
30
31
 
31
32
#include "config.h"
32
33
 
33
 
#include <gtk/gtk.h>
34
 
 
35
34
#include <libgimp/gimp.h>
36
35
#include <libgimp/gimpui.h>
37
36
 
38
37
#include "libgimp/stdplugins-intl.h"
39
38
 
40
39
 
 
40
#define PLUG_IN_PROC   "plug-in-sel-gauss"
 
41
#define PLUG_IN_BINARY "sel_gauss"
 
42
 
 
43
#ifndef ALWAYS_INLINE
 
44
#if defined(__GNUC__) && (__GNUC__ > 3 || __GNUC__ == 3 && __GNUC_MINOR__ > 0)
 
45
#    define ALWAYS_INLINE __attribute__((always_inline)) inline
 
46
#else
 
47
#    define ALWAYS_INLINE inline
 
48
#endif
 
49
#endif
 
50
 
 
51
 
41
52
typedef struct
42
53
{
43
54
  gdouble  radius;
62
73
static void      preview_update   (GimpPreview      *preview);
63
74
 
64
75
 
65
 
GimpPlugInInfo PLUG_IN_INFO =
 
76
const GimpPlugInInfo PLUG_IN_INFO =
66
77
{
67
78
  NULL,  /* init_proc  */
68
79
  NULL,  /* quit_proc  */
82
93
static void
83
94
query (void)
84
95
{
85
 
  static GimpParamDef args[] =
 
96
  static const GimpParamDef args[] =
86
97
  {
87
 
    { GIMP_PDB_INT32,    "run_mode", "Interactive, non-interactive" },
88
 
    { GIMP_PDB_IMAGE,    "image",    "Input image (unused)" },
89
 
    { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
90
 
    { GIMP_PDB_FLOAT,    "radius",   "Radius of gaussian blur (in pixels, > 0.0)" },
91
 
    { GIMP_PDB_INT32,    "maxdelta", "Maximum delta" }
 
98
    { GIMP_PDB_INT32,    "run-mode",  "Interactive, non-interactive" },
 
99
    { GIMP_PDB_IMAGE,    "image",     "Input image (unused)"         },
 
100
    { GIMP_PDB_DRAWABLE, "drawable",  "Input drawable"               },
 
101
    { GIMP_PDB_FLOAT,    "radius",    "Radius of gaussian blur (in pixels, > 0.0)" },
 
102
    { GIMP_PDB_INT32,    "max-delta", "Maximum delta"                }
92
103
  };
93
104
 
94
 
  gimp_install_procedure ("plug_in_sel_gauss",
95
 
                          "Applies a selective gaussian blur to the "
96
 
                          "specified drawable.",
 
105
  gimp_install_procedure (PLUG_IN_PROC,
 
106
                          N_("Blur neighboring pixels, but only in low-contrast areas"),
97
107
                          "This filter functions similar to the regular "
98
108
                          "gaussian blur filter except that neighbouring "
99
109
                          "pixels that differ more than the given maxdelta "
110
120
                          G_N_ELEMENTS (args), 0,
111
121
                          args, NULL);
112
122
 
113
 
  gimp_plugin_menu_register ("plug_in_sel_gauss", "<Image>/Filters/Blur");
 
123
  gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/Filters/Blur");
114
124
}
115
125
 
116
126
static void
144
154
    {
145
155
    case GIMP_RUN_INTERACTIVE:
146
156
      /* Possibly retrieve data */
147
 
      gimp_get_data ("plug_in_sel_gauss", &bvals);
 
157
      gimp_get_data (PLUG_IN_PROC, &bvals);
148
158
 
149
159
      /* First acquire information with a dialog */
150
160
      if (! sel_gauss_dialog (drawable))
167
177
 
168
178
    case GIMP_RUN_WITH_LAST_VALS:
169
179
      /* Possibly retrieve data */
170
 
      gimp_get_data ("plug_in_sel_gauss", &bvals);
 
180
      gimp_get_data (PLUG_IN_PROC, &bvals);
171
181
      break;
172
182
 
173
183
    default:
184
194
  if (gimp_drawable_is_rgb (drawable->drawable_id) ||
185
195
      gimp_drawable_is_gray (drawable->drawable_id))
186
196
    {
187
 
      gimp_progress_init (_("Selective Gaussian Blur..."));
 
197
      gimp_progress_init (_("Selective Gaussian Blur"));
188
198
 
189
199
      radius = fabs (bvals.radius) + 1.0;
190
200
 
193
203
 
194
204
      /* Store data */
195
205
      if (run_mode == GIMP_RUN_INTERACTIVE)
196
 
        gimp_set_data ("plug_in_sel_gauss",
197
 
                       &bvals, sizeof (BlurValues));
 
206
        gimp_set_data (PLUG_IN_PROC, &bvals, sizeof (BlurValues));
198
207
 
199
208
      if (run_mode != GIMP_RUN_NONINTERACTIVE)
200
209
        gimp_displays_flush ();
220
229
  GtkObject *adj;
221
230
  gboolean   run;
222
231
 
223
 
  gimp_ui_init ("sel_gauss", FALSE);
 
232
  gimp_ui_init (PLUG_IN_BINARY, FALSE);
224
233
 
225
 
  dialog = gimp_dialog_new (_("Selective Gaussian Blur"), "sel_gauss",
 
234
  dialog = gimp_dialog_new (_("Selective Gaussian Blur"), PLUG_IN_BINARY,
226
235
                            NULL, 0,
227
 
                            gimp_standard_help_func, "plug-in-sel-gauss",
 
236
                            gimp_standard_help_func, PLUG_IN_PROC,
228
237
 
229
238
                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
230
239
                            GTK_STOCK_OK,     GTK_RESPONSE_OK,
231
240
 
232
241
                            NULL);
233
242
 
 
243
  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
 
244
                                           GTK_RESPONSE_OK,
 
245
                                           GTK_RESPONSE_CANCEL,
 
246
                                           -1);
 
247
 
 
248
  gimp_window_set_transient (GTK_WINDOW (dialog));
 
249
 
234
250
  main_vbox = gtk_vbox_new (FALSE, 12);
235
251
  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
236
252
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox);
256
272
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
257
273
                             _("_Blur radius:"), 0.0, 0.5,
258
274
                             spinbutton, 1, TRUE);
259
 
  g_signal_connect (adj, "value_changed",
 
275
  g_signal_connect (adj, "value-changed",
260
276
                    G_CALLBACK (gimp_double_adjustment_update),
261
277
                    &bvals.radius);
262
 
  g_signal_connect_swapped (spinbutton, "value_changed",
 
278
  g_signal_connect_swapped (spinbutton, "value-changed",
263
279
                            G_CALLBACK (gimp_preview_invalidate),
264
280
                            preview);
265
281
 
268
284
                              bvals.maxdelta, 0, 255, 1, 8, 0,
269
285
                              TRUE, 0, 0,
270
286
                              NULL, NULL);
271
 
  g_signal_connect (adj, "value_changed",
 
287
  g_signal_connect (adj, "value-changed",
272
288
                    G_CALLBACK (gimp_int_adjustment_update),
273
289
                    &bvals.maxdelta);
274
 
  g_signal_connect_swapped (adj, "value_changed",
 
290
  g_signal_connect_swapped (adj, "value-changed",
275
291
                            G_CALLBACK (gimp_preview_invalidate),
276
292
                            preview);
277
293
 
285
301
}
286
302
 
287
303
static void
288
 
init_matrix (gdouble   radius,
289
 
             gdouble **mat,
290
 
             gint      num)
 
304
init_matrix (gdouble  radius,
 
305
             gdouble *mat,
 
306
             gint     num)
291
307
{
292
 
  gint    dx, dy;
 
308
  gint    dx;
293
309
  gdouble sd, c1, c2;
294
310
 
295
311
  /* This formula isn't really correct, but it'll do */
297
313
  c1 = 1.0 / sqrt (2.0 * G_PI * sd);
298
314
  c2 = -2.0 * (sd * sd);
299
315
 
300
 
  for (dy = 0; dy < num; dy++)
301
 
    {
302
 
      for (dx = dy; dx < num; dx++)
303
 
        {
304
 
          mat[dx][dy] = c1 * exp ((dx * dx + dy * dy)/ c2);
305
 
          mat[dy][dx] = mat[dx][dy];
306
 
        }
307
 
    }
 
316
  for (dx = 0; dx < num; dx++)
 
317
    mat[dx] = c1 * exp ((dx * dx)/ c2);
308
318
}
309
319
 
310
 
static void
311
 
matrixmult (guchar   *src,
312
 
            guchar   *dest,
313
 
            gint      width,
314
 
            gint      height,
315
 
            gdouble **mat,
316
 
            gint      numrad,
317
 
            gint      bytes,
318
 
            gboolean  has_alpha,
319
 
            gint      maxdelta,
320
 
            gboolean  preview_mode)
 
320
 
 
321
#if defined(ARCH_X86) && defined(USE_MMX) && defined(__GNUC__)
 
322
#define HAVE_ACCEL 1
 
323
 
 
324
static ALWAYS_INLINE void
 
325
matrixmult_mmx (const guchar  *src,
 
326
                guchar        *dest,
 
327
                gint           width,
 
328
                gint           height,
 
329
                const gdouble *mat,
 
330
                gint           numrad,
 
331
                gint           bytes,
 
332
                gboolean       has_alpha,
 
333
                gint           maxdelta,
 
334
                gboolean       preview_mode)
321
335
{
322
 
  gint     i, j, b, nb, x, y;
323
 
  gint     six, dix, tmp;
324
 
  gint     rowstride;
325
 
  gdouble  sum, fact, d, alpha = 1.0;
326
 
  guchar  *src_b, *src_db;
327
 
  gdouble *m;
328
 
  gint     offset;
329
 
 
330
 
  nb = bytes - (has_alpha ? 1 : 0);
331
 
  rowstride = width * bytes;
 
336
  const gint       rowstride = width * bytes;
 
337
  const long long  maxdelta4 = maxdelta * 0x0001000100010001ULL;
 
338
  gushort         *imat;
 
339
  gdouble          fsum, fscale;
 
340
  gint             i, j, x, y, d;
 
341
 
 
342
  g_assert (has_alpha ? (bytes == 4) : (bytes == 3 || bytes == 1));
 
343
 
 
344
  imat = g_new (gushort, 2 * numrad + 3);
 
345
 
 
346
  fsum = 0.0;
 
347
  for (y = 1 - numrad; y < numrad; y++)
 
348
    fsum += mat[ABS(y)];
 
349
 
 
350
  /* Ensure that one pixel's product fits in 16bits,
 
351
   * and that the sum fits in 32bits.
 
352
   */
 
353
  fscale = MIN (0x100 / mat[0], 0x1000 / fsum);
 
354
  for (y = 0; y < numrad; y++)
 
355
    imat[numrad - y] = imat[numrad + y] = mat[y] * fscale;
 
356
 
 
357
  for (y = numrad; y < numrad + 3; y++)
 
358
    imat[numrad + y] = 0;
332
359
 
333
360
  for (y = 0; y < height; y++)
334
361
    {
 
362
      asm volatile (
 
363
        "pxor  %%mm7, %%mm7 \n\t":
 
364
      );
 
365
 
335
366
      for (x = 0; x < width; x++)
336
367
        {
 
368
          guint r, g, b, fr, fg, fb;
 
369
          gint  offset;
 
370
          gint  dix;
 
371
 
 
372
          r = g = b = fr = fg = fb = 0;
 
373
 
337
374
          dix = bytes * (width * y + x);
 
375
 
 
376
          if (has_alpha)
 
377
            {
 
378
              *(guint*) &dest[dix] = *(guint*) &src[dix];
 
379
 
 
380
              if (!src[dix + 3])
 
381
                continue;
 
382
            }
 
383
 
 
384
          asm volatile (
 
385
            "movd         %0, %%mm6 \n\t"
 
386
            "punpcklbw %%mm7, %%mm6 \n\t" /* center pixel */
 
387
            :: "m"(src[dix])
 
388
          );
 
389
 
 
390
          offset = rowstride * (y - numrad) + bytes * (x - numrad);
 
391
 
 
392
          if (bytes == 1)
 
393
            {
 
394
              asm volatile (
 
395
                "pshufw $0, %%mm6, %%mm6 \n\t": /* center pixel x4 */
 
396
              );
 
397
              for (j = 1 - numrad; j < numrad; j++)
 
398
                {
 
399
                  const guchar *src_b;
 
400
                  guint         rowsum  = 0;
 
401
                  guint         rowfact = 0;
 
402
 
 
403
                  offset += rowstride;
 
404
 
 
405
                  if (y + j < 0 || y + j >= height)
 
406
                    continue;
 
407
 
 
408
                  src_b = src + offset - 3;
 
409
 
 
410
                  asm volatile (
 
411
                    "pxor  %%mm5, %%mm5 \n\t" /* row fact */
 
412
                    "pxor  %%mm4, %%mm4 \n\t" /* row sum  */
 
413
                    :
 
414
                  );
 
415
 
 
416
                  for (i = 1 - numrad; i < numrad; i += 4)
 
417
                    {
 
418
                      src_b += 4;
 
419
                      if (x + i < 0 || x + i >= width)
 
420
                        continue;
 
421
 
 
422
                      asm volatile (
 
423
                        "movd         %0, %%mm0 \n\t"
 
424
                        "movq      %%mm6, %%mm1 \n\t"
 
425
                        "punpcklbw %%mm7, %%mm0 \n\t" /* one pixel      */
 
426
                        "psubusw   %%mm0, %%mm1 \n\t" /* diff           */
 
427
                        "movq      %%mm0, %%mm2 \n\t"
 
428
                        "psubusw   %%mm6, %%mm2 \n\t"
 
429
                        "por       %%mm2, %%mm1 \n\t" /* abs diff       */
 
430
                        "pcmpgtw      %1, %%mm1 \n\t" /* threshold      */
 
431
                        "pandn        %2, %%mm1 \n\t" /* weight         */
 
432
                        "pmullw    %%mm1, %%mm0 \n\t" /* pixel * weight */
 
433
                        "paddusw   %%mm1, %%mm5 \n\t" /* fact           */
 
434
                        "movq      %%mm0, %%mm2 \n\t"
 
435
                        "punpcklwd %%mm7, %%mm0 \n\t"
 
436
                        "punpckhwd %%mm7, %%mm2 \n\t"
 
437
                        "paddd     %%mm0, %%mm4 \n\t"
 
438
                        "paddd     %%mm2, %%mm4 \n\t" /* sum            */
 
439
                        :: "m"(*src_b), "m"(maxdelta4), "m"(imat[numrad + i])
 
440
                      );
 
441
                    }
 
442
 
 
443
                  asm volatile (
 
444
                    "pshufw $0xb1, %%mm5, %%mm3 \n\t"
 
445
                    "paddusw       %%mm3, %%mm5 \n\t"
 
446
                    "pshufw $0x0e, %%mm4, %%mm2 \n\t"
 
447
                    "pshufw $0x0e, %%mm5, %%mm3 \n\t"
 
448
                    "paddd         %%mm2, %%mm4 \n\t"
 
449
                    "paddusw       %%mm3, %%mm5 \n\t"
 
450
                    "movd          %%mm4, %0    \n\t"
 
451
                    "movd          %%mm5, %1    \n\t"
 
452
                    :"=g"(rowsum), "=g"(rowfact)
 
453
                  );
 
454
                  d = imat[numrad + j];
 
455
                  r += d * rowsum;
 
456
                  fr += d * (gushort) rowfact;
 
457
                }
 
458
 
 
459
              dest[dix] = r / fr;
 
460
            }
 
461
          else
 
462
            {
 
463
              for (j = 1 - numrad; j < numrad; j++)
 
464
                {
 
465
                  const guchar *src_b;
 
466
                  gushort       rf[4];
 
467
                  guint         rr, rg, rb;
 
468
 
 
469
                  offset += rowstride;
 
470
                  if (y + j < 0 || y + j >= height)
 
471
                    continue;
 
472
 
 
473
                  src_b = src + offset;
 
474
 
 
475
                  asm volatile (
 
476
                    "pxor  %%mm5, %%mm5 \n\t" /* row fact   */
 
477
                    "pxor  %%mm4, %%mm4 \n\t" /* row sum RG */
 
478
                    "pxor  %%mm3, %%mm3 \n\t" /* row sum B  */
 
479
                    :
 
480
                  );
 
481
 
 
482
                  for (i = 1 - numrad; i < numrad; i++)
 
483
                    {
 
484
                      src_b += bytes;
 
485
                      if (x + i < 0 || x + i >= width)
 
486
                        continue;
 
487
 
 
488
                      if (has_alpha)
 
489
                        asm volatile (
 
490
                          "movd         %0, %%mm0 \n\t"
 
491
                          "movq      %%mm6, %%mm1 \n\t"
 
492
                          "punpcklbw %%mm7, %%mm0 \n\t" /* one pixel       */
 
493
                          "psubusw   %%mm0, %%mm1 \n\t" /* diff            */
 
494
                          "movq      %%mm0, %%mm2 \n\t"
 
495
                          "psubusw   %%mm6, %%mm2 \n\t"
 
496
                          "por       %%mm2, %%mm1 \n\t" /* abs diff        */
 
497
                          "pcmpgtw      %1, %%mm1 \n\t" /* threshold       */
 
498
                          "pshufw   $0, %2, %%mm2 \n\t" /* weight          */
 
499
                          "pandn     %%mm2, %%mm1 \n\t"
 
500
                          "pshufw $0xff, %%mm0, %%mm2 \n\t" /* alpha       */
 
501
                          "psllw        $8, %%mm2 \n\t"
 
502
                          "pmulhuw   %%mm2, %%mm1 \n\t" /* weight *= alpha */
 
503
                          "pmullw    %%mm1, %%mm0 \n\t" /* pixel * weight  */
 
504
                          "paddusw   %%mm1, %%mm5 \n\t" /* fact            */
 
505
                          "movq      %%mm0, %%mm2 \n\t"
 
506
                          "punpcklwd %%mm7, %%mm0 \n\t" /* RG              */
 
507
                          "punpckhwd %%mm7, %%mm2 \n\t" /* B               */
 
508
                          "paddd     %%mm0, %%mm4 \n\t"
 
509
                          "paddd     %%mm2, %%mm3 \n\t"
 
510
                          :: "m"(*src_b), "m"(maxdelta4), "m"(imat[numrad + i])
 
511
                        );
 
512
                      else
 
513
                        asm volatile (
 
514
                          "movd         %0, %%mm0 \n\t"
 
515
                          "movq      %%mm6, %%mm1 \n\t"
 
516
                          "punpcklbw %%mm7, %%mm0 \n\t" /* one pixel       */
 
517
                          "psubusw   %%mm0, %%mm1 \n\t" /* diff            */
 
518
                          "movq      %%mm0, %%mm2 \n\t"
 
519
                          "psubusw   %%mm6, %%mm2 \n\t"
 
520
                          "por       %%mm2, %%mm1 \n\t" /* abs diff        */
 
521
                          "pcmpgtw      %1, %%mm1 \n\t" /* threshold       */
 
522
                          "pshufw   $0, %2, %%mm2 \n\t" /* weight          */
 
523
                          "pandn     %%mm2, %%mm1 \n\t"
 
524
                          "pmullw    %%mm1, %%mm0 \n\t" /* pixel * weight  */
 
525
                          "paddusw   %%mm1, %%mm5 \n\t" /* fact            */
 
526
                          "movq      %%mm0, %%mm2 \n\t"
 
527
                          "punpcklwd %%mm7, %%mm0 \n\t" /* RG              */
 
528
                          "punpckhwd %%mm7, %%mm2 \n\t" /* B               */
 
529
                          "paddd     %%mm0, %%mm4 \n\t"
 
530
                          "paddd     %%mm2, %%mm3 \n\t"
 
531
                          :: "m"(*src_b), "m"(maxdelta4), "m"(imat[numrad + i])
 
532
                        );
 
533
                    }
 
534
 
 
535
                  asm volatile (
 
536
                    "movd    %%mm4, %0 \n\t"
 
537
                    "movd    %%mm3, %2 \n\t"
 
538
                    "psrlq  $32, %%mm4 \n\t"
 
539
                    "movq    %%mm5, %3 \n\t"
 
540
                    "movd    %%mm4, %1 \n\t"
 
541
                    :"=g"(rr), "=g"(rg), "=g"(rb), "=m"(*rf)
 
542
                    ::"memory"
 
543
                  );
 
544
                  d = imat[numrad + j];
 
545
                  r += d * rr;
 
546
                  g += d * rg;
 
547
                  b += d * rb;
 
548
                  fr += d * rf[0];
 
549
                  fg += d * rf[1];
 
550
                  fb += d * rf[2];
 
551
                }
 
552
 
 
553
              if (has_alpha)
 
554
                {
 
555
                  if (fr)
 
556
                    dest[dix+0] = r / fr;
 
557
                  if (fg)
 
558
                    dest[dix+1] = g / fg;
 
559
                  if (fb)
 
560
                    dest[dix+2] = b / fb;
 
561
                }
 
562
              else
 
563
                {
 
564
                  dest[dix+0] = r / fr;
 
565
                  dest[dix+1] = g / fg;
 
566
                  dest[dix+2] = b / fb;
 
567
                }
 
568
            }
 
569
        }
 
570
 
 
571
      if (!(y % 10) && !preview_mode)
 
572
        {
 
573
          asm volatile ("emms");
 
574
          gimp_progress_update ((double)y / (double)height);
 
575
        }
 
576
    }
 
577
 
 
578
  asm volatile ("emms");
 
579
 
 
580
  g_free (imat);
 
581
}
 
582
#endif /* ARCH_X86 && USE_MMX && __GNUC__ */
 
583
 
 
584
 
 
585
static ALWAYS_INLINE void
 
586
matrixmult_int (const guchar  *src,
 
587
                guchar        *dest,
 
588
                gint           width,
 
589
                gint           height,
 
590
                const gdouble *mat,
 
591
                gint           numrad,
 
592
                gint           bytes,
 
593
                gboolean       has_alpha,
 
594
                gint           maxdelta,
 
595
                gboolean       preview_mode)
 
596
{
 
597
  const gint  nb        = bytes - (has_alpha ? 1 : 0);
 
598
  const gint  rowstride = width * bytes;
 
599
  gushort    *imat;
 
600
  gdouble     fsum, fscale;
 
601
  gint        i, j, b, x, y, d;
 
602
 
 
603
#ifdef HAVE_ACCEL
 
604
  GimpCpuAccelFlags cpu = gimp_cpu_accel_get_support ();
 
605
 
 
606
  if ((has_alpha ? (bytes == 4) : (bytes == 3 || bytes == 1))
 
607
      && (cpu & (GIMP_CPU_ACCEL_X86_MMXEXT | GIMP_CPU_ACCEL_X86_SSE)))
 
608
    return matrixmult_mmx (src, dest, width, height, mat, numrad,
 
609
                           bytes, has_alpha, maxdelta, preview_mode);
 
610
#endif
 
611
 
 
612
  imat = g_new (gushort, 2 * numrad);
 
613
 
 
614
  fsum = 0.0;
 
615
  for (y = 1 - numrad; y < numrad; y++)
 
616
    fsum += mat[ABS(y)];
 
617
 
 
618
  /* Ensure that the sum fits in 32bits. */
 
619
  fscale = 0x1000 / fsum;
 
620
  for (y = 0; y < numrad; y++)
 
621
    imat[numrad - y] = imat[numrad + y] = mat[y] * fscale;
 
622
 
 
623
  for (y = 0; y < height; y++)
 
624
    {
 
625
      for (x = 0; x < width; x++)
 
626
        {
 
627
          gint dix = bytes * (width * y + x);
 
628
 
338
629
          if (has_alpha)
339
630
            dest[dix + nb] = src[dix + nb];
340
631
 
341
632
          for (b = 0; b < nb; b++)
342
633
            {
343
 
              sum = 0.0;
344
 
              fact = 0.0;
345
 
              src_db = src + dix + b;
 
634
              const guchar *src_db = src + dix + b;
 
635
              guint         sum    = 0;
 
636
              guint         fact   = 0;
 
637
              gint          offset;
346
638
 
347
639
              offset = rowstride * (y - numrad) + bytes * (x - numrad);
348
640
 
349
 
              for (i = 1 - numrad; i < numrad; i++)
 
641
              for (j = 1 - numrad; j < numrad; j++)
350
642
                {
351
 
                  offset += bytes;
352
 
                  if (x + i < 0 || x + i >= width)
 
643
                  const guchar *src_b;
 
644
                  guint         rowsum  = 0;
 
645
                  guint         rowfact = 0;
 
646
 
 
647
                  offset += rowstride;
 
648
                  if (y + j < 0 || y + j >= height)
353
649
                    continue;
354
650
 
355
 
                  six = offset;
356
 
                  m = mat[ABS(i)];
357
 
 
358
 
                  src_b = src + six + b;
359
 
 
360
 
                  for (j = 1 - numrad; j < numrad; j++)
 
651
                  src_b = src + offset + b;
 
652
 
 
653
                  for (i = 1 - numrad; i < numrad; i++)
361
654
                    {
362
 
                      src_b += rowstride;
363
 
                      six += rowstride;
364
 
 
365
 
                      if (y + j < 0 || y + j >= height)
 
655
                      gint tmp;
 
656
 
 
657
                      src_b += bytes;
 
658
 
 
659
                      if (x + i < 0 || x + i >= width)
366
660
                        continue;
367
661
 
368
662
                      tmp = *src_db - *src_b;
369
663
                      if (tmp > maxdelta || tmp < -maxdelta)
370
664
                        continue;
371
665
 
372
 
                      d = m[ABS(j)];
 
666
                      d = imat[numrad+i];
373
667
                      if (has_alpha)
374
 
                        {
375
 
                          if (!src[six + nb])
376
 
                            continue;
377
 
                          alpha = (double) src[six + nb] / 255.0;
378
 
                          d *= alpha;
379
 
                        }
380
 
                      sum += d * *src_b;
381
 
                      fact += d;
382
 
                    }
 
668
                        d *= src_b[nb - b];
 
669
 
 
670
                      rowsum += d * *src_b;
 
671
                      rowfact += d;
 
672
                    }
 
673
 
 
674
                  d = imat[numrad+j];
 
675
 
 
676
                  if (has_alpha)
 
677
                    {
 
678
                      rowsum >>= 8;
 
679
                      rowfact >>= 8;
 
680
                    }
 
681
 
 
682
                  sum += d * rowsum;
 
683
                  fact += d * rowfact;
383
684
                }
384
 
              if (fact == 0.0)
 
685
 
 
686
              if (fact == 0)
385
687
                dest[dix + b] = *src_db;
386
688
              else
387
689
                dest[dix + b] = sum / fact;
389
691
        }
390
692
 
391
693
      if (!(y % 10) && !preview_mode)
392
 
        gimp_progress_update ((double)y / (double)height);
393
 
    }
 
694
        gimp_progress_update ((gdouble) y / (gdouble) height);
 
695
    }
 
696
 
 
697
  g_free (imat);
 
698
}
 
699
 
 
700
/* Force compilation of several versions with inlined constants. */
 
701
static void
 
702
matrixmult (const guchar  *src,
 
703
            guchar        *dest,
 
704
            gint           width,
 
705
            gint           height,
 
706
            const gdouble *mat,
 
707
            gint           numrad,
 
708
            gint           bytes,
 
709
            gboolean       has_alpha,
 
710
            gint           maxdelta,
 
711
            gboolean       preview_mode)
 
712
{
 
713
  has_alpha = has_alpha ? 1 : 0;
 
714
 
 
715
#define EXPAND(BYTES, ALPHA)\
 
716
  if (bytes == BYTES && has_alpha == ALPHA)\
 
717
    {\
 
718
      matrixmult_int (src, dest, width, height, mat, numrad,\
 
719
                      BYTES, ALPHA, maxdelta, preview_mode);\
 
720
      return;\
 
721
    }
 
722
 
 
723
  EXPAND (1, 0)
 
724
  EXPAND (2, 1)
 
725
  EXPAND (3, 0)
 
726
  EXPAND (4, 1)
 
727
  EXPAND (bytes, has_alpha)
 
728
#undef EXPAND
394
729
}
395
730
 
396
731
static void
405
740
  guchar      *dest;
406
741
  guchar      *src;
407
742
  gint         x1, y1, x2, y2;
408
 
  gint         i;
409
 
  gdouble    **mat;
 
743
  gdouble     *mat;
410
744
  gint         numrad;
411
745
 
412
746
  gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);
417
751
  has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);
418
752
 
419
753
  numrad = (gint) (radius + 1.0);
420
 
  mat = g_new (gdouble *, numrad);
421
 
  for (i = 0; i < numrad; i++)
422
 
    mat[i] = g_new (gdouble, numrad);
 
754
  mat = g_new (gdouble, numrad);
423
755
  init_matrix(radius, mat, numrad);
424
756
 
425
757
  src  = g_new (guchar, width * height * bytes);
444
776
  /* free up buffers */
445
777
  g_free (src);
446
778
  g_free (dest);
447
 
  for (i = 0; i < numrad; i++)
448
 
    g_free (mat[i]);
449
779
  g_free (mat);
450
780
}
451
781
 
462
792
  GimpPixelRgn   srcPR;           /* Pixel region */
463
793
  guchar        *src;
464
794
  gboolean       has_alpha;
465
 
  gint           numrad, i;
466
 
  gdouble      **mat;
 
795
  gint           numrad;
 
796
  gdouble       *mat;
467
797
  gdouble       radius;
468
798
 
469
799
  /* Get drawable info */
492
822
  radius = fabs (bvals.radius) + 1.0;
493
823
  numrad = (gint) (radius + 1.0);
494
824
 
495
 
  mat = g_new (gdouble *, numrad);
496
 
  for (i = 0; i < numrad; i++)
497
 
    mat[i] = g_new (gdouble, numrad);
498
 
 
499
 
  init_matrix(radius, mat, numrad);
 
825
  mat = g_new (gdouble, numrad);
 
826
  init_matrix (radius, mat, numrad);
500
827
 
501
828
  matrixmult (src, render_buffer,
502
829
              width, height,
503
830
              mat, numrad,
504
831
              bytes, has_alpha, bvals.maxdelta, TRUE);
505
832
 
506
 
  for (i = 0; i < numrad; i++)
507
 
    g_free (mat[i]);
508
833
  g_free (mat);
509
834
  g_free (src);
510
835