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 / destripe.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-24  |  19.0 KB  |  757 lines

  1. /*
  2.  *   Destripe filter for The GIMP -- an image manipulation
  3.  *   program
  4.  *
  5.  *   Copyright 1997 Marc Lehmann, heavily modified from a filter by
  6.  *   Michael Sweet.
  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.  * Contents:
  23.  *
  24.  *   main()                      - Main entry - just call gimp_main()...
  25.  *   query()                     - Respond to a plug-in query...
  26.  *   run()                       - Run the filter...
  27.  *   destripe()                  - Destripe an image.
  28.  *   destripe_dialog()           - Popup a dialog window...
  29.  *   preview_init()              - Initialize the preview window...
  30.  *   preview_scroll_callback()   - Update the preview when a scrollbar is moved.
  31.  *   preview_update()            - Update the preview window.
  32.  *   preview_exit()              - Free all memory used by the preview window...
  33.  *   dialog_iscale_update()      - Update the value field using the scale.
  34.  *   dialog_histogram_callback()
  35.  *   dialog_ok_callback()        - Start the filter...
  36.  *
  37.  *   1997/08/16 * Initial Revision.
  38.  *   1998/02/06 * Minor changes.
  39.  */
  40.  
  41. #ifdef HAVE_CONFIG_H
  42. #include "config.h"
  43. #endif
  44.  
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47. #include <string.h>
  48.  
  49. #include <gtk/gtk.h>
  50.  
  51. #include <libgimp/gimp.h>
  52. #include <libgimp/gimpui.h>
  53.  
  54. #include "libgimp/stdplugins-intl.h"
  55.  
  56.  
  57. /*
  58.  * Constants...
  59.  */
  60.  
  61. #define PLUG_IN_NAME     "plug_in_destripe"
  62. #define PLUG_IN_VERSION  "0.2"
  63. #define PREVIEW_SIZE     200
  64. #define SCALE_WIDTH      140
  65. #define MAX_AVG          100
  66.  
  67. /*
  68.  * Local functions...
  69.  */
  70.  
  71. static void    query (void);
  72. static void    run   (gchar   *name,
  73.                gint     nparams,
  74.                GimpParam  *param,
  75.                gint    *nreturn_vals,
  76.                GimpParam **return_vals);
  77.  
  78. static void    destripe (void);
  79.  
  80. static gint    destripe_dialog           (void);
  81. static void     dialog_histogram_callback (GtkWidget *, gpointer);
  82. static void    dialog_iscale_update      (GtkAdjustment *, gint *);
  83. static void    dialog_ok_callback        (GtkWidget *, gpointer);
  84.  
  85. static void    preview_init            (void);
  86. static void    preview_exit            (void);
  87. static void    preview_update          (void);
  88. static void    preview_scroll_callback (void);
  89.  
  90.  
  91. /*
  92.  * Globals...
  93.  */
  94.  
  95. GimpPlugInInfo PLUG_IN_INFO =
  96. {
  97.   NULL,  /* init_proc  */
  98.   NULL,  /* quit_proc  */
  99.   query, /* query_proc */
  100.   run    /* run_proc   */
  101. };
  102.  
  103. GtkWidget      *preview;        /* Preview widget */
  104. gint        preview_width,        /* Width of preview widget */
  105.         preview_height,        /* Height of preview widget */
  106.         preview_x1,        /* Upper-left X of preview */
  107.         preview_y1,        /* Upper-left Y of preview */
  108.         preview_x2,        /* Lower-right X of preview */
  109.         preview_y2;        /* Lower-right Y of preview */
  110. GtkObject      *hscroll_data,        /* Horizontal scrollbar data */
  111.            *vscroll_data;        /* Vertical scrollbar data */
  112.  
  113. GimpDrawable      *drawable = NULL;    /* Current image */
  114. gint        sel_x1,            /* Selection bounds */
  115.         sel_y1,
  116.         sel_x2,
  117.         sel_y2;
  118. gint        histogram = FALSE;
  119. gint        img_bpp;        /* Bytes-per-pixel in image */
  120. gint        run_filter = FALSE;    /* True if we should run the filter */
  121.  
  122. gint        avg_width = 36;
  123.  
  124.  
  125. MAIN ()
  126.  
  127. static void
  128. query (void)
  129. {
  130.   static GimpParamDef    args[] =
  131.   {
  132.     { GIMP_PDB_INT32,    "run_mode",    "Interactive, non-interactive" },
  133.     { GIMP_PDB_IMAGE,    "image",    "Input image" },
  134.     { GIMP_PDB_DRAWABLE,    "drawable",    "Input drawable" },
  135.     { GIMP_PDB_INT32,    "avg_width",    "Averaging filter width (default = 36)" }
  136.   };
  137.   static gint nargs = sizeof (args) / sizeof (args[0]);
  138.  
  139.   gimp_install_procedure (PLUG_IN_NAME,
  140.               "Destripe filter, used to remove vertical stripes "
  141.               "caused by cheap scanners.",
  142.               "This plug-in tries to remove vertical stripes from "
  143.               "an image.",
  144.               "Marc Lehmann <pcg@goof.com>",
  145.               "Marc Lehmann <pcg@goof.com>",
  146.               PLUG_IN_VERSION,
  147.               N_("<Image>/Filters/Enhance/Destripe..."),
  148.               "RGB*, GRAY*",
  149.               GIMP_PLUGIN,
  150.               nargs, 0,
  151.               args, NULL);
  152. }
  153.  
  154. static void
  155. run (gchar  *name,
  156.      gint   nparams,
  157.      GimpParam *param,
  158.      gint   *nreturn_vals,
  159.      GimpParam **return_vals)
  160. {
  161.   GimpRunModeType    run_mode;    /* Current run mode */
  162.   GimpPDBStatusType    status;        /* Return status */
  163.   static GimpParam    values[1];    /* Return values */
  164.  
  165.   INIT_I18N_UI();
  166.  
  167.   /*
  168.    * Initialize parameter data...
  169.    */
  170.  
  171.   status   = GIMP_PDB_SUCCESS;
  172.   run_mode = param[0].data.d_int32;
  173.  
  174.   values[0].type          = GIMP_PDB_STATUS;
  175.   values[0].data.d_status = status;
  176.  
  177.   *nreturn_vals = 1;
  178.   *return_vals  = values;
  179.  
  180.   /*
  181.    * Get drawable information...
  182.    */
  183.  
  184.   drawable = gimp_drawable_get (param[2].data.d_drawable);
  185.  
  186.   gimp_drawable_mask_bounds (drawable->id, &sel_x1, &sel_y1, &sel_x2, &sel_y2);
  187.  
  188.   img_bpp = gimp_drawable_bpp (drawable->id);
  189.  
  190.   /*
  191.    * See how we will run
  192.    */
  193.  
  194.   switch (run_mode)
  195.     {
  196.     case GIMP_RUN_INTERACTIVE:
  197.       /*
  198.        * Possibly retrieve data...
  199.        */
  200.       gimp_get_data (PLUG_IN_NAME, &avg_width);
  201.  
  202.       /*
  203.        * Get information from the dialog...
  204.        */
  205.       if (!destripe_dialog ())
  206.     return;
  207.       break;
  208.  
  209.     case GIMP_RUN_NONINTERACTIVE:
  210.       /*
  211.        * Make sure all the arguments are present...
  212.        */
  213.       if (nparams != 4)
  214.     status = GIMP_PDB_CALLING_ERROR;
  215.       else
  216.     avg_width = param[3].data.d_int32;
  217.       break;
  218.  
  219.     case GIMP_RUN_WITH_LAST_VALS :
  220.       /*
  221.        * Possibly retrieve data...
  222.        */
  223.       gimp_get_data (PLUG_IN_NAME, &avg_width);
  224.       break;
  225.  
  226.     default :
  227.       status = GIMP_PDB_CALLING_ERROR;
  228.       break;
  229.     };
  230.  
  231.   /*
  232.    * Destripe the image...
  233.    */
  234.  
  235.   if (status == GIMP_PDB_SUCCESS)
  236.     {
  237.       if ((gimp_drawable_is_rgb (drawable->id) ||
  238.        gimp_drawable_is_gray (drawable->id)))
  239.     {
  240.       /*
  241.        * Set the tile cache size...
  242.        */
  243.       gimp_tile_cache_ntiles ((drawable->width + gimp_tile_width () - 1) /
  244.                   gimp_tile_width ());
  245.  
  246.       /*
  247.        * Run!
  248.        */
  249.       destripe ();
  250.  
  251.       /*
  252.        * If run mode is interactive, flush displays...
  253.        */
  254.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  255.         gimp_displays_flush();
  256.  
  257.       /*
  258.        * Store data...
  259.        */
  260.       if (run_mode == GIMP_RUN_INTERACTIVE)
  261.         gimp_set_data (PLUG_IN_NAME, &avg_width, sizeof(avg_width));
  262.     }
  263.       else
  264.     status = GIMP_PDB_EXECUTION_ERROR;
  265.     };
  266.  
  267.   /*
  268.    * Reset the current run status...
  269.    */
  270.   values[0].data.d_status = status;
  271.  
  272.   /*
  273.    * Detach from the drawable...
  274.    */
  275.   gimp_drawable_detach (drawable);
  276. }
  277.  
  278. static inline void
  279. preview_draw_row (gint    x,
  280.           gint    y,
  281.           gint    w,
  282.           guchar *row)
  283. {
  284.   guchar *rgb = g_new (guchar, w * 3);
  285.   guchar *rgb_ptr;
  286.   gint i;
  287.  
  288.   switch (img_bpp)
  289.     {
  290.     case 1:
  291.     case 2:
  292.       for (i = 0, rgb_ptr = rgb; i < w; i++, row += img_bpp, rgb_ptr += 3)
  293.     rgb_ptr[0] = rgb_ptr[1] = rgb_ptr[2] = *row;
  294.  
  295.       gtk_preview_draw_row (GTK_PREVIEW (preview), rgb, x, y, w);
  296.       break;
  297.  
  298.     case 3:
  299.       gtk_preview_draw_row (GTK_PREVIEW (preview), row, x, y, w);
  300.       break;
  301.  
  302.     case 4:
  303.       for (i = 0, rgb_ptr = rgb; i < w; i++, row += 4, rgb_ptr += 3)
  304.     {
  305.       rgb_ptr[0] = row[0];
  306.           rgb_ptr[1] = row[1];
  307.           rgb_ptr[2] = row[2];
  308.     }
  309.  
  310.       gtk_preview_draw_row (GTK_PREVIEW (preview), rgb, x, y, w);
  311.       break;
  312.     }
  313.   g_free (rgb);
  314. }
  315.  
  316.  
  317. static void
  318. destripe_rect (gint      sel_x1,
  319.            gint      sel_y1,
  320.            gint      sel_x2,
  321.            gint      sel_y2,
  322.            gboolean  do_preview)
  323. {
  324.   GimpPixelRgn src_rgn;    /* source image region */
  325.   GimpPixelRgn dst_rgn;    /* destination image region */
  326.   guchar *src_rows;    /* image data */
  327.   double progress, progress_inc;
  328.   int sel_width = sel_x2 - sel_x1;
  329.   int sel_height = sel_y2 - sel_y1;
  330.   long *hist, *corr;    /* "histogram" data */
  331.   int tile_width = gimp_tile_width ();
  332.   int i, x, y, ox, cols;
  333.   
  334.   /* initialize */
  335.  
  336.   progress = 0.0;
  337.   progress_inc = 0.0;
  338.  
  339.   /*
  340.    * Let the user know what we're doing...
  341.    */
  342.  
  343.   if (!do_preview)
  344.     {
  345.       gimp_progress_init (_("Destriping..."));
  346.  
  347.       progress = 0;
  348.       progress_inc = 0.5 * tile_width / sel_width;
  349.     }
  350.  
  351.   /*
  352.    * Setup for filter...
  353.    */
  354.  
  355.   gimp_pixel_rgn_init (&src_rgn, drawable,
  356.                sel_x1, sel_y1, sel_width, sel_height, FALSE, FALSE);
  357.   gimp_pixel_rgn_init (&dst_rgn, drawable,
  358.                sel_x1, sel_y1, sel_width, sel_height, TRUE, TRUE);
  359.   
  360.   hist = g_new (long, sel_width * img_bpp);
  361.   corr = g_new (long, sel_width * img_bpp);
  362.   src_rows = g_new (guchar, tile_width * sel_height * img_bpp);
  363.  
  364.   memset (hist, 0, sel_width * img_bpp * sizeof (long));
  365.   
  366.   /*
  367.    * collect "histogram" data.
  368.    */
  369.  
  370.   for (ox = sel_x1; ox < sel_x2; ox += tile_width)
  371.     {
  372.       guchar *rows = src_rows;
  373.  
  374.       cols = sel_x2 - ox;
  375.       if (cols > tile_width)
  376.         cols = tile_width;
  377.  
  378.       gimp_pixel_rgn_get_rect (&src_rgn, rows, ox, sel_y1, cols, sel_height);
  379.  
  380.       for (y = 0; y < sel_height; y++)
  381.         {
  382.           long *h = hist + (ox - sel_x1) * img_bpp;
  383.           guchar *row_end = rows + cols * img_bpp;
  384.  
  385.           while (rows < row_end)
  386.             *h++ += *rows++;
  387.         }
  388.  
  389.       if (!do_preview)
  390.         gimp_progress_update (progress += progress_inc);
  391.     }
  392.   
  393.   /*
  394.    * average out histogram
  395.    */
  396.   
  397.   if (1)
  398.     {
  399.       gint extend = (avg_width >> 1) * img_bpp;
  400.  
  401.       for (i = 0; i < MIN (3, img_bpp); i++)
  402.         {
  403.           long *h = hist - extend + i;
  404.           long *c = corr - extend + i;
  405.           long sum = 0;
  406.           gint cnt = 0;
  407.  
  408.           for (x = -extend; x < sel_width * img_bpp; x += img_bpp)
  409.             {
  410.               if (x + extend < sel_width * img_bpp)
  411.         {
  412.           sum += h[ extend]; cnt++;
  413.         }
  414.               if (x - extend >= 0)
  415.         {
  416.           sum -= h[-extend]; cnt--;
  417.         }
  418.               if (x >= 0)
  419.         {
  420.           *c = ((sum / cnt - *h) << 10) / *h;
  421.         }
  422.  
  423.               h += img_bpp;
  424.               c += img_bpp;
  425.             }
  426.         }
  427.     }
  428.   else
  429.     {
  430.       for (i = 0; i < MIN (3, img_bpp); i++)
  431.         {
  432.           long *h = hist + i + sel_width * img_bpp - img_bpp;
  433.           long *c = corr + i + sel_width * img_bpp - img_bpp;
  434.           long i = *h;
  435.           *c = 0;
  436.  
  437.           do
  438.             {
  439.               h -= img_bpp;
  440.               c -= img_bpp;
  441.  
  442.               if (*h - i > avg_width && i - *h > avg_width)
  443.                 i = *h;
  444.  
  445.               *c = (i-128) << 10 / *h;
  446.             }
  447.           while (h > hist);
  448.         }
  449.     }
  450.  
  451.   /*
  452.    * remove stripes.
  453.    */
  454.  
  455.   for (ox = sel_x1; ox < sel_x2; ox += tile_width)
  456.     {
  457.       guchar *rows = src_rows;
  458.  
  459.       cols = sel_x2 - ox;
  460.       if (cols > tile_width)
  461.         cols = tile_width;
  462.  
  463.       gimp_pixel_rgn_get_rect (&src_rgn, rows, ox, sel_y1, cols, sel_height);
  464.  
  465.       if (!do_preview)
  466.         gimp_progress_update (progress += progress_inc);
  467.  
  468.       for (y = 0; y < sel_height; y++)
  469.         {
  470.           long *c = corr + (ox - sel_x1) * img_bpp;
  471.           guchar *row_end = rows + cols * img_bpp;
  472.  
  473.           if (histogram)
  474.             while (rows < row_end)
  475.               {
  476.                 *rows = MIN (255, MAX (0, 128 + (*rows * *c >> 10)));
  477.                 c++; rows++;
  478.               }
  479.           else
  480.             while (rows < row_end)
  481.               {
  482.                 *rows = MIN (255, MAX (0, *rows + (*rows * *c >> 10) ));
  483.                 c++; rows++;
  484.               }
  485.  
  486.           if (do_preview)
  487.             preview_draw_row (ox - sel_x1, y, cols, rows - cols * img_bpp);
  488.         }
  489.  
  490.       if (!do_preview)
  491.         {
  492.           gimp_pixel_rgn_set_rect (&dst_rgn, src_rows,
  493.                    ox, sel_y1, cols, sel_height);
  494.           gimp_progress_update (progress += progress_inc);
  495.         }
  496.     }
  497.  
  498.   g_free (src_rows);
  499.  
  500.   /*
  501.    * Update the screen...
  502.    */
  503.  
  504.   if (do_preview)
  505.     {
  506.       gtk_widget_draw (preview, NULL);
  507.       gdk_flush ();
  508.     }
  509.   else
  510.     {
  511.       gimp_drawable_flush (drawable);
  512.       gimp_drawable_merge_shadow (drawable->id, TRUE);
  513.       gimp_drawable_update (drawable->id, sel_x1, sel_y1, sel_width, sel_height);
  514.     }
  515.   g_free (hist);
  516.   g_free (corr);
  517. }
  518.  
  519. /*
  520.  * 'destripe()' - Destripe an image.
  521.  *
  522.  */
  523.  
  524. static void
  525. destripe (void)
  526. {
  527.   destripe_rect (sel_x1, sel_y1, sel_x2, sel_y2, FALSE);
  528. }
  529.  
  530. static gint
  531. destripe_dialog (void)
  532. {
  533.   GtkWidget *dialog;
  534.   GtkWidget *vbox;
  535.   GtkWidget *abox;
  536.   GtkWidget *table;
  537.   GtkWidget *ptable;
  538.   GtkWidget *frame;
  539.   GtkWidget *scrollbar;
  540.   GtkWidget *button;
  541.   GtkObject *adj;
  542.  
  543.   gimp_ui_init ("destripe", TRUE);
  544.  
  545.   dialog = gimp_dialog_new (_("Destripe"), "destripe",
  546.                 gimp_standard_help_func, "filters/destripe.html",
  547.                 GTK_WIN_POS_MOUSE,
  548.                 FALSE, TRUE, FALSE,
  549.  
  550.                 _("OK"), dialog_ok_callback,
  551.                 NULL, NULL, NULL, TRUE, FALSE,
  552.                 _("Cancel"), gtk_widget_destroy,
  553.                 NULL, 1, NULL, FALSE, TRUE,
  554.  
  555.                 NULL);
  556.  
  557.   gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
  558.               GTK_SIGNAL_FUNC (gtk_main_quit),
  559.               NULL);
  560.  
  561.   /*
  562.    * Top-level table for dialog...
  563.    */
  564.  
  565.   vbox = gtk_vbox_new (FALSE, 4);
  566.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
  567.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox,
  568.               FALSE, FALSE, 0);
  569.   gtk_widget_show (vbox);
  570.  
  571.   /*
  572.    * Preview window...
  573.    */
  574.  
  575.   frame = gtk_frame_new (_("Preview"));
  576.   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  577.   gtk_widget_show (frame);
  578.  
  579.   abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  580.   gtk_container_set_border_width (GTK_CONTAINER (abox), 4);
  581.   gtk_container_add (GTK_CONTAINER (frame), abox);
  582.   gtk_widget_show (abox);
  583.  
  584.   ptable = gtk_table_new (2, 2, FALSE);
  585.   gtk_container_add (GTK_CONTAINER (abox), ptable);
  586.   gtk_widget_show (ptable);
  587.  
  588.   frame = gtk_frame_new (NULL);
  589.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  590.   gtk_table_attach(GTK_TABLE(ptable), frame, 0, 1, 0, 1,
  591.            0, 0, 0, 0);
  592.   gtk_widget_show (frame);
  593.  
  594.   preview_width  = MIN (sel_x2 - sel_x1, PREVIEW_SIZE);
  595.   preview_height = MIN (sel_y2 - sel_y1, PREVIEW_SIZE);
  596.  
  597.   preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  598.   gtk_preview_size (GTK_PREVIEW (preview), preview_width, preview_height);
  599.   gtk_container_add (GTK_CONTAINER (frame), preview);
  600.   gtk_widget_show (preview);
  601.  
  602.   hscroll_data = gtk_adjustment_new (0, 0, sel_x2 - sel_x1 - 1, 1.0,
  603.                      MIN (preview_width, sel_x2 - sel_x1),
  604.                      MIN (preview_width, sel_x2 - sel_x1));
  605.  
  606.   gtk_signal_connect (hscroll_data, "value_changed",
  607.               GTK_SIGNAL_FUNC (preview_scroll_callback),
  608.               NULL);
  609.  
  610.   scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT (hscroll_data));
  611.   gtk_range_set_update_policy (GTK_RANGE (scrollbar), GTK_UPDATE_CONTINUOUS);
  612.   gtk_table_attach (GTK_TABLE (ptable), scrollbar, 0, 1, 1, 2,
  613.             GTK_FILL, 0, 0, 0);
  614.   gtk_widget_show (scrollbar);
  615.  
  616.   vscroll_data = gtk_adjustment_new (0, 0, sel_y2 - sel_y1 - 1, 1.0,
  617.                      MIN (preview_height, sel_y2 - sel_y1),
  618.                      MIN (preview_height, sel_y2 - sel_y1));
  619.  
  620.   gtk_signal_connect (vscroll_data, "value_changed",
  621.               GTK_SIGNAL_FUNC (preview_scroll_callback),
  622.               NULL);
  623.  
  624.   scrollbar = gtk_vscrollbar_new (GTK_ADJUSTMENT (vscroll_data));
  625.   gtk_range_set_update_policy (GTK_RANGE (scrollbar), GTK_UPDATE_CONTINUOUS);
  626.   gtk_table_attach (GTK_TABLE (ptable), scrollbar, 1, 2, 0, 1, 0,
  627.             GTK_FILL, 0, 0);
  628.   gtk_widget_show (scrollbar);
  629.  
  630.   preview_init ();
  631.  
  632.   /*
  633.    * Filter type controls...
  634.    */
  635.  
  636.   frame = gtk_frame_new (_("Parameter Settings"));
  637.   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  638.   gtk_widget_show (frame);
  639.  
  640.   table = gtk_table_new (2, 3, FALSE);
  641.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  642.   gtk_table_set_row_spacings (GTK_TABLE (table), 4);
  643.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  644.   gtk_container_add (GTK_CONTAINER (frame), table);
  645.   gtk_widget_show (table);
  646.  
  647.   button = gtk_check_button_new_with_label (_("Create Histogram"));
  648.   gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 3, 0, 1);
  649.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
  650.                 histogram ? TRUE : FALSE);
  651.   gtk_signal_connect (GTK_OBJECT (button), "toggled",
  652.               GTK_SIGNAL_FUNC (dialog_histogram_callback),
  653.               NULL);
  654.   gtk_widget_show (button);
  655.  
  656. /*  button = gtk_check_button_new_with_label("Recursive");
  657.   gtk_table_attach_defaults (GTK_TABLE (table), button, 0, 1, 1, 2);
  658.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button),
  659.                                 (filter_type & FILTER_RECURSIVE) ? TRUE : FALSE);
  660.   gtk_signal_connect (GTK_OBJECT (button), "toggled",
  661.               GTK_SIGNAL_FUNC (dialog_recursive_callback),
  662.               NULL);
  663.   gtk_widget_show (button);*/
  664.  
  665.   /*
  666.    * Box size (radius) control...
  667.    */
  668.  
  669.   adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  670.                   _("Width:"), SCALE_WIDTH, 0,
  671.                   avg_width, 2, MAX_AVG, 1, 10, 0,
  672.                   TRUE, 0, 0,
  673.                   NULL, NULL);
  674.   gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  675.               GTK_SIGNAL_FUNC (dialog_iscale_update),
  676.               &avg_width);
  677.  
  678.   gtk_widget_show (dialog);
  679.  
  680.   preview_update ();
  681.  
  682.   gtk_main ();
  683.   gdk_flush ();
  684.  
  685.   preview_exit ();
  686.  
  687.   return run_filter;
  688. }
  689.  
  690. /*  preview functions  */
  691.  
  692. static void
  693. preview_init (void)
  694. {
  695.   gint width;  /* Byte width of the image */
  696.  
  697.   /*
  698.    * Setup for preview filter...
  699.    */
  700.   width = preview_width * img_bpp;
  701.  
  702.   preview_x1 = sel_x1;
  703.   preview_y1 = sel_y1;
  704.   preview_x2 = preview_x1 + MIN (preview_width, sel_x2 - sel_x1);
  705.   preview_y2 = preview_y1 + MIN (preview_height, sel_y2 -sel_y1);
  706. }
  707.  
  708. static void
  709. preview_scroll_callback (void)
  710. {
  711.   preview_x1 = sel_x1 + GTK_ADJUSTMENT (hscroll_data)->value;
  712.   preview_y1 = sel_y1 + GTK_ADJUSTMENT (vscroll_data)->value;
  713.   preview_x2 = preview_x1 + MIN (preview_width, sel_x2 - sel_x1);
  714.   preview_y2 = preview_y1 + MIN (preview_height, sel_y2 - sel_y1);
  715.  
  716.   preview_update ();
  717. }
  718.  
  719. static void
  720. preview_update (void)
  721. {
  722.   destripe_rect (preview_x1, preview_y1, preview_x2, preview_y2, TRUE);
  723. }
  724.  
  725. static void
  726. preview_exit (void)
  727. {
  728. }
  729.  
  730. /*  dialog callbacks  */
  731.  
  732. static void
  733. dialog_histogram_callback (GtkWidget *widget,
  734.                gpointer  data)
  735. {
  736.   histogram = !histogram;
  737.   preview_update ();
  738. }
  739.  
  740. static void
  741. dialog_iscale_update (GtkAdjustment *adjustment,
  742.                       gint          *value)
  743. {
  744.   gimp_int_adjustment_update (adjustment, value);
  745.  
  746.   preview_update ();
  747. }
  748.  
  749. static void
  750. dialog_ok_callback (GtkWidget *widget,
  751.             gpointer   data)
  752. {
  753.   run_filter = TRUE;
  754.  
  755.   gtk_widget_destroy (GTK_WIDGET (data));
  756. }
  757.