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