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