]> granicus.if.org Git - imagemagick/blob - MagickCore/threshold.c
(no commit message)
[imagemagick] / MagickCore / threshold.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %       TTTTT  H   H  RRRR   EEEEE  SSSSS  H   H   OOO   L      DDDD          %
7 %         T    H   H  R   R  E      SS     H   H  O   O  L      D   D         %
8 %         T    HHHHH  RRRR   EEE     SSS   HHHHH  O   O  L      D   D         %
9 %         T    H   H  R R    E         SS  H   H  O   O  L      D   D         %
10 %         T    H   H  R  R   EEEEE  SSSSS  H   H   OOO   LLLLL  DDDD          %
11 %                                                                             %
12 %                                                                             %
13 %                      MagickCore Image Threshold Methods                     %
14 %                                                                             %
15 %                               Software Design                               %
16 %                                 John Cristy                                 %
17 %                                 October 1996                                %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 %
38 */
39 \f
40 /*
41   Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/property.h"
45 #include "MagickCore/blob.h"
46 #include "MagickCore/cache-view.h"
47 #include "MagickCore/color.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colormap.h"
50 #include "MagickCore/colorspace.h"
51 #include "MagickCore/configure.h"
52 #include "MagickCore/constitute.h"
53 #include "MagickCore/decorate.h"
54 #include "MagickCore/draw.h"
55 #include "MagickCore/enhance.h"
56 #include "MagickCore/exception.h"
57 #include "MagickCore/exception-private.h"
58 #include "MagickCore/effect.h"
59 #include "MagickCore/fx.h"
60 #include "MagickCore/gem.h"
61 #include "MagickCore/geometry.h"
62 #include "MagickCore/image-private.h"
63 #include "MagickCore/list.h"
64 #include "MagickCore/log.h"
65 #include "MagickCore/memory_.h"
66 #include "MagickCore/monitor.h"
67 #include "MagickCore/monitor-private.h"
68 #include "MagickCore/montage.h"
69 #include "MagickCore/option.h"
70 #include "MagickCore/pixel-accessor.h"
71 #include "MagickCore/quantize.h"
72 #include "MagickCore/quantum.h"
73 #include "MagickCore/random_.h"
74 #include "MagickCore/random-private.h"
75 #include "MagickCore/resize.h"
76 #include "MagickCore/resource_.h"
77 #include "MagickCore/segment.h"
78 #include "MagickCore/shear.h"
79 #include "MagickCore/signature-private.h"
80 #include "MagickCore/string_.h"
81 #include "MagickCore/string-private.h"
82 #include "MagickCore/thread-private.h"
83 #include "MagickCore/threshold.h"
84 #include "MagickCore/token.h"
85 #include "MagickCore/transform.h"
86 #include "MagickCore/xml-tree.h"
87 #include "MagickCore/xml-tree-private.h"
88 \f
89 /*
90   Define declarations.
91 */
92 #define ThresholdsFilename  "thresholds.xml"
93 \f
94 /*
95   Typedef declarations.
96 */
97 struct _ThresholdMap
98 {
99   char
100     *map_id,
101     *description;
102
103   size_t
104     width,
105     height;
106
107   ssize_t
108     divisor,
109     *levels;
110 };
111 \f
112 /*
113   Forward declarations.
114 */
115 static ThresholdMap
116   *GetThresholdMapFile(const char *,const char *,const char *,ExceptionInfo *);
117 \f
118 /*
119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
120 %                                                                             %
121 %                                                                             %
122 %                                                                             %
123 %     A d a p t i v e T h r e s h o l d I m a g e                             %
124 %                                                                             %
125 %                                                                             %
126 %                                                                             %
127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
128 %
129 %  AdaptiveThresholdImage() selects an individual threshold for each pixel
130 %  based on the range of intensity values in its local neighborhood.  This
131 %  allows for thresholding of an image whose global intensity histogram
132 %  doesn't contain distinctive peaks.
133 %
134 %  The format of the AdaptiveThresholdImage method is:
135 %
136 %      Image *AdaptiveThresholdImage(const Image *image,const size_t width,
137 %        const size_t height,const double bias,ExceptionInfo *exception)
138 %
139 %  A description of each parameter follows:
140 %
141 %    o image: the image.
142 %
143 %    o width: the width of the local neighborhood.
144 %
145 %    o height: the height of the local neighborhood.
146 %
147 %    o bias: the mean bias.
148 %
149 %    o exception: return any errors or warnings in this structure.
150 %
151 */
152 MagickExport Image *AdaptiveThresholdImage(const Image *image,
153   const size_t width,const size_t height,const double bias,
154   ExceptionInfo *exception)
155 {
156 #define AdaptiveThresholdImageTag  "AdaptiveThreshold/Image"
157
158   CacheView
159     *image_view,
160     *threshold_view;
161
162   Image
163     *threshold_image;
164
165   MagickBooleanType
166     status;
167
168   MagickOffsetType
169     progress;
170
171   MagickSizeType
172     number_pixels;
173
174   ssize_t
175     y;
176
177   /*
178     Initialize threshold image attributes.
179   */
180   assert(image != (Image *) NULL);
181   assert(image->signature == MagickSignature);
182   if (image->debug != MagickFalse)
183     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
184   assert(exception != (ExceptionInfo *) NULL);
185   assert(exception->signature == MagickSignature);
186   if ((width % 2) == 0)
187     ThrowImageException(OptionError,"KernelWidthMustBeAnOddNumber");
188   threshold_image=CloneImage(image,image->columns,image->rows,MagickTrue,
189     exception);
190   if (threshold_image == (Image *) NULL)
191     return((Image *) NULL);
192   status=SetImageStorageClass(threshold_image,DirectClass,exception);
193   if (status == MagickFalse)
194     {
195       threshold_image=DestroyImage(threshold_image);
196       return((Image *) NULL);
197     }
198   /*
199     Threshold image.
200   */
201   status=MagickTrue;
202   progress=0;
203   number_pixels=(MagickSizeType) width*height;
204   image_view=AcquireCacheView(image);
205   threshold_view=AcquireCacheView(threshold_image);
206 #if defined(MAGICKCORE_OPENMP_SUPPORT)
207   #pragma omp parallel for schedule(static,4) shared(progress,status)
208 #endif
209   for (y=0; y < (ssize_t) image->rows; y++)
210   {
211     register const Quantum
212       *restrict p;
213
214     register Quantum
215       *restrict q;
216
217     register ssize_t
218       x;
219
220     ssize_t
221       center;
222
223     if (status == MagickFalse)
224       continue;
225     p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
226       (height/2L),image->columns+width,height,exception);
227     q=QueueCacheViewAuthenticPixels(threshold_view,0,y,threshold_image->columns,
228       1,exception);
229     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
230       {
231         status=MagickFalse;
232         continue;
233       }
234     center=(ssize_t) GetPixelChannels(image)*(image->columns+width)*(height/2L)+
235       GetPixelChannels(image)*(width/2);
236     for (x=0; x < (ssize_t) image->columns; x++)
237     {
238       register ssize_t
239         i;
240
241       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
242       {
243         MagickRealType
244           mean,
245           pixel;
246
247         PixelChannel
248           channel;
249
250         PixelTrait
251           threshold_traits,
252           traits;
253
254         register const Quantum
255           *restrict pixels;
256
257         register ssize_t
258           u;
259
260         ssize_t
261           v;
262
263         channel=GetPixelChannelMapChannel(image,i);
264         traits=GetPixelChannelMapTraits(image,channel);
265         threshold_traits=GetPixelChannelMapTraits(threshold_image,channel);
266         if ((traits == UndefinedPixelTrait) ||
267             (threshold_traits == UndefinedPixelTrait))
268           continue;
269         if ((threshold_traits & CopyPixelTrait) != 0)
270           {
271             SetPixelChannel(threshold_image,channel,p[center+i],q);
272             continue;
273           }
274         pixels=p;
275         pixel=0.0;
276         for (v=0; v < (ssize_t) height; v++)
277         {
278           for (u=0; u < (ssize_t) width; u++)
279           {
280             pixel+=pixels[i];
281             pixels+=GetPixelChannels(image);
282           }
283           pixels+=image->columns*GetPixelChannels(image);
284         }
285         mean=(MagickRealType) (pixel/number_pixels+bias);
286         SetPixelChannel(threshold_image,channel,(Quantum) ((MagickRealType)
287           p[center+i] <= mean ? 0 : QuantumRange),q);
288       }
289       p+=GetPixelChannels(image);
290       q+=GetPixelChannels(threshold_image);
291     }
292     if (SyncCacheViewAuthenticPixels(threshold_view,exception) == MagickFalse)
293       status=MagickFalse;
294     if (image->progress_monitor != (MagickProgressMonitor) NULL)
295       {
296         MagickBooleanType
297           proceed;
298
299 #if defined(MAGICKCORE_OPENMP_SUPPORT)
300   #pragma omp critical (MagickCore_AdaptiveThresholdImage)
301 #endif
302         proceed=SetImageProgress(image,AdaptiveThresholdImageTag,progress++,
303           image->rows);
304         if (proceed == MagickFalse)
305           status=MagickFalse;
306       }
307   }
308   threshold_image->type=image->type;
309   threshold_view=DestroyCacheView(threshold_view);
310   image_view=DestroyCacheView(image_view);
311   if (status == MagickFalse)
312     threshold_image=DestroyImage(threshold_image);
313   return(threshold_image);
314 }
315 \f
316 /*
317 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318 %                                                                             %
319 %                                                                             %
320 %                                                                             %
321 %     B i l e v e l I m a g e                                                 %
322 %                                                                             %
323 %                                                                             %
324 %                                                                             %
325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
326 %
327 %  BilevelImage() changes the value of individual pixels based on the
328 %  intensity of each pixel channel.  The result is a high-contrast image.
329 %
330 %  More precisely each channel value of the image is 'thresholded' so that if
331 %  it is equal to or less than the given value it is set to zero, while any
332 %  value greater than that give is set to it maximum or QuantumRange.
333 %
334 %  This function is what is used to implement the "-threshold" operator for
335 %  the command line API.
336 %
337 %  If the default channel setting is given the image is thresholded using just
338 %  the gray 'intensity' of the image, rather than the individual channels.
339 %
340 %  The format of the BilevelImage method is:
341 %
342 %      MagickBooleanType BilevelImage(Image *image,const double threshold,
343 %        ExceptionInfo *exception)
344 %
345 %  A description of each parameter follows:
346 %
347 %    o image: the image.
348 %
349 %    o threshold: define the threshold values.
350 %
351 %    o exception: return any errors or warnings in this structure.
352 %
353 %  Aside: You can get the same results as operator using LevelImages()
354 %  with the 'threshold' value for both the black_point and the white_point.
355 %
356 */
357 MagickExport MagickBooleanType BilevelImage(Image *image,const double threshold,
358   ExceptionInfo *exception)
359 {
360 #define ThresholdImageTag  "Threshold/Image"
361
362   CacheView
363     *image_view;
364
365   MagickBooleanType
366     status;
367
368   MagickOffsetType
369     progress;
370
371   ssize_t
372     y;
373
374   assert(image != (Image *) NULL);
375   assert(image->signature == MagickSignature);
376   if (image->debug != MagickFalse)
377     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
378   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
379     return(MagickFalse);
380   /*
381     Bilevel threshold image.
382   */
383   status=MagickTrue;
384   progress=0;
385   image_view=AcquireCacheView(image);
386 #if defined(MAGICKCORE_OPENMP_SUPPORT)
387   #pragma omp parallel for schedule(static,4) shared(progress,status)
388 #endif
389   for (y=0; y < (ssize_t) image->rows; y++)
390   {
391     register ssize_t
392       x;
393
394     register Quantum
395       *restrict q;
396
397     if (status == MagickFalse)
398       continue;
399     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
400     if (q == (Quantum *) NULL)
401       {
402         status=MagickFalse;
403         continue;
404       }
405     for (x=0; x < (ssize_t) image->columns; x++)
406     {
407       register ssize_t
408         i;
409
410       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
411       {
412         PixelChannel
413           channel;
414
415         PixelTrait
416           traits;
417
418         channel=GetPixelChannelMapChannel(image,i);
419         traits=GetPixelChannelMapTraits(image,channel);
420         if ((traits & UpdatePixelTrait) != 0)
421           q[i]=(Quantum) ((MagickRealType) q[i] <= threshold ? 0 :
422             QuantumRange);
423       }
424       q+=GetPixelChannels(image);
425     }
426     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
427       status=MagickFalse;
428     if (image->progress_monitor != (MagickProgressMonitor) NULL)
429       {
430         MagickBooleanType
431           proceed;
432
433 #if defined(MAGICKCORE_OPENMP_SUPPORT)
434   #pragma omp critical (MagickCore_BilevelImage)
435 #endif
436         proceed=SetImageProgress(image,ThresholdImageTag,progress++,
437           image->rows);
438         if (proceed == MagickFalse)
439           status=MagickFalse;
440       }
441   }
442   image_view=DestroyCacheView(image_view);
443   return(status);
444 }
445 \f
446 /*
447 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
448 %                                                                             %
449 %                                                                             %
450 %                                                                             %
451 %     B l a c k T h r e s h o l d I m a g e                                   %
452 %                                                                             %
453 %                                                                             %
454 %                                                                             %
455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
456 %
457 %  BlackThresholdImage() is like ThresholdImage() but forces all pixels below
458 %  the threshold into black while leaving all pixels at or above the threshold
459 %  unchanged.
460 %
461 %  The format of the BlackThresholdImage method is:
462 %
463 %      MagickBooleanType BlackThresholdImage(Image *image,
464 %        const char *threshold,ExceptionInfo *exception)
465 %
466 %  A description of each parameter follows:
467 %
468 %    o image: the image.
469 %
470 %    o threshold: define the threshold value.
471 %
472 %    o exception: return any errors or warnings in this structure.
473 %
474 */
475 MagickExport MagickBooleanType BlackThresholdImage(Image *image,
476   const char *thresholds,ExceptionInfo *exception)
477 {
478 #define ThresholdImageTag  "Threshold/Image"
479
480   CacheView
481     *image_view;
482
483   GeometryInfo
484     geometry_info;
485
486   MagickBooleanType
487     status;
488
489   MagickOffsetType
490     progress;
491
492   MagickRealType
493     threshold[5];
494
495   MagickStatusType
496     flags;
497
498   register ssize_t
499     i;
500
501   ssize_t
502     y;
503
504   assert(image != (Image *) NULL);
505   assert(image->signature == MagickSignature);
506   if (image->debug != MagickFalse)
507     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
508   if (thresholds == (const char *) NULL)
509     return(MagickTrue);
510   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
511     return(MagickFalse);
512   flags=ParseGeometry(thresholds,&geometry_info);
513   for (i=0; i < 5; i++)
514     threshold[i]=geometry_info.rho;
515   if ((flags & SigmaValue) != 0)
516     threshold[1]=geometry_info.sigma;
517   if ((flags & XiValue) != 0)
518     threshold[2]=geometry_info.xi;
519   if ((flags & PsiValue) != 0)
520     threshold[3]=geometry_info.psi;
521   if ((flags & ChiValue) != 0)
522     threshold[4]=geometry_info.chi;
523   if ((flags & PercentValue) != 0)
524     for (i=0; i < 5; i++)
525       threshold[i]*=(QuantumRange/100.0);
526   /*
527     White threshold image.
528   */
529   status=MagickTrue;
530   progress=0;
531   image_view=AcquireCacheView(image);
532 #if defined(MAGICKCORE_OPENMP_SUPPORT)
533   #pragma omp parallel for schedule(static,4) shared(progress,status)
534 #endif
535   for (y=0; y < (ssize_t) image->rows; y++)
536   {
537     register ssize_t
538       x;
539
540     register Quantum
541       *restrict q;
542
543     if (status == MagickFalse)
544       continue;
545     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
546     if (q == (Quantum *) NULL)
547       {
548         status=MagickFalse;
549         continue;
550       }
551     for (x=0; x < (ssize_t) image->columns; x++)
552     {
553       register ssize_t
554         i;
555
556       ssize_t
557         n;
558
559       n=0;
560       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
561       {
562         PixelChannel
563           channel;
564
565         PixelTrait
566           traits;
567
568         channel=GetPixelChannelMapChannel(image,i);
569         traits=GetPixelChannelMapTraits(image,channel);
570         if ((traits & UpdatePixelTrait) == 0)
571           continue;
572         if ((MagickRealType) q[i] < threshold[n++ % 5])
573           q[i]=QuantumRange;
574       }
575       q+=GetPixelChannels(image);
576     }
577     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
578       status=MagickFalse;
579     if (image->progress_monitor != (MagickProgressMonitor) NULL)
580       {
581         MagickBooleanType
582           proceed;
583
584 #if defined(MAGICKCORE_OPENMP_SUPPORT)
585   #pragma omp critical (MagickCore_WhiteThresholdImage)
586 #endif
587         proceed=SetImageProgress(image,ThresholdImageTag,progress++,
588           image->rows);
589         if (proceed == MagickFalse)
590           status=MagickFalse;
591       }
592   }
593   image_view=DestroyCacheView(image_view);
594   return(status);
595 }
596 \f
597 /*
598 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
599 %                                                                             %
600 %                                                                             %
601 %                                                                             %
602 %     C l a m p I m a g e                                                     %
603 %                                                                             %
604 %                                                                             %
605 %                                                                             %
606 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
607 %
608 %  ClampImage() restricts the color range from 0 to the quantum depth.
609 %
610 %  The format of the ClampImage method is:
611 %
612 %      MagickBooleanType ClampImage(Image *image,ExceptionInfo *exception)
613 %
614 %  A description of each parameter follows:
615 %
616 %    o image: the image.
617 %
618 %    o exception: return any errors or warnings in this structure.
619 %
620 */
621
622 static inline Quantum ClampToUnsignedQuantum(const Quantum quantum)
623 {
624 #if defined(MAGICKCORE_HDRI_SUPPORT)
625   if (quantum <= 0)
626     return(0);
627   if (quantum >= QuantumRange)
628     return(QuantumRange);
629   return(quantum);
630 #else
631   return(quantum);
632 #endif
633 }
634
635 MagickExport MagickBooleanType ClampImage(Image *image,ExceptionInfo *exception)
636 {
637 #define ClampImageTag  "Clamp/Image"
638
639   CacheView
640     *image_view;
641
642   MagickBooleanType
643     status;
644
645   MagickOffsetType
646     progress;
647
648   ssize_t
649     y;
650
651   assert(image != (Image *) NULL);
652   assert(image->signature == MagickSignature);
653   if (image->debug != MagickFalse)
654     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
655   if (image->storage_class == PseudoClass)
656     {
657       register ssize_t
658         i;
659
660       register PixelInfo
661         *restrict q;
662
663       q=image->colormap;
664       for (i=0; i < (ssize_t) image->colors; i++)
665       {
666         q->red=ClampToUnsignedQuantum(q->red);
667         q->green=ClampToUnsignedQuantum(q->green);
668         q->blue=ClampToUnsignedQuantum(q->blue);
669         q->alpha=ClampToUnsignedQuantum(q->alpha);
670         q++;
671       }
672       return(SyncImage(image,exception));
673     }
674   /*
675     Clamp image.
676   */
677   status=MagickTrue;
678   progress=0;
679   image_view=AcquireCacheView(image);
680 #if defined(MAGICKCORE_OPENMP_SUPPORT)
681   #pragma omp parallel for schedule(static,4) shared(progress,status)
682 #endif
683   for (y=0; y < (ssize_t) image->rows; y++)
684   {
685     register ssize_t
686       x;
687
688     register Quantum
689       *restrict q;
690
691     if (status == MagickFalse)
692       continue;
693     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
694     if (q == (Quantum *) NULL)
695       {
696         status=MagickFalse;
697         continue;
698       }
699     for (x=0; x < (ssize_t) image->columns; x++)
700     {
701       register ssize_t
702         i;
703
704       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
705       {
706         PixelChannel
707           channel;
708
709         PixelTrait
710           traits;
711
712         channel=GetPixelChannelMapChannel(image,i);
713         traits=GetPixelChannelMapTraits(image,channel);
714         if (traits == UndefinedPixelTrait)
715           continue;
716         q[i]=ClampToUnsignedQuantum(q[i]);
717       }
718       q+=GetPixelChannels(image);
719     }
720     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
721       status=MagickFalse;
722     if (image->progress_monitor != (MagickProgressMonitor) NULL)
723       {
724         MagickBooleanType
725           proceed;
726
727 #if defined(MAGICKCORE_OPENMP_SUPPORT)
728   #pragma omp critical (MagickCore_ClampImage)
729 #endif
730         proceed=SetImageProgress(image,ClampImageTag,progress++,
731           image->rows);
732         if (proceed == MagickFalse)
733           status=MagickFalse;
734       }
735   }
736   image_view=DestroyCacheView(image_view);
737   return(status);
738 }
739 \f
740 /*
741 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
742 %                                                                             %
743 %                                                                             %
744 %                                                                             %
745 %  D e s t r o y T h r e s h o l d M a p                                      %
746 %                                                                             %
747 %                                                                             %
748 %                                                                             %
749 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
750 %
751 %  DestroyThresholdMap() de-allocate the given ThresholdMap
752 %
753 %  The format of the ListThresholdMaps method is:
754 %
755 %      ThresholdMap *DestroyThresholdMap(Threshold *map)
756 %
757 %  A description of each parameter follows.
758 %
759 %    o map:    Pointer to the Threshold map to destroy
760 %
761 */
762 MagickExport ThresholdMap *DestroyThresholdMap(ThresholdMap *map)
763 {
764   assert(map != (ThresholdMap *) NULL);
765   if (map->map_id != (char *) NULL)
766     map->map_id=DestroyString(map->map_id);
767   if (map->description != (char *) NULL)
768     map->description=DestroyString(map->description);
769   if (map->levels != (ssize_t *) NULL)
770     map->levels=(ssize_t *) RelinquishMagickMemory(map->levels);
771   map=(ThresholdMap *) RelinquishMagickMemory(map);
772   return(map);
773 }
774 \f
775 /*
776 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
777 %                                                                             %
778 %                                                                             %
779 %                                                                             %
780 %  G e t T h r e s h o l d M a p                                              %
781 %                                                                             %
782 %                                                                             %
783 %                                                                             %
784 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
785 %
786 %  GetThresholdMap() loads and searches one or more threshold map files for the
787 %  map matching the given name or alias.
788 %
789 %  The format of the GetThresholdMap method is:
790 %
791 %      ThresholdMap *GetThresholdMap(const char *map_id,
792 %        ExceptionInfo *exception)
793 %
794 %  A description of each parameter follows.
795 %
796 %    o map_id:  ID of the map to look for.
797 %
798 %    o exception: return any errors or warnings in this structure.
799 %
800 */
801 MagickExport ThresholdMap *GetThresholdMap(const char *map_id,
802   ExceptionInfo *exception)
803 {
804   const StringInfo
805     *option;
806
807   LinkedListInfo
808     *options;
809
810   ThresholdMap
811     *map;
812
813   map=(ThresholdMap *)NULL;
814   options=GetConfigureOptions(ThresholdsFilename,exception);
815   while ((option=(const StringInfo *) GetNextValueInLinkedList(options)) !=
816          (const StringInfo *) NULL && (map == (ThresholdMap *) NULL))
817     map=GetThresholdMapFile((const char *) GetStringInfoDatum(option),
818       GetStringInfoPath(option),map_id,exception);
819   options=DestroyConfigureOptions(options);
820   return(map);
821 }
822 \f
823 /*
824 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
825 %                                                                             %
826 %                                                                             %
827 %                                                                             %
828 +  G e t T h r e s h o l d M a p F i l e                                      %
829 %                                                                             %
830 %                                                                             %
831 %                                                                             %
832 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
833 %
834 %  GetThresholdMapFile() look for a given threshold map name or alias in the
835 %  given XML file data, and return the allocated the map when found.
836 %
837 %  The format of the ListThresholdMaps method is:
838 %
839 %      ThresholdMap *GetThresholdMap(const char *xml,const char *filename,
840 %         const char *map_id,ExceptionInfo *exception)
841 %
842 %  A description of each parameter follows.
843 %
844 %    o xml:  The threshold map list in XML format.
845 %
846 %    o filename:  The threshold map XML filename.
847 %
848 %    o map_id:  ID of the map to look for in XML list.
849 %
850 %    o exception: return any errors or warnings in this structure.
851 %
852 */
853 static ThresholdMap *GetThresholdMapFile(const char *xml,
854   const char *filename,const char *map_id,ExceptionInfo *exception)
855 {
856   char
857     *p;
858
859   const char
860     *attribute,
861     *content;
862
863   double
864     value;
865
866   register ssize_t
867     i;
868
869   ThresholdMap
870     *map;
871
872   XMLTreeInfo
873     *description,
874     *levels,
875     *threshold,
876     *thresholds;
877
878   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
879     "Loading threshold map file \"%s\" ...",filename);
880   map=(ThresholdMap *) NULL;
881   thresholds=NewXMLTree(xml,exception);
882   if (thresholds == (XMLTreeInfo *) NULL)
883     return(map);
884   for (threshold=GetXMLTreeChild(thresholds,"threshold");
885        threshold != (XMLTreeInfo *) NULL;
886        threshold=GetNextXMLTreeTag(threshold))
887   {
888     attribute=GetXMLTreeAttribute(threshold,"map");
889     if ((attribute != (char *) NULL) && (LocaleCompare(map_id,attribute) == 0))
890       break;
891     attribute=GetXMLTreeAttribute(threshold,"alias");
892     if ((attribute != (char *) NULL) && (LocaleCompare(map_id,attribute) == 0))
893       break;
894   }
895   if (threshold == (XMLTreeInfo *) NULL)
896     return(map);
897   description=GetXMLTreeChild(threshold,"description");
898   if (description == (XMLTreeInfo *) NULL)
899     {
900       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
901         "XmlMissingElement", "<description>, map \"%s\"",map_id);
902       thresholds=DestroyXMLTree(thresholds);
903       return(map);
904     }
905   levels=GetXMLTreeChild(threshold,"levels");
906   if (levels == (XMLTreeInfo *) NULL)
907     {
908       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
909         "XmlMissingElement", "<levels>, map \"%s\"", map_id);
910       thresholds=DestroyXMLTree(thresholds);
911       return(map);
912     }
913   map=(ThresholdMap *) AcquireMagickMemory(sizeof(ThresholdMap));
914   if (map == (ThresholdMap *) NULL)
915     ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireThresholdMap");
916   map->map_id=(char *) NULL;
917   map->description=(char *) NULL;
918   map->levels=(ssize_t *) NULL;
919   attribute=GetXMLTreeAttribute(threshold,"map");
920   if (attribute != (char *) NULL)
921     map->map_id=ConstantString(attribute);
922   content=GetXMLTreeContent(description);
923   if (content != (char *) NULL)
924     map->description=ConstantString(content);
925   attribute=GetXMLTreeAttribute(levels,"width");
926   if (attribute == (char *) NULL)
927     {
928       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
929         "XmlMissingAttribute", "<levels width>, map \"%s\"",map_id);
930       thresholds=DestroyXMLTree(thresholds);
931       map=DestroyThresholdMap(map);
932       return(map);
933     }
934   map->width=StringToUnsignedLong(attribute);
935   if (map->width == 0)
936     {
937       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
938        "XmlInvalidAttribute", "<levels width>, map \"%s\"",map_id);
939       thresholds=DestroyXMLTree(thresholds);
940       map=DestroyThresholdMap(map);
941       return(map);
942     }
943   attribute=GetXMLTreeAttribute(levels,"height");
944   if (attribute == (char *) NULL)
945     {
946       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
947         "XmlMissingAttribute", "<levels height>, map \"%s\"",map_id);
948       thresholds=DestroyXMLTree(thresholds);
949       map=DestroyThresholdMap(map);
950       return(map);
951     }
952   map->height=StringToUnsignedLong(attribute);
953   if (map->height == 0)
954     {
955       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
956         "XmlInvalidAttribute", "<levels height>, map \"%s\"",map_id);
957       thresholds=DestroyXMLTree(thresholds);
958       map=DestroyThresholdMap(map);
959       return(map);
960     }
961   attribute=GetXMLTreeAttribute(levels,"divisor");
962   if (attribute == (char *) NULL)
963     {
964       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
965         "XmlMissingAttribute", "<levels divisor>, map \"%s\"",map_id);
966       thresholds=DestroyXMLTree(thresholds);
967       map=DestroyThresholdMap(map);
968       return(map);
969     }
970   map->divisor=(ssize_t) StringToLong(attribute);
971   if (map->divisor < 2)
972     {
973       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
974         "XmlInvalidAttribute", "<levels divisor>, map \"%s\"",map_id);
975       thresholds=DestroyXMLTree(thresholds);
976       map=DestroyThresholdMap(map);
977       return(map);
978     }
979   content=GetXMLTreeContent(levels);
980   if (content == (char *) NULL)
981     {
982       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
983         "XmlMissingContent", "<levels>, map \"%s\"",map_id);
984       thresholds=DestroyXMLTree(thresholds);
985       map=DestroyThresholdMap(map);
986       return(map);
987     }
988   map->levels=(ssize_t *) AcquireQuantumMemory((size_t) map->width,map->height*
989     sizeof(*map->levels));
990   if (map->levels == (ssize_t *) NULL)
991     ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireThresholdMap");
992   for (i=0; i < (ssize_t) (map->width*map->height); i++)
993   {
994     map->levels[i]=(ssize_t) strtol(content,&p,10);
995     if (p == content)
996       {
997         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
998           "XmlInvalidContent", "<level> too few values, map \"%s\"",map_id);
999         thresholds=DestroyXMLTree(thresholds);
1000         map=DestroyThresholdMap(map);
1001         return(map);
1002       }
1003     if ((map->levels[i] < 0) || (map->levels[i] > map->divisor))
1004       {
1005         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1006           "XmlInvalidContent", "<level> %.20g out of range, map \"%s\"",
1007           (double) map->levels[i],map_id);
1008         thresholds=DestroyXMLTree(thresholds);
1009         map=DestroyThresholdMap(map);
1010         return(map);
1011       }
1012     content=p;
1013   }
1014   value=(double) strtol(content,&p,10);
1015   (void) value;
1016   if (p != content)
1017     {
1018       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1019         "XmlInvalidContent", "<level> too many values, map \"%s\"",map_id);
1020      thresholds=DestroyXMLTree(thresholds);
1021      map=DestroyThresholdMap(map);
1022      return(map);
1023    }
1024   thresholds=DestroyXMLTree(thresholds);
1025   return(map);
1026 }
1027 \f
1028 /*
1029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1030 %                                                                             %
1031 %                                                                             %
1032 %                                                                             %
1033 +  L i s t T h r e s h o l d M a p F i l e                                    %
1034 %                                                                             %
1035 %                                                                             %
1036 %                                                                             %
1037 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1038 %
1039 %  ListThresholdMapFile() lists the threshold maps and their descriptions
1040 %  in the given XML file data.
1041 %
1042 %  The format of the ListThresholdMaps method is:
1043 %
1044 %      MagickBooleanType ListThresholdMaps(FILE *file,const char*xml,
1045 %         const char *filename,ExceptionInfo *exception)
1046 %
1047 %  A description of each parameter follows.
1048 %
1049 %    o file:  An pointer to the output FILE.
1050 %
1051 %    o xml:  The threshold map list in XML format.
1052 %
1053 %    o filename:  The threshold map XML filename.
1054 %
1055 %    o exception: return any errors or warnings in this structure.
1056 %
1057 */
1058 MagickBooleanType ListThresholdMapFile(FILE *file,const char *xml,
1059   const char *filename,ExceptionInfo *exception)
1060 {
1061   const char
1062     *alias,
1063     *content,
1064     *map;
1065
1066   XMLTreeInfo
1067     *description,
1068     *threshold,
1069     *thresholds;
1070
1071   assert( xml != (char *)NULL );
1072   assert( file != (FILE *)NULL );
1073   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1074     "Loading threshold map file \"%s\" ...",filename);
1075   thresholds=NewXMLTree(xml,exception);
1076   if ( thresholds == (XMLTreeInfo *)NULL )
1077     return(MagickFalse);
1078   (void) FormatLocaleFile(file,"%-16s %-12s %s\n","Map","Alias","Description");
1079   (void) FormatLocaleFile(file,
1080     "----------------------------------------------------\n");
1081   threshold=GetXMLTreeChild(thresholds,"threshold");
1082   for ( ; threshold != (XMLTreeInfo *) NULL;
1083           threshold=GetNextXMLTreeTag(threshold))
1084   {
1085     map=GetXMLTreeAttribute(threshold,"map");
1086     if (map == (char *) NULL)
1087       {
1088         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1089           "XmlMissingAttribute", "<map>");
1090         thresholds=DestroyXMLTree(thresholds);
1091         return(MagickFalse);
1092       }
1093     alias=GetXMLTreeAttribute(threshold,"alias");
1094     description=GetXMLTreeChild(threshold,"description");
1095     if (description == (XMLTreeInfo *) NULL)
1096       {
1097         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1098           "XmlMissingElement", "<description>, map \"%s\"",map);
1099         thresholds=DestroyXMLTree(thresholds);
1100         return(MagickFalse);
1101       }
1102     content=GetXMLTreeContent(description);
1103     if (content == (char *) NULL)
1104       {
1105         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1106           "XmlMissingContent", "<description>, map \"%s\"", map);
1107         thresholds=DestroyXMLTree(thresholds);
1108         return(MagickFalse);
1109       }
1110     (void) FormatLocaleFile(file,"%-16s %-12s %s\n",map,alias ? alias : "",
1111       content);
1112   }
1113   thresholds=DestroyXMLTree(thresholds);
1114   return(MagickTrue);
1115 }
1116 \f
1117 /*
1118 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1119 %                                                                             %
1120 %                                                                             %
1121 %                                                                             %
1122 %  L i s t T h r e s h o l d M a p s                                          %
1123 %                                                                             %
1124 %                                                                             %
1125 %                                                                             %
1126 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1127 %
1128 %  ListThresholdMaps() lists the threshold maps and their descriptions
1129 %  as defined by "threshold.xml" to a file.
1130 %
1131 %  The format of the ListThresholdMaps method is:
1132 %
1133 %      MagickBooleanType ListThresholdMaps(FILE *file,ExceptionInfo *exception)
1134 %
1135 %  A description of each parameter follows.
1136 %
1137 %    o file:  An pointer to the output FILE.
1138 %
1139 %    o exception: return any errors or warnings in this structure.
1140 %
1141 */
1142 MagickExport MagickBooleanType ListThresholdMaps(FILE *file,
1143   ExceptionInfo *exception)
1144 {
1145   const StringInfo
1146     *option;
1147
1148   LinkedListInfo
1149     *options;
1150
1151   MagickStatusType
1152     status;
1153
1154   status=MagickFalse;
1155   if (file == (FILE *) NULL)
1156     file=stdout;
1157   options=GetConfigureOptions(ThresholdsFilename,exception);
1158   (void) FormatLocaleFile(file,
1159     "\n   Threshold Maps for Ordered Dither Operations\n");
1160   while ((option=(const StringInfo *) GetNextValueInLinkedList(options)) !=
1161          (const StringInfo *) NULL)
1162   {
1163     (void) FormatLocaleFile(file,"\nPATH: %s\n\n",GetStringInfoPath(option));
1164     status|=ListThresholdMapFile(file,(const char *) GetStringInfoDatum(option),
1165       GetStringInfoPath(option),exception);
1166   }
1167   options=DestroyConfigureOptions(options);
1168   return(status != 0 ? MagickTrue : MagickFalse);
1169 }
1170 \f
1171 /*
1172 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1173 %                                                                             %
1174 %                                                                             %
1175 %                                                                             %
1176 %     O r d e r e d P o s t e r i z e I m a g e                               %
1177 %                                                                             %
1178 %                                                                             %
1179 %                                                                             %
1180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1181 %
1182 %  OrderedPosterizeImage() will perform a ordered dither based on a number
1183 %  of pre-defined dithering threshold maps, but over multiple intensity
1184 %  levels, which can be different for different channels, according to the
1185 %  input argument.
1186 %
1187 %  The format of the OrderedPosterizeImage method is:
1188 %
1189 %      MagickBooleanType OrderedPosterizeImage(Image *image,
1190 %        const char *threshold_map,ExceptionInfo *exception)
1191 %
1192 %  A description of each parameter follows:
1193 %
1194 %    o image: the image.
1195 %
1196 %    o threshold_map: A string containing the name of the threshold dither
1197 %      map to use, followed by zero or more numbers representing the number
1198 %      of color levels tho dither between.
1199 %
1200 %      Any level number less than 2 will be equivalent to 2, and means only
1201 %      binary dithering will be applied to each color channel.
1202 %
1203 %      No numbers also means a 2 level (bitmap) dither will be applied to all
1204 %      channels, while a single number is the number of levels applied to each
1205 %      channel in sequence.  More numbers will be applied in turn to each of
1206 %      the color channels.
1207 %
1208 %      For example: "o3x3,6" will generate a 6 level posterization of the
1209 %      image with a ordered 3x3 diffused pixel dither being applied between
1210 %      each level. While checker,8,8,4 will produce a 332 colormaped image
1211 %      with only a single checkerboard hash pattern (50% grey) between each
1212 %      color level, to basically double the number of color levels with
1213 %      a bare minimim of dithering.
1214 %
1215 %    o exception: return any errors or warnings in this structure.
1216 %
1217 */
1218 MagickExport MagickBooleanType OrderedPosterizeImage(Image *image,
1219   const char *threshold_map,ExceptionInfo *exception)
1220 {
1221 #define DitherImageTag  "Dither/Image"
1222
1223   CacheView
1224     *image_view;
1225
1226   char
1227     token[MaxTextExtent];
1228
1229   const char
1230     *p;
1231
1232   MagickBooleanType
1233     status;
1234
1235   MagickOffsetType
1236     progress;
1237
1238   MagickRealType
1239     levels[CompositePixelChannel];
1240
1241   register ssize_t
1242     i;
1243
1244   ssize_t
1245     y;
1246
1247   ThresholdMap
1248     *map;
1249
1250   assert(image != (Image *) NULL);
1251   assert(image->signature == MagickSignature);
1252   if (image->debug != MagickFalse)
1253     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1254   assert(exception != (ExceptionInfo *) NULL);
1255   assert(exception->signature == MagickSignature);
1256   if (threshold_map == (const char *) NULL)
1257     return(MagickTrue);
1258   p=(char *) threshold_map;
1259   while (((isspace((int) ((unsigned char) *p)) != 0) || (*p == ',')) &&
1260          (*p != '\0'))
1261     p++;
1262   threshold_map=p;
1263   while (((isspace((int) ((unsigned char) *p)) == 0) && (*p != ',')) &&
1264          (*p != '\0'))
1265   {
1266     if ((p-threshold_map) >= (MaxTextExtent-1))
1267       break;
1268     token[p-threshold_map]=(*p);
1269     p++;
1270   }
1271   token[p-threshold_map]='\0';
1272   map=GetThresholdMap(token,exception);
1273   if (map == (ThresholdMap *) NULL)
1274     {
1275       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1276         "InvalidArgument","%s : '%s'","ordered-dither",threshold_map);
1277       return(MagickFalse);
1278     }
1279   for (i=0; i < MaxPixelChannels; i++)
1280     levels[i]=2.0;
1281   p=strchr((char *) threshold_map,',');
1282   if ((p != (char *) NULL) && (isdigit((int) ((unsigned char) *(++p))) != 0))
1283     for (i=0; (*p != '\0') && (i < MaxPixelChannels); i++)
1284     {
1285       GetMagickToken(p,&p,token);
1286       if (*token == ',')
1287         GetMagickToken(p,&p,token);
1288       levels[i]=StringToDouble(token,(char **) NULL);
1289     }
1290   for (i=0; i < MaxPixelChannels; i++)
1291     if (fabs(levels[i]) >= 1)
1292       levels[i]-=1.0;
1293   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1294     return(MagickFalse);
1295   status=MagickTrue;
1296   progress=0;
1297   image_view=AcquireCacheView(image);
1298 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1299   #pragma omp parallel for schedule(static,4) shared(progress,status)
1300 #endif
1301   for (y=0; y < (ssize_t) image->rows; y++)
1302   {
1303     register ssize_t
1304       x;
1305
1306     register Quantum
1307       *restrict q;
1308
1309     if (status == MagickFalse)
1310       continue;
1311     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1312     if (q == (Quantum *) NULL)
1313       {
1314         status=MagickFalse;
1315         continue;
1316       }
1317     for (x=0; x < (ssize_t) image->columns; x++)
1318     {
1319       register ssize_t
1320         i;
1321
1322       ssize_t
1323         n;
1324
1325       n=0;
1326       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1327       {
1328         PixelChannel
1329           channel;
1330
1331         PixelTrait
1332           traits;
1333
1334         ssize_t
1335           level,
1336           threshold;
1337
1338         channel=GetPixelChannelMapChannel(image,i);
1339         traits=GetPixelChannelMapTraits(image,channel);
1340         if ((traits & UpdatePixelTrait) == 0)
1341           continue;
1342         if (fabs(levels[n++]) < MagickEpsilon)
1343           continue;
1344         threshold=(ssize_t) (QuantumScale*q[i]*(levels[n]*(map->divisor-1)+1));
1345         level=threshold/(map->divisor-1);
1346         threshold-=level*(map->divisor-1);
1347         q[i]=RoundToQuantum((level+(threshold >= map->levels[(x % map->width)+
1348           map->width*(y % map->height)]))*QuantumRange/levels[n]);
1349         n++;
1350       }
1351       q+=GetPixelChannels(image);
1352     }
1353     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1354       status=MagickFalse;
1355     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1356       {
1357         MagickBooleanType
1358           proceed;
1359
1360 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1361 #pragma omp critical (MagickCore_OrderedPosterizeImage)
1362 #endif
1363         proceed=SetImageProgress(image,DitherImageTag,progress++,image->rows);
1364         if (proceed == MagickFalse)
1365           status=MagickFalse;
1366       }
1367   }
1368   image_view=DestroyCacheView(image_view);
1369   map=DestroyThresholdMap(map);
1370   return(MagickTrue);
1371 }
1372 \f
1373 /*
1374 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1375 %                                                                             %
1376 %                                                                             %
1377 %                                                                             %
1378 %     R a n d o m T h r e s h o l d I m a g e                                 %
1379 %                                                                             %
1380 %                                                                             %
1381 %                                                                             %
1382 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1383 %
1384 %  RandomThresholdImage() changes the value of individual pixels based on the
1385 %  intensity of each pixel compared to a random threshold.  The result is a
1386 %  low-contrast, two color image.
1387 %
1388 %  The format of the RandomThresholdImage method is:
1389 %
1390 %      MagickBooleanType RandomThresholdImage(Image *image,
1391 %        const char *thresholds,ExceptionInfo *exception)
1392 %
1393 %  A description of each parameter follows:
1394 %
1395 %    o image: the image.
1396 %
1397 %    o thresholds: a geometry string containing low,high thresholds.  If the
1398 %      string contains 2x2, 3x3, or 4x4, an ordered dither of order 2, 3, or 4
1399 %      is performed instead.
1400 %
1401 %    o exception: return any errors or warnings in this structure.
1402 %
1403 */
1404 MagickExport MagickBooleanType RandomThresholdImage(Image *image,
1405   const char *thresholds,ExceptionInfo *exception)
1406 {
1407 #define ThresholdImageTag  "Threshold/Image"
1408
1409   CacheView
1410     *image_view;
1411
1412   GeometryInfo
1413     geometry_info;
1414
1415   MagickStatusType
1416     flags;
1417
1418   MagickBooleanType
1419     status;
1420
1421   MagickOffsetType
1422     progress;
1423
1424   PixelInfo
1425     threshold;
1426
1427   MagickRealType
1428     min_threshold,
1429     max_threshold;
1430
1431   RandomInfo
1432     **restrict random_info;
1433
1434   ssize_t
1435     y;
1436
1437   assert(image != (Image *) NULL);
1438   assert(image->signature == MagickSignature);
1439   if (image->debug != MagickFalse)
1440     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1441   assert(exception != (ExceptionInfo *) NULL);
1442   assert(exception->signature == MagickSignature);
1443   if (thresholds == (const char *) NULL)
1444     return(MagickTrue);
1445   GetPixelInfo(image,&threshold);
1446   min_threshold=0.0;
1447   max_threshold=(MagickRealType) QuantumRange;
1448   flags=ParseGeometry(thresholds,&geometry_info);
1449   min_threshold=geometry_info.rho;
1450   max_threshold=geometry_info.sigma;
1451   if ((flags & SigmaValue) == 0)
1452     max_threshold=min_threshold;
1453   if (strchr(thresholds,'%') != (char *) NULL)
1454     {
1455       max_threshold*=(MagickRealType) (0.01*QuantumRange);
1456       min_threshold*=(MagickRealType) (0.01*QuantumRange);
1457     }
1458   /*
1459     Random threshold image.
1460   */
1461   status=MagickTrue;
1462   progress=0;
1463   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1464     return(MagickFalse);
1465   random_info=AcquireRandomInfoThreadSet();
1466   image_view=AcquireCacheView(image);
1467 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1468   #pragma omp parallel for schedule(static,4) shared(progress,status)
1469 #endif
1470   for (y=0; y < (ssize_t) image->rows; y++)
1471   {
1472     const int
1473       id = GetOpenMPThreadId();
1474
1475     register Quantum
1476       *restrict q;
1477
1478     register ssize_t
1479       x;
1480
1481     if (status == MagickFalse)
1482       continue;
1483     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1484     if (q == (Quantum *) NULL)
1485       {
1486         status=MagickFalse;
1487         continue;
1488       }
1489     for (x=0; x < (ssize_t) image->columns; x++)
1490     {
1491       register ssize_t
1492         i;
1493
1494       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1495       {
1496         MagickRealType
1497           threshold;
1498
1499         PixelChannel
1500           channel;
1501
1502         PixelTrait
1503           traits;
1504
1505         channel=GetPixelChannelMapChannel(image,i);
1506         traits=GetPixelChannelMapTraits(image,channel);
1507         if ((traits & UpdatePixelTrait) == 0)
1508           continue;
1509         if ((MagickRealType) q[i] < min_threshold)
1510           threshold=min_threshold;
1511         else
1512           if ((MagickRealType) q[i] > max_threshold)
1513             threshold=max_threshold;
1514           else
1515             threshold=(MagickRealType) (QuantumRange*
1516               GetPseudoRandomValue(random_info[id]));
1517           q[i]=(Quantum) ((MagickRealType) q[i] <= threshold ? 0 :
1518             QuantumRange);
1519       }
1520       q+=GetPixelChannels(image);
1521     }
1522     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1523       status=MagickFalse;
1524     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1525       {
1526         MagickBooleanType
1527           proceed;
1528
1529 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1530   #pragma omp critical (MagickCore_RandomThresholdImage)
1531 #endif
1532         proceed=SetImageProgress(image,ThresholdImageTag,progress++,
1533           image->rows);
1534         if (proceed == MagickFalse)
1535           status=MagickFalse;
1536       }
1537   }
1538   image_view=DestroyCacheView(image_view);
1539   random_info=DestroyRandomInfoThreadSet(random_info);
1540   return(status);
1541 }
1542 \f
1543 /*
1544 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1545 %                                                                             %
1546 %                                                                             %
1547 %                                                                             %
1548 %     W h i t e T h r e s h o l d I m a g e                                   %
1549 %                                                                             %
1550 %                                                                             %
1551 %                                                                             %
1552 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1553 %
1554 %  WhiteThresholdImage() is like ThresholdImage() but forces all pixels above
1555 %  the threshold into white while leaving all pixels at or below the threshold
1556 %  unchanged.
1557 %
1558 %  The format of the WhiteThresholdImage method is:
1559 %
1560 %      MagickBooleanType WhiteThresholdImage(Image *image,
1561 %        const char *threshold,ExceptionInfo *exception)
1562 %
1563 %  A description of each parameter follows:
1564 %
1565 %    o image: the image.
1566 %
1567 %    o threshold: Define the threshold value.
1568 %
1569 %    o exception: return any errors or warnings in this structure.
1570 %
1571 */
1572 MagickExport MagickBooleanType WhiteThresholdImage(Image *image,
1573   const char *thresholds,ExceptionInfo *exception)
1574 {
1575 #define ThresholdImageTag  "Threshold/Image"
1576
1577   CacheView
1578     *image_view;
1579
1580   GeometryInfo
1581     geometry_info;
1582
1583   MagickBooleanType
1584     status;
1585
1586   MagickOffsetType
1587     progress;
1588
1589   MagickRealType
1590     threshold[5];
1591
1592   MagickStatusType
1593     flags;
1594
1595   register ssize_t
1596     i;
1597
1598   ssize_t
1599     y;
1600
1601   assert(image != (Image *) NULL);
1602   assert(image->signature == MagickSignature);
1603   if (image->debug != MagickFalse)
1604     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1605   if (thresholds == (const char *) NULL)
1606     return(MagickTrue);
1607   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1608     return(MagickFalse);
1609   flags=ParseGeometry(thresholds,&geometry_info);
1610   for (i=0; i < 5; i++)
1611     threshold[i]=geometry_info.rho;
1612   if ((flags & SigmaValue) != 0)
1613     threshold[1]=geometry_info.sigma;
1614   if ((flags & XiValue) != 0)
1615     threshold[2]=geometry_info.xi;
1616   if ((flags & PsiValue) != 0)
1617     threshold[3]=geometry_info.psi;
1618   if ((flags & ChiValue) != 0)
1619     threshold[4]=geometry_info.chi;
1620   if ((flags & PercentValue) != 0)
1621     for (i=0; i < 5; i++)
1622       threshold[i]*=(QuantumRange/100.0);
1623   /*
1624     White threshold image.
1625   */
1626   status=MagickTrue;
1627   progress=0;
1628   image_view=AcquireCacheView(image);
1629 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1630   #pragma omp parallel for schedule(static,4) shared(progress,status)
1631 #endif
1632   for (y=0; y < (ssize_t) image->rows; y++)
1633   {
1634     register ssize_t
1635       x;
1636
1637     register Quantum
1638       *restrict q;
1639
1640     if (status == MagickFalse)
1641       continue;
1642     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1643     if (q == (Quantum *) NULL)
1644       {
1645         status=MagickFalse;
1646         continue;
1647       }
1648     for (x=0; x < (ssize_t) image->columns; x++)
1649     {
1650       register ssize_t
1651         i;
1652
1653       ssize_t
1654         n;
1655
1656       n=0;
1657       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1658       {
1659         PixelChannel
1660           channel;
1661
1662         PixelTrait
1663           traits;
1664
1665         channel=GetPixelChannelMapChannel(image,i);
1666         traits=GetPixelChannelMapTraits(image,channel);
1667         if ((traits & UpdatePixelTrait) == 0)
1668           continue;
1669         if ((MagickRealType) q[i] > threshold[n++ % 5])
1670           q[i]=QuantumRange;
1671       }
1672       q+=GetPixelChannels(image);
1673     }
1674     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1675       status=MagickFalse;
1676     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1677       {
1678         MagickBooleanType
1679           proceed;
1680
1681 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1682   #pragma omp critical (MagickCore_WhiteThresholdImage)
1683 #endif
1684         proceed=SetImageProgress(image,ThresholdImageTag,progress++,
1685           image->rows);
1686         if (proceed == MagickFalse)
1687           status=MagickFalse;
1688       }
1689   }
1690   image_view=DestroyCacheView(image_view);
1691   return(status);
1692 }