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 / noisify.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-10-01  |  22.0 KB  |  815 lines

  1. /*
  2.  * This is a plugin for the GIMP.
  3.  *
  4.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  5.  * Copyright (C) 1996 Torsten Martinsen
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 2 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program; if not, write to the Free Software
  19.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20.  *
  21.  * $Id: noisify.c,v 1.22 2000/09/30 20:13:06 nicklamb Exp $
  22.  */
  23.  
  24. /*
  25.  * This filter adds random noise to an image.
  26.  * The amount of noise can be set individually for each RGB channel.
  27.  * This filter does not operate on indexed images.
  28.  *
  29.  * May 2000 tim copperfield [timecop@japan.co.jp]
  30.  * Added dynamic preview.
  31.  *
  32.  * alt@gimp.org. Fixed previews so they handle alpha channels correctly.
  33.  */
  34.  
  35. #include "config.h"
  36.  
  37. #include <stdlib.h>
  38. #include <stdio.h>
  39. #include <string.h>
  40. #include <time.h>
  41.  
  42. #include <gtk/gtk.h>
  43.  
  44. #include <libgimp/gimp.h>
  45. #include <libgimp/gimpui.h>
  46.  
  47. #include "libgimp/stdplugins-intl.h"
  48.  
  49.  
  50. #define SCALE_WIDTH      125
  51. #define TILE_CACHE_SIZE  16
  52. #define PREVIEW_SIZE     128 
  53.  
  54. typedef struct
  55. {
  56.   gint    independent;
  57.   gdouble noise[4];     /*  per channel  */
  58. } NoisifyVals;
  59.  
  60. typedef struct
  61. {
  62.   gint       channels;
  63.   GtkObject *channel_adj[4];
  64.   gint       run;
  65. } NoisifyInterface;
  66.  
  67. /* Declare local functions.
  68.  */
  69. static void       query  (void);
  70. static void       run    (gchar     *name,
  71.               gint       nparams,
  72.               GimpParam    *param,
  73.               gint      *nreturn_vals,
  74.               GimpParam   **return_vals);
  75.  
  76. static void       noisify (GimpDrawable *drawable, gboolean preview_mode);
  77. static gdouble    gauss   (void);
  78.  
  79. static void       fill_preview   (GtkWidget *preview_widget, 
  80.                   GimpDrawable *drawable);
  81. static GtkWidget *preview_widget (GimpDrawable *drawable);
  82.  
  83. static gint       noisify_dialog                   (GimpDrawable *drawable, 
  84.                             gint           channels);
  85. static void       noisify_ok_callback              (GtkWidget     *widget,
  86.                             gpointer       data);
  87. static void       noisify_double_adjustment_update (GtkAdjustment *adjustment,
  88.                             gpointer       data);
  89.  
  90. GimpPlugInInfo PLUG_IN_INFO =
  91. {
  92.   NULL,  /* init_proc */
  93.   NULL,  /* quit_proc */
  94.   query, /* query_proc */
  95.   run,   /* run_proc */
  96. };
  97.  
  98. static NoisifyVals nvals =
  99. {
  100.   TRUE,
  101.   { 0.20, 0.20, 0.20, 0.20 }
  102. };
  103.  
  104. static NoisifyInterface noise_int =
  105. {
  106.   0,
  107.   { NULL, NULL, NULL, NULL },
  108.   FALSE     /* run */
  109. };
  110.  
  111. static GtkWidget *preview;
  112. static guchar    *preview_cache;
  113. static gint       preview_cache_rowstride;
  114. static gint       preview_cache_bpp;
  115.  
  116.  
  117. MAIN ()
  118.  
  119. static void
  120. query (void)
  121. {
  122.   static GimpParamDef args[] =
  123.   {
  124.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  125.     { GIMP_PDB_IMAGE, "image", "Input image (unused)" },
  126.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
  127.     { GIMP_PDB_INT32, "independent", "Noise in channels independent" },
  128.     { GIMP_PDB_FLOAT, "noise_1", "Noise in the first channel (red, gray)" },
  129.     { GIMP_PDB_FLOAT, "noise_2", "Noise in the second channel (green, gray_alpha)" },
  130.     { GIMP_PDB_FLOAT, "noise_3", "Noise in the third channel (blue)" },
  131.     { GIMP_PDB_FLOAT, "noise_4", "Noise in the fourth channel (alpha)" }
  132.   };
  133.   static gint nargs = sizeof (args) / sizeof (args[0]);
  134.  
  135.   gimp_install_procedure ("plug_in_noisify",
  136.               "Adds random noise to a drawable's channels",
  137.               "More here later",
  138.               "Torsten Martinsen",
  139.               "Torsten Martinsen",
  140.               "May 2000",
  141.               N_("<Image>/Filters/Noise/Noisify..."),
  142.               "RGB*, GRAY*",
  143.               GIMP_PLUGIN,
  144.               nargs, 0,
  145.               args, NULL);
  146. }
  147.  
  148. static void
  149. run (gchar   *name,
  150.      gint     nparams,
  151.      GimpParam  *param,
  152.      gint    *nreturn_vals,
  153.      GimpParam **return_vals)
  154. {
  155.   static GimpParam values[1];
  156.   GimpDrawable *drawable;
  157.   GimpRunModeType run_mode;
  158.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  159.  
  160.   run_mode = param[0].data.d_int32;
  161.  
  162.   *nreturn_vals = 1;
  163.   *return_vals = values;
  164.  
  165.   values[0].type = GIMP_PDB_STATUS;
  166.   values[0].data.d_status = status;
  167.  
  168.   /*  Get the specified drawable  */
  169.   drawable = gimp_drawable_get (param[2].data.d_drawable);
  170.  
  171.   switch (run_mode)
  172.     {
  173.     case GIMP_RUN_INTERACTIVE:
  174.       INIT_I18N_UI();
  175.       /*  Possibly retrieve data  */
  176.       gimp_get_data ("plug_in_noisify", &nvals);
  177.  
  178.       /*  First acquire information with a dialog  */
  179.       if (! noisify_dialog (drawable, drawable->bpp))
  180.     {
  181.       gimp_drawable_detach (drawable);
  182.       return;
  183.     }
  184.       break;
  185.  
  186.     case GIMP_RUN_NONINTERACTIVE:
  187.       INIT_I18N();
  188.       /*  Make sure all the arguments are there!  */
  189.       if (nparams != 8)
  190.     {
  191.       status = GIMP_PDB_CALLING_ERROR;
  192.     }
  193.       else
  194.     {
  195.       nvals.independent = param[3].data.d_int32 ? TRUE : FALSE;
  196.       nvals.noise[0]    = param[4].data.d_float;
  197.       nvals.noise[1]    = param[5].data.d_float;
  198.       nvals.noise[2]    = param[6].data.d_float;
  199.       nvals.noise[3]    = param[7].data.d_float;
  200.     }
  201.       break;
  202.  
  203.     case GIMP_RUN_WITH_LAST_VALS:
  204.       INIT_I18N();
  205.       /*  Possibly retrieve data  */
  206.       gimp_get_data ("plug_in_noisify", &nvals);
  207.       break;
  208.  
  209.     default:
  210.       break;
  211.     }
  212.  
  213.   /*  Make sure that the drawable is gray or RGB color  */
  214.   if (gimp_drawable_is_rgb (drawable->id) ||
  215.       gimp_drawable_is_gray (drawable->id))
  216.     {
  217.       gimp_progress_init (_("Adding Noise..."));
  218.       gimp_tile_cache_ntiles (TILE_CACHE_SIZE);
  219.  
  220.       /*  seed the random number generator  */
  221.       srand (time (NULL));
  222.  
  223.       /*  compute the luminosity which exceeds the luminosity threshold  */
  224.       noisify (drawable, FALSE);
  225.  
  226.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  227.     gimp_displays_flush ();
  228.  
  229.       /*  Store data  */
  230.       if (run_mode == GIMP_RUN_INTERACTIVE) {
  231.     gimp_set_data ("plug_in_noisify", &nvals, sizeof (NoisifyVals));
  232.     g_free(preview_cache);
  233.       }
  234.     }
  235.   else
  236.     {
  237.       /* gimp_message ("blur: cannot operate on indexed color images"); ??? BLUR ??? */
  238.       status = GIMP_PDB_EXECUTION_ERROR;
  239.     }
  240.  
  241.   values[0].data.d_status = status;
  242.  
  243.   gimp_drawable_detach (drawable);
  244. }
  245.  
  246. static void
  247. preview_do_row(gint    row,
  248.            gint    width,
  249.            guchar *even,
  250.            guchar *odd,
  251.            guchar *src)
  252. {
  253.   gint    x;
  254.   
  255.   guchar *p0 = even;
  256.   guchar *p1 = odd;
  257.   
  258.   gdouble    r, g, b, a;
  259.   gdouble    c0, c1;
  260.   
  261.   for (x = 0; x < width; x++) 
  262.     {
  263.       if (preview_cache_bpp == 4)
  264.     {
  265.       r = ((gdouble)src[x*4+0]) / 255.0;
  266.       g = ((gdouble)src[x*4+1]) / 255.0;
  267.       b = ((gdouble)src[x*4+2]) / 255.0;
  268.       a = ((gdouble)src[x*4+3]) / 255.0;
  269.     }
  270.       else if (preview_cache_bpp == 3)
  271.     {
  272.       r = ((gdouble)src[x*3+0]) / 255.0;
  273.       g = ((gdouble)src[x*3+1]) / 255.0;
  274.       b = ((gdouble)src[x*3+2]) / 255.0;
  275.       a = 1.0;
  276.     }
  277.       else
  278.     {
  279.       r = ((gdouble)src[x*preview_cache_bpp+0]) / 255.0;
  280.       g = b = r;
  281.       if (preview_cache_bpp == 2)
  282.             a = ((gdouble)src[x*preview_cache_bpp+1]) / 255.0;
  283.       else
  284.         a = 1.0;
  285.     }
  286.       
  287.       if ((x / GIMP_CHECK_SIZE) & 1) 
  288.     {
  289.       c0 = GIMP_CHECK_LIGHT;
  290.       c1 = GIMP_CHECK_DARK;
  291.     } 
  292.       else 
  293.     {
  294.       c0 = GIMP_CHECK_DARK;
  295.       c1 = GIMP_CHECK_LIGHT;
  296.     }
  297.       
  298.       *p0++ = (c0 + (r - c0) * a) * 255.0;
  299.       *p0++ = (c0 + (g - c0) * a) * 255.0;
  300.       *p0++ = (c0 + (b - c0) * a) * 255.0;
  301.       
  302.       *p1++ = (c1 + (r - c1) * a) * 255.0;
  303.       *p1++ = (c1 + (g - c1) * a) * 255.0;
  304.       *p1++ = (c1 + (b - c1) * a) * 255.0;
  305.       
  306.     } /* for */
  307.   
  308.   if ((row / GIMP_CHECK_SIZE) & 1)
  309.     {
  310.       gtk_preview_draw_row (GTK_PREVIEW (preview), (guchar *)odd,  0, row, width); 
  311.     }
  312.   else
  313.     {
  314.       gtk_preview_draw_row (GTK_PREVIEW (preview), (guchar *)even, 0, row, width); 
  315.     }
  316. }
  317.  
  318. static void
  319. noisify (GimpDrawable *drawable, 
  320.      gboolean   preview_mode)
  321. {
  322.   GimpPixelRgn src_rgn, dest_rgn;
  323.   guchar *src_row, *dest_row;
  324.   guchar *src, *dest, *dest_data;
  325.   gint row, col, b;
  326.   gint x1, y1, x2, y2, p, bpp = 3;
  327.   gint noise;
  328.   gint progress = 0, max_progress = 0;
  329.   gpointer pr;
  330.   gint row_stride = 0;
  331.   guchar *odd = NULL;
  332.   guchar *even = NULL;
  333.   /* initialize */
  334.  
  335.   noise = 0;
  336.  
  337.   if (preview_mode) 
  338.     {
  339.       x1 = y1 = 0;
  340.       x2 = GTK_PREVIEW (preview)->buffer_width;
  341.       y2 = GTK_PREVIEW (preview)->buffer_height;
  342.       bpp = preview_cache_bpp;
  343.       row_stride = preview_cache_rowstride;
  344.       even = g_malloc (x2 * 3);
  345.       odd  = g_malloc (x2 * 3);
  346.     } 
  347.   else 
  348.     {
  349.       gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  350.       gimp_pixel_rgn_init (&src_rgn, drawable,
  351.                x1, y1, (x2 - x1), (y2 - y1), FALSE, FALSE);
  352.       gimp_pixel_rgn_init (&dest_rgn, drawable,
  353.                x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
  354.       /* Initialize progress */
  355.       progress = 0;
  356.       max_progress = (x2 - x1) * (y2 - y1);
  357.     }
  358.  
  359.   if (preview_mode) 
  360.     {
  361.       dest_data = g_malloc (row_stride * y2);
  362.  
  363.       for (row = 0; row < y2; row++)
  364.     {
  365.       src  = preview_cache + row * row_stride;
  366.       dest = dest_data + row * row_stride;
  367.       
  368.       for (col = 0; col < x2; col++)
  369.         {
  370.           if (nvals.independent == FALSE)
  371.         noise = (gint) (nvals.noise[0] * gauss() * 127);
  372.  
  373.           for (b = 0; b < bpp; b++)
  374.         {
  375.           if (nvals.independent == TRUE)
  376.             noise = (gint) (nvals.noise[b] * gauss() * 127);
  377.  
  378.           if (nvals.noise[b] > 0.0)
  379.             {
  380.               p = src[b] + noise;
  381.               if (p < 0)
  382.                 p = 0;
  383.               else if (p > 255)
  384.                 p = 255;
  385.               dest[b] = p;
  386.             }
  387.           else
  388.             dest[b] = src[b];
  389.  
  390.         }
  391.           src += bpp;
  392.           dest += bpp;
  393.         }
  394.     }
  395.  
  396.       for (row = 0; row < y2; row++)
  397.     {
  398.       preview_do_row(row,x2,even,odd,dest_data + row * row_stride);
  399.     }
  400.  
  401.       gtk_widget_queue_draw (preview);
  402.  
  403.       if(even)
  404.     g_free(even);
  405.       
  406.       if(odd)
  407.     g_free(odd);
  408.  
  409.     } 
  410.   else 
  411.     {
  412.       for (pr = gimp_pixel_rgns_register (2, &src_rgn, &dest_rgn);
  413.        pr != NULL;
  414.        pr = gimp_pixel_rgns_process (pr))
  415.     {
  416.       src_row = src_rgn.data;
  417.       dest_row = dest_rgn.data;
  418.  
  419.       for (row = 0; row < src_rgn.h; row++)
  420.         {
  421.           src = src_row;
  422.           dest = dest_row;
  423.           
  424.           for (col = 0; col < src_rgn.w; col++)
  425.         {
  426.           if (nvals.independent == FALSE)
  427.             noise = (gint) (nvals.noise[0] * gauss() * 127);
  428.           
  429.           for (b = 0; b < src_rgn.bpp; b++)
  430.             {
  431.               if (nvals.independent == TRUE)
  432.             noise = (gint) (nvals.noise[b] * gauss() * 127);
  433.               
  434.               if (nvals.noise[b] > 0.0)
  435.             {
  436.               p = src[b] + noise;
  437.               if (p < 0)
  438.                 p = 0;
  439.               else if (p > 255)
  440.                 p = 255;
  441.               dest[b] = p;
  442.             }
  443.               else
  444.             dest[b] = src[b];
  445.               
  446.             }
  447.           src += src_rgn.bpp;
  448.           dest += dest_rgn.bpp;
  449.         }
  450.           
  451.           src_row += src_rgn.rowstride;
  452.           dest_row += dest_rgn.rowstride;
  453.         }
  454.       
  455.       /* Update progress */
  456.       progress += src_rgn.w * src_rgn.h;
  457.       gimp_progress_update ((double) progress / (double) max_progress);
  458.     }
  459.  
  460.       /*  update the blurred region  */
  461.       gimp_drawable_flush (drawable);
  462.       gimp_drawable_merge_shadow (drawable->id, TRUE);
  463.       gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
  464.  
  465.     } /* endif normal mode */
  466. }
  467.  
  468. static gint
  469. noisify_dialog (GimpDrawable *drawable, 
  470.         gint       channels)
  471. {
  472.   GtkWidget *dlg;
  473.   GtkWidget *main_vbox;
  474.   GtkWidget *abox;
  475.   GtkWidget *toggle;
  476.   GtkWidget *frame;
  477.   GtkWidget *table;
  478.   GtkObject *adj;
  479.   gchar *buffer;
  480.   gint   i;
  481.  
  482.   gimp_ui_init ("noisify", FALSE);
  483.  
  484.   dlg = gimp_dialog_new (_("Noisify"), "noisify",
  485.              gimp_standard_help_func, "filters/noisify.html",
  486.              GTK_WIN_POS_MOUSE,
  487.              FALSE, TRUE, FALSE,
  488.  
  489.              _("OK"), noisify_ok_callback,
  490.              NULL, NULL, NULL, TRUE, FALSE,
  491.              _("Cancel"), gtk_widget_destroy,
  492.              NULL, 1, NULL, FALSE, TRUE,
  493.  
  494.              NULL);
  495.  
  496.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  497.               GTK_SIGNAL_FUNC (gtk_main_quit),
  498.               NULL);
  499.  
  500.   main_vbox = gtk_vbox_new (FALSE, 2);
  501.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 0);
  502.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), main_vbox, TRUE, TRUE, 0);
  503.   gtk_widget_show (main_vbox);
  504.  
  505.   /* preview */
  506.   frame = gtk_frame_new (_("Preview"));
  507.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  508.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  509.   gtk_widget_show (frame);
  510.   abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
  511.   gtk_container_set_border_width (GTK_CONTAINER (abox), 4);
  512.   gtk_container_add (GTK_CONTAINER (frame), abox);
  513.   gtk_widget_show (abox);
  514.   frame = gtk_frame_new (NULL);
  515.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  516.   gtk_container_add (GTK_CONTAINER (abox), frame);
  517.   gtk_widget_show (frame);
  518.   preview = preview_widget (drawable);
  519.   gtk_container_add (GTK_CONTAINER (frame), preview);
  520.   noisify (drawable, TRUE); /* preview noisify */
  521.   gtk_widget_show (preview);
  522.   
  523.   /*  parameter settings  */
  524.   frame = gtk_frame_new (_("Parameter Settings"));
  525.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  526.   gtk_container_set_border_width (GTK_CONTAINER (frame), 6);
  527.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 0);
  528.  
  529.   table = gtk_table_new (channels + 1, 3, FALSE);
  530.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  531.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  532.   gtk_table_set_row_spacing (GTK_TABLE (table), 0, 4);
  533.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  534.   gtk_container_add (GTK_CONTAINER (frame), table);
  535.  
  536.   toggle = gtk_check_button_new_with_label (_("Independent"));
  537.   gtk_table_attach (GTK_TABLE (table), toggle, 0, 3, 0, 1, GTK_FILL, 0, 0, 0);
  538.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  539.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  540.               &nvals.independent);
  541.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), nvals.independent);
  542.   gtk_widget_show (toggle);
  543.  
  544.   noise_int.channels = channels;
  545.  
  546.   if (channels == 1) 
  547.     {
  548.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  549.                   _("Gray:"), SCALE_WIDTH, 0,
  550.                   nvals.noise[0], 0.0, 1.0, 0.01, 0.1, 2,
  551.                   TRUE, 0, 0,
  552.                   NULL, NULL);
  553.  
  554.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  555.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  556.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  557.               &nvals.noise[0]);
  558.       noise_int.channel_adj[0] = adj;
  559.     }
  560.   else if (channels == 2)
  561.     {
  562.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  563.                   _("Gray:"), SCALE_WIDTH, 0,
  564.                   nvals.noise[0], 0.0, 1.0, 0.01, 0.1, 2,
  565.                   TRUE, 0, 0,
  566.                   NULL, NULL);
  567.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  568.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  569.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  570.               &nvals.noise[0]);
  571.       noise_int.channel_adj[0] = adj;
  572.  
  573.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
  574.                   _("Alpha:"), SCALE_WIDTH, 0,
  575.                   nvals.noise[1], 0.0, 1.0, 0.01, 0.1, 2,
  576.                   TRUE, 0, 0,
  577.                   NULL, NULL);
  578.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  579.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  580.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  581.               &nvals.noise[1]);
  582.       noise_int.channel_adj[1] = adj;
  583.     }
  584.   
  585.   else if (channels == 3)
  586.     {
  587.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  588.                   _("Red:"), SCALE_WIDTH, 0,
  589.                   nvals.noise[0], 0.0, 1.0, 0.01, 0.1, 2,
  590.                   TRUE, 0, 0,
  591.                   NULL, NULL);
  592.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  593.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  594.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  595.               &nvals.noise[0]);
  596.       noise_int.channel_adj[0] = adj;
  597.  
  598.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
  599.                   _("Green:"), SCALE_WIDTH, 0,
  600.                   nvals.noise[1], 0.0, 1.0, 0.01, 0.1, 2,
  601.                   TRUE, 0, 0,
  602.                   NULL, NULL);
  603.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  604.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  605.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  606.               &nvals.noise[1]);
  607.       noise_int.channel_adj[1] = adj;
  608.  
  609.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 3,
  610.                   _("Blue:"), SCALE_WIDTH, 0,
  611.                   nvals.noise[2], 0.0, 1.0, 0.01, 0.1, 2,
  612.                   TRUE, 0, 0,
  613.                   NULL, NULL);
  614.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  615.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  616.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  617.               &nvals.noise[2]);
  618.       noise_int.channel_adj[2] = adj;
  619.     }
  620.  
  621.   else if (channels == 4)
  622.     {
  623.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  624.                   _("Red:"), SCALE_WIDTH, 0,
  625.                   nvals.noise[0], 0.0, 1.0, 0.01, 0.1, 2,
  626.                   TRUE, 0, 0,
  627.                   NULL, NULL);
  628.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  629.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  630.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  631.               &nvals.noise[0]);
  632.       noise_int.channel_adj[0] = adj;
  633.  
  634.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 2,
  635.                   _("Green:"), SCALE_WIDTH, 0,
  636.                   nvals.noise[1], 0.0, 1.0, 0.01, 0.1, 2,
  637.                   TRUE, 0, 0,
  638.                   NULL, NULL);
  639.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  640.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  641.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  642.               &nvals.noise[1]);
  643.       noise_int.channel_adj[1] = adj;
  644.  
  645.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 3,
  646.                   _("Blue:"), SCALE_WIDTH, 0,
  647.                   nvals.noise[2], 0.0, 1.0, 0.01, 0.1, 2,
  648.                   TRUE, 0, 0,
  649.                   NULL, NULL);
  650.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  651.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  652.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  653.               &nvals.noise[2]);
  654.       noise_int.channel_adj[2] = adj;
  655.  
  656.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, 4,
  657.                   _("Alpha:"), SCALE_WIDTH, 0,
  658.                   nvals.noise[3], 0.0, 1.0, 0.01, 0.1, 2,
  659.                   TRUE, 0, 0,
  660.                   NULL, NULL);
  661.       gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  662.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  663.               GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  664.               &nvals.noise[3]);
  665.       noise_int.channel_adj[3] = adj;
  666.     }
  667.   else
  668.     {
  669.       for (i = 0; i < channels; i++)
  670.     {
  671.       buffer = g_strdup_printf (_("Channel #%d:"), i);
  672.  
  673.       adj = gimp_scale_entry_new (GTK_TABLE (table), 0, i + 1,
  674.                       buffer, SCALE_WIDTH, 0,
  675.                       nvals.noise[i], 0.0, 1.0, 0.01, 0.1, 2,
  676.                       TRUE, 0, 0,
  677.                       NULL, NULL);
  678.           gtk_object_set_data (GTK_OBJECT (adj), "drawable", drawable);
  679.       gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
  680.                   GTK_SIGNAL_FUNC (noisify_double_adjustment_update),
  681.                   &nvals.noise[i]);
  682.       noise_int.channel_adj[i] = adj;
  683.  
  684.       g_free (buffer);
  685.     }
  686.     }
  687.  
  688.   gtk_widget_show (frame);
  689.   gtk_widget_show (table);
  690.  
  691.   gtk_widget_show (dlg);
  692.  
  693.   gtk_main ();
  694.   gdk_flush ();
  695.  
  696.   return noise_int.run;
  697. }
  698.  
  699. /*
  700.  * Return a Gaussian (aka normal) random variable.
  701.  *
  702.  * Adapted from ppmforge.c, which is part of PBMPLUS.
  703.  * The algorithm comes from:
  704.  * 'The Science Of Fractal Images'. Peitgen, H.-O., and Saupe, D. eds.
  705.  * Springer Verlag, New York, 1988.
  706.  */
  707. static gdouble
  708. gauss (void)
  709. {
  710.   gint i;
  711.   gdouble sum = 0.0;
  712.  
  713.   for (i = 0; i < 4; i++)
  714.     sum += rand () & 0x7FFF;
  715.  
  716.   return sum * 5.28596089837e-5 - 3.46410161514;
  717. }
  718.  
  719. static void
  720. noisify_ok_callback (GtkWidget *widget,
  721.              gpointer   data)
  722. {
  723.   noise_int.run = TRUE;
  724.  
  725.   gtk_widget_destroy (GTK_WIDGET (data));
  726. }
  727.  
  728. static void
  729. noisify_double_adjustment_update (GtkAdjustment *adjustment,
  730.                   gpointer       data)
  731. {
  732.   GimpDrawable *drawable;
  733.   
  734.   gimp_double_adjustment_update (adjustment, data);
  735.   drawable = gtk_object_get_data (GTK_OBJECT (adjustment), "drawable");
  736.   noisify (drawable, TRUE);
  737.  
  738.   if (! nvals.independent)
  739.     {
  740.       gint i;
  741.  
  742.       for (i = 0; i < noise_int.channels; i++)
  743.     if (adjustment != GTK_ADJUSTMENT (noise_int.channel_adj[i]))
  744.       gtk_adjustment_set_value (GTK_ADJUSTMENT (noise_int.channel_adj[i]),
  745.                     adjustment->value);
  746.     }
  747. }
  748.  
  749. static GtkWidget *
  750. preview_widget (GimpDrawable *drawable)
  751. {
  752.   gint       size;
  753.  
  754.   preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  755.   fill_preview (preview, drawable);
  756.   size = GTK_PREVIEW (preview)->rowstride * GTK_PREVIEW (preview)->buffer_height;
  757.   return preview;
  758. }
  759.  
  760. static void
  761. fill_preview (GtkWidget *widget, 
  762.           GimpDrawable *drawable)
  763. {
  764.   GimpPixelRgn  srcPR;
  765.   gint       width;
  766.   gint       height;
  767.   gint       x1, x2, y1, y2;
  768.   gint       bpp;
  769.   gint       y;
  770.   guchar    *src;
  771.   guchar    *even, *odd;
  772.   
  773.   gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  774.  
  775.   if (x2 - x1 > PREVIEW_SIZE)
  776.     x2 = x1 + PREVIEW_SIZE;
  777.   
  778.   if (y2 - y1 > PREVIEW_SIZE)
  779.     y2 = y1 + PREVIEW_SIZE;
  780.   
  781.   width  = x2 - x1;
  782.   height = y2 - y1;
  783.   bpp    = gimp_drawable_bpp (drawable->id);
  784.   
  785.   if (width < 1 || height < 1)
  786.     return;
  787.  
  788.   gtk_preview_size (GTK_PREVIEW (widget), width, height);
  789.  
  790.   gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, x2, y2, FALSE, FALSE);
  791.  
  792.   even = g_malloc (width * 3);
  793.   odd  = g_malloc (width * 3);
  794.   src  = g_malloc (width * bpp);
  795.   preview_cache = g_malloc(width * bpp * height);
  796.   preview_cache_rowstride = width * bpp;
  797.   preview_cache_bpp = bpp;
  798.  
  799.  
  800.   for (y = 0; y < height; y++)
  801.     {
  802.       gimp_pixel_rgn_get_row (&srcPR, src, x1, y + y1, width);
  803.       memcpy(preview_cache + (y*width*bpp),src,width*bpp);
  804.     }
  805.  
  806.   for (y = 0; y < height; y++)
  807.     {
  808.       preview_do_row(y,width,even,odd,preview_cache + (y*width*bpp));
  809.     }
  810.  
  811.   g_free (even);
  812.   g_free (odd);
  813.   g_free (src);
  814. }
  815.