home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / common / hot.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-24  |  20.3 KB  |  764 lines

  1. /*
  2.  * file: hot/hot.c
  3.  *
  4.  * $Id: hot.c,v 1.17 2000/08/22 01:26:54 neo 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.  
  81. struct Grgb
  82. {
  83.   guint8 red;
  84.   guint8 green;
  85.   guint8 blue;
  86. };
  87.  
  88. struct GRegion
  89. {
  90.   gint32 x;
  91.   gint32 y;
  92.   gint32 width;
  93.   gint32 height;
  94. };
  95.  
  96. struct piArgs
  97. {
  98.   gint32 image;
  99.   gint32 drawable;
  100.   gint32 mode;
  101.   gint32 action;
  102.   gint32 new_layerp;
  103. };
  104.  
  105. typedef enum
  106. {
  107.   act_lredux = 0,
  108.   act_sredux = 1,
  109.   act_flag   = 2
  110. } hotAction;
  111.  
  112. typedef enum
  113. {
  114.   mode_ntsc = 0,
  115.   mode_pal  = 1
  116. } hotModes;
  117.  
  118. #define    CHROMA_LIM      50.0        /* chroma amplitude limit */
  119. #define    COMPOS_LIM      110.0        /* max IRE amplitude */
  120.  
  121. /*
  122.  * RGB to YIQ encoding matrix.
  123.  */
  124.  
  125. struct
  126. {
  127.   gdouble pedestal;
  128.   gdouble gamma;
  129.   gdouble code[3][3];
  130. } mode[2] = {
  131.   {
  132.     7.5,
  133.     2.2,
  134.     {
  135.       { 0.2989,  0.5866,  0.1144 },
  136.       { 0.5959, -0.2741, -0.3218 },
  137.       { 0.2113, -0.5227,  0.3113 }
  138.     }
  139.   },
  140.   {
  141.     0.0,
  142.     2.8,
  143.     {
  144.       { 0.2989,  0.5866,  0.1144 },
  145.       { -0.1473, -0.2891,  0.4364 },
  146.       { 0.6149, -0.5145, -0.1004 }
  147.     }
  148.   }
  149. };
  150.  
  151.  
  152. #define SCALE    8192            /* scale factor: do floats with int math */
  153. #define MAXPIX     255            /* white value */
  154.  
  155. static gint    tab[3][3][MAXPIX+1]; /* multiply lookup table */
  156. static gdouble    chroma_lim;          /* chroma limit */
  157. static gdouble    compos_lim;          /* composite amplitude limit */
  158. static glong    ichroma_lim2;        /* chroma limit squared (scaled integer) */
  159. static gint    icompos_lim;         /* composite amplitude limit (scaled integer) */
  160.  
  161. static void query        (void);
  162. static void run          (gchar   *name,
  163.               gint     nparam,
  164.               GimpParam  *param,
  165.               gint    *nretvals,
  166.               GimpParam **retvals);
  167.  
  168. static gint pluginCore   (struct piArgs *argp);
  169. static gint pluginCoreIA (struct piArgs *argp);
  170. static gint hotp         (register guint8 r,
  171.               register guint8 g,
  172.               register guint8 b);
  173. static void build_tab    (int m);
  174.  
  175. /*
  176.  * gc: apply the gamma correction specified for this video standard.
  177.  * inv_gc: inverse function of gc.
  178.  *
  179.  * These are generally just a call to pow(), but be careful!
  180.  * Future standards may use more complex functions.
  181.  * (e.g. SMPTE 240M's "electro-optic transfer characteristic").
  182.  */
  183. #define gc(x,m) pow(x, 1.0 / mode[m].gamma)
  184. #define inv_gc(x,m) pow(x, mode[m].gamma)
  185.  
  186. /*
  187.  * pix_decode: decode an integer pixel value into a floating-point
  188.  *    intensity in the range [0, 1].
  189.  *
  190.  * pix_encode: encode a floating-point intensity into an integer
  191.  *    pixel value.
  192.  *
  193.  * The code given here assumes simple linear encoding; you must change
  194.  * these routines if you use a different pixel encoding technique.
  195.  */
  196. #define pix_decode(v)  ((double)v / (double)MAXPIX)
  197. #define pix_encode(v)  ((int)(v * (double)MAXPIX + 0.5))
  198.  
  199. GimpPlugInInfo PLUG_IN_INFO =
  200. {
  201.   NULL,  /* init_proc  */
  202.   NULL,  /* quit_proc  */
  203.   query, /* query_proc */
  204.   run,   /* run_proc   */
  205. };
  206.  
  207. MAIN ()
  208.  
  209. static void
  210. query (void)
  211. {
  212.   static GimpParamDef args[] =
  213.   {
  214.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  215.     { GIMP_PDB_IMAGE, "image", "The Image" },
  216.     { GIMP_PDB_DRAWABLE, "drawable", "The Drawable" },
  217.     { GIMP_PDB_INT32, "mode", "Mode -- NTSC/PAL" },
  218.     { GIMP_PDB_INT32, "action", "The action to perform" },
  219.     { GIMP_PDB_INT32, "new_layerp", "Create a new layer iff True" }
  220.   };
  221.   static gint nargs = sizeof (args) / sizeof (args[0]);
  222.  
  223.   gimp_install_procedure ("plug_in_hot",
  224.               "Look for hot NTSC or PAL pixels ",
  225.               "hot scans an image for pixels that will give unsave "
  226.               "values of chrominance or composite signale "
  227.               "amplitude when encoded into an NTSC or PAL signal.  "
  228.               "Three actions can be performed on these ``hot'' "
  229.               "pixels. (0) reduce luminance, (1) reduce "
  230.               "saturation, or (2) Blacken.",
  231.               "Eric L. Hernes, Alan Wm Paeth",
  232.               "Eric L. Hernes",
  233.               "1997",
  234.               N_("<Image>/Filters/Colors/Hot..."),
  235.               "RGB",
  236.               GIMP_PLUGIN,
  237.               nargs, 0,
  238.               args, NULL);
  239. }
  240.  
  241. static void
  242. run (gchar   *name,
  243.      gint     nparam,
  244.      GimpParam  *param,
  245.      gint    *nretvals,
  246.      GimpParam **retvals)
  247. {
  248.   static GimpParam rvals[1];
  249.  
  250.   struct piArgs args;
  251.  
  252.   *nretvals = 1;
  253.   *retvals = rvals;
  254.  
  255.   memset (&args, (int) 0, sizeof (struct piArgs));
  256.   args.mode = -1;
  257.  
  258.   gimp_get_data ("plug_in_hot", &args);
  259.  
  260.   args.image = param[1].data.d_image;
  261.   args.drawable = param[2].data.d_drawable;
  262.  
  263.   rvals[0].type = GIMP_PDB_STATUS;
  264.   rvals[0].data.d_status = GIMP_PDB_SUCCESS;
  265.   switch (param[0].data.d_int32)
  266.     {
  267.     case GIMP_RUN_INTERACTIVE:
  268.       INIT_I18N_UI();
  269.       /* XXX: add code here for interactive running */
  270.       if (args.mode == -1)
  271.     {
  272.       args.mode       = mode_ntsc;
  273.       args.action     = act_lredux;
  274.       args.new_layerp = 1;
  275.     }
  276.  
  277.       if (pluginCoreIA(&args) == -1)
  278.     {
  279.       rvals[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  280.     }
  281.       gimp_set_data ("plug_in_hot", &args, sizeof (struct piArgs));
  282.  
  283.     break;
  284.  
  285.     case GIMP_RUN_NONINTERACTIVE:
  286.       INIT_I18N();
  287.       /* XXX: add code here for non-interactive running */
  288.       if (nparam != 6)
  289.     {
  290.       rvals[0].data.d_status = GIMP_PDB_CALLING_ERROR;
  291.       break;
  292.     }
  293.       args.mode       = param[3].data.d_int32;
  294.       args.action     = param[4].data.d_int32;
  295.       args.new_layerp = param[5].data.d_int32;
  296.  
  297.       if (pluginCore(&args) == -1)
  298.     {
  299.       rvals[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  300.       break;
  301.     }
  302.     break;
  303.  
  304.     case GIMP_RUN_WITH_LAST_VALS:
  305.       INIT_I18N();
  306.       /* XXX: add code here for last-values running */
  307.       if (pluginCore (&args) == -1)
  308.     {
  309.       rvals[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  310.     }
  311.     break;
  312.   }
  313. }
  314.  
  315. static gint
  316. pluginCore (struct piArgs *argp)
  317. {
  318.   GimpDrawable *drw, *ndrw=NULL;
  319.   GimpPixelRgn srcPr, dstPr;
  320.   gint retval = 0;
  321.   gint nl=0;
  322.   gint y, x, i;
  323.   gint Y, I, Q;
  324.   guint width, height, Bpp;
  325.   gint prog_interval;
  326.   guchar *src, *s, *dst, *d;
  327.   guchar r, prev_r=0, new_r=0;
  328.   guchar g, prev_g=0, new_g=0;
  329.   guchar b, prev_b=0, new_b=0;
  330.   gdouble fy, fc, t, scale;
  331.   gdouble pr, pg, pb;
  332.   gdouble py;
  333.   
  334.   drw = gimp_drawable_get (argp->drawable);
  335.  
  336.   width = drw->width;
  337.   height = drw->height;
  338.   Bpp = drw->bpp;
  339.   if (argp->new_layerp)
  340.     {
  341.       gchar name[40];
  342.       gchar *mode_names[] =
  343.       {
  344.     "ntsc",
  345.     "pal",
  346.       };
  347.       gchar *action_names[] =
  348.       {
  349.     "lum redux",
  350.     "sat redux",
  351.     "flag",
  352.       };
  353.  
  354.       g_snprintf (name, sizeof (name), "hot mask (%s, %s)",
  355.           mode_names[argp->mode],
  356.           action_names[argp->action]);
  357.  
  358.       nl = gimp_layer_new (argp->image, name, width, height,
  359.                GIMP_RGBA_IMAGE, (gdouble)100, GIMP_NORMAL_MODE);
  360.       ndrw = gimp_drawable_get (nl);
  361.       gimp_drawable_fill (nl, GIMP_TRANS_IMAGE_FILL);
  362.       gimp_image_add_layer (argp->image, nl, 0);
  363.     }
  364.  
  365.   src = g_new (guchar, width * height * Bpp);
  366.   dst = g_new (guchar, width * height * 4);
  367.   gimp_pixel_rgn_init (&srcPr, drw, 0, 0, width, height, FALSE, FALSE);
  368.   if (argp->new_layerp)
  369.     {
  370.       gimp_pixel_rgn_init (&dstPr, ndrw, 0, 0, width, height, FALSE, FALSE);
  371.     }
  372.   else
  373.     {
  374.       gimp_pixel_rgn_init (&dstPr, drw, 0, 0, width, height, TRUE, TRUE);
  375.     }
  376.  
  377.   gimp_pixel_rgn_get_rect (&srcPr, src, 0, 0, width, height);
  378.  
  379.   s = src;
  380.   d = dst;
  381.  
  382.   build_tab (argp->mode);
  383.  
  384.   gimp_progress_init (_("Hot"));
  385.   prog_interval = height / 10;
  386.  
  387.   for (y = 0; y < height; y++)
  388.     {
  389.       if (y % prog_interval == 0)
  390.     gimp_progress_update ((double) y / (double) height);
  391.       for (x = 0; x < width; x++)
  392.     {
  393.       if (hotp (r = *(s + 0), g = *(s + 1), b = *(s + 2)))
  394.         {
  395.           if (argp->action == act_flag)
  396.         {
  397.           for (i = 0; i < 3; i++)
  398.             *d++ = 0;
  399.           s += 3;
  400.           if (Bpp == 4)
  401.             *d++ = *s++;
  402.           else if (argp->new_layerp)
  403.             *d++ = 255;
  404.         }
  405.           else
  406.         {
  407.           /*
  408.            * Optimization: cache the last-computed hot pixel.
  409.            */
  410.           if (r == prev_r && g == prev_g && b == prev_b)
  411.             {
  412.               *d++ = new_r;
  413.               *d++ = new_g;
  414.               *d++ = new_b;
  415.               s += 3;
  416.               if (Bpp == 4)
  417.             *d++ = *s++;
  418.               else if (argp->new_layerp)
  419.             *d++ = 255;
  420.             }
  421.           else
  422.             {
  423.               Y = tab[0][0][r] + tab[0][1][g] + tab[0][2][b];
  424.               I = tab[1][0][r] + tab[1][1][g] + tab[1][2][b];
  425.               Q = tab[2][0][r] + tab[2][1][g] + tab[2][2][b];
  426.  
  427.               prev_r = r;
  428.               prev_g = g;
  429.               prev_b = b;
  430.               /*
  431.                * Get Y and chroma amplitudes in floating point.
  432.                *
  433.                * If your C library doesn't have hypot(), just use
  434.                * hypot(a,b) = sqrt(a*a, b*b);
  435.                *
  436.                * Then extract linear (un-gamma-corrected)
  437.                * floating-point pixel RGB values.
  438.                */
  439.               fy = (double)Y / (double)SCALE;
  440.               fc = hypot ((double) I / (double) SCALE,
  441.                   (double) Q / (double) SCALE);
  442.  
  443.               pr = (double) pix_decode (r);
  444.               pg = (double) pix_decode (g);
  445.               pb = (double) pix_decode (b);
  446.  
  447.               /*
  448.                * Reducing overall pixel intensity by scaling R,
  449.                * G, and B reduces Y, I, and Q by the same factor.
  450.                * This changes luminance but not saturation, since
  451.                * saturation is determined by the chroma/luminance
  452.                * ratio.
  453.                *
  454.                * On the other hand, by linearly interpolating
  455.                * between the original pixel value and a grey
  456.                * pixel with the same luminance (R=G=B=Y), we
  457.                * change saturation without affecting luminance.
  458.                */
  459.               if (argp->action == act_lredux)
  460.             {
  461.               /*
  462.                * Calculate a scale factor that will bring the pixel
  463.                * within both chroma and composite limits, if we scale
  464.                * luminance and chroma simultaneously.
  465.                *
  466.                * The calculated chrominance reduction applies
  467.                * to the gamma-corrected RGB values that are
  468.                * the input to the RGB-to-YIQ operation.
  469.                * Multiplying the original un-gamma-corrected
  470.                * pixel values by the scaling factor raised to
  471.                * the "gamma" power is equivalent, and avoids
  472.                * calling gc() and inv_gc() three times each.  */
  473.               scale = chroma_lim / fc;
  474.               t = compos_lim / (fy + fc);
  475.               if (t < scale)
  476.                 scale = t;
  477.               scale = pow (scale, mode[argp->mode].gamma);
  478.  
  479.               r = (guint8) pix_encode (scale * pr);
  480.               g = (guint8) pix_encode (scale * pg);
  481.               b = (guint8) pix_encode (scale * pb);
  482.             }
  483.               else
  484.             { /* act_sredux hopefully */
  485.               /*
  486.                * Calculate a scale factor that will bring the
  487.                * pixel within both chroma and composite
  488.                * limits, if we scale chroma while leaving
  489.                * luminance unchanged.
  490.                *
  491.                * We have to interpolate gamma-corrected RGB
  492.                * values, so we must convert from linear to
  493.                * gamma-corrected before interpolation and then
  494.                * back to linear afterwards.
  495.                */
  496.               scale = chroma_lim / fc;
  497.               t = (compos_lim - fy) / fc;
  498.               if (t < scale)
  499.                 scale = t;
  500.  
  501.               pr = gc (pr, argp->mode);
  502.               pg = gc (pg, argp->mode);
  503.               pb = gc (pb, argp->mode);
  504.               py = pr * mode[argp->mode].code[0][0] + pg * 
  505.                 mode[argp->mode].code[0][1] + pb *
  506.                 mode[argp->mode].code[0][2];
  507.               r = pix_encode (inv_gc (py + scale * (pr - py),
  508.                           argp->mode));
  509.               g = pix_encode (inv_gc (py + scale * (pg - py),
  510.                           argp->mode));
  511.               b = pix_encode (inv_gc (py + scale * (pb - py),
  512.                           argp->mode));
  513.             }
  514.               *d++ = new_r = r;
  515.               *d++ = new_g = g;
  516.               *d++ = new_b = b;
  517.               s += 3;
  518.               if (Bpp == 4)
  519.             *d++ = *s++;
  520.               else if (argp->new_layerp)
  521.             *d++ = 255;
  522.             }
  523.         }
  524.         }
  525.       else
  526.         {
  527.           if (!argp->new_layerp)
  528.         {
  529.           for (i = 0; i < Bpp; i++)
  530.             *d++ = *s++;
  531.         } 
  532.           else
  533.         {
  534.           s += Bpp;
  535.           d += 4;
  536.         }
  537.         }
  538.     }
  539.     }
  540.   gimp_pixel_rgn_set_rect (&dstPr, dst, 0, 0, width, height);
  541.  
  542.   free (src);
  543.   free (dst);
  544.  
  545.   if (argp->new_layerp)
  546.     {
  547.       gimp_drawable_flush (ndrw);
  548.       gimp_drawable_update (nl, 0, 0, width, height);
  549.     }
  550.   else
  551.     {
  552.       gimp_drawable_flush (drw);
  553.       gimp_drawable_merge_shadow (drw->id, TRUE);
  554.       gimp_drawable_update (drw->id, 0, 0, width, height);
  555.     }
  556.  
  557.   gimp_displays_flush ();
  558.   
  559.   return retval;
  560. }
  561.  
  562. gboolean run_flag = FALSE;
  563.  
  564. static void
  565. hot_ok_callback (GtkWidget *widget,
  566.          gpointer   data)
  567. {
  568.   run_flag = TRUE;
  569.  
  570.   gtk_widget_destroy (GTK_WIDGET (data));
  571. }
  572.  
  573. static gint
  574. pluginCoreIA (struct piArgs *argp)
  575. {
  576.   GtkWidget *dlg;
  577.   GtkWidget *hbox;
  578.   GtkWidget *vbox;
  579.   GtkWidget *toggle;
  580.   GtkWidget *frame;
  581.  
  582.   gimp_ui_init ("hot", FALSE);
  583.  
  584.   dlg = gimp_dialog_new (_("Hot"), "hot",
  585.              gimp_standard_help_func, "filters/hot.html",
  586.              GTK_WIN_POS_MOUSE,
  587.              FALSE, TRUE, FALSE,
  588.  
  589.              _("OK"), hot_ok_callback,
  590.              NULL, NULL, NULL, TRUE, FALSE,
  591.              _("Cancel"), gtk_widget_destroy,
  592.              NULL, 1, NULL, FALSE, TRUE,
  593.  
  594.              NULL);
  595.  
  596.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  597.               GTK_SIGNAL_FUNC (gtk_main_quit),
  598.               NULL);
  599.  
  600.   hbox = gtk_hbox_new (FALSE, 5);
  601.   gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
  602.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), hbox, TRUE, TRUE, 0);
  603.   gtk_widget_show (hbox);
  604.  
  605.   vbox = gtk_vbox_new (FALSE, 5);
  606.   gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
  607.   gtk_widget_show (vbox);
  608.  
  609.   toggle = gtk_check_button_new_with_label (_("Create New Layer"));
  610.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), argp->new_layerp);
  611.   gtk_box_pack_start (GTK_BOX (vbox), toggle, FALSE, FALSE, 0);
  612.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  613.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  614.               &argp->new_layerp);
  615.   gtk_widget_show (toggle);
  616.  
  617.   frame = gimp_radio_group_new2 (TRUE, _("Mode"),
  618.                  gimp_radio_button_update,
  619.                  &argp->mode, (gpointer) argp->mode,
  620.  
  621.                  "NTSC", (gpointer) mode_ntsc, NULL,
  622.                  "PAL",  (gpointer) mode_pal, NULL,
  623.  
  624.                  NULL);
  625.  
  626.   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  627.   gtk_widget_show (frame);
  628.  
  629.   frame =
  630.     gimp_radio_group_new2 (TRUE, _("Action"),
  631.                gimp_radio_button_update,
  632.                &argp->action, (gpointer) argp->action,
  633.  
  634.                _("Reduce Luminance"),  (gpointer) act_lredux, NULL,
  635.                _("Reduce Saturation"), (gpointer) act_sredux, NULL,
  636.                _("Blacken"),           (gpointer) act_flag, NULL,
  637.  
  638.                NULL);
  639.  
  640.   gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
  641.   gtk_widget_show (frame);
  642.  
  643.   gtk_widget_show (dlg);
  644.  
  645.   gtk_main ();
  646.   gdk_flush ();
  647.  
  648.   if (run_flag)
  649.     return pluginCore (argp);
  650.   else
  651.     return -1;
  652. }
  653.  
  654. /*
  655.  * build_tab: Build multiply lookup table.
  656.  *
  657.  * For each possible pixel value, decode value into floating-point
  658.  * intensity.  Then do gamma correction required by the video
  659.  * standard.  Scale the result by our fixed-point scale factor.
  660.  * Then calculate 9 lookup table entries for this pixel value.
  661.  *
  662.  * We also calculate floating-point and scaled integer versions
  663.  * of our limits here.  This prevents evaluating expressions every pixel
  664.  * when the compiler is too stupid to evaluate constant-valued
  665.  * floating-point expressions at compile time.
  666.  *
  667.  * For convenience, the limits are #defined using IRE units.
  668.  * We must convert them here into the units in which YIQ
  669.  * are measured.  The conversion from IRE to internal units
  670.  * depends on the pedestal level in use, since as Y goes from
  671.  * 0 to 1, the signal goes from the pedestal level to 100 IRE.
  672.  * Chroma is always scaled to remain consistent with Y.
  673.  */
  674. static void
  675. build_tab (int m)
  676. {
  677.   register double f;
  678.   register int pv;
  679.  
  680.   for (pv = 0; pv <= MAXPIX; pv++)
  681.     {
  682.       f = (double)SCALE * (double)gc((double)pix_decode(pv),m);
  683.       tab[0][0][pv] = (int)(f * mode[m].code[0][0] + 0.5);
  684.       tab[0][1][pv] = (int)(f * mode[m].code[0][1] + 0.5);
  685.       tab[0][2][pv] = (int)(f * mode[m].code[0][2] + 0.5);
  686.       tab[1][0][pv] = (int)(f * mode[m].code[1][0] + 0.5);
  687.       tab[1][1][pv] = (int)(f * mode[m].code[1][1] + 0.5);
  688.       tab[1][2][pv] = (int)(f * mode[m].code[1][2] + 0.5);
  689.       tab[2][0][pv] = (int)(f * mode[m].code[2][0] + 0.5);
  690.       tab[2][1][pv] = (int)(f * mode[m].code[2][1] + 0.5);
  691.       tab[2][2][pv] = (int)(f * mode[m].code[2][2] + 0.5);
  692.     }
  693.  
  694.   chroma_lim = (double)CHROMA_LIM / (100.0 - mode[m].pedestal);
  695.   compos_lim = ((double)COMPOS_LIM - mode[m].pedestal) /
  696.     (100.0 - mode[m].pedestal);
  697.  
  698.   ichroma_lim2 = (int)(chroma_lim * SCALE + 0.5);
  699.   ichroma_lim2 *= ichroma_lim2;
  700.   icompos_lim = (int)(compos_lim * SCALE + 0.5);
  701. }
  702.  
  703. static int
  704. hotp (register guint8 r,
  705.       register guint8 g,
  706.       register guint8 b)
  707. {
  708.   register int    y, i, q;
  709.   register long    y2, c2;
  710.  
  711.   /*  fprintf(stderr, "\tr: %d, g: %d, b: %d\n", r, g, b);*/
  712.   
  713.   /*
  714.    * Pixel decoding, gamma correction, and matrix multiplication
  715.    * all done by lookup table.
  716.    *
  717.    * "i" and "q" are the two chrominance components;
  718.    * they are I and Q for NTSC.
  719.    * For PAL, "i" is U (scaled B-Y) and "q" is V (scaled R-Y).
  720.    * Since we only care about the length of the chroma vector,
  721.    * not its angle, we don't care which is which.
  722.    */
  723.   y = tab[0][0][r] + tab[0][1][g] + tab[0][2][b];
  724.   i = tab[1][0][r] + tab[1][1][g] + tab[1][2][b];
  725.   q = tab[2][0][r] + tab[2][1][g] + tab[2][2][b];
  726.  
  727.   /*
  728.    * Check to see if the chrominance vector is too long or the
  729.    * composite waveform amplitude is too large.
  730.    *
  731.    * Chrominance is too large if
  732.    *
  733.    *    sqrt(i^2, q^2)  >  chroma_lim.
  734.    *
  735.    * The composite signal amplitude is too large if
  736.    *
  737.    *    y + sqrt(i^2, q^2)  >  compos_lim.
  738.    *
  739.    * We avoid doing the sqrt by checking
  740.    *
  741.    *    i^2 + q^2  >  chroma_lim^2
  742.    * and
  743.    *    y + sqrt(i^2 + q^2)  >  compos_lim
  744.    *    sqrt(i^2 + q^2)  >  compos_lim - y
  745.    *    i^2 + q^2  >  (compos_lim - y)^2
  746.    *
  747.    */
  748.  
  749.   c2 = (long)i * i + (long)q * q;
  750.   y2 = (long)icompos_lim - y;
  751.   y2 *= y2;
  752.   /*  fprintf(stderr, "hotp: c2: %d; ichroma_lim2: %d; y2: %d; ",
  753.       c2, ichroma_lim2, y2);*/
  754.   
  755.   if (c2 <= ichroma_lim2 && c2 <= y2)
  756.     {    /* no problems */
  757.       /*    fprintf(stderr, "nope\n");*/
  758.       return 0;
  759.     }
  760.  
  761.   /*  fprintf(stderr, "yup\n");*/
  762.   return 1;
  763. }
  764.