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