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 / vpropagate.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-01  |  32.2 KB  |  1,104 lines

  1. /* vpropagate.c -- This is a plug-in for the GIMP (1.0's API)
  2.  * Author: Shuji Narazaki <narazaki@InetQ.or.jp>
  3.  * Time-stamp: <2000-01-09 15:50:46 yasuhiro>
  4.  * Version: 0.89a
  5.  *
  6.  * Copyright (C) 1996-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. /* memo
  24.    the initial value of each pixel is the value of the pixel itself.
  25.    To determine whether it is an isolated local peak point, use:
  26.    (self == min && (! modified_flag))   ; modified_flag holds history of update
  27.    In other word, pixel itself is not a neighbor of it.
  28. */
  29.  
  30. #include "config.h"
  31.  
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35.  
  36. #include <gtk/gtk.h>
  37.  
  38. #include <libgimp/gimp.h>
  39. #include <libgimp/gimpui.h>
  40.  
  41. #include "libgimp/stdplugins-intl.h"
  42.  
  43.  
  44. #define    PLUG_IN_NAME    "plug_in_vpropagate"
  45. #define SHORT_NAME    "vpropagate"
  46.  
  47. typedef guchar CH;
  48. #define    VP_RGB            (1 << 0)
  49. #define VP_GRAY            (1 << 1)
  50. #define VP_WITH_ALPHA    (1 << 2)
  51. #define VP_WO_ALPHA    (1 << 3)
  52. #define num_direction    4
  53. #define Right2Left    0
  54. #define Bottom2Top    1
  55. #define    Left2Right    2
  56. #define Top2Bottom    3
  57.  
  58. static void        query                   (void);
  59. static void        run                        (gchar         *name,
  60.                             gint           nparams,
  61.                             GimpParam        *param,   
  62.                                                 gint          *nreturn_vals,
  63.                             GimpParam      **return_vals);
  64.  
  65. static GimpPDBStatusType  value_propagate            (gint           drawable_id);
  66. static void         value_propagate_body       (gint           drawable_id);
  67. static int        vpropagate_dialog          (GimpImageBaseType     image_type);
  68. static void        prepare_row                (GimpPixelRgn     *pixel_rgn,
  69.                         guchar        *data,
  70.                         int            x,
  71.                         int            y,
  72.                         int            w);
  73.  
  74. static void         vpropagate_ok_callback     (GtkWidget     *widget,
  75.                         gpointer       data);
  76. static GtkWidget *  gtk_table_add_toggle       (GtkWidget     *table,
  77.                         gchar          *name,
  78.                         gint           x1,
  79.                         gint           x2,
  80.                         gint           y,
  81.                         GtkSignalFunc  update,
  82.                         gint          *value);
  83.  
  84. static int        value_difference_check  (CH *, CH *, int);
  85. static void         set_value               (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  86. static void        initialize_white        (GimpImageBaseType, int, CH *, CH *, void **);
  87. static void        propagate_white         (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  88. static void        initialize_black        (GimpImageBaseType, int, CH *, CH *, void **);
  89. static void         propagate_black         (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  90. static void        initialize_middle       (GimpImageBaseType, int, CH *, CH *, void **);
  91. static void        propagate_middle        (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  92. static void        set_middle_to_peak      (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  93. static void        set_foreground_to_peak  (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  94. static void        initialize_foreground   (GimpImageBaseType, int, CH *, CH *, void **);
  95. static void        initialize_background   (GimpImageBaseType, int, CH *, CH *, void **);
  96. static void        propagate_a_color       (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  97. static void        propagate_opaque        (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  98. static void        propagate_transparent   (GimpImageBaseType, int, CH *, CH *, CH *, void *);
  99.  
  100. GimpPlugInInfo PLUG_IN_INFO =
  101. {
  102.   NULL,  /* init_proc  */
  103.   NULL,  /* quit_proc  */
  104.   query, /* query_proc */
  105.   run,   /* run_proc   */
  106. };
  107.  
  108. #define UPDATE_STEP        20
  109. #define SCALE_WIDTH       100
  110. #define PROPAGATING_VALUE  1<<0
  111. #define PROPAGATING_ALPHA  1<<1
  112.  
  113. /* parameters */
  114. typedef struct
  115. {
  116.   gint        propagate_mode;
  117.   gint        propagating_channel;
  118.   gdouble    propagating_rate;
  119.   gint        direction_mask;
  120.   gint        lower_limit;
  121.   gint        upper_limit;
  122.   /* gint    channel_mask[3]; */
  123.   /* gint    peak_includes_equals; */
  124.   /* gint    overwrite; */
  125. } VPValueType;
  126.  
  127. static VPValueType vpvals = 
  128. {
  129.   0,
  130.   3,                /* PROPAGATING_VALUE + PROPAGATING_ALPHA */
  131.   1.0,                /* [0.0:1.0] */
  132.   15,                /* propagate to all 4 directions */
  133.   0,
  134.   255
  135. };
  136.  
  137. /* dialog vairables */
  138. static gint    propagate_alpha;
  139. static gint    propagate_value;
  140. static gint    direction_mask_vec[4];
  141. static gint    channel_mask[] = { 1, 1, 1 };
  142. static gint    peak_max = 1;
  143. static gint    peak_min = 1;
  144. static gint    peak_includes_equals = 1;
  145. static guchar    fore[3];
  146.  
  147. typedef struct
  148. {
  149.   gint    applicable_image_type;
  150.   gchar  *name;
  151.   void  (*initializer) ();
  152.   void  (*updater) ();
  153.   void  (*finalizer) ();
  154. } ModeParam;
  155.  
  156. #define num_mode 8
  157. static ModeParam modes[num_mode] = 
  158. {
  159.   { VP_RGB | VP_GRAY | VP_WITH_ALPHA | VP_WO_ALPHA,
  160.     N_("More White (Larger Value)"),
  161.     initialize_white,      propagate_white,       set_value },
  162.   { VP_RGB | VP_GRAY | VP_WITH_ALPHA | VP_WO_ALPHA,
  163.     N_("More Black (Smaller Value)"),
  164.     initialize_black,      propagate_black,       set_value },
  165.   { VP_RGB | VP_GRAY | VP_WITH_ALPHA | VP_WO_ALPHA,
  166.     N_("Middle Value to Peaks"),
  167.     initialize_middle,     propagate_middle,      set_middle_to_peak },
  168.   { VP_RGB | VP_GRAY | VP_WITH_ALPHA | VP_WO_ALPHA,
  169.     N_("Foreground to Peaks"),
  170.     initialize_middle,     propagate_middle,      set_foreground_to_peak },
  171.   { VP_RGB | VP_WITH_ALPHA | VP_WO_ALPHA,
  172.     N_("Only Foreground"),
  173.     initialize_foreground, propagate_a_color,     set_value },
  174.   { VP_RGB | VP_WITH_ALPHA | VP_WO_ALPHA,
  175.     N_("Only Background"),
  176.     initialize_background, propagate_a_color,     set_value },
  177.   { VP_RGB | VP_GRAY | VP_WITH_ALPHA,
  178.     N_("More Opaque"),
  179.     NULL,                  propagate_opaque,      set_value },
  180.   { VP_RGB | VP_GRAY | VP_WITH_ALPHA,
  181.     N_("More Transparent"),
  182.     NULL,                  propagate_transparent, set_value },
  183. };
  184.  
  185. typedef struct 
  186. {
  187.   gint run;
  188. } VPInterface;
  189.  
  190. static VPInterface vpropagate_interface = { FALSE };
  191. static gint       drawable_id;
  192.  
  193. MAIN ()
  194.  
  195. static void
  196. query (void)
  197. {
  198.   static GimpParamDef args[] =
  199.   {
  200.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  201.     { GIMP_PDB_IMAGE, "image", "Input image (not used)" },
  202.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
  203.     { GIMP_PDB_INT32, "propagate-mode", "propagate 0:white, 1:black, 2:middle value 3:foreground to peak, 4:foreground, 5:background, 6:opaque, 7:transparent" },
  204.     { GIMP_PDB_INT32, "propagating-channel", "channels which values are propagated" },
  205.     { GIMP_PDB_FLOAT, "propagating-rate", "0.0 <= propagatating_rate <= 1.0" },
  206.     { GIMP_PDB_INT32, "direction-mask", "0 <= direction-mask <= 15" },
  207.     { GIMP_PDB_INT32, "lower-limit", "0 <= lower-limit <= 255" },
  208.     { GIMP_PDB_INT32, "upper-limit", "0 <= upper-limit <= 255" }
  209.   };
  210.   static gint nargs = sizeof (args) / sizeof (args[0]);
  211.  
  212.   gimp_install_procedure (PLUG_IN_NAME,
  213.               "Propagate values of the layer",
  214.               "Propagate values of the layer",
  215.               "Shuji Narazaki (narazaki@InetQ.or.jp)",
  216.               "Shuji Narazaki",
  217.               "1996-1997",
  218.               N_("<Image>/Filters/Distorts/Value Propagate..."),
  219.               "RGB*,GRAY*",
  220.               GIMP_PLUGIN,
  221.               nargs, 0,
  222.               args, NULL);
  223. }
  224.  
  225. static void
  226. run (gchar   *name,
  227.      gint     nparams,
  228.      GimpParam  *param,
  229.      gint    *nreturn_vals,
  230.      GimpParam **return_vals)
  231. {
  232.   static GimpParam     values[1];
  233.   GimpPDBStatusType    status = GIMP_PDB_SUCCESS;
  234.   GimpRunModeType    run_mode;
  235.   
  236.   run_mode = param[0].data.d_int32;
  237.   drawable_id = param[2].data.d_int32;
  238.  
  239.   *nreturn_vals = 1;
  240.   *return_vals = values;
  241.   
  242.   values[0].type = GIMP_PDB_STATUS;
  243.   values[0].data.d_status = status;
  244.  
  245.   switch (run_mode)
  246.     {
  247.     case GIMP_RUN_INTERACTIVE:
  248.       INIT_I18N_UI();
  249.       gimp_get_data (PLUG_IN_NAME, &vpvals);
  250.       /* building the values of dialog variables from vpvals. */
  251.       propagate_alpha =
  252.     (vpvals.propagating_channel & PROPAGATING_ALPHA) ? TRUE : FALSE;
  253.       propagate_value =
  254.     (vpvals.propagating_channel & PROPAGATING_VALUE) ? TRUE : FALSE;
  255.       {
  256.     int    i;
  257.     for (i = 0; i < 4; i++)
  258.       direction_mask_vec[i] = (vpvals.direction_mask & (1 << i))
  259.         ? TRUE : FALSE;
  260.       }
  261.       if (! vpropagate_dialog (gimp_drawable_type(drawable_id)))
  262.     return;
  263.       break;
  264.     case GIMP_RUN_NONINTERACTIVE:
  265.       INIT_I18N();
  266.       vpvals.propagate_mode = param[3].data.d_int32;
  267.       vpvals.propagating_channel = param[4].data.d_int32;
  268.       vpvals.propagating_rate = param[5].data.d_float;
  269.       vpvals.direction_mask = param[6].data.d_int32;
  270.       vpvals.lower_limit = param[7].data.d_int32;
  271.       vpvals.upper_limit = param[8].data.d_int32;
  272.       break;
  273.     case GIMP_RUN_WITH_LAST_VALS:
  274.       INIT_I18N();
  275.       gimp_get_data (PLUG_IN_NAME, &vpvals);
  276.       break;
  277.     }
  278.   
  279.   status = value_propagate (drawable_id);
  280.  
  281.   if (run_mode != GIMP_RUN_NONINTERACTIVE)
  282.     gimp_displays_flush();
  283.   if (run_mode == GIMP_RUN_INTERACTIVE && status == GIMP_PDB_SUCCESS)
  284.     gimp_set_data (PLUG_IN_NAME, &vpvals, sizeof (VPValueType));
  285.  
  286.   values[0].type = GIMP_PDB_STATUS;
  287.   values[0].data.d_status = status;
  288. }
  289.  
  290. /* registered function entry */
  291. static GimpPDBStatusType
  292. value_propagate (gint drawable_id)
  293. {
  294.   /* check the validness of parameters */
  295.   if (!(vpvals.propagating_channel & (PROPAGATING_VALUE | PROPAGATING_ALPHA)))
  296.     {
  297.       /* gimp_message ("No channel selected."); */
  298.       return GIMP_PDB_EXECUTION_ERROR;
  299.     }
  300.   if (vpvals.direction_mask == 0)
  301.     {
  302.       /* gimp_message ("No direction selected."); */
  303.       return GIMP_PDB_EXECUTION_ERROR;
  304.     }
  305.   if ((vpvals.lower_limit < 0) || (255 < vpvals.lower_limit) ||
  306.        (vpvals.upper_limit < 0) || (255 < vpvals.lower_limit) ||
  307.        (vpvals.upper_limit < vpvals.lower_limit))
  308.     {
  309.       /* gimp_message ("Limit values are not valid."); */
  310.       return GIMP_PDB_EXECUTION_ERROR;
  311.     }
  312.   value_propagate_body (drawable_id);
  313.   return GIMP_PDB_SUCCESS;
  314. }
  315.  
  316. static void
  317. value_propagate_body (gint drawable_id)
  318. {
  319.   GimpDrawable  *drawable;
  320.   GimpImageBaseType  dtype;
  321.   ModeParam   operation;
  322.   GimpPixelRgn   srcRgn, destRgn;
  323.   guchar     *here, *best, *dest;
  324.   guchar     *dest_row, *prev_row, *cur_row, *next_row, *pr, *cr, *nr, *swap;
  325.   gint        width, height, bytes, index;
  326.   gint        begx, begy, endx, endy, x, y, dx;
  327.   gint        left_index, right_index, up_index, down_index;
  328.   void       *tmp;
  329.  
  330.   /* calculate neighbors' indexes */
  331.   left_index    = (vpvals.direction_mask & (1 << Left2Right)) ? -1 : 0;
  332.   right_index    = (vpvals.direction_mask & (1 << Right2Left)) ?  1 : 0;
  333.   up_index    = (vpvals.direction_mask & (1 << Top2Bottom)) ? -1 : 0;
  334.   down_index    = (vpvals.direction_mask & (1 << Bottom2Top)) ?  1 : 0;
  335.   operation = modes[vpvals.propagate_mode];
  336.   tmp = NULL;
  337.  
  338.   drawable = gimp_drawable_get (drawable_id);
  339.   dtype = gimp_drawable_type (drawable_id);
  340.  
  341.   /* Here I use the algorithm of blur.c . */
  342.   gimp_drawable_mask_bounds (drawable->id, &begx, &begy, &endx, &endy);
  343.  
  344.   width = drawable->width;
  345.   height = drawable->height;
  346.   bytes = drawable->bpp;
  347.  
  348.   prev_row = g_new (guchar, (endx - begx + 2) * bytes);
  349.   cur_row  = g_new (guchar, (endx - begx + 2) * bytes);
  350.   next_row = g_new (guchar, (endx - begx + 2) * bytes);
  351.   dest_row = g_new (guchar, (endx - begx) * bytes);
  352.  
  353.   gimp_pixel_rgn_init (&srcRgn, drawable, 0, 0, width, height, FALSE, FALSE);
  354.   gimp_pixel_rgn_init (&destRgn, drawable, 0, 0, width, height, TRUE, TRUE);
  355.  
  356.   pr = prev_row + bytes;
  357.   cr = cur_row + bytes;
  358.   nr = next_row + bytes;
  359.  
  360.   prepare_row (&srcRgn, pr, begx, (0 < begy) ? begy : begy - 1, endx-begx);
  361.   prepare_row (&srcRgn, cr, begx, begy, endx-begx);
  362.  
  363.   best = g_new (guchar, bytes);
  364.  
  365.   gimp_progress_init (_("Value propagating..."));
  366.   gimp_palette_get_foreground (fore+0, fore+1, fore+2);
  367.  
  368.   /* start real job */
  369.   for (y = begy ; y < endy ; y++) 
  370.     {
  371.       prepare_row (&srcRgn, nr, begx, ((y+1) < endy) ? y+1 : endy, endx-begx);
  372.       for (index = 0; index < (endx - begx) * bytes; index++)
  373.     dest_row[index] = cr[index];
  374.       for (x = 0 ; x < endx - begx; x++) 
  375.     {
  376.       dest = dest_row + (x * bytes);
  377.       here = cr + (x * bytes);
  378.       /* *** copy source value to best value holder *** */
  379.       memcpy ((void *)best, (void *)here, bytes);
  380.       if (operation.initializer)
  381.         (* operation.initializer)(dtype, bytes, best, here, &tmp);
  382.       /* *** gather neighbors' values: loop-unfolded version *** */
  383.       if (up_index == -1)
  384.         for (dx = left_index ; dx <= right_index ; dx++)
  385.           (* operation.updater)(dtype, bytes, here, pr+((x+dx)*bytes), best, tmp);
  386.       for (dx = left_index ; dx <= right_index ; dx++)
  387.         if (dx != 0)
  388.           (* operation.updater)(dtype, bytes, here, cr+((x+dx)*bytes), best, tmp);
  389.       if (down_index == 1)
  390.         for (dx = left_index ; dx <= right_index ; dx++)
  391.           (* operation.updater)(dtype, bytes, here, nr+((x+dx)*bytes), best, tmp);
  392.       /* *** store it to dest_row*** */
  393.       (* operation.finalizer)(dtype, bytes, best, here, dest, tmp);
  394.     }
  395.       /* now store destline to destRgn */
  396.       gimp_pixel_rgn_set_row (&destRgn, dest_row, begx, y, endx - begx);
  397.       /* shift the row pointers  */
  398.       swap = pr;
  399.       pr = cr;
  400.       cr = nr;
  401.       nr = swap;
  402.       /* update each UPDATE_STEP (optimizer must generate cheap code) */ 
  403.       if ((y % 5) == 0) /*(y % (int) ((endy - begy) / UPDATE_STEP)) == 0 */
  404.     gimp_progress_update ((double)y / (double)(endy - begy));
  405.     }
  406.   /*  update the region  */
  407.   gimp_progress_update(1.0);
  408.   gimp_drawable_flush (drawable);
  409.   gimp_drawable_merge_shadow (drawable->id, TRUE);
  410.   gimp_drawable_update (drawable->id, begx, begy, endx-begx, endy-begy);
  411. }
  412.  
  413. static void
  414. prepare_row (GimpPixelRgn *pixel_rgn,
  415.          guchar    *data,
  416.          gint       x,
  417.          gint       y,
  418.          gint       w)
  419. {
  420.   gint b;
  421.  
  422.   if (y == 0)
  423.     gimp_pixel_rgn_get_row (pixel_rgn, data, x, (y + 1), w);
  424.   else if (y == pixel_rgn->h)
  425.     gimp_pixel_rgn_get_row (pixel_rgn, data, x, (y - 1), w);
  426.   else
  427.     gimp_pixel_rgn_get_row (pixel_rgn, data, x, y, w);
  428.  
  429.   /*  Fill in edge pixels  */
  430.   for (b = 0; b < pixel_rgn->bpp; b++)
  431.     {
  432.       data[-(gint)pixel_rgn->bpp + b] = data[b];
  433.       data[w * pixel_rgn->bpp + b] = data[(w - 1) * pixel_rgn->bpp + b];
  434.     }
  435. }
  436.  
  437. static void
  438. set_value (GimpImageBaseType  dtype, 
  439.        gint        bytes, 
  440.        guchar     *best, 
  441.        guchar     *here, 
  442.        guchar     *dest, 
  443.        void       *tmp)
  444. {
  445.   gint    value_chs = 0;
  446.   gint    alpha = 0;
  447.   gint    ch;
  448.  
  449.   switch (dtype)
  450.     {
  451.     case GIMP_RGB_IMAGE:
  452.       value_chs = 3;
  453.       break;
  454.     case GIMP_RGBA_IMAGE:
  455.       value_chs = 3;
  456.       alpha = 3;
  457.       break;
  458.     case GIMP_GRAY_IMAGE:
  459.       value_chs = 1;
  460.       break;
  461.     case GIMP_GRAYA_IMAGE:
  462.       value_chs = 1;
  463.       alpha = 1;
  464.       break;
  465.     default:
  466.       break;
  467.     }
  468.   for (ch = 0; ch < value_chs; ch++)
  469.     {
  470.       if (vpvals.propagating_channel & PROPAGATING_VALUE) /* value channel */
  471.     *dest++ = (CH)(vpvals.propagating_rate * best[ch]
  472.                + (1.0 - vpvals.propagating_rate) * here[ch]);
  473.       else
  474.     *dest++ = here[ch];
  475.     }
  476.   if (alpha)
  477.     {
  478.       if (vpvals.propagating_channel & PROPAGATING_ALPHA) /* alpha channel */
  479.     *dest++ = (CH)(vpvals.propagating_rate * best[alpha]
  480.                + (1.0 - vpvals.propagating_rate) * here[alpha]);
  481.       else
  482.     *dest++ = here[alpha];
  483.     }
  484. }
  485.  
  486. static int
  487. value_difference_check (CH  *pos1, 
  488.             CH  *pos2, 
  489.             gint ch)
  490. {
  491.   gint    index;
  492.   int    diff;
  493.  
  494.   for (index = 0 ; index < ch; index++)
  495.     if (channel_mask[index] != 0)
  496.       {
  497.     diff = abs(pos1[index] - pos2[index]);
  498.     if (! ((vpvals.lower_limit <= diff) && (diff <= vpvals.upper_limit)))
  499.       return 0;
  500.       }
  501.   return 1;
  502. }
  503.  
  504. /* mothods for each mode */
  505. static void
  506. initialize_white (GimpImageBaseType   dtype, 
  507.           gint         bytes, 
  508.           CH          *best, 
  509.           CH          *here, 
  510.           void       **tmp)
  511. {
  512.   if (*tmp == NULL)
  513.     *tmp = (void *) g_new (gfloat, 1);
  514.   *(float *)*tmp = sqrt (channel_mask[0] * here[0] * here[0] 
  515.              + channel_mask[1] * here[1] * here[1] 
  516.              + channel_mask[2] * here[2] * here[2]);
  517. }
  518.  
  519. static void
  520. propagate_white (GimpImageBaseType  dtype, 
  521.          gint        bytes, 
  522.          CH         *orig, 
  523.          CH         *here, 
  524.          CH         *best, 
  525.          void       *tmp)
  526. {
  527.   float    v_here;
  528.  
  529.   switch (dtype)
  530.     {
  531.     case GIMP_RGB_IMAGE:
  532.     case GIMP_RGBA_IMAGE:
  533.       v_here = sqrt (channel_mask[0] * here[0] * here[0] 
  534.              + channel_mask[1] * here[1] * here[1] 
  535.              + channel_mask[2] * here[2] * here[2]);
  536.      if (*(float *)tmp < v_here && value_difference_check(orig, here, 3))
  537.     {
  538.       *(float *)tmp = v_here;
  539.       memcpy(best, here, 3 * sizeof(CH)); /* alpha channel holds old value */
  540.     }
  541.       break;
  542.     case GIMP_GRAYA_IMAGE:
  543.     case GIMP_GRAY_IMAGE:
  544.       if (*best < *here && value_difference_check(orig, here, 1))
  545.     *best = *here;
  546.       break;
  547.     default:
  548.       break;
  549.     }
  550. }
  551.  
  552. static void
  553. initialize_black (GimpImageBaseType   dtype, 
  554.           gint         channels, 
  555.           CH          *best, 
  556.           CH          *here, 
  557.           void       **tmp)
  558. {
  559.   if (*tmp == NULL)
  560.     *tmp = (void *) g_new (gfloat, 1);
  561.   *(float *)*tmp = sqrt (channel_mask[0] * here[0] * here[0] 
  562.              + channel_mask[1] * here[1] * here[1] 
  563.              + channel_mask[2] * here[2] * here[2]);
  564. }
  565.  
  566. static void
  567. propagate_black (GimpImageBaseType  image_type, 
  568.          gint        channels, 
  569.          CH         *orig, 
  570.          CH         *here, 
  571.          CH         *best, 
  572.          void       *tmp)
  573. {
  574.   float    v_here;
  575.  
  576.   switch (image_type)
  577.     {
  578.     case GIMP_RGB_IMAGE:
  579.     case GIMP_RGBA_IMAGE:
  580.       v_here = sqrt (channel_mask[0] * here[0] * here[0] 
  581.              + channel_mask[1] * here[1] * here[1] 
  582.              + channel_mask[2] * here[2] * here[2]);
  583.       if (v_here < *(float *)tmp && value_difference_check(orig, here, 3))
  584.     {    
  585.       *(float *)tmp = v_here;
  586.       memcpy (best, here, 3 * sizeof(CH)); /* alpha channel holds old value */
  587.     }
  588.       break;
  589.     case GIMP_GRAYA_IMAGE:
  590.     case GIMP_GRAY_IMAGE:
  591.       if (*here < *best && value_difference_check(orig, here, 1))
  592.     *best = *here;
  593.       break;
  594.     default:
  595.       break;
  596.     }
  597. }
  598.  
  599. typedef struct
  600. {
  601.   gshort min_modified;
  602.   gshort max_modified;
  603.   glong  original_value;
  604.   glong  minv;
  605.   CH     min[3];
  606.   glong  maxv;
  607.   CH     max[3];
  608. } MiddlePacket;
  609.  
  610. static void
  611. initialize_middle (GimpImageBaseType   image_type, 
  612.            gint         channels, 
  613.            CH          *best, 
  614.            CH          *here, 
  615.            void       **tmp)
  616. {
  617.   int index;
  618.   MiddlePacket *data;
  619.  
  620.   if (*tmp == NULL)
  621.     *tmp = (void *) g_new (MiddlePacket, 1);
  622.   data = (MiddlePacket *)*tmp;
  623.   for (index = 0; index < channels; index++)
  624.     data->min[index] = data->max[index] = here[index];
  625.   switch (image_type)
  626.     {
  627.     case GIMP_RGB_IMAGE:
  628.     case GIMP_RGBA_IMAGE:
  629.       data->original_value = sqrt (channel_mask[0] * here[0] * here[0]
  630.                    + channel_mask[1] * here[1] * here[1] 
  631.                    + channel_mask[2] * here[2] * here[2]);
  632.       break;
  633.     case GIMP_GRAYA_IMAGE:
  634.     case GIMP_GRAY_IMAGE:
  635.       data->original_value = *here;
  636.       break;
  637.     default:
  638.       break;
  639.     }
  640.   data->minv = data->maxv = data->original_value;
  641.   data->min_modified = data->max_modified = 0;
  642. }
  643.   
  644. static void
  645. propagate_middle (GimpImageBaseType  image_type, 
  646.           gint        channels, 
  647.           CH         *orig, 
  648.           CH         *here, 
  649.           CH         *best, 
  650.           void       *tmp)
  651. {
  652.   float    v_here;
  653.   MiddlePacket *data;
  654.  
  655.   data = (MiddlePacket *)tmp;
  656.  
  657.   switch (image_type)
  658.     {
  659.     case GIMP_RGB_IMAGE:
  660.     case GIMP_RGBA_IMAGE:
  661.       v_here = sqrt (channel_mask[0] * here[0] * here[0] 
  662.              + channel_mask[1] * here[1] * here[1] 
  663.              + channel_mask[2] * here[2] * here[2]);
  664.       if ((v_here <= data->minv) && value_difference_check(orig, here, 3))
  665.     {    
  666.       data->minv = v_here;
  667.       memcpy (data->min, here, 3*sizeof(CH));
  668.       data->min_modified = 1;
  669.     }
  670.       if (data->maxv <= v_here && value_difference_check(orig, here, 3))
  671.     {    
  672.       data->maxv = v_here;
  673.       memcpy (data->max, here, 3*sizeof(CH));
  674.       data->max_modified = 1;
  675.     }
  676.       break;
  677.     case GIMP_GRAYA_IMAGE:
  678.     case GIMP_GRAY_IMAGE:
  679.       if ((*here <= data->min[0]) && value_difference_check(orig, here, 1))
  680.     {
  681.       data->min[0] = *here;
  682.       data->min_modified = 1;
  683.     }
  684.       if ((data->max[0] <= *here) && value_difference_check(orig, here, 1))
  685.     {
  686.       data->max[0] = *here;
  687.       data->max_modified = 1;
  688.     }
  689.       break;
  690.     default:
  691.       break;
  692.     }
  693. }
  694.  
  695. static void
  696. set_middle_to_peak (GimpImageBaseType  image_type, 
  697.             gint        channels, 
  698.             CH         *here, 
  699.             CH         *best, 
  700.             CH         *dest, 
  701.             void       *tmp)
  702. {
  703.   gint    value_chs = 0;
  704.   gint    alpha = 0;
  705.   gint    ch;
  706.   MiddlePacket    *data;
  707.  
  708.   data = (MiddlePacket *)tmp;
  709.   if (! ((peak_min & (data->minv == data->original_value))
  710.      || (peak_max & (data->maxv == data->original_value))))
  711.     return;
  712.   if ((! peak_includes_equals)
  713.       && ((peak_min & (! data->min_modified))
  714.       || (peak_max & (! data->max_modified))))
  715.       return;
  716.  
  717.   switch (image_type)
  718.     {
  719.     case GIMP_RGB_IMAGE:
  720.       value_chs = 3;
  721.       break;
  722.     case GIMP_RGBA_IMAGE:
  723.       value_chs = 3;
  724.       alpha = 3;
  725.       break;
  726.     case GIMP_GRAY_IMAGE:
  727.       value_chs = 1;
  728.       break;
  729.     case GIMP_GRAYA_IMAGE:
  730.       value_chs = 1;
  731.       alpha = 1;
  732.       break;
  733.     default:
  734.       break;
  735.     }
  736.   for (ch = 0; ch < value_chs; ch++)
  737.     {
  738.       if (vpvals.propagating_channel & PROPAGATING_VALUE) /* value channel */
  739.     *dest++ = (CH)(vpvals.propagating_rate * 0.5 * (data->min[ch] + data->max[ch])
  740.                + (1.0 - vpvals.propagating_rate) * here[ch]);
  741.       else
  742.     *dest++ = here[ch];
  743.     }
  744.   if (alpha)
  745.     {
  746.       if (vpvals.propagating_channel & PROPAGATING_ALPHA) /* alpha channel */
  747.     *dest++ = (CH)(vpvals.propagating_rate * best[alpha]
  748.                + (1.0 - vpvals.propagating_rate) * here[alpha]);
  749.       else
  750.     *dest++ = here[alpha];
  751.     }
  752. }
  753.  
  754. static void
  755. set_foreground_to_peak (GimpImageBaseType  image_type, 
  756.             gint        channels, 
  757.             CH         *here, 
  758.             CH         *best, 
  759.             CH         *dest, 
  760.             void       *tmp)
  761. {
  762.   gint    value_chs = 0;
  763.   gint    alpha = 0;
  764.   gint    ch;
  765.   MiddlePacket    *data;
  766.  
  767.   data = (MiddlePacket *)tmp;
  768.   if (! ((peak_min & (data->minv == data->original_value))
  769.      || (peak_max & (data->maxv == data->original_value))))
  770.     return;
  771.   if (peak_includes_equals
  772.       && ((peak_min & (! data->min_modified))
  773.       || (peak_max & (! data->max_modified))))
  774.       return;
  775.  
  776.   switch (image_type)
  777.     {
  778.     case GIMP_RGB_IMAGE:
  779.       value_chs = 3;
  780.       break;
  781.     case GIMP_RGBA_IMAGE:
  782.       value_chs = 3;
  783.       alpha = 3;
  784.       break;
  785.     case GIMP_GRAY_IMAGE:
  786.       value_chs = 1;
  787.       break;
  788.     case GIMP_GRAYA_IMAGE:
  789.       value_chs = 1;
  790.       alpha = 1;
  791.       break;
  792.     default:
  793.       break;
  794.     }
  795.   for (ch = 0; ch < value_chs; ch++)
  796.     {
  797.       if (vpvals.propagating_channel & PROPAGATING_VALUE) /* value channel */
  798.     *dest++ = (CH)(vpvals.propagating_rate*fore[ch]
  799.                + (1.0 - vpvals.propagating_rate)*here[ch]);
  800.       else
  801.     *dest++ = here[ch];
  802.     }
  803. }
  804.  
  805. static void
  806. initialize_foreground (GimpImageBaseType   image_type, 
  807.                gint         channels, 
  808.                CH          *here, 
  809.                CH          *best, 
  810.                void       **tmp)
  811. {
  812.   CH *ch;
  813.  
  814.   if (*tmp == NULL)
  815.     {
  816.       *tmp = (void *) g_new (CH, 3);
  817.       ch = (CH *)*tmp;
  818.       gimp_palette_get_foreground (&ch[0], &ch[1], &ch[2]);
  819.     }
  820. }
  821.  
  822. static void
  823. initialize_background (GimpImageBaseType   image_type, 
  824.                gint         channels, 
  825.                CH          *here, 
  826.                CH          *best, 
  827.                void       **tmp)
  828. {
  829.   CH *ch;
  830.  
  831.   if (*tmp == NULL)
  832.     {
  833.       *tmp = (void *) g_new (CH, 3);
  834.       ch = (CH *)*tmp;
  835.       gimp_palette_get_background (&ch[0], &ch[1], &ch[2]);
  836.     }
  837. }
  838.  
  839. static void
  840. propagate_a_color (GimpImageBaseType  image_type, 
  841.            gint        channels, 
  842.            CH         *orig, 
  843.            CH         *here, 
  844.            CH         *best, 
  845.            void       *tmp)
  846. {
  847.   CH *fg = (CH *)tmp;
  848.  
  849.   switch (image_type)
  850.     {
  851.     case GIMP_RGB_IMAGE:
  852.     case GIMP_RGBA_IMAGE:
  853.       if (here[0] == fg[0] && here[1] == fg[1] && here[2] == fg[2] &&
  854.       value_difference_check(orig, here, 3))
  855.     {
  856.       memcpy (best, here, 3 * sizeof(CH)); /* alpha channel holds old value */
  857.     }
  858.       break;
  859.     case GIMP_GRAYA_IMAGE:
  860.     case GIMP_GRAY_IMAGE:
  861.       break;
  862.     default:
  863.       break;
  864.     }
  865. }
  866.  
  867. static void
  868. propagate_opaque (GimpImageBaseType  image_type, 
  869.           gint        channels, 
  870.           CH         *orig, 
  871.           CH         *here, 
  872.           CH         *best, 
  873.           void       *tmp)
  874. {
  875.   switch (image_type)
  876.     {
  877.     case GIMP_RGBA_IMAGE:
  878.       if (best[3] < here[3] && value_difference_check(orig, here, 3))
  879.     memcpy(best, here, channels * sizeof(CH));
  880.       break;
  881.     case GIMP_GRAYA_IMAGE:
  882.       if (best[1] < here[1] && value_difference_check(orig, here, 1))
  883.     memcpy(best, here, channels * sizeof(CH));
  884.       break;
  885.     default:
  886.       break;
  887.     }
  888. }
  889.  
  890. static void
  891. propagate_transparent (GimpImageBaseType  image_type, 
  892.                gint        channels, 
  893.                CH         *orig, 
  894.                CH         *here, 
  895.                CH         *best, 
  896.                void       *tmp)
  897. {
  898.   switch (image_type)
  899.     {
  900.     case GIMP_RGBA_IMAGE:
  901.       if (here[3] < best[3] && value_difference_check(orig, here, 3))
  902.     memcpy(best, here, channels * sizeof(CH));
  903.       break;
  904.     case GIMP_GRAYA_IMAGE:
  905.       if (here[1] < best[1] && value_difference_check(orig, here, 1))
  906.     memcpy(best, here, channels * sizeof(CH));
  907.       break;
  908.     default:
  909.       break;
  910.     }
  911. }
  912.  
  913. /* dialog stuff */
  914.  
  915. static int
  916. vpropagate_dialog (GimpImageBaseType image_type)
  917. {
  918.   GtkWidget *dlg;
  919.   GtkWidget *hbox;
  920.   GtkWidget *frame;
  921.   GtkWidget *table;
  922.   GtkWidget *toggle_vbox;
  923.   GtkWidget *button;
  924.   GtkWidget *sep;
  925.   GtkObject *adj;
  926.   GSList *group = NULL;
  927.   gint      index = 0;
  928.  
  929.   gimp_ui_init ("vpropagate", FALSE);
  930.  
  931.   dlg = gimp_dialog_new (_("Value Propagate"), "vpropagate",
  932.              gimp_standard_help_func, "filters/vpropagate.html",
  933.              GTK_WIN_POS_MOUSE,
  934.              FALSE, TRUE, FALSE,
  935.              _("OK"), vpropagate_ok_callback,
  936.              NULL, NULL, NULL, TRUE, FALSE,
  937.              _("Cancel"), gtk_widget_destroy,
  938.              NULL, 1, NULL, FALSE, TRUE,
  939.              NULL);
  940.  
  941.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  942.               GTK_SIGNAL_FUNC (gtk_main_quit),
  943.               NULL);
  944.  
  945.   hbox = gtk_hbox_new (FALSE, 4);
  946.   gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
  947.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), hbox, FALSE, FALSE, 0);
  948.   gtk_widget_show (hbox);
  949.  
  950.   /* Propagate Mode */
  951.   frame = gtk_frame_new (_("Propagate Mode"));
  952.   gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
  953.  
  954.   toggle_vbox = gtk_vbox_new (FALSE, 1);
  955.   gtk_container_set_border_width (GTK_CONTAINER (toggle_vbox), 2);
  956.   gtk_container_add (GTK_CONTAINER (frame), toggle_vbox);
  957.     
  958.   for (index = 0; index < num_mode; index++)
  959.     {
  960.       button = gtk_radio_button_new_with_label (group,
  961.                         gettext (modes[index].name));
  962.       group = gtk_radio_button_group (GTK_RADIO_BUTTON (button));
  963.       gtk_box_pack_start (GTK_BOX (toggle_vbox), button, FALSE, FALSE, 0);
  964.       gtk_object_set_user_data (GTK_OBJECT (button), (gpointer) index);
  965.       gtk_signal_connect (GTK_OBJECT (button), "toggled",
  966.               GTK_SIGNAL_FUNC (gimp_radio_button_update),
  967.               &vpvals.propagate_mode);
  968.       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
  969.                     index == vpvals.propagate_mode);
  970.       gtk_widget_show (button);
  971.     }
  972.  
  973.   gtk_widget_show (toggle_vbox);
  974.   gtk_widget_show (frame);
  975.  
  976.   /* Parameter settings */
  977.   frame = gtk_frame_new (_("Parameter Settings"));
  978.   gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
  979.  
  980.   table = gtk_table_new (10, 3, FALSE); /* 4 raw, 2 columns(name and value) */
  981.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  982.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  983.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  984.   gtk_container_add (GTK_CONTAINER (frame), table);
  985.  
  986.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
  987.                   _("Lower Threshold:"), SCALE_WIDTH, 0,
  988.                   vpvals.lower_limit, 0, 255, 1, 8, 0,
  989.                   TRUE, 0, 0,
  990.                   NULL, NULL);
  991.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  992.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  993.               &vpvals.lower_limit);
  994.  
  995.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  996.                   _("Upper Threshold:"), SCALE_WIDTH, 0,
  997.                   vpvals.upper_limit, 0, 255, 1, 8, 0,
  998.                   TRUE, 0, 0,
  999.                   NULL, NULL);
  1000.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1001.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  1002.               &vpvals.upper_limit);
  1003.  
  1004.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
  1005.                   _("Propagating Rate:"), SCALE_WIDTH, 0,
  1006.                   vpvals.propagating_rate, 0, 1, 0.01, 0.1, 2,
  1007.                   TRUE, 0, 0,
  1008.                   NULL, NULL);
  1009.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  1010.               GTK_SIGNAL_FUNC (gimp_double_adjustment_update),
  1011.               &vpvals.propagating_rate);
  1012.  
  1013.   sep = gtk_hseparator_new ();
  1014.   gtk_table_attach (GTK_TABLE (table), sep, 0, 3, 3, 4, GTK_FILL, 0, 0, 0);
  1015.   gtk_widget_show (sep);
  1016.  
  1017.   gtk_table_add_toggle (table, _("To Left"), 0, 1, 5,
  1018.             GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  1019.             &direction_mask_vec[Right2Left]);
  1020.   gtk_table_add_toggle (table, _("To Right"), 2, 3, 5,
  1021.             GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  1022.             &direction_mask_vec[Left2Right]);
  1023.   gtk_table_add_toggle (table, _("To Top"), 1, 2, 4,
  1024.             GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  1025.             &direction_mask_vec[Bottom2Top]);
  1026.   gtk_table_add_toggle (table, _("To Bottom"), 1, 2, 6,
  1027.             GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  1028.             &direction_mask_vec[Top2Bottom]);
  1029.   if ((image_type == GIMP_RGBA_IMAGE) | (image_type == GIMP_GRAYA_IMAGE))
  1030.     {
  1031.       sep = gtk_hseparator_new ();
  1032.       gtk_table_attach (GTK_TABLE (table), sep, 0, 3, 7, 8, GTK_FILL, 0, 0, 0);
  1033.       gtk_widget_show (sep);
  1034.  
  1035.       {
  1036.     GtkWidget *toggle;
  1037.     
  1038.     toggle =
  1039.       gtk_table_add_toggle (table, _("Propagating Alpha Channel"),
  1040.                 0, 3, 8,
  1041.                 (GtkSignalFunc) gimp_toggle_button_update,
  1042.                 &propagate_alpha);
  1043.     if (gimp_layer_get_preserve_transparency (drawable_id))
  1044.       {
  1045.         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), 0);
  1046.         gtk_widget_set_sensitive (toggle, FALSE);
  1047.       }
  1048.       }
  1049.       gtk_table_add_toggle (table, _("Propagating Value Channel"), 0, 3, 9,
  1050.                 (GtkSignalFunc) gimp_toggle_button_update,
  1051.                 &propagate_value);
  1052.     }
  1053.   gtk_widget_show (table);
  1054.   gtk_widget_show (frame);
  1055.   gtk_widget_show (hbox);
  1056.   gtk_widget_show (dlg);
  1057.   
  1058.   gtk_main ();
  1059.   gdk_flush ();
  1060.  
  1061.   return vpropagate_interface.run;
  1062. }
  1063.  
  1064. static void
  1065. vpropagate_ok_callback (GtkWidget *widget,
  1066.             gpointer   data)
  1067. {
  1068.   gint i, result;
  1069.  
  1070.   for (i = result = 0; i < 4; i++)
  1071.     result |= (direction_mask_vec[i] ? 1 : 0) << i;
  1072.   vpvals.direction_mask = result;
  1073.  
  1074.   vpvals.propagating_channel = ((propagate_alpha ? PROPAGATING_ALPHA : 0) |
  1075.                 (propagate_value ? PROPAGATING_VALUE : 0));
  1076.  
  1077.   vpropagate_interface.run = TRUE;
  1078.  
  1079.   gtk_widget_destroy (GTK_WIDGET (data));
  1080. }
  1081.  
  1082. static GtkWidget *
  1083. gtk_table_add_toggle (GtkWidget     *table,
  1084.               gchar        *name,
  1085.               gint         x1,
  1086.               gint         x2,
  1087.               gint         y,
  1088.               GtkSignalFunc  update,
  1089.               gint        *value)
  1090. {
  1091.   GtkWidget *toggle;
  1092.   
  1093.   toggle = gtk_check_button_new_with_label(name);
  1094.   gtk_table_attach (GTK_TABLE (table), toggle, x1, x2, y, y+1,
  1095.             GTK_FILL|GTK_EXPAND, 0, 0, 0);
  1096.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  1097.               (GtkSignalFunc) update,
  1098.               value);
  1099.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), *value);
  1100.   gtk_widget_show (toggle);
  1101.  
  1102.   return toggle;
  1103. }
  1104.