1 /* despeckle.c: Bitmap despeckler
2 
3    Copyright (C) 2001 David A. Bartold
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public License
7    as published by the Free Software Foundation; either version 2.1 of
8    the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, write to the Free Software
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18    USA. */
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif /* Def: HAVE_CONFIG_H */
23 
24 #include <assert.h>
25 #include <math.h>
26 #include <stdio.h>
27 #include <time.h>
28 #include "xstd.h"
29 #include "types.h"
30 #include "bitmap.h"
31 #include "despeckle.h"
32 
33 /* Calculate Error - compute the error between two colors
34  *
35  *   Input parameters:
36  *     Two 24 bit RGB colors
37  *
38  *   Returns:
39  *     The squared error between the two colors
40  */
41 
42 static int
calc_error(unsigned char * color1,unsigned char * color2)43 calc_error (unsigned char *color1,
44             unsigned char *color2)
45 {
46   int the_error;
47   int temp;
48 
49   temp = color1[0] - color2[0];
50   the_error = temp * temp;
51   temp = color1[1] - color2[1];
52   the_error += temp * temp;
53   temp = color1[2] - color2[2];
54   the_error += temp * temp;
55 
56   return the_error;
57 }
58 
59 
60 /* Calculate Error - compute the error between two colors
61  *
62  *   Input parameters:
63  *     Two 8 bit gray scale colors
64  *
65  *   Returns:
66  *     The squared error between the two colors
67  */
68 
69 static int
calc_error_8(unsigned char * color1,unsigned char * color2)70 calc_error_8 (unsigned char *color1,
71             unsigned char *color2)
72 {
73   int the_error;
74   int temp;
75 
76   temp = color1[0] - color2[0];
77   the_error = temp * temp;
78 
79   return the_error;
80 }
81 
82 
83 /* Find Size - Find the number of adjacent pixels of the same color
84  *
85  * Input Parameters:
86  *   An 24 bit image, the current location inside the image, and the palette
87  *   index of the color we are looking for
88  *
89  * Modified Parameters:
90  *   A mask array used to prevent backtracking over already counted pixels
91  *
92  * Returns:
93  *   Number of adjacent pixels found having the same color
94  */
95 
96 static int
find_size(unsigned char * index,int x,int y,int width,int height,unsigned char * bitmap,unsigned char * mask)97 find_size (/* in */     unsigned char *index,
98            /* in */     int    x,
99            /* in */     int    y,
100            /* in */     int    width,
101            /* in */     int    height,
102            /* in */     unsigned char *bitmap,
103            /* in/out */ unsigned char *mask)
104 {
105   int count;
106   int x1, x2;
107 
108   if (y < 0 || y >= height ||
109     mask[y * width + x] == 1 ||
110     bitmap[3 * (y * width + x)    ] != index[0] ||
111     bitmap[3 * (y * width + x) + 1] != index[1] ||
112 	bitmap[3 * (y * width + x) + 2] != index[2])
113       return 0;
114 
115   for (x1 = x; x1 >= 0 &&
116 	bitmap[3 * (y * width + x1)    ] == index[0] &&
117     bitmap[3 * (y * width + x1) + 1] == index[1] &&
118 	bitmap[3 * (y * width + x1) + 2] == index[2] &&
119 	mask[y * width + x] != 1; x1--) ;
120   x1++;
121 
122   for (x2 = x; x2 < width &&
123 	bitmap[3 * (y * width + x2)    ] == index[0] &&
124     bitmap[3 * (y * width + x2) + 1] == index[1] &&
125 	bitmap[3 * (y * width + x2) + 2] == index[2] &&
126 	mask[y * width + x] != 1; x2++) ;
127   x2--;
128 
129   count = x2 - x1 + 1;
130   for (x = x1; x <= x2; x++)
131     mask[y * width + x] = 1;
132 
133   for (x = x1; x <= x2; x++)
134     {
135       count += find_size (index, x, y - 1, width, height, bitmap, mask);
136       count += find_size (index, x, y + 1, width, height, bitmap, mask);
137     }
138 
139   return count;
140 }
141 
142 
143 /* Find Size - Find the number of adjacent pixels of the same color
144  *
145  * Input Parameters:
146  *   An 8 bit image, the current location inside the image, and the palette
147  *   index of the color we are looking for
148  *
149  * Modified Parameters:
150  *   A mask array used to prevent backtracking over already counted pixels
151  *
152  * Returns:
153  *   Number of adjacent pixels found having the same color
154  */
155 
156 static int
find_size_8(unsigned char * index,int x,int y,int width,int height,unsigned char * bitmap,unsigned char * mask)157 find_size_8 (/* in */   unsigned char *index,
158            /* in */     int    x,
159            /* in */     int    y,
160            /* in */     int    width,
161            /* in */     int    height,
162            /* in */     unsigned char *bitmap,
163            /* in/out */ unsigned char *mask)
164 {
165   int count;
166   int x1, x2;
167 
168   if (y < 0 || y >= height ||
169     mask[y * width + x] == 1 ||
170     bitmap[(y * width + x)    ] != index[0])
171       return 0;
172 
173   for (x1 = x; x1 >= 0 &&
174 	bitmap[(y * width + x1)    ] == index[0] &&
175 	mask[y * width + x] != 1; x1--) ;
176   x1++;
177 
178   for (x2 = x; x2 < width &&
179 	bitmap[(y * width + x2)    ] == index[0] &&
180 	mask[y * width + x] != 1; x2++) ;
181   x2--;
182 
183   count = x2 - x1 + 1;
184   for (x = x1; x <= x2; x++)
185     mask[y * width + x] = 1;
186 
187   for (x = x1; x <= x2; x++)
188     {
189       count += find_size_8 (index, x, y - 1, width, height, bitmap, mask);
190       count += find_size_8 (index, x, y + 1, width, height, bitmap, mask);
191     }
192 
193   return count;
194 }
195 
196 
197 /* Find Most Similar Neighbor - Given a position in an 8bit bitmap and a color
198  * index, traverse over a blob of adjacent pixels having the same value.
199  * Return the color index of the neighbor pixel that has the most similar
200  * color.
201  *
202  * Input parameters:
203  *   24 bit bitmap, the current location inside the image,
204  *   and the color index of the blob
205  *
206  * Modified parameters:
207  *   Mask used to prevent backtracking
208  *
209  * Output parameters:
210  *   Closest index != index and the error between the two colors squared
211  */
212 
213 static void
find_most_similar_neighbor(unsigned char * index,unsigned char ** closest_index,int * error_amt,int x,int y,int width,int height,unsigned char * bitmap,unsigned char * mask)214 find_most_similar_neighbor (/* in */     unsigned char *index,
215                             /* in/out */ unsigned char **closest_index,
216                             /* in/out */ int   *error_amt,
217                             /* in */     int    x,
218                             /* in */     int    y,
219                             /* in */     int    width,
220                             /* in */     int    height,
221                             /* in */     unsigned char *bitmap,
222                             /* in/out */ unsigned char *mask)
223 {
224   int x1, x2;
225   int temp_error;
226   unsigned char *value, *temp;
227 
228   if (y < 0 || y >= height || mask[y * width + x] == 2)
229     return;
230 
231   temp = &bitmap[3 * (y * width + x)];
232 
233   assert (closest_index != NULL);
234 
235   if (temp[0] != index[0] || temp[1] != index[1] || temp[2] != index[2])
236     {
237       value = temp;
238 
239       temp_error = calc_error (index, value);
240 
241       if (*closest_index == NULL || temp_error < *error_amt)
242         *closest_index = value, *error_amt = temp_error;
243 
244       return;
245     }
246 
247   for (x1 = x; x1 >= 0 &&
248 	bitmap[ 3 * (y * width + x1)    ] == index[0] &&
249     bitmap[ 3 * (y * width + x1) + 1] == index[1] &&
250 	bitmap[ 3 * (y * width + x1) + 2] == index[2]; x1--) ;
251   x1++;
252 
253   for (x2 = x; x2 < width &&
254 	bitmap[ 3 * (y * width + x2)    ] == index[0] &&
255     bitmap[ 3 * (y * width + x2) + 1] == index[1] &&
256 	bitmap[ 3 * (y * width + x2) + 2] == index[2]; x2++) ;
257   x2--;
258 
259   if (x1 > 0)
260     {
261       value = &bitmap[ 3 * (y * width + x1 - 1)    ];
262 
263       temp_error = calc_error (index, value);
264 
265       if (*closest_index == NULL || temp_error < *error_amt)
266         *closest_index = value, *error_amt = temp_error;
267     }
268 
269   if (x2 < width - 1)
270     {
271       value = &bitmap[ 3 * (y * width + x2 + 1)    ];
272 
273       temp_error = calc_error (index, value);
274 
275       if (*closest_index == NULL || temp_error < *error_amt)
276         *closest_index = value, *error_amt = temp_error;
277     }
278 
279   for (x = x1; x <= x2; x++)
280     mask[y * width + x] = 2;
281 
282   for (x = x1; x <= x2; x++)
283     {
284       find_most_similar_neighbor (index, closest_index, error_amt, x, y - 1,
285                                   width, height, bitmap, mask);
286       find_most_similar_neighbor (index, closest_index, error_amt, x, y + 1,
287                                   width, height, bitmap, mask);
288     }
289 }
290 
291 
292 /* Find Most Similar Neighbor - Given a position in an 8bit bitmap and a color
293  * index, traverse over a blob of adjacent pixels having the same value.
294  * Return the color index of the neighbor pixel that has the most similar
295  * color.
296  *
297  * Input parameters:
298  *   8 bit bitmap, the current location inside the image,
299  *   and the color index of the blob
300  *
301  * Modified parameters:
302  *   Mask used to prevent backtracking
303  *
304  * Output parameters:
305  *   Closest index != index and the error between the two colors squared
306  */
307 
308 static void
find_most_similar_neighbor_8(unsigned char * index,unsigned char ** closest_index,int * error_amt,int x,int y,int width,int height,unsigned char * bitmap,unsigned char * mask)309 find_most_similar_neighbor_8 (/* in */   unsigned char *index,
310                             /* in/out */ unsigned char **closest_index,
311                             /* in/out */ int   *error_amt,
312                             /* in */     int    x,
313                             /* in */     int    y,
314                             /* in */     int    width,
315                             /* in */     int    height,
316                             /* in */     unsigned char *bitmap,
317                             /* in/out */ unsigned char *mask)
318 {
319   int x1, x2;
320   int temp_error;
321   unsigned char *value, *temp;
322 
323   if (y < 0 || y >= height || mask[y * width + x] == 2)
324     return;
325 
326   temp = &bitmap[(y * width + x)];
327 
328   assert (closest_index != NULL);
329 
330   if (temp[0] != index[0])
331     {
332       value = temp;
333 
334       temp_error = calc_error_8 (index, value);
335 
336       if (*closest_index == NULL || temp_error < *error_amt)
337         *closest_index = value, *error_amt = temp_error;
338 
339       return;
340     }
341 
342   for (x1 = x; x1 >= 0 &&
343 	bitmap[(y * width + x1)    ] == index[0]; x1--) ;
344   x1++;
345 
346   for (x2 = x; x2 < width &&
347 	bitmap[(y * width + x2)    ] == index[0]; x2++) ;
348   x2--;
349 
350   if (x1 > 0)
351     {
352       value = &bitmap[(y * width + x1 - 1)    ];
353 
354       temp_error = calc_error_8 (index, value);
355 
356       if (*closest_index == NULL || temp_error < *error_amt)
357         *closest_index = value, *error_amt = temp_error;
358     }
359 
360   if (x2 < width - 1)
361     {
362       value = &bitmap[(y * width + x2 + 1)    ];
363 
364       temp_error = calc_error_8 (index, value);
365 
366       if (*closest_index == NULL || temp_error < *error_amt)
367         *closest_index = value, *error_amt = temp_error;
368     }
369 
370   for (x = x1; x <= x2; x++)
371     mask[y * width + x] = 2;
372 
373   for (x = x1; x <= x2; x++)
374     {
375       find_most_similar_neighbor_8 (index, closest_index, error_amt, x, y - 1,
376                                   width, height, bitmap, mask);
377       find_most_similar_neighbor_8 (index, closest_index, error_amt, x, y + 1,
378                                   width, height, bitmap, mask);
379     }
380 }
381 
382 
383 /* Fill - change the color of a blob
384  *
385  * Input parameters:
386  *   The new color
387  *
388  * Modified parameters:
389  *   24 bit pixbuf and its mask (used to prevent backtracking)
390  */
391 
392 static void
fill(unsigned char * to_index,int x,int y,int width,int height,unsigned char * bitmap,unsigned char * mask)393 fill (/* in */     unsigned char *to_index,
394       /* in */     int    x,
395       /* in */     int    y,
396       /* in */     int    width,
397       /* in */     int    height,
398       /* in/out */ unsigned char *bitmap,
399       /* in/out */ unsigned char *mask)
400 {
401   int x1, x2;
402 
403   if (y < 0 || y >= height || mask[y * width + x] != 2)
404     return;
405 
406   for (x1 = x; x1 >= 0 && mask[y * width + x1] == 2; x1--) ;
407   x1++;
408   for (x2 = x; x2 < width && mask[y * width + x2] == 2; x2++) ;
409   x2--;
410 
411   assert (x1 >= 0 && x2 < width);
412 
413   for (x = x1; x <= x2; x++)
414     {
415       bitmap[3 * (y * width + x)    ] = to_index[0];
416       bitmap[3 * (y * width + x) + 1] = to_index[1];
417       bitmap[3 * (y * width + x) + 2] = to_index[2];
418       mask[y * width + x] = 3;
419     }
420 
421   for (x = x1; x <= x2; x++)
422     {
423       fill (to_index, x, y - 1, width, height, bitmap, mask);
424       fill (to_index, x, y + 1, width, height, bitmap, mask);
425     }
426 }
427 
428 
429 /* Fill - change the color of a blob
430  *
431  * Input parameters:
432  *   The new color
433  *
434  * Modified parameters:
435  *   8 bit pixbuf and its mask (used to prevent backtracking)
436  */
437 
438 static void
fill_8(unsigned char * to_index,int x,int y,int width,int height,unsigned char * bitmap,unsigned char * mask)439 fill_8 (/* in */   unsigned char *to_index,
440       /* in */     int    x,
441       /* in */     int    y,
442       /* in */     int    width,
443       /* in */     int    height,
444       /* in/out */ unsigned char *bitmap,
445       /* in/out */ unsigned char *mask)
446 {
447   int x1, x2;
448 
449   if (y < 0 || y >= height || mask[y * width + x] != 2)
450     return;
451 
452   for (x1 = x; x1 >= 0 && mask[y * width + x1] == 2; x1--) ;
453   x1++;
454   for (x2 = x; x2 < width && mask[y * width + x2] == 2; x2++) ;
455   x2--;
456 
457   assert (x1 >= 0 && x2 < width);
458 
459   for (x = x1; x <= x2; x++)
460     {
461       bitmap[(y * width + x)    ] = to_index[0];
462       mask[y * width + x] = 3;
463     }
464 
465   for (x = x1; x <= x2; x++)
466     {
467       fill_8 (to_index, x, y - 1, width, height, bitmap, mask);
468       fill_8 (to_index, x, y + 1, width, height, bitmap, mask);
469     }
470 }
471 
472 
473 /* Ignore - blob is big enough, mask it off
474  *
475  * Modified parameters:
476  *   its mask (used to prevent backtracking)
477  */
478 
479 static void
ignore(int x,int y,int width,int height,unsigned char * mask)480 ignore (/* in */     int    x,
481         /* in */     int    y,
482         /* in */     int    width,
483         /* in */     int    height,
484         /* in/out */ unsigned char *mask)
485 {
486   int x1, x2;
487 
488   if (y < 0 || y >= height || mask[y * width + x] != 1)
489     return;
490 
491   for (x1 = x; x1 >= 0 && mask[y * width + x1] == 1; x1--) ;
492   x1++;
493   for (x2 = x; x2 < width && mask[y * width + x2] == 1; x2++) ;
494   x2--;
495 
496   assert (x1 >= 0 && x2 < width);
497 
498   for (x = x1; x <= x2; x++)
499     mask[y * width + x] = 3;
500 
501   for (x = x1; x <= x2; x++)
502     {
503       ignore (x, y - 1, width, height, mask);
504       ignore (x, y + 1, width, height, mask);
505     }
506 }
507 
508 
509 /* Recolor - conditionally change a feature's color to the closest color of all
510  * neighboring pixels
511  *
512  * Input parameters:
513  *   The color palette, current blob size, and adaptive tightness
514  *
515  *   Adaptive Tightness: (integer 1 to 256)
516  *     1   = really tight
517  *     256 = turn off the feature
518  *
519  * Modified parameters:
520  *   24 bit pixbuf and its mask (used to prevent backtracking)
521  *
522  * Returns:
523  *   TRUE  - feature was recolored, thus coalesced
524  *   FALSE - feature wasn't recolored
525  */
526 
527 static at_bool
recolor(double adaptive_tightness,int x,int y,int width,int height,unsigned char * bitmap,unsigned char * mask)528 recolor (/* in */     double adaptive_tightness,
529          /* in */     int    x,
530          /* in */     int    y,
531          /* in */     int    width,
532          /* in */     int    height,
533          /* in/out */ unsigned char *bitmap,
534          /* in/out */ unsigned char *mask)
535 {
536   unsigned char *index, *to_index;
537   int error_amt;
538 
539   index = &bitmap[3 * (y * width + x)    ];
540   to_index = NULL;
541   error_amt = 0;
542 
543   find_most_similar_neighbor (index, &to_index, &error_amt,
544                               x, y, width, height, bitmap, mask);
545 
546   /* This condition only fails if the bitmap is all the same color */
547   if (to_index != NULL)
548     {
549       double temp_error;
550 
551       /* Adaptive */
552       temp_error = calc_error (index, to_index);
553 
554       temp_error = sqrt (temp_error / 3.0);
555 
556       /*
557        * If the difference between the two colors is too great,
558        * don't coalesce the feature with its neighbor(s).  This prevents a
559        * color from turning into its complement.
560        */
561 
562       if (temp_error > adaptive_tightness)
563         fill (index, x, y, width, height, bitmap, mask);
564       else
565         {
566           fill (to_index, x, y, width, height, bitmap, mask);
567 
568           return true;
569         }
570     }
571 
572   return false;
573 }
574 
575 
576 /* Recolor - conditionally change a feature's color to the closest color of all
577  * neighboring pixels
578  *
579  * Input parameters:
580  *   The color palette, current blob size, and adaptive tightness
581  *
582  *   Adaptive Tightness: (integer 1 to 256)
583  *     1   = really tight
584  *     256 = turn off the feature
585  *
586  * Modified parameters:
587  *   8 bit pixbuf and its mask (used to prevent backtracking)
588  *
589  * Returns:
590  *   TRUE  - feature was recolored, thus coalesced
591  *   FALSE - feature wasn't recolored
592  */
593 
594 static at_bool
recolor_8(double adaptive_tightness,int x,int y,int width,int height,unsigned char * bitmap,unsigned char * mask)595 recolor_8 (/* in */   double adaptive_tightness,
596          /* in */     int    x,
597          /* in */     int    y,
598          /* in */     int    width,
599          /* in */     int    height,
600          /* in/out */ unsigned char *bitmap,
601          /* in/out */ unsigned char *mask)
602 {
603   unsigned char *index, *to_index;
604   int error_amt;
605 
606   index = &bitmap[(y * width + x)    ];
607   to_index = NULL;
608   error_amt = 0;
609 
610   find_most_similar_neighbor_8 (index, &to_index, &error_amt,
611                               x, y, width, height, bitmap, mask);
612 
613   /* This condition only fails if the bitmap is all the same color */
614   if (to_index != NULL)
615     {
616       double temp_error;
617 
618       /* Adaptive */
619       temp_error = calc_error_8 (index, to_index);
620 
621       temp_error = sqrt (temp_error / 3.0);
622 
623       /*
624        * If the difference between the two colors is too great,
625        * don't coalesce the feature with its neighbor(s).  This prevents a
626        * color from turning into its complement.
627        */
628 
629       if (temp_error > adaptive_tightness)
630         fill_8 (index, x, y, width, height, bitmap, mask);
631       else
632         {
633           fill_8 (to_index, x, y, width, height, bitmap, mask);
634 
635           return true;
636         }
637     }
638 
639   return false;
640 }
641 
642 
643 /* Despeckle Iteration - Despeckle all regions smaller than cur_size pixels
644  *
645  * Input Parameters:
646  *   Current blob size, maximum blob size
647  *   for all iterations (used to selectively recolor blobs), and adaptive
648  *   tightness
649  *
650  * Modified Parameters:
651  *   The 24 bit pixbuf is despeckled
652  */
653 
654 static void
despeckle_iteration(int level,double adaptive_tightness,int width,int height,unsigned char * bitmap)655 despeckle_iteration (/* in */     int    level,
656                      /* in */     double adaptive_tightness,
657                      /* in */     int    width,
658                      /* in */     int    height,
659                      /* in/out */ unsigned char *bitmap)
660 {
661   unsigned char *mask;
662   int    x, y;
663   int    i;
664   int    current_size;
665   int    tightness;
666 
667   for (i = 0, current_size = 1; i < level; i++, current_size *= 2)
668     tightness = (int) (256 / (1.0 + adaptive_tightness * level));
669 
670   mask = (unsigned char *) calloc (width * height, sizeof(unsigned char));
671   for (y = 0; y < height; y++)
672     {
673       for (x = 0; x < width; x++)
674         {
675           if (mask[y * width + x] == 0)
676             {
677               int size;
678 
679               size = find_size (&bitmap[3 * (y * width + x)], x, y,
680                                 width, height, bitmap, mask);
681 
682               assert (size > 0);
683 
684               if (size < current_size)
685                 {
686                   if (recolor (tightness,
687                                x, y, width, height,
688                                bitmap, mask))
689                     x--;
690                 }
691               else
692                 ignore (x, y, width, height, mask);
693             }
694         }
695     }
696 
697   free (mask);
698 }
699 
700 
701 /* Despeckle Iteration - Despeckle all regions smaller than cur_size pixels
702  *
703  * Input Parameters:
704  *   Current blob size, maximum blob size
705  *   for all iterations (used to selectively recolor blobs), and adaptive
706  *   tightness
707  *
708  * Modified Parameters:
709  *   The 8 bit pixbuf is despeckled
710  */
711 
712 static void
despeckle_iteration_8(int level,double adaptive_tightness,int width,int height,unsigned char * bitmap)713 despeckle_iteration_8 (/* in */   int    level,
714                      /* in */     double adaptive_tightness,
715                      /* in */     int    width,
716                      /* in */     int    height,
717                      /* in/out */ unsigned char *bitmap)
718 {
719   unsigned char *mask;
720   int    x, y;
721   int    i;
722   int    current_size;
723   int    tightness;
724 
725   for (i = 0, current_size = 1; i < level; i++, current_size *= 2)
726   tightness = (int) (256 / (1.0 + adaptive_tightness * level));
727 
728   mask = (unsigned char *) calloc (width * height, sizeof(unsigned char));
729   for (y = 0; y < height; y++)
730     {
731       for (x = 0; x < width; x++)
732         {
733           if (mask[y * width + x] == 0)
734             {
735               int size;
736 
737               size = find_size_8 (&bitmap[(y * width + x)], x, y,
738                                 width, height, bitmap, mask);
739 
740               assert (size > 0);
741 
742               if (size < current_size)
743                 {
744                   if (recolor_8 (tightness,
745                                x, y, width, height,
746                                bitmap, mask))
747                     x--;
748                 }
749               else
750                 ignore (x, y, width, height, mask);
751             }
752         }
753     }
754 
755   free (mask);
756 }
757 
758 
759 /* Despeckle - Despeckle an 8/24 bit image
760  *
761  * Input Parameters:
762  *   Color palette, current blob size, and the despeckling level
763  *
764  *   Despeckling level: Integer from 0 to ~20
765  *     0 = perform no despeckling
766  *     An increase of the despeckling level by one doubles the size of features
767  *
768  *   Adaptive tightness:
769  *     0 = Turn it off (whites may turn black and vice versa, etc)
770  *     3 = Good middle value
771  *     8 = Really tight
772  *
773  * Modified Parameters:
774  *   The 24 bit pixbuf is despeckled
775  */
776 
777 void
despeckle(bitmap_type * bitmap,int level,at_real tightness,at_exception_type * excep)778 despeckle (/* in/out */ bitmap_type *bitmap,
779            /* in */     int          level,
780            /* in */     at_real      tightness,
781 	   at_exception_type * excep)
782 {
783   int i;
784   int planes;
785 
786   planes = BITMAP_PLANES (*bitmap);
787 
788   assert (tightness >= 0.0 && tightness <= 8.0);
789   assert (level >= 0 && level <= 20);
790 
791   if (planes == 3) {
792   for (i = 0; i < level; i++)
793     despeckle_iteration (i, tightness, BITMAP_WIDTH (*bitmap),
794     BITMAP_HEIGHT (*bitmap), BITMAP_BITS(*bitmap));
795   }
796   else if (planes == 1) {
797   for (i = 0; i < level; i++)
798     despeckle_iteration_8 (i, tightness, BITMAP_WIDTH (*bitmap),
799     BITMAP_HEIGHT (*bitmap), BITMAP_BITS(*bitmap));
800   }
801   else
802     {
803       LOG1 ("despeckle: %u-plane images are not supported", planes);
804       at_exception_fatal(excep, "despeckle: wrong plane images are passed");
805       return;
806     }
807 
808 }
809