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