~ubuntu-branches/ubuntu/hoary/gimp/hoary

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2005-04-04 14:51:23 UTC
  • Revision ID: james.westby@ubuntu.com-20050404145123-9py049eeelfymur8
Tags: upstream-2.2.2
ImportĀ upstreamĀ versionĀ 2.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * file: hot/hot.c
 
3
 *
 
4
 * $Id: hot.c,v 1.38 2004/10/12 21:48:38 mitch Exp $
 
5
 */
 
6
 
 
7
/*
 
8
 * hot.c - Scan an image for pixels with RGB values that will give
 
9
 *      "unsafe" values of chrominance signal or composite signal
 
10
 *      amplitude when encoded into an NTSC or PAL colour signal.
 
11
 *      (This happens for certain high-intensity high-saturation colours
 
12
 *      that are rare in real scenes, but can easily be present
 
13
 *      in synthetic images.)
 
14
 *
 
15
 *      Such pixels can be flagged so the user may then choose other
 
16
 *      colours.  Or, the offending pixels can be made "safe"
 
17
 *      in a manner that preserves hue.
 
18
 *
 
19
 *      There are two reasonable ways to make a pixel "safe":
 
20
 *      We can reduce its intensity (luminance) while leaving
 
21
 *      hue and saturation the same.  Or, we can reduce saturation
 
22
 *      while leaving hue and luminance the same.  A #define selects
 
23
 *      which strategy to use.
 
24
 *
 
25
 * Note to the user: You must add your own read_pixel() and write_pixel()
 
26
 *      routines.  You may have to modify pix_decode() and pix_encode().
 
27
 *      MAXPIX, WID, and HGT are likely to need modification.
 
28
 */
 
29
 
 
30
/*
 
31
 * Originally written as "ikNTSC.c" by Alan Wm Paeth,
 
32
 *      University of Waterloo, August, 1985
 
33
 * Updated by Dave Martindale, Imax Systems Corp., December 1990
 
34
 */
 
35
 
 
36
/*
 
37
 * Compile time options:
 
38
 *
 
39
 *
 
40
 * CHROMA_LIM is the limit (in IRE units) of the overall
 
41
 *      chrominance amplitude; it should be 50 or perhaps
 
42
 *      very slightly higher.
 
43
 *
 
44
 * COMPOS_LIM is the maximum amplitude (in IRE units) allowed for
 
45
 *      the composite signal.  A value of 100 is the maximum
 
46
 *      monochrome white, and is always safe.  120 is the absolute
 
47
 *      limit for NTSC broadcasting, since the transmitter's carrier
 
48
 *      goes to zero with 120 IRE input signal.  Generally, 110
 
49
 *      is a good compromise - it allows somewhat brighter colours
 
50
 *      than 100, while staying safely away from the hard limit.
 
51
 */
 
52
 
 
53
/*
 
54
 * run-time options:
 
55
 *
 
56
 * Define either NTSC or PAL as 1 to select the colour system.
 
57
 * Define the other one as zero, or leave it undefined.
 
58
 *
 
59
 * Define FLAG_HOT as 1 if you want "hot" pixels set to black
 
60
 *      to identify them.  Otherwise they will be made safe.
 
61
 *
 
62
 * Define REDUCE_SAT as 1 if you want hot pixels to be repaired by
 
63
 *      reducing their saturation.  By default, luminance is reduced.
 
64
 *
 
65
 */
 
66
 
 
67
#include "config.h"
 
68
 
 
69
#include <stdio.h>
 
70
#include <stdlib.h>
 
71
#include <string.h>
 
72
 
 
73
#include <gtk/gtk.h>
 
74
 
 
75
#include <libgimp/gimp.h>
 
76
#include <libgimp/gimpui.h>
 
77
 
 
78
#include "libgimp/stdplugins-intl.h"
 
79
 
 
80
typedef struct
 
81
{
 
82
  gint32 image;
 
83
  gint32 drawable;
 
84
  gint32 mode;
 
85
  gint32 action;
 
86
  gint32 new_layerp;
 
87
} piArgs;
 
88
 
 
89
typedef enum
 
90
{
 
91
  ACT_LREDUX,
 
92
  ACT_SREDUX,
 
93
  ACT_FLAG
 
94
} hotAction;
 
95
 
 
96
typedef enum
 
97
{
 
98
  MODE_NTSC,
 
99
  MODE_PAL
 
100
} hotModes;
 
101
 
 
102
#define CHROMA_LIM      50.0            /* chroma amplitude limit */
 
103
#define COMPOS_LIM      110.0           /* max IRE amplitude */
 
104
 
 
105
/*
 
106
 * RGB to YIQ encoding matrix.
 
107
 */
 
108
 
 
109
struct
 
110
{
 
111
  gdouble pedestal;
 
112
  gdouble gamma;
 
113
  gdouble code[3][3];
 
114
} mode[2] = {
 
115
  {
 
116
    7.5,
 
117
    2.2,
 
118
    {
 
119
      { 0.2989,  0.5866,  0.1144 },
 
120
      { 0.5959, -0.2741, -0.3218 },
 
121
      { 0.2113, -0.5227,  0.3113 }
 
122
    }
 
123
  },
 
124
  {
 
125
    0.0,
 
126
    2.8,
 
127
    {
 
128
      { 0.2989,  0.5866,  0.1144 },
 
129
      { -0.1473, -0.2891,  0.4364 },
 
130
      { 0.6149, -0.5145, -0.1004 }
 
131
    }
 
132
  }
 
133
};
 
134
 
 
135
 
 
136
#define SCALE   8192            /* scale factor: do floats with int math */
 
137
#define MAXPIX   255            /* white value */
 
138
 
 
139
static gint     tab[3][3][MAXPIX+1]; /* multiply lookup table */
 
140
static gdouble  chroma_lim;          /* chroma limit */
 
141
static gdouble  compos_lim;          /* composite amplitude limit */
 
142
static glong    ichroma_lim2;        /* chroma limit squared (scaled integer) */
 
143
static gint     icompos_lim;         /* composite amplitude limit (scaled integer) */
 
144
 
 
145
static void query        (void);
 
146
static void run          (const gchar      *name,
 
147
                          gint              nparam,
 
148
                          const GimpParam  *param,
 
149
                          gint             *nretvals,
 
150
                          GimpParam       **retvals);
 
151
 
 
152
static gint pluginCore   (piArgs   *argp);
 
153
static gint pluginCoreIA (piArgs   *argp);
 
154
static gboolean hotp     (guint8  r,
 
155
                          guint8  g,
 
156
                          guint8  b);
 
157
static void build_tab    (gint    m);
 
158
 
 
159
/*
 
160
 * gc: apply the gamma correction specified for this video standard.
 
161
 * inv_gc: inverse function of gc.
 
162
 *
 
163
 * These are generally just a call to pow(), but be careful!
 
164
 * Future standards may use more complex functions.
 
165
 * (e.g. SMPTE 240M's "electro-optic transfer characteristic").
 
166
 */
 
167
#define gc(x,m) pow(x, 1.0 / mode[m].gamma)
 
168
#define inv_gc(x,m) pow(x, mode[m].gamma)
 
169
 
 
170
/*
 
171
 * pix_decode: decode an integer pixel value into a floating-point
 
172
 *      intensity in the range [0, 1].
 
173
 *
 
174
 * pix_encode: encode a floating-point intensity into an integer
 
175
 *      pixel value.
 
176
 *
 
177
 * The code given here assumes simple linear encoding; you must change
 
178
 * these routines if you use a different pixel encoding technique.
 
179
 */
 
180
#define pix_decode(v)  ((double)v / (double)MAXPIX)
 
181
#define pix_encode(v)  ((int)(v * (double)MAXPIX + 0.5))
 
182
 
 
183
GimpPlugInInfo PLUG_IN_INFO =
 
184
{
 
185
  NULL,  /* init_proc  */
 
186
  NULL,  /* quit_proc  */
 
187
  query, /* query_proc */
 
188
  run,   /* run_proc   */
 
189
};
 
190
 
 
191
MAIN ()
 
192
 
 
193
static void
 
194
query (void)
 
195
{
 
196
  static GimpParamDef args[] =
 
197
  {
 
198
    { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
 
199
    { GIMP_PDB_IMAGE, "image", "The Image" },
 
200
    { GIMP_PDB_DRAWABLE, "drawable", "The Drawable" },
 
201
    { GIMP_PDB_INT32, "mode", "Mode -- NTSC/PAL" },
 
202
    { GIMP_PDB_INT32, "action", "The action to perform" },
 
203
    { GIMP_PDB_INT32, "new_layerp", "Create a new layer iff True" }
 
204
  };
 
205
 
 
206
  gimp_install_procedure ("plug_in_hot",
 
207
                          "Look for hot NTSC or PAL pixels ",
 
208
                          "hot scans an image for pixels that will give unsave "
 
209
                          "values of chrominance or composite signale "
 
210
                          "amplitude when encoded into an NTSC or PAL signal.  "
 
211
                          "Three actions can be performed on these ``hot'' "
 
212
                          "pixels. (0) reduce luminance, (1) reduce "
 
213
                          "saturation, or (2) Blacken.",
 
214
                          "Eric L. Hernes, Alan Wm Paeth",
 
215
                          "Eric L. Hernes",
 
216
                          "1997",
 
217
                          N_("_Hot..."),
 
218
                          "RGB",
 
219
                          GIMP_PLUGIN,
 
220
                          G_N_ELEMENTS (args), 0,
 
221
                          args, NULL);
 
222
 
 
223
  gimp_plugin_menu_register ("plug_in_hot", "<Image>/Filters/Colors");
 
224
}
 
225
 
 
226
static void
 
227
run (const gchar      *name,
 
228
     gint              nparam,
 
229
     const GimpParam  *param,
 
230
     gint             *nretvals,
 
231
     GimpParam       **retvals)
 
232
{
 
233
  static GimpParam rvals[1];
 
234
  piArgs    args;
 
235
 
 
236
  *nretvals = 1;
 
237
  *retvals  = rvals;
 
238
 
 
239
  INIT_I18N ();
 
240
 
 
241
  memset (&args, (int) 0, sizeof (args));
 
242
  args.mode = -1;
 
243
 
 
244
  gimp_get_data ("plug_in_hot", &args);
 
245
 
 
246
  args.image    = param[1].data.d_image;
 
247
  args.drawable = param[2].data.d_drawable;
 
248
 
 
249
  rvals[0].type          = GIMP_PDB_STATUS;
 
250
  rvals[0].data.d_status = GIMP_PDB_SUCCESS;
 
251
 
 
252
  switch (param[0].data.d_int32)
 
253
    {
 
254
    case GIMP_RUN_INTERACTIVE:
 
255
      /* XXX: add code here for interactive running */
 
256
      if (args.mode == -1)
 
257
        {
 
258
          args.mode       = MODE_NTSC;
 
259
          args.action     = ACT_LREDUX;
 
260
          args.new_layerp = 1;
 
261
        }
 
262
 
 
263
      if (pluginCoreIA(&args) == -1)
 
264
        {
 
265
          rvals[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
 
266
        }
 
267
      gimp_set_data ("plug_in_hot", &args, sizeof (args));
 
268
 
 
269
    break;
 
270
 
 
271
    case GIMP_RUN_NONINTERACTIVE:
 
272
      /* XXX: add code here for non-interactive running */
 
273
      if (nparam != 6)
 
274
        {
 
275
          rvals[0].data.d_status = GIMP_PDB_CALLING_ERROR;
 
276
          break;
 
277
        }
 
278
      args.mode       = param[3].data.d_int32;
 
279
      args.action     = param[4].data.d_int32;
 
280
      args.new_layerp = param[5].data.d_int32;
 
281
 
 
282
      if (pluginCore(&args) == -1)
 
283
        {
 
284
          rvals[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
 
285
          break;
 
286
        }
 
287
    break;
 
288
 
 
289
    case GIMP_RUN_WITH_LAST_VALS:
 
290
      /* XXX: add code here for last-values running */
 
291
      if (pluginCore (&args) == -1)
 
292
        {
 
293
          rvals[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
 
294
        }
 
295
    break;
 
296
  }
 
297
}
 
298
 
 
299
static gint
 
300
pluginCore (piArgs *argp)
 
301
{
 
302
  GimpDrawable *drw, *ndrw=NULL;
 
303
  GimpPixelRgn srcPr, dstPr;
 
304
  gint retval = 0;
 
305
  gint nl=0;
 
306
  gint y, x, i;
 
307
  gint Y, I, Q;
 
308
  guint width, height, bpp;
 
309
  gint sel_x1, sel_x2, sel_y1, sel_y2;
 
310
  gint prog_interval;
 
311
  guchar *src, *s, *dst, *d;
 
312
  guchar r, prev_r=0, new_r=0;
 
313
  guchar g, prev_g=0, new_g=0;
 
314
  guchar b, prev_b=0, new_b=0;
 
315
  gdouble fy, fc, t, scale;
 
316
  gdouble pr, pg, pb;
 
317
  gdouble py;
 
318
 
 
319
  drw = gimp_drawable_get (argp->drawable);
 
320
 
 
321
  width = drw->width;
 
322
  height = drw->height;
 
323
  bpp = drw->bpp;
 
324
  if (argp->new_layerp)
 
325
    {
 
326
      gchar name[40];
 
327
      gchar *mode_names[] =
 
328
      {
 
329
        "ntsc",
 
330
        "pal",
 
331
      };
 
332
      gchar *action_names[] =
 
333
      {
 
334
        "lum redux",
 
335
        "sat redux",
 
336
        "flag",
 
337
      };
 
338
 
 
339
      g_snprintf (name, sizeof (name), "hot mask (%s, %s)",
 
340
                  mode_names[argp->mode],
 
341
                  action_names[argp->action]);
 
342
 
 
343
      nl = gimp_layer_new (argp->image, name, width, height,
 
344
                           GIMP_RGBA_IMAGE, (gdouble)100, GIMP_NORMAL_MODE);
 
345
      ndrw = gimp_drawable_get (nl);
 
346
      gimp_drawable_fill (nl, GIMP_TRANSPARENT_FILL);
 
347
      gimp_image_add_layer (argp->image, nl, 0);
 
348
    }
 
349
 
 
350
  gimp_drawable_mask_bounds (drw->drawable_id,
 
351
                             &sel_x1, &sel_y1, &sel_x2, &sel_y2);
 
352
 
 
353
  width = sel_x2 - sel_x1;
 
354
  height = sel_y2 - sel_y1;
 
355
 
 
356
  src = g_new (guchar, width * height * bpp);
 
357
  dst = g_new (guchar, width * height * 4);
 
358
  gimp_pixel_rgn_init (&srcPr, drw, sel_x1, sel_y1, width, height,
 
359
                       FALSE, FALSE);
 
360
 
 
361
  if (argp->new_layerp)
 
362
    {
 
363
      gimp_pixel_rgn_init (&dstPr, ndrw, sel_x1, sel_y1, width, height,
 
364
                           FALSE, FALSE);
 
365
    }
 
366
  else
 
367
    {
 
368
      gimp_pixel_rgn_init (&dstPr, drw, sel_x1, sel_y1, width, height,
 
369
                           TRUE, TRUE);
 
370
    }
 
371
 
 
372
  gimp_pixel_rgn_get_rect (&srcPr, src, sel_x1, sel_y1, width, height);
 
373
 
 
374
  s = src;
 
375
  d = dst;
 
376
 
 
377
  build_tab (argp->mode);
 
378
 
 
379
  gimp_progress_init (_("Hot..."));
 
380
  prog_interval = height / 10;
 
381
 
 
382
  for (y = sel_y1; y < sel_y2; y++)
 
383
    {
 
384
      if (y % prog_interval == 0)
 
385
        gimp_progress_update ((double) y / (double) (sel_y2 - sel_y1));
 
386
 
 
387
      for (x = sel_x1; x < sel_x2; x++)
 
388
        {
 
389
          if (hotp (r = *(s + 0), g = *(s + 1), b = *(s + 2)))
 
390
            {
 
391
              if (argp->action == ACT_FLAG)
 
392
                {
 
393
                  for (i = 0; i < 3; i++)
 
394
                    *d++ = 0;
 
395
                  s += 3;
 
396
                  if (bpp == 4)
 
397
                    *d++ = *s++;
 
398
                  else if (argp->new_layerp)
 
399
                    *d++ = 255;
 
400
                }
 
401
              else
 
402
                {
 
403
                  /*
 
404
                   * Optimization: cache the last-computed hot pixel.
 
405
                   */
 
406
                  if (r == prev_r && g == prev_g && b == prev_b)
 
407
                    {
 
408
                      *d++ = new_r;
 
409
                      *d++ = new_g;
 
410
                      *d++ = new_b;
 
411
                      s += 3;
 
412
                      if (bpp == 4)
 
413
                        *d++ = *s++;
 
414
                      else if (argp->new_layerp)
 
415
                        *d++ = 255;
 
416
                    }
 
417
                  else
 
418
                    {
 
419
                      Y = tab[0][0][r] + tab[0][1][g] + tab[0][2][b];
 
420
                      I = tab[1][0][r] + tab[1][1][g] + tab[1][2][b];
 
421
                      Q = tab[2][0][r] + tab[2][1][g] + tab[2][2][b];
 
422
 
 
423
                      prev_r = r;
 
424
                      prev_g = g;
 
425
                      prev_b = b;
 
426
                      /*
 
427
                       * Get Y and chroma amplitudes in floating point.
 
428
                       *
 
429
                       * If your C library doesn't have hypot(), just use
 
430
                       * hypot(a,b) = sqrt(a*a, b*b);
 
431
                       *
 
432
                       * Then extract linear (un-gamma-corrected)
 
433
                       * floating-point pixel RGB values.
 
434
                       */
 
435
                      fy = (double)Y / (double)SCALE;
 
436
                      fc = hypot ((double) I / (double) SCALE,
 
437
                                  (double) Q / (double) SCALE);
 
438
 
 
439
                      pr = (double) pix_decode (r);
 
440
                      pg = (double) pix_decode (g);
 
441
                      pb = (double) pix_decode (b);
 
442
 
 
443
                      /*
 
444
                       * Reducing overall pixel intensity by scaling R,
 
445
                       * G, and B reduces Y, I, and Q by the same factor.
 
446
                       * This changes luminance but not saturation, since
 
447
                       * saturation is determined by the chroma/luminance
 
448
                       * ratio.
 
449
                       *
 
450
                       * On the other hand, by linearly interpolating
 
451
                       * between the original pixel value and a grey
 
452
                       * pixel with the same luminance (R=G=B=Y), we
 
453
                       * change saturation without affecting luminance.
 
454
                       */
 
455
                      if (argp->action == ACT_LREDUX)
 
456
                        {
 
457
                          /*
 
458
                           * Calculate a scale factor that will bring the pixel
 
459
                           * within both chroma and composite limits, if we scale
 
460
                           * luminance and chroma simultaneously.
 
461
                           *
 
462
                           * The calculated chrominance reduction applies
 
463
                           * to the gamma-corrected RGB values that are
 
464
                           * the input to the RGB-to-YIQ operation.
 
465
                           * Multiplying the original un-gamma-corrected
 
466
                           * pixel values by the scaling factor raised to
 
467
                           * the "gamma" power is equivalent, and avoids
 
468
                           * calling gc() and inv_gc() three times each.  */
 
469
                          scale = chroma_lim / fc;
 
470
                          t = compos_lim / (fy + fc);
 
471
                          if (t < scale)
 
472
                            scale = t;
 
473
                          scale = pow (scale, mode[argp->mode].gamma);
 
474
 
 
475
                          r = (guint8) pix_encode (scale * pr);
 
476
                          g = (guint8) pix_encode (scale * pg);
 
477
                          b = (guint8) pix_encode (scale * pb);
 
478
                        }
 
479
                      else
 
480
                        { /* ACT_SREDUX hopefully */
 
481
                          /*
 
482
                           * Calculate a scale factor that will bring the
 
483
                           * pixel within both chroma and composite
 
484
                           * limits, if we scale chroma while leaving
 
485
                           * luminance unchanged.
 
486
                           *
 
487
                           * We have to interpolate gamma-corrected RGB
 
488
                           * values, so we must convert from linear to
 
489
                           * gamma-corrected before interpolation and then
 
490
                           * back to linear afterwards.
 
491
                           */
 
492
                          scale = chroma_lim / fc;
 
493
                          t = (compos_lim - fy) / fc;
 
494
                          if (t < scale)
 
495
                            scale = t;
 
496
 
 
497
                          pr = gc (pr, argp->mode);
 
498
                          pg = gc (pg, argp->mode);
 
499
                          pb = gc (pb, argp->mode);
 
500
                          py = pr * mode[argp->mode].code[0][0] + pg *
 
501
                            mode[argp->mode].code[0][1] + pb *
 
502
                            mode[argp->mode].code[0][2];
 
503
                          r = pix_encode (inv_gc (py + scale * (pr - py),
 
504
                                                  argp->mode));
 
505
                          g = pix_encode (inv_gc (py + scale * (pg - py),
 
506
                                                  argp->mode));
 
507
                          b = pix_encode (inv_gc (py + scale * (pb - py),
 
508
                                                  argp->mode));
 
509
                        }
 
510
                      *d++ = new_r = r;
 
511
                      *d++ = new_g = g;
 
512
                      *d++ = new_b = b;
 
513
                      s += 3;
 
514
                      if (bpp == 4)
 
515
                        *d++ = *s++;
 
516
                      else if (argp->new_layerp)
 
517
                        *d++ = 255;
 
518
                    }
 
519
                }
 
520
            }
 
521
          else
 
522
            {
 
523
              if (!argp->new_layerp)
 
524
                {
 
525
                  for (i = 0; i < bpp; i++)
 
526
                    *d++ = *s++;
 
527
                }
 
528
              else
 
529
                {
 
530
                  s += bpp;
 
531
                  d += 4;
 
532
                }
 
533
            }
 
534
        }
 
535
    }
 
536
  gimp_pixel_rgn_set_rect (&dstPr, dst, sel_x1, sel_y1, width, height);
 
537
 
 
538
  g_free (src);
 
539
  g_free (dst);
 
540
 
 
541
  if (argp->new_layerp)
 
542
    {
 
543
      gimp_drawable_flush (ndrw);
 
544
      gimp_drawable_update (nl, sel_x1, sel_y1, width, height);
 
545
    }
 
546
  else
 
547
    {
 
548
      gimp_drawable_flush (drw);
 
549
      gimp_drawable_merge_shadow (drw->drawable_id, TRUE);
 
550
      gimp_drawable_update (drw->drawable_id, sel_x1, sel_y1, width, height);
 
551
    }
 
552
 
 
553
  gimp_displays_flush ();
 
554
 
 
555
  return retval;
 
556
}
 
557
 
 
558
static gint
 
559
pluginCoreIA (piArgs *argp)
 
560
{
 
561
  GtkWidget *dlg;
 
562
  GtkWidget *hbox;
 
563
  GtkWidget *vbox;
 
564
  GtkWidget *toggle;
 
565
  GtkWidget *frame;
 
566
  gboolean   run;
 
567
 
 
568
  gimp_ui_init ("hot", FALSE);
 
569
 
 
570
  dlg = gimp_dialog_new (_("Hot"), "hot",
 
571
                         NULL, 0,
 
572
                         gimp_standard_help_func, "plug-in-hot",
 
573
 
 
574
                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 
575
                         GTK_STOCK_OK,     GTK_RESPONSE_OK,
 
576
 
 
577
                         NULL);
 
578
 
 
579
  hbox = gtk_hbox_new (FALSE, 12);
 
580
  gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
 
581
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), hbox, TRUE, TRUE, 0);
 
582
  gtk_widget_show (hbox);
 
583
 
 
584
  vbox = gtk_vbox_new (FALSE, 12);
 
585
  gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
 
586
  gtk_widget_show (vbox);
 
587
 
 
588
  frame = gimp_int_radio_group_new (TRUE, _("Mode"),
 
589
                                    G_CALLBACK (gimp_radio_button_update),
 
590
                                    &argp->mode, argp->mode,
 
591
 
 
592
                                    "N_TSC", MODE_NTSC, NULL,
 
593
                                    "_PAL",  MODE_PAL,  NULL,
 
594
 
 
595
                                    NULL);
 
596
 
 
597
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
 
598
  gtk_widget_show (frame);
 
599
 
 
600
  toggle = gtk_check_button_new_with_mnemonic (_("Create _New layer"));
 
601
  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), argp->new_layerp);
 
602
  gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
 
603
  gtk_widget_show (toggle);
 
604
 
 
605
  g_signal_connect (toggle, "toggled",
 
606
                    G_CALLBACK (gimp_toggle_button_update),
 
607
                    &argp->new_layerp);
 
608
 
 
609
  frame = gimp_int_radio_group_new (TRUE, _("Action"),
 
610
                                    G_CALLBACK (gimp_radio_button_update),
 
611
                                    &argp->action, argp->action,
 
612
 
 
613
                                    _("Reduce _Luminance"),  ACT_LREDUX, NULL,
 
614
                                    _("Reduce _Saturation"), ACT_SREDUX, NULL,
 
615
                                    _("_Blacken"),           ACT_FLAG,   NULL,
 
616
 
 
617
                                    NULL);
 
618
 
 
619
  gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
 
620
  gtk_widget_show (frame);
 
621
 
 
622
  gtk_widget_show (dlg);
 
623
 
 
624
  run = (gimp_dialog_run (GIMP_DIALOG (dlg)) == GTK_RESPONSE_OK);
 
625
 
 
626
  gtk_widget_destroy (dlg);
 
627
 
 
628
  if (run)
 
629
    return pluginCore (argp);
 
630
  else
 
631
    return -1;
 
632
}
 
633
 
 
634
/*
 
635
 * build_tab: Build multiply lookup table.
 
636
 *
 
637
 * For each possible pixel value, decode value into floating-point
 
638
 * intensity.  Then do gamma correction required by the video
 
639
 * standard.  Scale the result by our fixed-point scale factor.
 
640
 * Then calculate 9 lookup table entries for this pixel value.
 
641
 *
 
642
 * We also calculate floating-point and scaled integer versions
 
643
 * of our limits here.  This prevents evaluating expressions every pixel
 
644
 * when the compiler is too stupid to evaluate constant-valued
 
645
 * floating-point expressions at compile time.
 
646
 *
 
647
 * For convenience, the limits are #defined using IRE units.
 
648
 * We must convert them here into the units in which YIQ
 
649
 * are measured.  The conversion from IRE to internal units
 
650
 * depends on the pedestal level in use, since as Y goes from
 
651
 * 0 to 1, the signal goes from the pedestal level to 100 IRE.
 
652
 * Chroma is always scaled to remain consistent with Y.
 
653
 */
 
654
static void
 
655
build_tab (int m)
 
656
{
 
657
  double f;
 
658
  int pv;
 
659
 
 
660
  for (pv = 0; pv <= MAXPIX; pv++)
 
661
    {
 
662
      f = (double)SCALE * (double)gc((double)pix_decode(pv),m);
 
663
      tab[0][0][pv] = (int)(f * mode[m].code[0][0] + 0.5);
 
664
      tab[0][1][pv] = (int)(f * mode[m].code[0][1] + 0.5);
 
665
      tab[0][2][pv] = (int)(f * mode[m].code[0][2] + 0.5);
 
666
      tab[1][0][pv] = (int)(f * mode[m].code[1][0] + 0.5);
 
667
      tab[1][1][pv] = (int)(f * mode[m].code[1][1] + 0.5);
 
668
      tab[1][2][pv] = (int)(f * mode[m].code[1][2] + 0.5);
 
669
      tab[2][0][pv] = (int)(f * mode[m].code[2][0] + 0.5);
 
670
      tab[2][1][pv] = (int)(f * mode[m].code[2][1] + 0.5);
 
671
      tab[2][2][pv] = (int)(f * mode[m].code[2][2] + 0.5);
 
672
    }
 
673
 
 
674
  chroma_lim = (double)CHROMA_LIM / (100.0 - mode[m].pedestal);
 
675
  compos_lim = ((double)COMPOS_LIM - mode[m].pedestal) /
 
676
    (100.0 - mode[m].pedestal);
 
677
 
 
678
  ichroma_lim2 = (int)(chroma_lim * SCALE + 0.5);
 
679
  ichroma_lim2 *= ichroma_lim2;
 
680
  icompos_lim = (int)(compos_lim * SCALE + 0.5);
 
681
}
 
682
 
 
683
static gboolean
 
684
hotp (guint8 r,
 
685
      guint8 g,
 
686
      guint8 b)
 
687
{
 
688
  int   y, i, q;
 
689
  long  y2, c2;
 
690
 
 
691
  /*
 
692
   * Pixel decoding, gamma correction, and matrix multiplication
 
693
   * all done by lookup table.
 
694
   *
 
695
   * "i" and "q" are the two chrominance components;
 
696
   * they are I and Q for NTSC.
 
697
   * For PAL, "i" is U (scaled B-Y) and "q" is V (scaled R-Y).
 
698
   * Since we only care about the length of the chroma vector,
 
699
   * not its angle, we don't care which is which.
 
700
   */
 
701
  y = tab[0][0][r] + tab[0][1][g] + tab[0][2][b];
 
702
  i = tab[1][0][r] + tab[1][1][g] + tab[1][2][b];
 
703
  q = tab[2][0][r] + tab[2][1][g] + tab[2][2][b];
 
704
 
 
705
  /*
 
706
   * Check to see if the chrominance vector is too long or the
 
707
   * composite waveform amplitude is too large.
 
708
   *
 
709
   * Chrominance is too large if
 
710
   *
 
711
   *    sqrt(i^2, q^2)  >  chroma_lim.
 
712
   *
 
713
   * The composite signal amplitude is too large if
 
714
   *
 
715
   *    y + sqrt(i^2, q^2)  >  compos_lim.
 
716
   *
 
717
   * We avoid doing the sqrt by checking
 
718
   *
 
719
   *    i^2 + q^2  >  chroma_lim^2
 
720
   * and
 
721
   *    y + sqrt(i^2 + q^2)  >  compos_lim
 
722
   *    sqrt(i^2 + q^2)  >  compos_lim - y
 
723
   *    i^2 + q^2  >  (compos_lim - y)^2
 
724
   *
 
725
   */
 
726
 
 
727
  c2 = (long)i * i + (long)q * q;
 
728
  y2 = (long)icompos_lim - y;
 
729
  y2 *= y2;
 
730
 
 
731
  if (c2 <= ichroma_lim2 && c2 <= y2)
 
732
    {   /* no problems */
 
733
      return FALSE;
 
734
    }
 
735
 
 
736
  return TRUE;
 
737
}