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