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

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2008-10-06 13:30:41 UTC
  • mto: This revision was merged to the branch mainline in revision 35.
  • Revision ID: james.westby@ubuntu.com-20081006133041-3panbkcanaymfsmp
Tags: upstream-2.6.0
ImportĀ upstreamĀ versionĀ 2.6.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* scatter_hsv.c -- This is a plug-in for GIMP (1.0's API)
2
 
 * Author: Shuji Narazaki <narazaki@InetQ.or.jp>
3
 
 * Time-stamp: <2000-01-08 02:49:39 yasuhiro>
4
 
 * Version: 0.42
5
 
 *
6
 
 * Copyright (C) 1997 Shuji Narazaki <narazaki@InetQ.or.jp>
7
 
 *
8
 
 * This program is free software; you can redistribute it and/or modify
9
 
 * it under the terms of the GNU General Public License as published by
10
 
 * the Free Software Foundation; either version 2 of the License, or
11
 
 * (at your option) any later version.
12
 
 *
13
 
 * This program is distributed in the hope that it will be useful,
14
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
 * GNU General Public License for more details.
17
 
 *
18
 
 * You should have received a copy of the GNU General Public License
19
 
 * along with this program; if not, write to the Free Software
20
 
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
 
 */
22
 
 
23
 
#include "config.h"
24
 
 
25
 
#include <stdlib.h>
26
 
 
27
 
#include <libgimp/gimp.h>
28
 
#include <libgimp/gimpui.h>
29
 
 
30
 
#include "libgimp/stdplugins-intl.h"
31
 
 
32
 
 
33
 
#define HSV_NOISE_PROC   "plug-in-hsv-noise"
34
 
#define SCATTER_HSV_PROC "plug-in-scatter-hsv"
35
 
#define PLUG_IN_BINARY   "scatter_hsv"
36
 
#define SCALE_WIDTH      100
37
 
#define ENTRY_WIDTH        3
38
 
 
39
 
 
40
 
static void     query               (void);
41
 
static void     run                 (const gchar      *name,
42
 
                                     gint              nparams,
43
 
                                     const GimpParam  *param,
44
 
                                     gint             *nreturn_vals,
45
 
                                     GimpParam       **return_vals);
46
 
 
47
 
static void     scatter_hsv         (GimpDrawable     *drawable);
48
 
static gboolean scatter_hsv_dialog  (GimpDrawable     *drawable);
49
 
static void     scatter_hsv_preview (GimpPreview      *preview);
50
 
 
51
 
static void     scatter_hsv_scatter (guchar           *r,
52
 
                                     guchar           *g,
53
 
                                     guchar           *b);
54
 
 
55
 
static gint     randomize_value     (gint              now,
56
 
                                     gint              min,
57
 
                                     gint              max,
58
 
                                     gboolean          wraps_around,
59
 
                                     gint              rand_max);
60
 
 
61
 
 
62
 
const GimpPlugInInfo PLUG_IN_INFO =
63
 
{
64
 
  NULL,  /* init_proc  */
65
 
  NULL,  /* quit_proc  */
66
 
  query, /* query_proc */
67
 
  run,   /* run_proc   */
68
 
};
69
 
 
70
 
typedef struct
71
 
{
72
 
  gint     holdness;
73
 
  gint     hue_distance;
74
 
  gint     saturation_distance;
75
 
  gint     value_distance;
76
 
} ValueType;
77
 
 
78
 
static ValueType VALS =
79
 
{
80
 
  2,
81
 
  3,
82
 
  10,
83
 
  10
84
 
};
85
 
 
86
 
MAIN ()
87
 
 
88
 
static void
89
 
query (void)
90
 
{
91
 
  static const GimpParamDef args [] =
92
 
  {
93
 
    { GIMP_PDB_INT32,    "run-mode",            "Interactive, non-interactive" },
94
 
    { GIMP_PDB_IMAGE,    "image",               "Input image (not used)" },
95
 
    { GIMP_PDB_DRAWABLE, "drawable",            "Input drawable" },
96
 
    { GIMP_PDB_INT32,    "holdness",            "convolution strength" },
97
 
    { GIMP_PDB_INT32,    "hue-distance",        "scattering of hue angle [0,180]" },
98
 
    { GIMP_PDB_INT32,    "saturation-distance", "distribution distance on saturation axis [0,255]" },
99
 
    { GIMP_PDB_INT32,    "value-distance",      "distribution distance on value axis [0,255]" }
100
 
  };
101
 
 
102
 
  gimp_install_procedure (HSV_NOISE_PROC,
103
 
                          N_("Randomize hue/saturation/value independently"),
104
 
                          "Scattering pixel values in HSV space",
105
 
                          "Shuji Narazaki (narazaki@InetQ.or.jp)",
106
 
                          "Shuji Narazaki",
107
 
                          "1997",
108
 
                          N_("HSV Noise..."),
109
 
                          "RGB*",
110
 
                          GIMP_PLUGIN,
111
 
                          G_N_ELEMENTS (args), 0,
112
 
                          args, NULL);
113
 
 
114
 
  gimp_plugin_menu_register (HSV_NOISE_PROC, "<Image>/Filters/Noise");
115
 
 
116
 
  gimp_install_procedure (SCATTER_HSV_PROC,
117
 
                          "Scattering pixel values in HSV space",
118
 
                          "Scattering pixel values in HSV space",
119
 
                          "Shuji Narazaki (narazaki@InetQ.or.jp)",
120
 
                          "Shuji Narazaki",
121
 
                          "1997",
122
 
                          NULL,
123
 
                          "RGB*",
124
 
                          GIMP_PLUGIN,
125
 
                          G_N_ELEMENTS (args), 0,
126
 
                          args, NULL);
127
 
}
128
 
 
129
 
static void
130
 
run (const gchar      *name,
131
 
     gint              nparams,
132
 
     const GimpParam  *param,
133
 
     gint             *nreturn_vals,
134
 
     GimpParam       **return_vals)
135
 
{
136
 
  static GimpParam   values[1];
137
 
  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
138
 
  GimpRunMode        run_mode;
139
 
  GimpDrawable      *drawable;
140
 
 
141
 
  INIT_I18N ();
142
 
 
143
 
  run_mode = param[0].data.d_int32;
144
 
  drawable = gimp_drawable_get (param[2].data.d_int32);
145
 
 
146
 
  *nreturn_vals = 1;
147
 
  *return_vals  = values;
148
 
 
149
 
  values[0].type          = GIMP_PDB_STATUS;
150
 
  values[0].data.d_status = status;
151
 
 
152
 
  switch (run_mode)
153
 
    {
154
 
    case GIMP_RUN_INTERACTIVE:
155
 
      gimp_get_data (HSV_NOISE_PROC, &VALS);
156
 
      if (!gimp_drawable_is_rgb (drawable->drawable_id))
157
 
        {
158
 
          g_message (_("Can only operate on RGB drawables."));
159
 
          return;
160
 
        }
161
 
      if (! scatter_hsv_dialog (drawable))
162
 
        return;
163
 
      break;
164
 
 
165
 
    case GIMP_RUN_NONINTERACTIVE:
166
 
      VALS.holdness            = CLAMP (param[3].data.d_int32, 1, 8);
167
 
      VALS.hue_distance        = CLAMP (param[4].data.d_int32, 0, 180);
168
 
      VALS.saturation_distance = CLAMP (param[5].data.d_int32, 0, 255);
169
 
      VALS.value_distance      = CLAMP (param[6].data.d_int32, 0, 255);
170
 
      break;
171
 
 
172
 
    case GIMP_RUN_WITH_LAST_VALS:
173
 
      gimp_get_data (HSV_NOISE_PROC, &VALS);
174
 
      break;
175
 
    }
176
 
 
177
 
  scatter_hsv (drawable);
178
 
 
179
 
  if (run_mode != GIMP_RUN_NONINTERACTIVE)
180
 
    gimp_displays_flush();
181
 
  if (run_mode == GIMP_RUN_INTERACTIVE && status == GIMP_PDB_SUCCESS )
182
 
    gimp_set_data (HSV_NOISE_PROC, &VALS, sizeof (ValueType));
183
 
 
184
 
  values[0].type = GIMP_PDB_STATUS;
185
 
  values[0].data.d_status = status;
186
 
}
187
 
 
188
 
static void
189
 
scatter_hsv_func (const guchar *src,
190
 
                  guchar       *dest,
191
 
                  gint          bpp,
192
 
                  gpointer      data)
193
 
{
194
 
  guchar h, s, v;
195
 
 
196
 
  h = src[0];
197
 
  s = src[1];
198
 
  v = src[2];
199
 
 
200
 
  scatter_hsv_scatter (&h, &s, &v);
201
 
 
202
 
  dest[0] = h;
203
 
  dest[1] = s;
204
 
  dest[2] = v;
205
 
 
206
 
  if (bpp == 4)
207
 
    dest[3] = src[3];
208
 
}
209
 
 
210
 
static void
211
 
scatter_hsv (GimpDrawable *drawable)
212
 
{
213
 
  gimp_tile_cache_ntiles (2 * (drawable->width / gimp_tile_width () + 1));
214
 
 
215
 
  gimp_progress_init (_("HSV Noise"));
216
 
 
217
 
  gimp_rgn_iterate2 (drawable, 0 /* unused */, scatter_hsv_func, NULL);
218
 
 
219
 
  gimp_drawable_detach (drawable);
220
 
}
221
 
 
222
 
static gint
223
 
randomize_value (gint     now,
224
 
                 gint     min,
225
 
                 gint     max,
226
 
                 gboolean wraps_around,
227
 
                 gint     rand_max)
228
 
{
229
 
  gint    flag, new, steps, index;
230
 
  gdouble rand_val;
231
 
 
232
 
  steps = max - min + 1;
233
 
  rand_val = g_random_double ();
234
 
  for (index = 1; index < VALS.holdness; index++)
235
 
    {
236
 
      double tmp = g_random_double ();
237
 
      if (tmp < rand_val)
238
 
        rand_val = tmp;
239
 
    }
240
 
 
241
 
  if (g_random_double () < 0.5)
242
 
    flag = -1;
243
 
  else
244
 
    flag = 1;
245
 
 
246
 
  new = now + flag * ((int) (rand_max * rand_val) % steps);
247
 
 
248
 
  if (new < min)
249
 
    {
250
 
      if (wraps_around)
251
 
        new += steps;
252
 
      else
253
 
        new = min;
254
 
    }
255
 
  if (max < new)
256
 
    {
257
 
      if (wraps_around)
258
 
        new -= steps;
259
 
      else
260
 
        new = max;
261
 
    }
262
 
  return new;
263
 
}
264
 
 
265
 
static void
266
 
scatter_hsv_scatter (guchar *r,
267
 
                     guchar *g,
268
 
                     guchar *b)
269
 
{
270
 
  gint h, s, v;
271
 
  gint h1, s1, v1;
272
 
  gint h2, s2, v2;
273
 
 
274
 
  h = *r; s = *g; v = *b;
275
 
 
276
 
  gimp_rgb_to_hsv_int (&h, &s, &v);
277
 
 
278
 
  /* there is no need for scattering hue of desaturated pixels here */
279
 
  if ((VALS.hue_distance > 0) && (s > 0))
280
 
    h = randomize_value (h, 0, 359, TRUE,  VALS.hue_distance);
281
 
 
282
 
  /* desaturated pixels get random hue before increasing saturation */
283
 
  if (VALS.saturation_distance > 0) {
284
 
    if (s == 0)
285
 
      h = g_random_int_range (0, 360);
286
 
    s = randomize_value (s, 0, 255, FALSE, VALS.saturation_distance);
287
 
  }
288
 
 
289
 
  if (VALS.value_distance > 0)
290
 
    v = randomize_value (v, 0, 255, FALSE, VALS.value_distance);
291
 
 
292
 
  h1 = h; s1 = s; v1 = v;
293
 
 
294
 
  gimp_hsv_to_rgb_int (&h, &s, &v); /* don't believe ! */
295
 
 
296
 
  h2 = h; s2 = s; v2 = v;
297
 
 
298
 
  gimp_rgb_to_hsv_int (&h2, &s2, &v2); /* h2 should be h1. But... */
299
 
 
300
 
  if ((abs (h1 - h2) <= VALS.hue_distance)        &&
301
 
      (abs (s1 - s2) <= VALS.saturation_distance) &&
302
 
      (abs (v1 - v2) <= VALS.value_distance))
303
 
    {
304
 
      *r = h;
305
 
      *g = s;
306
 
      *b = v;
307
 
    }
308
 
}
309
 
 
310
 
static void
311
 
scatter_hsv_preview (GimpPreview *preview)
312
 
{
313
 
  GimpDrawable *drawable;
314
 
  GimpPixelRgn  src_rgn;
315
 
  guchar       *src, *dst;
316
 
  gint          i;
317
 
  gint          x1, y1;
318
 
  gint          width, height;
319
 
  gint          bpp;
320
 
 
321
 
  drawable =
322
 
    gimp_drawable_preview_get_drawable (GIMP_DRAWABLE_PREVIEW (preview));
323
 
 
324
 
  gimp_preview_get_position (preview, &x1, &y1);
325
 
  gimp_preview_get_size (preview, &width, &height);
326
 
 
327
 
  bpp = drawable->bpp;
328
 
 
329
 
  src = g_new (guchar, width * height * bpp);
330
 
  dst = g_new (guchar, width * height * bpp);
331
 
 
332
 
  gimp_pixel_rgn_init (&src_rgn, drawable,
333
 
                       x1, y1, width, height,
334
 
                       FALSE, FALSE);
335
 
  gimp_pixel_rgn_get_rect (&src_rgn, src, x1, y1, width, height);
336
 
 
337
 
  for (i = 0; i < width * height; i++)
338
 
    scatter_hsv_func (src + i * bpp, dst + i * bpp, bpp, NULL);
339
 
 
340
 
  gimp_preview_draw_buffer (preview, dst, width * bpp);
341
 
 
342
 
  g_free (src);
343
 
  g_free (dst);
344
 
}
345
 
 
346
 
 
347
 
/* dialog stuff */
348
 
 
349
 
static gboolean
350
 
scatter_hsv_dialog (GimpDrawable *drawable)
351
 
{
352
 
  GtkWidget *dialog;
353
 
  GtkWidget *main_vbox;
354
 
  GtkWidget *preview;
355
 
  GtkWidget *table;
356
 
  GtkObject *adj;
357
 
  gboolean   run;
358
 
 
359
 
  gimp_ui_init (PLUG_IN_BINARY, TRUE);
360
 
 
361
 
  dialog = gimp_dialog_new (_("HSV Noise"), PLUG_IN_BINARY,
362
 
                            NULL, 0,
363
 
                            gimp_standard_help_func, HSV_NOISE_PROC,
364
 
 
365
 
                            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
366
 
                            GTK_STOCK_OK,     GTK_RESPONSE_OK,
367
 
 
368
 
                            NULL);
369
 
 
370
 
  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
371
 
                                           GTK_RESPONSE_OK,
372
 
                                           GTK_RESPONSE_CANCEL,
373
 
                                           -1);
374
 
 
375
 
  gimp_window_set_transient (GTK_WINDOW (dialog));
376
 
 
377
 
  main_vbox = gtk_vbox_new (FALSE, 12);
378
 
  gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
379
 
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), main_vbox);
380
 
  gtk_widget_show (main_vbox);
381
 
 
382
 
  preview = gimp_drawable_preview_new (drawable, NULL);
383
 
  gtk_box_pack_start_defaults (GTK_BOX (main_vbox), preview);
384
 
  gtk_widget_show (preview);
385
 
 
386
 
  g_signal_connect (preview, "invalidated",
387
 
                    G_CALLBACK (scatter_hsv_preview),
388
 
                    NULL);
389
 
 
390
 
  table = gtk_table_new (4, 3, FALSE);
391
 
  gtk_table_set_col_spacings (GTK_TABLE (table), 6);
392
 
  gtk_table_set_row_spacings (GTK_TABLE (table), 6);
393
 
  gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
394
 
  gtk_widget_show (table);
395
 
 
396
 
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
397
 
                              _("_Holdness:"), SCALE_WIDTH, ENTRY_WIDTH,
398
 
                              VALS.holdness, 1, 8, 1, 2, 0,
399
 
                              TRUE, 0, 0,
400
 
                              NULL, NULL);
401
 
  g_signal_connect (adj, "value-changed",
402
 
                    G_CALLBACK (gimp_int_adjustment_update),
403
 
                    &VALS.holdness);
404
 
  g_signal_connect_swapped (adj, "value-changed",
405
 
                            G_CALLBACK (gimp_preview_invalidate),
406
 
                            preview);
407
 
 
408
 
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
409
 
                              _("H_ue:"), SCALE_WIDTH, ENTRY_WIDTH,
410
 
                              VALS.hue_distance, 0, 180, 1, 6, 0,
411
 
                              TRUE, 0, 0,
412
 
                              NULL, NULL);
413
 
  g_signal_connect (adj, "value-changed",
414
 
                    G_CALLBACK (gimp_int_adjustment_update),
415
 
                    &VALS.hue_distance);
416
 
  g_signal_connect_swapped (adj, "value-changed",
417
 
                            G_CALLBACK (gimp_preview_invalidate),
418
 
                            preview);
419
 
 
420
 
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
421
 
                              _("_Saturation:"), SCALE_WIDTH, ENTRY_WIDTH,
422
 
                              VALS.saturation_distance, 0, 255, 1, 8, 0,
423
 
                              TRUE, 0, 0,
424
 
                              NULL, NULL);
425
 
  g_signal_connect (adj, "value-changed",
426
 
                    G_CALLBACK (gimp_int_adjustment_update),
427
 
                    &VALS.saturation_distance);
428
 
  g_signal_connect_swapped (adj, "value-changed",
429
 
                            G_CALLBACK (gimp_preview_invalidate),
430
 
                            preview);
431
 
 
432
 
  adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 3,
433
 
                              _("_Value:"), SCALE_WIDTH, ENTRY_WIDTH,
434
 
                              VALS.value_distance, 0, 255, 1, 8, 0,
435
 
                              TRUE, 0, 0,
436
 
                              NULL, NULL);
437
 
  g_signal_connect (adj, "value-changed",
438
 
                    G_CALLBACK (gimp_int_adjustment_update),
439
 
                    &VALS.value_distance);
440
 
  g_signal_connect_swapped (adj, "value-changed",
441
 
                            G_CALLBACK (gimp_preview_invalidate),
442
 
                            preview);
443
 
 
444
 
  gtk_widget_show (dialog);
445
 
 
446
 
  run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
447
 
 
448
 
  gtk_widget_destroy (dialog);
449
 
 
450
 
  return run;
451
 
}