]> 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-2011 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(dynamic,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         traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
264         channel=GetPixelChannelMapChannel(image,(PixelChannel) i);
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(dynamic,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         PixelTrait
413           traits;
414
415         traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
416         if ((traits & UpdatePixelTrait) != 0)
417           q[i]=(Quantum) ((MagickRealType) q[i] <= threshold ? 0 :
418             QuantumRange);
419       }
420       q+=GetPixelChannels(image);
421     }
422     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
423       status=MagickFalse;
424     if (image->progress_monitor != (MagickProgressMonitor) NULL)
425       {
426         MagickBooleanType
427           proceed;
428
429 #if defined(MAGICKCORE_OPENMP_SUPPORT)
430   #pragma omp critical (MagickCore_BilevelImage)
431 #endif
432         proceed=SetImageProgress(image,ThresholdImageTag,progress++,
433           image->rows);
434         if (proceed == MagickFalse)
435           status=MagickFalse;
436       }
437   }
438   image_view=DestroyCacheView(image_view);
439   return(status);
440 }
441 \f
442 /*
443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
444 %                                                                             %
445 %                                                                             %
446 %                                                                             %
447 %     B l a c k T h r e s h o l d I m a g e                                   %
448 %                                                                             %
449 %                                                                             %
450 %                                                                             %
451 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
452 %
453 %  BlackThresholdImage() is like ThresholdImage() but forces all pixels below
454 %  the threshold into black while leaving all pixels at or above the threshold
455 %  unchanged.
456 %
457 %  The format of the BlackThresholdImage method is:
458 %
459 %      MagickBooleanType BlackThresholdImage(Image *image,
460 %        const char *threshold,ExceptionInfo *exception)
461 %
462 %  A description of each parameter follows:
463 %
464 %    o image: the image.
465 %
466 %    o threshold: define the threshold value.
467 %
468 %    o exception: return any errors or warnings in this structure.
469 %
470 */
471 MagickExport MagickBooleanType BlackThresholdImage(Image *image,
472   const char *thresholds,ExceptionInfo *exception)
473 {
474 #define ThresholdImageTag  "Threshold/Image"
475
476   CacheView
477     *image_view;
478
479   GeometryInfo
480     geometry_info;
481
482   MagickBooleanType
483     status;
484
485   MagickOffsetType
486     progress;
487
488   MagickRealType
489     threshold[5];
490
491   MagickStatusType
492     flags;
493
494   register ssize_t
495     i;
496
497   ssize_t
498     y;
499
500   assert(image != (Image *) NULL);
501   assert(image->signature == MagickSignature);
502   if (image->debug != MagickFalse)
503     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
504   if (thresholds == (const char *) NULL)
505     return(MagickTrue);
506   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
507     return(MagickFalse);
508   flags=ParseGeometry(thresholds,&geometry_info);
509   for (i=0; i < 5; i++)
510     threshold[i]=geometry_info.rho;
511   if ((flags & SigmaValue) != 0)
512     threshold[1]=geometry_info.sigma;
513   if ((flags & XiValue) != 0)
514     threshold[2]=geometry_info.xi;
515   if ((flags & PsiValue) != 0)
516     threshold[3]=geometry_info.psi;
517   if ((flags & ChiValue) != 0)
518     threshold[4]=geometry_info.chi;
519   if ((flags & PercentValue) != 0)
520     for (i=0; i < 5; i++)
521       threshold[i]*=(QuantumRange/100.0);
522   /*
523     White threshold image.
524   */
525   status=MagickTrue;
526   progress=0;
527   image_view=AcquireCacheView(image);
528 #if defined(MAGICKCORE_OPENMP_SUPPORT)
529   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
530 #endif
531   for (y=0; y < (ssize_t) image->rows; y++)
532   {
533     register ssize_t
534       x;
535
536     register Quantum
537       *restrict q;
538
539     if (status == MagickFalse)
540       continue;
541     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
542     if (q == (Quantum *) NULL)
543       {
544         status=MagickFalse;
545         continue;
546       }
547     for (x=0; x < (ssize_t) image->columns; x++)
548     {
549       register ssize_t
550         i;
551
552       ssize_t
553         n;
554
555       n=0;
556       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
557       {
558         PixelTrait
559           traits;
560
561         traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
562         if ((traits & UpdatePixelTrait) == 0)
563           continue;
564         if ((MagickRealType) q[i] < threshold[n++ % 5])
565           q[i]=QuantumRange;
566       }
567       q+=GetPixelChannels(image);
568     }
569     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
570       status=MagickFalse;
571     if (image->progress_monitor != (MagickProgressMonitor) NULL)
572       {
573         MagickBooleanType
574           proceed;
575
576 #if defined(MAGICKCORE_OPENMP_SUPPORT)
577   #pragma omp critical (MagickCore_WhiteThresholdImage)
578 #endif
579         proceed=SetImageProgress(image,ThresholdImageTag,progress++,
580           image->rows);
581         if (proceed == MagickFalse)
582           status=MagickFalse;
583       }
584   }
585   image_view=DestroyCacheView(image_view);
586   return(status);
587 }
588 \f
589 /*
590 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
591 %                                                                             %
592 %                                                                             %
593 %                                                                             %
594 %     C l a m p I m a g e                                                     %
595 %                                                                             %
596 %                                                                             %
597 %                                                                             %
598 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
599 %
600 %  ClampImage() restricts the color range from 0 to the quantum depth.
601 %
602 %  The format of the ClampImage method is:
603 %
604 %      MagickBooleanType ClampImage(Image *image,ExceptionInfo *exception)
605 %
606 %  A description of each parameter follows:
607 %
608 %    o image: the image.
609 %
610 %    o exception: return any errors or warnings in this structure.
611 %
612 */
613
614 static inline Quantum ClampToUnsignedQuantum(const Quantum quantum)
615 {
616 #if defined(MAGICKCORE_HDRI_SUPPORT)
617   if (quantum <= 0)
618     return(0);
619   if (quantum >= QuantumRange)
620     return(QuantumRange);
621   return(quantum);
622 #else
623   return(quantum);
624 #endif
625 }
626
627 MagickExport MagickBooleanType ClampImage(Image *image,ExceptionInfo *exception)
628 {
629 #define ClampImageTag  "Clamp/Image"
630
631   CacheView
632     *image_view;
633
634   MagickBooleanType
635     status;
636
637   MagickOffsetType
638     progress;
639
640   ssize_t
641     y;
642
643   assert(image != (Image *) NULL);
644   assert(image->signature == MagickSignature);
645   if (image->debug != MagickFalse)
646     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
647   if (image->storage_class == PseudoClass)
648     {
649       register ssize_t
650         i;
651
652       register PixelInfo
653         *restrict q;
654
655       q=image->colormap;
656       for (i=0; i < (ssize_t) image->colors; i++)
657       {
658         q->red=ClampToUnsignedQuantum(q->red);
659         q->green=ClampToUnsignedQuantum(q->green);
660         q->blue=ClampToUnsignedQuantum(q->blue);
661         q->alpha=ClampToUnsignedQuantum(q->alpha);
662         q++;
663       }
664       return(SyncImage(image,exception));
665     }
666   /*
667     Clamp image.
668   */
669   status=MagickTrue;
670   progress=0;
671   image_view=AcquireCacheView(image);
672 #if defined(MAGICKCORE_OPENMP_SUPPORT)
673   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
674 #endif
675   for (y=0; y < (ssize_t) image->rows; y++)
676   {
677     register ssize_t
678       x;
679
680     register Quantum
681       *restrict q;
682
683     if (status == MagickFalse)
684       continue;
685     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
686     if (q == (Quantum *) NULL)
687       {
688         status=MagickFalse;
689         continue;
690       }
691     for (x=0; x < (ssize_t) image->columns; x++)
692     {
693       register ssize_t
694         i;
695
696       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
697       {
698         PixelTrait
699           traits;
700
701         traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
702         if (traits == UndefinedPixelTrait)
703           continue;
704         q[i]=ClampToUnsignedQuantum(q[i]);
705       }
706       q+=GetPixelChannels(image);
707     }
708     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
709       status=MagickFalse;
710     if (image->progress_monitor != (MagickProgressMonitor) NULL)
711       {
712         MagickBooleanType
713           proceed;
714
715 #if defined(MAGICKCORE_OPENMP_SUPPORT)
716   #pragma omp critical (MagickCore_ClampImage)
717 #endif
718         proceed=SetImageProgress(image,ClampImageTag,progress++,
719           image->rows);
720         if (proceed == MagickFalse)
721           status=MagickFalse;
722       }
723   }
724   image_view=DestroyCacheView(image_view);
725   return(status);
726 }
727 \f
728 /*
729 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
730 %                                                                             %
731 %                                                                             %
732 %                                                                             %
733 %  D e s t r o y T h r e s h o l d M a p                                      %
734 %                                                                             %
735 %                                                                             %
736 %                                                                             %
737 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
738 %
739 %  DestroyThresholdMap() de-allocate the given ThresholdMap
740 %
741 %  The format of the ListThresholdMaps method is:
742 %
743 %      ThresholdMap *DestroyThresholdMap(Threshold *map)
744 %
745 %  A description of each parameter follows.
746 %
747 %    o map:    Pointer to the Threshold map to destroy
748 %
749 */
750 MagickExport ThresholdMap *DestroyThresholdMap(ThresholdMap *map)
751 {
752   assert(map != (ThresholdMap *) NULL);
753   if (map->map_id != (char *) NULL)
754     map->map_id=DestroyString(map->map_id);
755   if (map->description != (char *) NULL)
756     map->description=DestroyString(map->description);
757   if (map->levels != (ssize_t *) NULL)
758     map->levels=(ssize_t *) RelinquishMagickMemory(map->levels);
759   map=(ThresholdMap *) RelinquishMagickMemory(map);
760   return(map);
761 }
762 \f
763 /*
764 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
765 %                                                                             %
766 %                                                                             %
767 %                                                                             %
768 %  G e t T h r e s h o l d M a p                                              %
769 %                                                                             %
770 %                                                                             %
771 %                                                                             %
772 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
773 %
774 %  GetThresholdMap() loads and searches one or more threshold map files for the
775 %  map matching the given name or alias.
776 %
777 %  The format of the GetThresholdMap method is:
778 %
779 %      ThresholdMap *GetThresholdMap(const char *map_id,
780 %        ExceptionInfo *exception)
781 %
782 %  A description of each parameter follows.
783 %
784 %    o map_id:  ID of the map to look for.
785 %
786 %    o exception: return any errors or warnings in this structure.
787 %
788 */
789 MagickExport ThresholdMap *GetThresholdMap(const char *map_id,
790   ExceptionInfo *exception)
791 {
792   const StringInfo
793     *option;
794
795   LinkedListInfo
796     *options;
797
798   ThresholdMap
799     *map;
800
801   map=(ThresholdMap *)NULL;
802   options=GetConfigureOptions(ThresholdsFilename,exception);
803   while ((option=(const StringInfo *) GetNextValueInLinkedList(options)) !=
804          (const StringInfo *) NULL && (map == (ThresholdMap *) NULL))
805     map=GetThresholdMapFile((const char *) GetStringInfoDatum(option),
806       GetStringInfoPath(option),map_id,exception);
807   options=DestroyConfigureOptions(options);
808   return(map);
809 }
810 \f
811 /*
812 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
813 %                                                                             %
814 %                                                                             %
815 %                                                                             %
816 +  G e t T h r e s h o l d M a p F i l e                                      %
817 %                                                                             %
818 %                                                                             %
819 %                                                                             %
820 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
821 %
822 %  GetThresholdMapFile() look for a given threshold map name or alias in the
823 %  given XML file data, and return the allocated the map when found.
824 %
825 %  The format of the ListThresholdMaps method is:
826 %
827 %      ThresholdMap *GetThresholdMap(const char *xml,const char *filename,
828 %         const char *map_id,ExceptionInfo *exception)
829 %
830 %  A description of each parameter follows.
831 %
832 %    o xml:  The threshold map list in XML format.
833 %
834 %    o filename:  The threshold map XML filename.
835 %
836 %    o map_id:  ID of the map to look for in XML list.
837 %
838 %    o exception: return any errors or warnings in this structure.
839 %
840 */
841 static ThresholdMap *GetThresholdMapFile(const char *xml,
842   const char *filename,const char *map_id,ExceptionInfo *exception)
843 {
844   char
845     *p;
846
847   const char
848     *attribute,
849     *content;
850
851   double
852     value;
853
854   register ssize_t
855     i;
856
857   ThresholdMap
858     *map;
859
860   XMLTreeInfo
861     *description,
862     *levels,
863     *threshold,
864     *thresholds;
865
866   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
867     "Loading threshold map file \"%s\" ...",filename);
868   map=(ThresholdMap *) NULL;
869   thresholds=NewXMLTree(xml,exception);
870   if (thresholds == (XMLTreeInfo *) NULL)
871     return(map);
872   for (threshold=GetXMLTreeChild(thresholds,"threshold");
873        threshold != (XMLTreeInfo *) NULL;
874        threshold=GetNextXMLTreeTag(threshold))
875   {
876     attribute=GetXMLTreeAttribute(threshold,"map");
877     if ((attribute != (char *) NULL) && (LocaleCompare(map_id,attribute) == 0))
878       break;
879     attribute=GetXMLTreeAttribute(threshold,"alias");
880     if ((attribute != (char *) NULL) && (LocaleCompare(map_id,attribute) == 0))
881       break;
882   }
883   if (threshold == (XMLTreeInfo *) NULL)
884     return(map);
885   description=GetXMLTreeChild(threshold,"description");
886   if (description == (XMLTreeInfo *) NULL)
887     {
888       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
889         "XmlMissingElement", "<description>, map \"%s\"",map_id);
890       thresholds=DestroyXMLTree(thresholds);
891       return(map);
892     }
893   levels=GetXMLTreeChild(threshold,"levels");
894   if (levels == (XMLTreeInfo *) NULL)
895     {
896       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
897         "XmlMissingElement", "<levels>, map \"%s\"", map_id);
898       thresholds=DestroyXMLTree(thresholds);
899       return(map);
900     }
901   map=(ThresholdMap *) AcquireMagickMemory(sizeof(ThresholdMap));
902   if (map == (ThresholdMap *) NULL)
903     ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireThresholdMap");
904   map->map_id=(char *) NULL;
905   map->description=(char *) NULL;
906   map->levels=(ssize_t *) NULL;
907   attribute=GetXMLTreeAttribute(threshold,"map");
908   if (attribute != (char *) NULL)
909     map->map_id=ConstantString(attribute);
910   content=GetXMLTreeContent(description);
911   if (content != (char *) NULL)
912     map->description=ConstantString(content);
913   attribute=GetXMLTreeAttribute(levels,"width");
914   if (attribute == (char *) NULL)
915     {
916       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
917         "XmlMissingAttribute", "<levels width>, map \"%s\"",map_id);
918       thresholds=DestroyXMLTree(thresholds);
919       map=DestroyThresholdMap(map);
920       return(map);
921     }
922   map->width=StringToUnsignedLong(attribute);
923   if (map->width == 0)
924     {
925       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
926        "XmlInvalidAttribute", "<levels width>, map \"%s\"",map_id);
927       thresholds=DestroyXMLTree(thresholds);
928       map=DestroyThresholdMap(map);
929       return(map);
930     }
931   attribute=GetXMLTreeAttribute(levels,"height");
932   if (attribute == (char *) NULL)
933     {
934       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
935         "XmlMissingAttribute", "<levels height>, map \"%s\"",map_id);
936       thresholds=DestroyXMLTree(thresholds);
937       map=DestroyThresholdMap(map);
938       return(map);
939     }
940   map->height=StringToUnsignedLong(attribute);
941   if (map->height == 0)
942     {
943       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
944         "XmlInvalidAttribute", "<levels height>, map \"%s\"",map_id);
945       thresholds=DestroyXMLTree(thresholds);
946       map=DestroyThresholdMap(map);
947       return(map);
948     }
949   attribute=GetXMLTreeAttribute(levels,"divisor");
950   if (attribute == (char *) NULL)
951     {
952       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
953         "XmlMissingAttribute", "<levels divisor>, map \"%s\"",map_id);
954       thresholds=DestroyXMLTree(thresholds);
955       map=DestroyThresholdMap(map);
956       return(map);
957     }
958   map->divisor=(ssize_t) StringToLong(attribute);
959   if (map->divisor < 2)
960     {
961       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
962         "XmlInvalidAttribute", "<levels divisor>, map \"%s\"",map_id);
963       thresholds=DestroyXMLTree(thresholds);
964       map=DestroyThresholdMap(map);
965       return(map);
966     }
967   content=GetXMLTreeContent(levels);
968   if (content == (char *) NULL)
969     {
970       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
971         "XmlMissingContent", "<levels>, map \"%s\"",map_id);
972       thresholds=DestroyXMLTree(thresholds);
973       map=DestroyThresholdMap(map);
974       return(map);
975     }
976   map->levels=(ssize_t *) AcquireQuantumMemory((size_t) map->width,map->height*
977     sizeof(*map->levels));
978   if (map->levels == (ssize_t *) NULL)
979     ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireThresholdMap");
980   for (i=0; i < (ssize_t) (map->width*map->height); i++)
981   {
982     map->levels[i]=(ssize_t) strtol(content,&p,10);
983     if (p == content)
984       {
985         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
986           "XmlInvalidContent", "<level> too few values, map \"%s\"",map_id);
987         thresholds=DestroyXMLTree(thresholds);
988         map=DestroyThresholdMap(map);
989         return(map);
990       }
991     if ((map->levels[i] < 0) || (map->levels[i] > map->divisor))
992       {
993         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
994           "XmlInvalidContent", "<level> %.20g out of range, map \"%s\"",
995           (double) map->levels[i],map_id);
996         thresholds=DestroyXMLTree(thresholds);
997         map=DestroyThresholdMap(map);
998         return(map);
999       }
1000     content=p;
1001   }
1002   value=(double) strtol(content,&p,10);
1003   (void) value;
1004   if (p != content)
1005     {
1006       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1007         "XmlInvalidContent", "<level> too many values, map \"%s\"",map_id);
1008      thresholds=DestroyXMLTree(thresholds);
1009      map=DestroyThresholdMap(map);
1010      return(map);
1011    }
1012   thresholds=DestroyXMLTree(thresholds);
1013   return(map);
1014 }
1015 \f
1016 /*
1017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1018 %                                                                             %
1019 %                                                                             %
1020 %                                                                             %
1021 +  L i s t T h r e s h o l d M a p F i l e                                    %
1022 %                                                                             %
1023 %                                                                             %
1024 %                                                                             %
1025 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1026 %
1027 %  ListThresholdMapFile() lists the threshold maps and their descriptions
1028 %  in the given XML file data.
1029 %
1030 %  The format of the ListThresholdMaps method is:
1031 %
1032 %      MagickBooleanType ListThresholdMaps(FILE *file,const char*xml,
1033 %         const char *filename,ExceptionInfo *exception)
1034 %
1035 %  A description of each parameter follows.
1036 %
1037 %    o file:  An pointer to the output FILE.
1038 %
1039 %    o xml:  The threshold map list in XML format.
1040 %
1041 %    o filename:  The threshold map XML filename.
1042 %
1043 %    o exception: return any errors or warnings in this structure.
1044 %
1045 */
1046 MagickBooleanType ListThresholdMapFile(FILE *file,const char *xml,
1047   const char *filename,ExceptionInfo *exception)
1048 {
1049   const char
1050     *alias,
1051     *content,
1052     *map;
1053
1054   XMLTreeInfo
1055     *description,
1056     *threshold,
1057     *thresholds;
1058
1059   assert( xml != (char *)NULL );
1060   assert( file != (FILE *)NULL );
1061   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1062     "Loading threshold map file \"%s\" ...",filename);
1063   thresholds=NewXMLTree(xml,exception);
1064   if ( thresholds == (XMLTreeInfo *)NULL )
1065     return(MagickFalse);
1066   (void) FormatLocaleFile(file,"%-16s %-12s %s\n","Map","Alias","Description");
1067   (void) FormatLocaleFile(file,
1068     "----------------------------------------------------\n");
1069   threshold=GetXMLTreeChild(thresholds,"threshold");
1070   for ( ; threshold != (XMLTreeInfo *) NULL;
1071           threshold=GetNextXMLTreeTag(threshold))
1072   {
1073     map=GetXMLTreeAttribute(threshold,"map");
1074     if (map == (char *) NULL)
1075       {
1076         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1077           "XmlMissingAttribute", "<map>");
1078         thresholds=DestroyXMLTree(thresholds);
1079         return(MagickFalse);
1080       }
1081     alias=GetXMLTreeAttribute(threshold,"alias");
1082     description=GetXMLTreeChild(threshold,"description");
1083     if (description == (XMLTreeInfo *) NULL)
1084       {
1085         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1086           "XmlMissingElement", "<description>, map \"%s\"",map);
1087         thresholds=DestroyXMLTree(thresholds);
1088         return(MagickFalse);
1089       }
1090     content=GetXMLTreeContent(description);
1091     if (content == (char *) NULL)
1092       {
1093         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1094           "XmlMissingContent", "<description>, map \"%s\"", map);
1095         thresholds=DestroyXMLTree(thresholds);
1096         return(MagickFalse);
1097       }
1098     (void) FormatLocaleFile(file,"%-16s %-12s %s\n",map,alias ? alias : "",
1099       content);
1100   }
1101   thresholds=DestroyXMLTree(thresholds);
1102   return(MagickTrue);
1103 }
1104 \f
1105 /*
1106 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1107 %                                                                             %
1108 %                                                                             %
1109 %                                                                             %
1110 %  L i s t T h r e s h o l d M a p s                                          %
1111 %                                                                             %
1112 %                                                                             %
1113 %                                                                             %
1114 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1115 %
1116 %  ListThresholdMaps() lists the threshold maps and their descriptions
1117 %  as defined by "threshold.xml" to a file.
1118 %
1119 %  The format of the ListThresholdMaps method is:
1120 %
1121 %      MagickBooleanType ListThresholdMaps(FILE *file,ExceptionInfo *exception)
1122 %
1123 %  A description of each parameter follows.
1124 %
1125 %    o file:  An pointer to the output FILE.
1126 %
1127 %    o exception: return any errors or warnings in this structure.
1128 %
1129 */
1130 MagickExport MagickBooleanType ListThresholdMaps(FILE *file,
1131   ExceptionInfo *exception)
1132 {
1133   const StringInfo
1134     *option;
1135
1136   LinkedListInfo
1137     *options;
1138
1139   MagickStatusType
1140     status;
1141
1142   status=MagickFalse;
1143   if (file == (FILE *) NULL)
1144     file=stdout;
1145   options=GetConfigureOptions(ThresholdsFilename,exception);
1146   (void) FormatLocaleFile(file,
1147     "\n   Threshold Maps for Ordered Dither Operations\n");
1148   while ((option=(const StringInfo *) GetNextValueInLinkedList(options)) !=
1149          (const StringInfo *) NULL)
1150   {
1151     (void) FormatLocaleFile(file,"\nPATH: %s\n\n",GetStringInfoPath(option));
1152     status|=ListThresholdMapFile(file,(const char *) GetStringInfoDatum(option),
1153       GetStringInfoPath(option),exception);
1154   }
1155   options=DestroyConfigureOptions(options);
1156   return(status != 0 ? MagickTrue : MagickFalse);
1157 }
1158 \f
1159 /*
1160 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1161 %                                                                             %
1162 %                                                                             %
1163 %                                                                             %
1164 %     O r d e r e d P o s t e r i z e I m a g e                               %
1165 %                                                                             %
1166 %                                                                             %
1167 %                                                                             %
1168 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1169 %
1170 %  OrderedPosterizeImage() will perform a ordered dither based on a number
1171 %  of pre-defined dithering threshold maps, but over multiple intensity
1172 %  levels, which can be different for different channels, according to the
1173 %  input argument.
1174 %
1175 %  The format of the OrderedPosterizeImage method is:
1176 %
1177 %      MagickBooleanType OrderedPosterizeImage(Image *image,
1178 %        const char *threshold_map,ExceptionInfo *exception)
1179 %
1180 %  A description of each parameter follows:
1181 %
1182 %    o image: the image.
1183 %
1184 %    o threshold_map: A string containing the name of the threshold dither
1185 %      map to use, followed by zero or more numbers representing the number
1186 %      of color levels tho dither between.
1187 %
1188 %      Any level number less than 2 will be equivalent to 2, and means only
1189 %      binary dithering will be applied to each color channel.
1190 %
1191 %      No numbers also means a 2 level (bitmap) dither will be applied to all
1192 %      channels, while a single number is the number of levels applied to each
1193 %      channel in sequence.  More numbers will be applied in turn to each of
1194 %      the color channels.
1195 %
1196 %      For example: "o3x3,6" will generate a 6 level posterization of the
1197 %      image with a ordered 3x3 diffused pixel dither being applied between
1198 %      each level. While checker,8,8,4 will produce a 332 colormaped image
1199 %      with only a single checkerboard hash pattern (50% grey) between each
1200 %      color level, to basically double the number of color levels with
1201 %      a bare minimim of dithering.
1202 %
1203 %    o exception: return any errors or warnings in this structure.
1204 %
1205 */
1206 MagickExport MagickBooleanType OrderedPosterizeImage(Image *image,
1207   const char *threshold_map,ExceptionInfo *exception)
1208 {
1209 #define DitherImageTag  "Dither/Image"
1210
1211   CacheView
1212     *image_view;
1213
1214   char
1215     token[MaxTextExtent];
1216
1217   const char
1218     *p;
1219
1220   MagickBooleanType
1221     status;
1222
1223   MagickOffsetType
1224     progress;
1225
1226   MagickRealType
1227     levels[CompositePixelChannel];
1228
1229   register ssize_t
1230     i;
1231
1232   ssize_t
1233     y;
1234
1235   ThresholdMap
1236     *map;
1237
1238   assert(image != (Image *) NULL);
1239   assert(image->signature == MagickSignature);
1240   if (image->debug != MagickFalse)
1241     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1242   assert(exception != (ExceptionInfo *) NULL);
1243   assert(exception->signature == MagickSignature);
1244   if (threshold_map == (const char *) NULL)
1245     return(MagickTrue);
1246   p=(char *) threshold_map;
1247   while (((isspace((int) ((unsigned char) *p)) != 0) || (*p == ',')) &&
1248          (*p != '\0'))
1249     p++;
1250   threshold_map=p;
1251   while (((isspace((int) ((unsigned char) *p)) == 0) && (*p != ',')) &&
1252          (*p != '\0'))
1253   {
1254     if ((p-threshold_map) >= (MaxTextExtent-1))
1255       break;
1256     token[p-threshold_map]=(*p);
1257     p++;
1258   }
1259   token[p-threshold_map]='\0';
1260   map=GetThresholdMap(token,exception);
1261   if (map == (ThresholdMap *) NULL)
1262     {
1263       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1264         "InvalidArgument","%s : '%s'","ordered-dither",threshold_map);
1265       return(MagickFalse);
1266     }
1267   for (i=0; i < MaxPixelChannels; i++)
1268     levels[i]=2.0;
1269   p=strchr((char *) threshold_map,',');
1270   if ((p != (char *) NULL) && (isdigit((int) ((unsigned char) *(++p))) != 0))
1271     for (i=0; (*p != '\0') && (i < MaxPixelChannels); i++)
1272     {
1273       GetMagickToken(p,&p,token);
1274       if (*token == ',')
1275         GetMagickToken(p,&p,token);
1276       levels[i]=StringToDouble(token,(char **) NULL);
1277     }
1278   for (i=0; i < MaxPixelChannels; i++)
1279     if (fabs(levels[i]) >= 1)
1280       levels[i]-=1.0;
1281   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1282     return(MagickFalse);
1283   status=MagickTrue;
1284   progress=0;
1285   image_view=AcquireCacheView(image);
1286 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1287   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1288 #endif
1289   for (y=0; y < (ssize_t) image->rows; y++)
1290   {
1291     register ssize_t
1292       x;
1293
1294     register Quantum
1295       *restrict q;
1296
1297     if (status == MagickFalse)
1298       continue;
1299     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1300     if (q == (Quantum *) NULL)
1301       {
1302         status=MagickFalse;
1303         continue;
1304       }
1305     for (x=0; x < (ssize_t) image->columns; x++)
1306     {
1307       register ssize_t
1308         i;
1309
1310       ssize_t
1311         n;
1312
1313       n=0;
1314       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1315       {
1316         PixelTrait
1317           traits;
1318
1319         ssize_t
1320           level,
1321           threshold;
1322
1323         traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
1324         if ((traits & UpdatePixelTrait) == 0)
1325           continue;
1326         if (fabs(levels[n++]) < MagickEpsilon)
1327           continue;
1328         threshold=(ssize_t) (QuantumScale*q[i]*(levels[n]*(map->divisor-1)+1));
1329         level=threshold/(map->divisor-1);
1330         threshold-=level*(map->divisor-1);
1331         q[i]=RoundToQuantum((level+(threshold >= map->levels[(x % map->width)+
1332           map->width*(y % map->height)]))*QuantumRange/levels[n]);
1333         n++;
1334       }
1335       q+=GetPixelChannels(image);
1336     }
1337     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1338       status=MagickFalse;
1339     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1340       {
1341         MagickBooleanType
1342           proceed;
1343
1344 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1345 #pragma omp critical (MagickCore_OrderedPosterizeImage)
1346 #endif
1347         proceed=SetImageProgress(image,DitherImageTag,progress++,image->rows);
1348         if (proceed == MagickFalse)
1349           status=MagickFalse;
1350       }
1351   }
1352   image_view=DestroyCacheView(image_view);
1353   map=DestroyThresholdMap(map);
1354   return(MagickTrue);
1355 }
1356 \f
1357 /*
1358 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1359 %                                                                             %
1360 %                                                                             %
1361 %                                                                             %
1362 %     R a n d o m T h r e s h o l d I m a g e                                 %
1363 %                                                                             %
1364 %                                                                             %
1365 %                                                                             %
1366 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1367 %
1368 %  RandomThresholdImage() changes the value of individual pixels based on the
1369 %  intensity of each pixel compared to a random threshold.  The result is a
1370 %  low-contrast, two color image.
1371 %
1372 %  The format of the RandomThresholdImage method is:
1373 %
1374 %      MagickBooleanType RandomThresholdImage(Image *image,
1375 %        const char *thresholds,ExceptionInfo *exception)
1376 %
1377 %  A description of each parameter follows:
1378 %
1379 %    o image: the image.
1380 %
1381 %    o thresholds: a geometry string containing low,high thresholds.  If the
1382 %      string contains 2x2, 3x3, or 4x4, an ordered dither of order 2, 3, or 4
1383 %      is performed instead.
1384 %
1385 %    o exception: return any errors or warnings in this structure.
1386 %
1387 */
1388 MagickExport MagickBooleanType RandomThresholdImage(Image *image,
1389   const char *thresholds,ExceptionInfo *exception)
1390 {
1391 #define ThresholdImageTag  "Threshold/Image"
1392
1393   CacheView
1394     *image_view;
1395
1396   GeometryInfo
1397     geometry_info;
1398
1399   MagickStatusType
1400     flags;
1401
1402   MagickBooleanType
1403     status;
1404
1405   MagickOffsetType
1406     progress;
1407
1408   PixelInfo
1409     threshold;
1410
1411   MagickRealType
1412     min_threshold,
1413     max_threshold;
1414
1415   RandomInfo
1416     **restrict random_info;
1417
1418   ssize_t
1419     y;
1420
1421   assert(image != (Image *) NULL);
1422   assert(image->signature == MagickSignature);
1423   if (image->debug != MagickFalse)
1424     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1425   assert(exception != (ExceptionInfo *) NULL);
1426   assert(exception->signature == MagickSignature);
1427   if (thresholds == (const char *) NULL)
1428     return(MagickTrue);
1429   GetPixelInfo(image,&threshold);
1430   min_threshold=0.0;
1431   max_threshold=(MagickRealType) QuantumRange;
1432   flags=ParseGeometry(thresholds,&geometry_info);
1433   min_threshold=geometry_info.rho;
1434   max_threshold=geometry_info.sigma;
1435   if ((flags & SigmaValue) == 0)
1436     max_threshold=min_threshold;
1437   if (strchr(thresholds,'%') != (char *) NULL)
1438     {
1439       max_threshold*=(MagickRealType) (0.01*QuantumRange);
1440       min_threshold*=(MagickRealType) (0.01*QuantumRange);
1441     }
1442   /*
1443     Random threshold image.
1444   */
1445   status=MagickTrue;
1446   progress=0;
1447   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1448     return(MagickFalse);
1449   random_info=AcquireRandomInfoThreadSet();
1450   image_view=AcquireCacheView(image);
1451 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1452   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1453 #endif
1454   for (y=0; y < (ssize_t) image->rows; y++)
1455   {
1456     const int
1457       id = GetOpenMPThreadId();
1458
1459     register Quantum
1460       *restrict q;
1461
1462     register ssize_t
1463       x;
1464
1465     if (status == MagickFalse)
1466       continue;
1467     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1468     if (q == (Quantum *) NULL)
1469       {
1470         status=MagickFalse;
1471         continue;
1472       }
1473     for (x=0; x < (ssize_t) image->columns; x++)
1474     {
1475       register ssize_t
1476         i;
1477
1478       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1479       {
1480         MagickRealType
1481           threshold;
1482
1483         PixelTrait
1484           traits;
1485
1486         traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
1487         if ((traits & UpdatePixelTrait) == 0)
1488           continue;
1489         if ((MagickRealType) q[i] < min_threshold)
1490           threshold=min_threshold;
1491         else
1492           if ((MagickRealType) q[i] > max_threshold)
1493             threshold=max_threshold;
1494           else
1495             threshold=(MagickRealType) (QuantumRange*
1496               GetPseudoRandomValue(random_info[id]));
1497           q[i]=(Quantum) ((MagickRealType) q[i] <= threshold ? 0 :
1498             QuantumRange);
1499       }
1500       q+=GetPixelChannels(image);
1501     }
1502     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1503       status=MagickFalse;
1504     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1505       {
1506         MagickBooleanType
1507           proceed;
1508
1509 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1510   #pragma omp critical (MagickCore_RandomThresholdImage)
1511 #endif
1512         proceed=SetImageProgress(image,ThresholdImageTag,progress++,
1513           image->rows);
1514         if (proceed == MagickFalse)
1515           status=MagickFalse;
1516       }
1517   }
1518   image_view=DestroyCacheView(image_view);
1519   random_info=DestroyRandomInfoThreadSet(random_info);
1520   return(status);
1521 }
1522 \f
1523 /*
1524 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1525 %                                                                             %
1526 %                                                                             %
1527 %                                                                             %
1528 %     W h i t e T h r e s h o l d I m a g e                                   %
1529 %                                                                             %
1530 %                                                                             %
1531 %                                                                             %
1532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1533 %
1534 %  WhiteThresholdImage() is like ThresholdImage() but forces all pixels above
1535 %  the threshold into white while leaving all pixels at or below the threshold
1536 %  unchanged.
1537 %
1538 %  The format of the WhiteThresholdImage method is:
1539 %
1540 %      MagickBooleanType WhiteThresholdImage(Image *image,
1541 %        const char *threshold,ExceptionInfo *exception)
1542 %
1543 %  A description of each parameter follows:
1544 %
1545 %    o image: the image.
1546 %
1547 %    o threshold: Define the threshold value.
1548 %
1549 %    o exception: return any errors or warnings in this structure.
1550 %
1551 */
1552 MagickExport MagickBooleanType WhiteThresholdImage(Image *image,
1553   const char *thresholds,ExceptionInfo *exception)
1554 {
1555 #define ThresholdImageTag  "Threshold/Image"
1556
1557   CacheView
1558     *image_view;
1559
1560   GeometryInfo
1561     geometry_info;
1562
1563   MagickBooleanType
1564     status;
1565
1566   MagickOffsetType
1567     progress;
1568
1569   MagickRealType
1570     threshold[5];
1571
1572   MagickStatusType
1573     flags;
1574
1575   register ssize_t
1576     i;
1577
1578   ssize_t
1579     y;
1580
1581   assert(image != (Image *) NULL);
1582   assert(image->signature == MagickSignature);
1583   if (image->debug != MagickFalse)
1584     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1585   if (thresholds == (const char *) NULL)
1586     return(MagickTrue);
1587   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1588     return(MagickFalse);
1589   flags=ParseGeometry(thresholds,&geometry_info);
1590   for (i=0; i < 5; i++)
1591     threshold[i]=geometry_info.rho;
1592   if ((flags & SigmaValue) != 0)
1593     threshold[1]=geometry_info.sigma;
1594   if ((flags & XiValue) != 0)
1595     threshold[2]=geometry_info.xi;
1596   if ((flags & PsiValue) != 0)
1597     threshold[3]=geometry_info.psi;
1598   if ((flags & ChiValue) != 0)
1599     threshold[4]=geometry_info.chi;
1600   if ((flags & PercentValue) != 0)
1601     for (i=0; i < 5; i++)
1602       threshold[i]*=(QuantumRange/100.0);
1603   /*
1604     White threshold image.
1605   */
1606   status=MagickTrue;
1607   progress=0;
1608   image_view=AcquireCacheView(image);
1609 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1610   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1611 #endif
1612   for (y=0; y < (ssize_t) image->rows; y++)
1613   {
1614     register ssize_t
1615       x;
1616
1617     register Quantum
1618       *restrict q;
1619
1620     if (status == MagickFalse)
1621       continue;
1622     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1623     if (q == (Quantum *) NULL)
1624       {
1625         status=MagickFalse;
1626         continue;
1627       }
1628     for (x=0; x < (ssize_t) image->columns; x++)
1629     {
1630       register ssize_t
1631         i;
1632
1633       ssize_t
1634         n;
1635
1636       n=0;
1637       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1638       {
1639         PixelTrait
1640           traits;
1641
1642         traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
1643         if ((traits & UpdatePixelTrait) == 0)
1644           continue;
1645         if ((MagickRealType) q[i] > threshold[n++ % 5])
1646           q[i]=QuantumRange;
1647       }
1648       q+=GetPixelChannels(image);
1649     }
1650     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1651       status=MagickFalse;
1652     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1653       {
1654         MagickBooleanType
1655           proceed;
1656
1657 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1658   #pragma omp critical (MagickCore_WhiteThresholdImage)
1659 #endif
1660         proceed=SetImageProgress(image,ThresholdImageTag,progress++,
1661           image->rows);
1662         if (proceed == MagickFalse)
1663           status=MagickFalse;
1664       }
1665   }
1666   image_view=DestroyCacheView(image_view);
1667   return(status);
1668 }