Index: despeckle.c
===================================================================
RCS file: /cvs/gnome/gimp/plug-ins/common/despeckle.c,v
retrieving revision 1.57
diff -u -p -r1.57 despeckle.c
--- a/despeckle.c	20 Jan 2004 17:07:33 -0000	1.57
+++ b/despeckle.c	27 May 2004 20:29:35 -0000
@@ -28,7 +28,7 @@
  *   despeckle()                 - Despeckle an image using a median filter.
  *   despeckle_dialog()          -  Popup a dialog window for the filter box size...
  *   preview_init()              - Initialize the preview window...
- *   preview_scroll_callback()   - Update the preview when a scrollbar is moved.
+ *   preview_srcoll_callback()   - Update the preview when a scrollbar is moved.
  *   preview_update()            - Update the preview window.
  *   preview_exit()              - Free all memory used by the preview window...
  *   dialog_iscale_update()      - Update the value field using the scale.
@@ -101,8 +101,14 @@ static void	dialog_recursive_callback (G
 
 static void	preview_init              (void);
 static void	preview_exit              (void);
-static void	preview_update            (void);
-static void	preview_scroll_callback   (void);
+//static void	preview_update            (void);
+static void     preview_update_new (void);
+static void	preview_srcoll_callback   (void);
+static void despeckle_new  (guchar *dst_buffer, gint width, gint height, gint bpp, gint initialradius); 
+static void fillMask   (guchar *mask, gint width);
+static void quickSort  (guchar *buffer, gint size);
+static void q_sort     (guchar *buffer, gint left, gint right);
+static void bubbleSort (guchar *buffer, gint size);
 
 
 /*
@@ -124,9 +130,8 @@ gint		preview_width,		/* Width of previe
 		preview_y1,		/* Upper-left Y of preview */
 		preview_x2,		/* Lower-right X of preview */
 		preview_y2;		/* Lower-right Y of preview */
-guchar	       *preview_src = NULL,	/* Source pixel rows */
-	       *preview_dst,		/* Destination pixel row */
-	       *preview_sort;		/* Pixel value sort array */
+//guchar	       *preview_src = NULL,	/* Source pixel rows */
+//	       *preview_dst;		/* Destination pixel row */
 GtkObject      *hscroll_data,		/* Horizontal scrollbar data */
 	       *vscroll_data;		/* Vertical scrollbar data */
 
@@ -479,6 +484,12 @@ despeckle (void)
 	{
 	  for (x = 0; x < width; x ++)
 	    {
+              /*
+               * Calculate only median for color channels
+               * Do keep the transparancy for the curent pixel 
+               */
+              if (img_bpp==4 && ((x+1)%4 == 0))
+                   continue;
 	      hist0   = 0;
 	      hist255 = 0;
 	      xmin    = x - radius * img_bpp;
@@ -658,7 +669,7 @@ despeckle_dialog (void)
 				     MIN (preview_width, sel_width));
 
   g_signal_connect (hscroll_data, "value_changed",
-                    G_CALLBACK (preview_scroll_callback),
+                    G_CALLBACK (preview_srcoll_callback),
                     NULL);
 
   scrollbar = gtk_hscrollbar_new (GTK_ADJUSTMENT(hscroll_data));
@@ -671,7 +682,7 @@ despeckle_dialog (void)
 				     MIN (preview_height, sel_height));
 
   g_signal_connect (vscroll_data, "value_changed",
-                    G_CALLBACK (preview_scroll_callback),
+                    G_CALLBACK (preview_srcoll_callback),
                     NULL);
 
   scrollbar = gtk_vscrollbar_new (GTK_ADJUSTMENT (vscroll_data));
@@ -776,7 +787,7 @@ despeckle_dialog (void)
 
   gtk_widget_show (dialog);
 
-  preview_update ();
+  preview_update_new ();
 
   run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
 
@@ -812,270 +823,52 @@ preview_init (void)
 
   size  = despeckle_radius * 2 + 1;
   width = preview_width * img_bpp;
-
+/*
   if (preview_src != NULL)
     {
       g_free (preview_src);
       g_free (preview_dst);
       g_free (preview_sort);
+      g_free (previewrgb_sort);
+      g_free (previewalpha_sort);
     }
 
   preview_src  = (guchar *) g_new (guchar *, width * preview_height);
   preview_dst  = g_new (guchar, width);
   preview_sort = g_new (guchar, size * size);
+  previewrgb_sort = g_new (guchar, size * size);
+  previewalpha_sort = g_new (guchar, size * size);
+*/
 }
 
 
 /*
- * 'preview_scroll_callback()' - Update the preview when a scrollbar is moved.
+ * 'preview_srcoll_callback()' - Update the preview when a scrollbar is moved.
  */
 
 static void
-preview_scroll_callback (void)
+preview_srcoll_callback (void)
 {
   preview_x1 = sel_x1 + GTK_ADJUSTMENT (hscroll_data)->value;
   preview_y1 = sel_y1 + GTK_ADJUSTMENT (vscroll_data)->value;
   preview_x2 = preview_x1 + MIN (preview_width, sel_width);
   preview_y2 = preview_y1 + MIN (preview_height, sel_height);
 
-  preview_update ();
+  preview_update_new ();
 }
 
 
-/*
- * 'preview_update()' - Update the preview window.
- */
-
-static void
-preview_update (void)
-{
-  GimpPixelRgn	src_rgn;	/* Source image region */
-  guchar       *sort_ptr,	/* Current preview_sort value */
-	       *src_ptr,	/* Current source pixel */
-	       *dst_ptr;	/* Current destination pixel */
-  gint		sort_count,	/* Number of soft values */
-		i, j, t, d,	/* Looping vars */
-		x, y,		/* Current location in image */
-		size,		/* Width/height of the filter box */
-		width,		/* Byte width of the image */
-		xmin, xmax, tx,	/* Looping vars */
-		radius,		/* Current radius */
-		hist0,		/* Histogram count for 0 values */
-		hist255;	/* Histogram count for 255 values */
-  guchar	check,		/* Checkerboard pattern */
-		rgb[PREVIEW_SIZE * PREVIEW_SIZE * 3],
-				/* Output image */
-	       *rgb_ptr;	/* Pixel pointer for output */
-
- /*
-  * Setup for filter...
-  */
-
-  gimp_pixel_rgn_init (&src_rgn, drawable,
-		       preview_x1, preview_y1, preview_width, preview_height,
-		       FALSE, FALSE);
-
-  /*
-   * Pre-load the preview rectangle...
-   */
-
-  size  = despeckle_radius * 2 + 1;
-  width = preview_width * img_bpp;
-
-  gimp_pixel_rgn_get_rect (&src_rgn, preview_src, preview_x1, preview_y1,
-			   preview_width, preview_height);
-
-  /*
-   * Despeckle...
-   */
-
-  for (y = 0; y < preview_height; y ++)
-    {
-      /*
-       * Now find the median pixels and save the results...
-       */
-
-      radius = despeckle_radius;
-
-      memcpy (preview_dst, preview_src + y * width, width);
-
-      if (y >= radius && y < (preview_height - radius))
-	{
-	  for (x = 0, dst_ptr = preview_dst; x < width; x ++, dst_ptr ++)
-	    {
-	      hist0   = 0;
-	      hist255 = 0;
-	      xmin    = x - radius * img_bpp;
-	      xmax    = x + (radius + 1) * img_bpp;
-
-	      if (xmin < 0)
-		xmin = x % img_bpp;
-
-	      if (xmax > width)
-		xmax = width;
-
-	      for (i = -radius, sort_ptr = preview_sort,
-		     src_ptr = preview_src + width * (y - radius);
-		   i <= radius;
-		   i ++, src_ptr += width)
-		for (tx = xmin; tx < xmax; tx += img_bpp)
-		  {
-		    if ((*sort_ptr = src_ptr[tx]) <= black_level)
-		      hist0 ++;
-		    else if (*sort_ptr >= white_level)
-		      hist255 ++;
-
-		    if (*sort_ptr < white_level && *sort_ptr > black_level)
-		      sort_ptr ++;
-		  };
-
-	      /*
-	       * Shell preview_sort the color values...
-	       */
-
-	      sort_count = sort_ptr - preview_sort;
-
-	      if (sort_count > 1)
-		{
-		  for (d = sort_count / 2; d > 0; d = d / 2)
-		    for (i = d; i < sort_count; i ++)
-		      for (j = i - d, sort_ptr = preview_sort + j;
-			   j >= 0 && sort_ptr[0] > sort_ptr[d];
-			   j -= d, sort_ptr -= d)
-			{
-			  t           = sort_ptr[0];
-			  sort_ptr[0] = sort_ptr[d];
-			  sort_ptr[d] = t;
-			};
-
-		  /*
-		   * Assign the median value...
-		   */
-
-		  t = sort_count / 2;
-
-		  if (sort_count & 1)
-		    *dst_ptr = (preview_sort[t] + preview_sort[t + 1]) / 2;
-		  else
-		    *dst_ptr = preview_sort[t];
-
-		  /*
-		   * Save the change to the source image too if the user
-		   * wants the recursive method...
-		   */
-
-		  if (filter_type & FILTER_RECURSIVE)
-		    preview_src[y * width + x] = *dst_ptr;
-		};
-
-	      /*
-	       * Check the histogram and adjust the radius accordingly...
-	       */
-
-	      if (filter_type & FILTER_ADAPTIVE)
-		{
-		  if (hist0 >= radius || hist255 >= radius)
-		    {
-		      if (radius < despeckle_radius)
-			radius ++;
-		    }
-		  else if (radius > 1)
-		    radius --;
-		};
-	    };
-	};
-
-      /*
-       * Draw this row...
-       */
-
-      rgb_ptr = rgb + y * preview_width * 3;
-
-      switch (img_bpp)
-	{
-	case 1:
-          for (x = preview_width, dst_ptr = preview_dst;
-               x > 0;
-               x --, dst_ptr ++, rgb_ptr += 3)
-            rgb_ptr[0] = rgb_ptr[1] = rgb_ptr[2] = *dst_ptr;
-          break;
-
-	case 2:
-	  for (x = preview_width, dst_ptr = preview_dst;
-	       x > 0;
-	       x --, dst_ptr += 2, rgb_ptr += 3)
-	    if (dst_ptr[1] == 255)
-	      rgb_ptr[0] = rgb_ptr[1] = rgb_ptr[2] = *dst_ptr;
-	    else
-	      {
-		if ((y & GIMP_CHECK_SIZE) ^ (x & GIMP_CHECK_SIZE))
-		  check = GIMP_CHECK_LIGHT * 255;
-		else
-		  check = GIMP_CHECK_DARK * 255;
-
-		if (dst_ptr[1] == 0)
-		  rgb_ptr[0] = rgb_ptr[1] = rgb_ptr[2] = check;
-		else
-		  rgb_ptr[0] = rgb_ptr[1] = rgb_ptr[2] =
-                    check + ((dst_ptr[0] - check) * dst_ptr[1]) / 255;
-	      };
-          break;
-
-	case 3:
-          memcpy (rgb_ptr, preview_dst, preview_width * 3);
-          break;
-
-	case 4:
-	  for (x = preview_width, dst_ptr = preview_dst;
-	       x > 0;
-	       x --, dst_ptr += 4, rgb_ptr += 3)
-	    if (dst_ptr[3] == 255)
-	      {
-		rgb_ptr[0] = dst_ptr[0];
-		rgb_ptr[1] = dst_ptr[1];
-		rgb_ptr[2] = dst_ptr[2];
-	      }
-	    else
-	      {
-		if ((y & GIMP_CHECK_SIZE) ^ (x & GIMP_CHECK_SIZE))
-		  check = GIMP_CHECK_LIGHT * 255;
-		else
-		  check = GIMP_CHECK_DARK * 255;
-
-		if (dst_ptr[3] == 0)
-		  rgb_ptr[0] = rgb_ptr[1] = rgb_ptr[2] = check;
-		else
-		  {
-		    rgb_ptr[0] =
-		      check + ((dst_ptr[0] - check) * dst_ptr[3]) / 255;
-		    rgb_ptr[1] =
-		      check + ((dst_ptr[1] - check) * dst_ptr[3]) / 255;
-		    rgb_ptr[2] =
-		      check + ((dst_ptr[2] - check) * dst_ptr[3]) / 255;
-		  };
-	      };
-          break;
-	};
-    };
-
-  /*
-   * Update the screen...
-   */
-
-  for (y = 0, rgb_ptr = rgb;
-       y < preview_height;
-       y ++, rgb_ptr += preview_width * 3)
-    gtk_preview_draw_row (GTK_PREVIEW (preview), rgb_ptr, 0, y, preview_width);
-
-  gtk_widget_queue_draw (preview);
-}
 
 static void
 preview_exit (void)
 {
+/*
   g_free (preview_src);
   g_free (preview_dst);
   g_free (preview_sort);
+  g_free (previewrgb_sort);
+  g_free (previewalpha_sort);
+*/
 }
 
 static void
@@ -1087,7 +880,7 @@ dialog_iscale_update (GtkAdjustment *adj
   if (value == &despeckle_radius)
     preview_init ();
 
-  preview_update ();
+  preview_update_new ();
 }
 
 static void
@@ -1099,7 +892,7 @@ dialog_adaptive_callback (GtkWidget *wid
   else
     filter_type &= ~FILTER_ADAPTIVE;
 
-  preview_update ();
+  preview_update_new ();
 }
 
 static void
@@ -1111,5 +904,492 @@ dialog_recursive_callback (GtkWidget *wi
   else
     filter_type &= ~FILTER_RECURSIVE;
 
-  preview_update ();
+  preview_update_new ();
+}
+
+static void fillMask (guchar *mask, gint width) 
+  {
+   /*    Radius 3 generates a mask like :
+         -     +
+  	 3210123
+  	
+      -3 0011100
+       2 0111110
+       1 1111111
+       0 1111111
+       1 1111111
+       2 0111110
+      +3 0011100
+      
+   */
+    gint r = (width-1)/2;
+    gint r2 = (gint) (r*r) + 1;
+    gint x,y;
+    for (x=-r; x<=r; x++)
+     {
+      for (y=-r; y<=r; y++)
+       {
+        if ((x*x+y*y)<=r2)
+          mask[r+x+(r+y)*width]=1;
+        else  
+          mask[r+x+(r+y)*width]=0;      
+       }
+     }
+}
+
+/* School book sort */
+static void quickSort(guchar *buffer, gint size)
+{
+  q_sort(buffer, 0, size - 1);
+}
+static void q_sort(guchar *buffer, gint left, gint right)
+{
+  gint p, l, r;
+
+  l = left;
+  r = right;
+  p = buffer[left];
+  while (left < right)
+  {
+    while ((buffer[right] >= p) && (left < right))
+      right--;
+    if (left != right)
+    {
+      buffer[left] = buffer[right];
+      left++;
+    }
+    while ((buffer[left] <= p) && (left < right))
+      left++;
+    if (left != right)
+    {
+      buffer[right] = buffer[left];
+      right--;
+    }
+  }
+  buffer[left] = p;
+  p = left;
+  left = l;
+  right = r;
+  if (left < p)
+    q_sort(buffer, l, p-1);
+  if (right > p)
+    q_sort(buffer, p+1, r);
 }
+
+/* School book sort */
+static void bubbleSort(guchar *buffer, gint size)
+{
+  int i, j, t;
+
+  for (i = (size - 1); i >= 0; i--)
+  {
+    for (j = 1; j <= i; j++)
+    {
+      if (buffer[j-1] > buffer[j])
+      {
+        t = buffer[j-1];
+        buffer[j-1] = buffer[j];
+        buffer[j] = t;
+      }
+    }
+  }
+}
+ 
+/* would not dear to call it improved despeckle algorithm */
+static void despeckle_new (guchar *dst_buffer, gint width, gint height, gint bpp, gint initialradius) 
+  {
+    gint    maskwidth;
+    gint    maxmaskwidth = initialradius * 2 +1;        /* Maximum mask width                         */
+    guchar *mask=NULL;                                  /* Mask buffer                                */
+    guchar *row_buffer = NULL;			        /* Row operations buffer                      */
+    guchar *rec_buffer = NULL;			        /* Non FILTER_RECURSIVE buffer                */
+    guchar *values_r = NULL;                            /* Channel buffer                             */
+    guchar *values_g = NULL;                            /* Channel buffer                             */
+    guchar *values_b = NULL;                            /* Channel buffer                             */
+    guchar *values_a = NULL;                            /* Channel buffer                             */
+    gint   row, col;                                    /* Row and column for buffer                  */
+    gint   maskrow, maskcol;                            /* Row and column for mask buffer             */
+    gint   absrow, abscol;                              /* Absolute row/column for surrounding pixels */
+    gint   valuecount;                                  /* Count sected pixels                        */ 
+    gint   pos;                                         /* Position within buffer                     */ 
+    gint   medpos;                                      /* Median value position in value buffer      */  
+    gint   alphasum;                                    /* Sum of alpha channel values                */
+    gint   radius;                                      /* Working radius                             */
+    gint   i;                                           /* Non specific loop variable                 */
+    
+    gint  hist0, hist255, low, high;
+    
+    /* Probaly too much allocated in FILTER_ADAPTIVE mode */
+    if (bpp>=1)
+      values_r = g_new(guchar, maxmaskwidth*maxmaskwidth);
+    if (bpp>=2)
+      values_g = g_new(guchar, maxmaskwidth*maxmaskwidth);
+    if (bpp>=3)
+      values_b = g_new(guchar, maxmaskwidth*maxmaskwidth);
+    if (bpp>=4) 
+       values_a = g_new(guchar, maxmaskwidth*maxmaskwidth);
+       
+    /* filter temporary buffer */
+    rec_buffer = g_new (guchar, width * height * bpp);
+    memcpy (rec_buffer, dst_buffer, width * height * bpp);
+    
+    /* Process each row */
+    for ( row = 0 ; row < height ; row++ )
+      {
+      	/* reset radius to initial size */
+        radius = initialradius;
+        /* Calculte mask for radius */	
+        g_free(mask);
+        maskwidth = radius * 2 + 1;    
+        mask = g_new(guchar, (maskwidth*maskwidth));
+        fillMask(mask, maskwidth);          
+        
+        /* Make sure row buffer is fresh */
+        g_free(row_buffer);
+        row_buffer = g_new(guchar, width*bpp);
+        
+        /* copy contents from tomporary buffer in row buffer */
+        memcpy (row_buffer, (rec_buffer+(row*width*bpp)), width*bpp);
+
+        /* process each column */	
+        for ( col = 0 ; col < width ; col++) 
+    	  {
+    	    /* Begin get surrounding pixels using mask */
+            valuecount = 0;
+    	    for ( maskcol=0 ; maskcol < maskwidth ; maskcol++ )
+              for ( maskrow=0 ; maskrow < maskwidth ; maskrow++ )  
+                /* if mask is true */
+                if ( mask[maskcol*maskcol+maskrow*maskrow] & 1 )
+    	        {
+    	          /*
+    	           *  don't want to go out of limits 
+    	           *  eg : 
+    	           *  radius = 2
+    	           *  mask = 2 * radius + 1  = 5
+    	           *  x, y = 1,1
+    	           *  
+    	           */          	                     
+    	          abscol = col-radius+maskcol;
+    	          absrow = row-radius+maskrow;
+                  /* check min limit */
+    	          if ( abscol >= 0 && absrow >=0 && abscol < width && absrow < height )
+    	            {
+                      pos = ((absrow*width)+abscol)*bpp;
+                      if (bpp>=1)
+                        *(values_r+valuecount) = *(rec_buffer+pos);
+                      if (bpp>=2)
+                        *(values_g+valuecount) = *(rec_buffer+pos+1);
+                      if (bpp>=3)
+                        *(values_b+valuecount) = *(rec_buffer+pos+2);
+                      if (bpp>=4)
+                        *(values_a+valuecount) = *(rec_buffer+pos+3);
+                      valuecount++;
+                    }
+    	        } 	                 	          
+            /* End get surrounding pixels */
+            if (valuecount > 100)
+              {               
+                 if (bpp>=1)
+                   quickSort(values_r, valuecount);
+                 if (bpp>=2)
+                   quickSort(values_g, valuecount);
+                 if (bpp>=3)
+                   quickSort(values_b, valuecount);
+                 if (bpp>=4)
+                   quickSort(values_a, valuecount);       
+              }
+            else 
+              {
+                 if (bpp>=1)
+                   bubbleSort(values_r, valuecount);
+                 if (bpp>=2)
+                   bubbleSort(values_g, valuecount);
+                 if (bpp>=3)
+                   bubbleSort(values_b, valuecount);
+                 if (bpp>=4)
+                   bubbleSort(values_a, valuecount);                                        
+              }  
+          
+            hist0   = 0;
+            hist255 = 0;
+
+            for ( i  = 0 ;  i < valuecount ; i++) 
+              {
+                 low=0;
+                 high=0;
+                 if (bpp>=1)
+                   {
+                     low  |= *(values_r+i) >= white_level ? 1:0;
+                     high |= *(values_r+i) <= black_level ? 1:0;
+                   }  
+                 if (bpp>=2)
+                   {
+                     low  |= *(values_g+i) >= white_level ? 1:0;
+                     high |= *(values_g+i) <= black_level ? 1:0;
+                   } 
+                 if (bpp>=3)
+                   {
+                     low  |= *(values_b+i) >= white_level ? 1:0;
+                     high |= *(values_b+i) <= black_level ? 1:0;
+                   } 
+                 if (bpp>=4)
+                   {
+                     low  |= *(values_a+i) >= white_level ? 1:0;
+                     high |= *(values_a+i) <= black_level ? 1:0;
+                   }
+                 if (low & 1) 
+  		   hist0++;
+  	         else if (high & 1)
+  		   hist255++;
+              }  
+
+            /* chop high and low values from list */
+            valuecount=valuecount-hist0-hist255;
+  		 
+            /*
+             * Assign the median value...
+             */
+            /* median position */   
+            medpos = (valuecount / 2)+hist0;
+            /* valuecount even so calculate mean of 2 median values */
+            if (valuecount & 1) 
+              {
+                 if (bpp>=1)
+                   *(row_buffer+col*bpp)   = *(values_r+medpos);
+                 if (bpp>=2)
+                   *(row_buffer+col*bpp+1) = *(values_g+medpos);
+                 if (bpp>=3)
+                   *(row_buffer+col*bpp+2) = *(values_b+medpos);
+                 if (bpp>=4)
+                   *(row_buffer+col*bpp+3) = *(values_a+medpos);
+              }
+            else
+              {
+                 if (bpp>=1)
+                   *(row_buffer+col*bpp)   = *(values_r+medpos) + *(values_r+medpos+1)/2;
+                 if (bpp>=2)
+                   *(row_buffer+col*bpp+1) = *(values_g+medpos) + *(values_g+medpos+1)/2;
+                 if (bpp>=3)
+                   *(row_buffer+col*bpp+2) = *(values_b+medpos) + *(values_b+medpos+1)/2;
+                 if (bpp>=4)
+                   {
+                      alphasum =   *(values_a+medpos) + *(values_a+medpos+1);                	
+                      alphasum =(alphasum == 0) ? 1 : alphasum;
+                      *(row_buffer+col*bpp)   = (*(values_r+medpos)   * *(values_a+medpos) + 
+                                                 *(values_r+medpos+1) * *(values_a+medpos+1))/alphasum;
+                      *(row_buffer+col*bpp+1) = (*(values_g+medpos)   * *(values_a+medpos) + 
+                                                 *(values_g+medpos+1) * *(values_a+medpos+1))/alphasum;
+                      *(row_buffer+col*bpp+2) = (*(values_b+medpos)   * *(values_a+medpos) + 
+                                                 *(values_b+medpos+1) * *(values_a+medpos+1))/alphasum;
+                      *(row_buffer+col*bpp+3) = alphasum / 2;   
+                   }                                        
+              }
+  
+             /*
+              * Save the change to the source image too if the user
+              * wants the recursive method...
+              */
+             if (filter_type & FILTER_RECURSIVE ) 
+               {
+                  pos = ((row * width)+col)*bpp;
+                  if (bpp>=1)
+                    *(rec_buffer+pos)   = *(row_buffer+col*bpp);
+                  if (bpp>=2)
+                    *(rec_buffer+pos+1) = *(row_buffer+col*bpp+1);
+                  if (bpp>=3)
+                    *(rec_buffer+pos+2) = *(row_buffer+col*bpp+2);
+                  if (bpp>=4)
+                    *(rec_buffer+pos+3) = *(row_buffer+col*bpp+3);
+               }
+             /*
+              * Check the histogram and adjust the radius accordingly...
+              */             
+             if (filter_type & FILTER_ADAPTIVE )
+               {
+                  if (hist0 >= radius || hist255 >= radius)
+  	          {
+  	             if (radius < despeckle_radius) 
+  	               {  	               	  
+  	                  radius ++;
+  	                  /* recalculate mask on radius change */
+  	                  g_free(mask);
+                          maskwidth = radius * 2 + 1;    
+                          mask = g_new(guchar, (maskwidth*maskwidth));
+                          fillMask(mask, maskwidth);
+                       }
+  	          }
+                  else if (radius > 1)
+  	            {  	               	  
+  	               radius --;
+  	               /* recalculate mask on radius change */
+  	               g_free(mask);
+                       maskwidth = radius * 2 + 1;    
+                       mask = g_new(guchar, (maskwidth*maskwidth));
+                       fillMask(mask, maskwidth);
+                    }
+  	     };  	 
+          } /* colum counter x */
+        /* Copy temporatry buffer back to destination buffer */
+        memcpy ((dst_buffer+(row*width*bpp)),row_buffer, width*bpp);
+      } /* row counter y */
+
+      g_free(mask);
+      g_free(row_buffer);      
+      g_free(rec_buffer);
+  }
+  
+  
+  /*
+   * 'preview_update()' - Update the preview window.
+   */
+  
+  static void
+  preview_update_new (void)
+  {
+    GimpPixelRgn	src_rgn;	/* Source image region */
+    gint	 x, y, offset,		/* Current location in image */
+  		 width;		/* Byte width of the image */
+    guchar	 check;		/* Checkerboard pattern */
+    guchar      *preview_src = NULL;
+    gint         radius=despeckle_radius;
+    gint         pos, preview_pos;                                         /* Position within buffer                     */ 
+    guchar      *render_buffer=NULL;   /* Buffer to hold rendered image */
+    
+   /*
+    * Setup for filter...
+    */
+    gimp_pixel_rgn_init (&src_rgn, drawable,
+  		       preview_x1, preview_y1, preview_width, preview_height,
+  		       FALSE, FALSE);
+  
+    /*
+     * Pre-load the preview rectangle...
+     */
+    g_free(preview_src);
+    preview_src  = g_new (guchar, preview_width * preview_height * img_bpp);
+    gimp_pixel_rgn_get_rect (&src_rgn, preview_src, preview_x1, preview_y1,
+  			   preview_width, preview_height);
+  
+    despeckle_new (preview_src, preview_width,  preview_height, img_bpp, radius); 
+    
+    /*
+     * Draw this row...
+     */
+    /* Preview is RGB */
+    g_free(render_buffer);
+    render_buffer = g_new (guchar, preview_width * preview_height * 3);
+    for ( y = 0 ; y < preview_height ; y++ )
+      for ( x = 0 ; x < preview_width ; x++ )     
+        {
+          pos = (y*preview_width+x)*img_bpp;
+          preview_pos = (y*preview_width+x)*3;
+          switch (img_bpp)
+            { 
+              case 1:
+                *(render_buffer+preview_pos)   = *(preview_src+pos);
+                *(render_buffer+preview_pos+1) = *(preview_src+pos);
+                *(render_buffer+preview_pos+2) = *(preview_src+pos);
+                break;
+              case 2:
+                if (*(preview_src+pos) == 255)
+                  {
+                    *(render_buffer+preview_pos)   = *(preview_src+pos);
+                    *(render_buffer+preview_pos+1) = *(preview_src+pos);
+                    *(render_buffer+preview_pos+2) = *(preview_src+pos);
+                  }
+                else
+                  {
+                    if ((y & GIMP_CHECK_SIZE) ^ (x & GIMP_CHECK_SIZE))
+                      check = GIMP_CHECK_LIGHT * 255;
+                    else
+  	              check = GIMP_CHECK_DARK * 255;
+                    if (*(preview_src+pos) == 0)
+                      {
+                        *(render_buffer+preview_pos)   = check;
+                        *(render_buffer+preview_pos+1) = check;
+                        *(render_buffer+preview_pos+2) = check;
+                      }
+  	            else
+                      {
+                        *(render_buffer+preview_pos)   = check+ ((*(preview_src+pos) - check) * *(preview_src+pos+1)) / 255;
+                        *(render_buffer+preview_pos+1) = *(render_buffer+preview_pos);
+                        *(render_buffer+preview_pos+2) = *(render_buffer+preview_pos);
+                      }
+  	          };
+                break;
+              case 3:
+                *(render_buffer+preview_pos)   = *(preview_src+pos);
+                *(render_buffer+preview_pos+1) = *(preview_src+pos+1);
+                *(render_buffer+preview_pos+2) = *(preview_src+pos+2);
+                break;
+              case 4:
+                if (*(preview_src+pos+3) == 255)
+  	          {
+                    *(render_buffer+preview_pos)   = *(preview_src+pos);
+                    *(render_buffer+preview_pos+1) = *(preview_src+pos+1);
+                    *(render_buffer+preview_pos+2) = *(preview_src+pos+2);
+  	          }
+                else
+                  {
+                    if ((y & GIMP_CHECK_SIZE) ^ (x & GIMP_CHECK_SIZE))
+                      check = GIMP_CHECK_LIGHT * 255;
+                    else
+                      check = GIMP_CHECK_DARK * 255;
+                    if (*(preview_src+pos+3) == 0) 
+                      {
+                        *(render_buffer+preview_pos)   = check;
+                        *(render_buffer+preview_pos+1) = check;
+                        *(render_buffer+preview_pos+2) = check;
+                      }
+  	            else
+  	              {
+                        *(render_buffer+preview_pos)   = check + ((*(preview_src+pos+0) - check) * *(preview_src+pos+3)) / 255;
+                        *(render_buffer+preview_pos+1) = check + ((*(preview_src+pos+1) - check) * *(preview_src+pos+3)) / 255;
+                        *(render_buffer+preview_pos+2) = check + ((*(preview_src+pos+2) - check) * *(preview_src+pos+3)) / 255;
+  	              }
+  	          }
+                break;
+  	    }
+     
+        }
+      
+      
+      /*
+       * Update the screen...
+       */
+      for (y = 0; y < preview_height; y++) 
+        {           
+           offset = y * 3 * preview_width;
+           gtk_preview_draw_row(GTK_PREVIEW (preview), render_buffer+offset, 0, y, preview_width);
+        }
+      gtk_widget_queue_draw (preview);
+      g_free(render_buffer);   
+      g_free(preview_src);
+  }
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
