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