MagickCore  6.7.5
threshold.c
Go to the documentation of this file.
00001 /*
00002 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00003 %                                                                             %
00004 %                                                                             %
00005 %                                                                             %
00006 %       TTTTT  H   H  RRRR   EEEEE  SSSSS  H   H   OOO   L      DDDD          %
00007 %         T    H   H  R   R  E      SS     H   H  O   O  L      D   D         %
00008 %         T    HHHHH  RRRR   EEE     SSS   HHHHH  O   O  L      D   D         %
00009 %         T    H   H  R R    E         SS  H   H  O   O  L      D   D         %
00010 %         T    H   H  R  R   EEEEE  SSSSS  H   H   OOO   LLLLL  DDDD          %
00011 %                                                                             %
00012 %                                                                             %
00013 %                      MagickCore Image Threshold Methods                     %
00014 %                                                                             %
00015 %                               Software Design                               %
00016 %                                 John Cristy                                 %
00017 %                                 October 1996                                %
00018 %                                                                             %
00019 %                                                                             %
00020 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
00021 %  dedicated to making software imaging solutions freely available.           %
00022 %                                                                             %
00023 %  You may not use this file except in compliance with the License.  You may  %
00024 %  obtain a copy of the License at                                            %
00025 %                                                                             %
00026 %    http://www.imagemagick.org/script/license.php                            %
00027 %                                                                             %
00028 %  Unless required by applicable law or agreed to in writing, software        %
00029 %  distributed under the License is distributed on an "AS IS" BASIS,          %
00030 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
00031 %  See the License for the specific language governing permissions and        %
00032 %  limitations under the License.                                             %
00033 %                                                                             %
00034 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00035 %
00036 %
00037 %
00038 */
00039 
00040 /*
00041   Include declarations.
00042 */
00043 #include "MagickCore/studio.h"
00044 #include "MagickCore/property.h"
00045 #include "MagickCore/blob.h"
00046 #include "MagickCore/cache-view.h"
00047 #include "MagickCore/color.h"
00048 #include "MagickCore/color-private.h"
00049 #include "MagickCore/colormap.h"
00050 #include "MagickCore/colorspace.h"
00051 #include "MagickCore/configure.h"
00052 #include "MagickCore/constitute.h"
00053 #include "MagickCore/decorate.h"
00054 #include "MagickCore/draw.h"
00055 #include "MagickCore/enhance.h"
00056 #include "MagickCore/exception.h"
00057 #include "MagickCore/exception-private.h"
00058 #include "MagickCore/effect.h"
00059 #include "MagickCore/fx.h"
00060 #include "MagickCore/gem.h"
00061 #include "MagickCore/geometry.h"
00062 #include "MagickCore/image-private.h"
00063 #include "MagickCore/list.h"
00064 #include "MagickCore/log.h"
00065 #include "MagickCore/memory_.h"
00066 #include "MagickCore/monitor.h"
00067 #include "MagickCore/monitor-private.h"
00068 #include "MagickCore/montage.h"
00069 #include "MagickCore/option.h"
00070 #include "MagickCore/pixel-accessor.h"
00071 #include "MagickCore/quantize.h"
00072 #include "MagickCore/quantum.h"
00073 #include "MagickCore/random_.h"
00074 #include "MagickCore/random-private.h"
00075 #include "MagickCore/resize.h"
00076 #include "MagickCore/resource_.h"
00077 #include "MagickCore/segment.h"
00078 #include "MagickCore/shear.h"
00079 #include "MagickCore/signature-private.h"
00080 #include "MagickCore/string_.h"
00081 #include "MagickCore/string-private.h"
00082 #include "MagickCore/thread-private.h"
00083 #include "MagickCore/threshold.h"
00084 #include "MagickCore/token.h"
00085 #include "MagickCore/transform.h"
00086 #include "MagickCore/xml-tree.h"
00087 #include "MagickCore/xml-tree-private.h"
00088 
00089 /*
00090   Define declarations.
00091 */
00092 #define ThresholdsFilename  "thresholds.xml"
00093 
00094 /*
00095   Typedef declarations.
00096 */
00097 struct _ThresholdMap
00098 {
00099   char
00100     *map_id,
00101     *description;
00102 
00103   size_t
00104     width,
00105     height;
00106 
00107   ssize_t
00108     divisor,
00109     *levels;
00110 };
00111 
00112 /*
00113   Forward declarations.
00114 */
00115 static ThresholdMap
00116   *GetThresholdMapFile(const char *,const char *,const char *,ExceptionInfo *);
00117 
00118 /*
00119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00120 %                                                                             %
00121 %                                                                             %
00122 %                                                                             %
00123 %     A d a p t i v e T h r e s h o l d I m a g e                             %
00124 %                                                                             %
00125 %                                                                             %
00126 %                                                                             %
00127 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00128 %
00129 %  AdaptiveThresholdImage() selects an individual threshold for each pixel
00130 %  based on the range of intensity values in its local neighborhood.  This
00131 %  allows for thresholding of an image whose global intensity histogram
00132 %  doesn't contain distinctive peaks.
00133 %
00134 %  The format of the AdaptiveThresholdImage method is:
00135 %
00136 %      Image *AdaptiveThresholdImage(const Image *image,const size_t width,
00137 %        const size_t height,const double bias,ExceptionInfo *exception)
00138 %
00139 %  A description of each parameter follows:
00140 %
00141 %    o image: the image.
00142 %
00143 %    o width: the width of the local neighborhood.
00144 %
00145 %    o height: the height of the local neighborhood.
00146 %
00147 %    o bias: the mean bias.
00148 %
00149 %    o exception: return any errors or warnings in this structure.
00150 %
00151 */
00152 MagickExport Image *AdaptiveThresholdImage(const Image *image,
00153   const size_t width,const size_t height,const double bias,
00154   ExceptionInfo *exception)
00155 {
00156 #define AdaptiveThresholdImageTag  "AdaptiveThreshold/Image"
00157 
00158   CacheView
00159     *image_view,
00160     *threshold_view;
00161 
00162   Image
00163     *threshold_image;
00164 
00165   MagickBooleanType
00166     status;
00167 
00168   MagickOffsetType
00169     progress;
00170 
00171   MagickSizeType
00172     number_pixels;
00173 
00174   ssize_t
00175     y;
00176 
00177   /*
00178     Initialize threshold image attributes.
00179   */
00180   assert(image != (Image *) NULL);
00181   assert(image->signature == MagickSignature);
00182   if (image->debug != MagickFalse)
00183     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00184   assert(exception != (ExceptionInfo *) NULL);
00185   assert(exception->signature == MagickSignature);
00186   if ((width % 2) == 0)
00187     ThrowImageException(OptionError,"KernelWidthMustBeAnOddNumber");
00188   threshold_image=CloneImage(image,image->columns,image->rows,MagickTrue,
00189     exception);
00190   if (threshold_image == (Image *) NULL)
00191     return((Image *) NULL);
00192   status=SetImageStorageClass(threshold_image,DirectClass,exception);
00193   if (status == MagickFalse)
00194     {
00195       threshold_image=DestroyImage(threshold_image);
00196       return((Image *) NULL);
00197     }
00198   /*
00199     Threshold image.
00200   */
00201   status=MagickTrue;
00202   progress=0;
00203   number_pixels=(MagickSizeType) width*height;
00204   image_view=AcquireCacheView(image);
00205   threshold_view=AcquireCacheView(threshold_image);
00206 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00207   #pragma omp parallel for schedule(static,4) shared(progress,status)
00208 #endif
00209   for (y=0; y < (ssize_t) image->rows; y++)
00210   {
00211     register const Quantum
00212       *restrict p;
00213 
00214     register Quantum
00215       *restrict q;
00216 
00217     register ssize_t
00218       x;
00219 
00220     ssize_t
00221       center;
00222 
00223     if (status == MagickFalse)
00224       continue;
00225     p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
00226       (height/2L),image->columns+width,height,exception);
00227     q=QueueCacheViewAuthenticPixels(threshold_view,0,y,threshold_image->columns,
00228       1,exception);
00229     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
00230       {
00231         status=MagickFalse;
00232         continue;
00233       }
00234     center=(ssize_t) GetPixelChannels(image)*(image->columns+width)*(height/2L)+
00235       GetPixelChannels(image)*(width/2);
00236     for (x=0; x < (ssize_t) image->columns; x++)
00237     {
00238       register ssize_t
00239         i;
00240 
00241       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
00242       {
00243         MagickRealType
00244           mean,
00245           pixel;
00246 
00247         PixelChannel
00248           channel;
00249 
00250         PixelTrait
00251           threshold_traits,
00252           traits;
00253 
00254         register const Quantum
00255           *restrict pixels;
00256 
00257         register ssize_t
00258           u;
00259 
00260         ssize_t
00261           v;
00262 
00263         channel=GetPixelChannelMapChannel(image,i);
00264         traits=GetPixelChannelMapTraits(image,channel);
00265         threshold_traits=GetPixelChannelMapTraits(threshold_image,channel);
00266         if ((traits == UndefinedPixelTrait) ||
00267             (threshold_traits == UndefinedPixelTrait))
00268           continue;
00269         if (((threshold_traits & CopyPixelTrait) != 0) ||
00270             (GetPixelMask(image,p) != 0))
00271           {
00272             SetPixelChannel(threshold_image,channel,p[center+i],q);
00273             continue;
00274           }
00275         pixels=p;
00276         pixel=0.0;
00277         for (v=0; v < (ssize_t) height; v++)
00278         {
00279           for (u=0; u < (ssize_t) width; u++)
00280           {
00281             pixel+=pixels[i];
00282             pixels+=GetPixelChannels(image);
00283           }
00284           pixels+=image->columns*GetPixelChannels(image);
00285         }
00286         mean=(MagickRealType) (pixel/number_pixels+bias);
00287         SetPixelChannel(threshold_image,channel,(Quantum) ((MagickRealType)
00288           p[center+i] <= mean ? 0 : QuantumRange),q);
00289       }
00290       p+=GetPixelChannels(image);
00291       q+=GetPixelChannels(threshold_image);
00292     }
00293     if (SyncCacheViewAuthenticPixels(threshold_view,exception) == MagickFalse)
00294       status=MagickFalse;
00295     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00296       {
00297         MagickBooleanType
00298           proceed;
00299 
00300 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00301   #pragma omp critical (MagickCore_AdaptiveThresholdImage)
00302 #endif
00303         proceed=SetImageProgress(image,AdaptiveThresholdImageTag,progress++,
00304           image->rows);
00305         if (proceed == MagickFalse)
00306           status=MagickFalse;
00307       }
00308   }
00309   threshold_image->type=image->type;
00310   threshold_view=DestroyCacheView(threshold_view);
00311   image_view=DestroyCacheView(image_view);
00312   if (status == MagickFalse)
00313     threshold_image=DestroyImage(threshold_image);
00314   return(threshold_image);
00315 }
00316 
00317 /*
00318 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00319 %                                                                             %
00320 %                                                                             %
00321 %                                                                             %
00322 %     B i l e v e l I m a g e                                                 %
00323 %                                                                             %
00324 %                                                                             %
00325 %                                                                             %
00326 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00327 %
00328 %  BilevelImage() changes the value of individual pixels based on the
00329 %  intensity of each pixel channel.  The result is a high-contrast image.
00330 %
00331 %  More precisely each channel value of the image is 'thresholded' so that if
00332 %  it is equal to or less than the given value it is set to zero, while any
00333 %  value greater than that give is set to it maximum or QuantumRange.
00334 %
00335 %  This function is what is used to implement the "-threshold" operator for
00336 %  the command line API.
00337 %
00338 %  If the default channel setting is given the image is thresholded using just
00339 %  the gray 'intensity' of the image, rather than the individual channels.
00340 %
00341 %  The format of the BilevelImage method is:
00342 %
00343 %      MagickBooleanType BilevelImage(Image *image,const double threshold,
00344 %        ExceptionInfo *exception)
00345 %
00346 %  A description of each parameter follows:
00347 %
00348 %    o image: the image.
00349 %
00350 %    o threshold: define the threshold values.
00351 %
00352 %    o exception: return any errors or warnings in this structure.
00353 %
00354 %  Aside: You can get the same results as operator using LevelImages()
00355 %  with the 'threshold' value for both the black_point and the white_point.
00356 %
00357 */
00358 MagickExport MagickBooleanType BilevelImage(Image *image,const double threshold,
00359   ExceptionInfo *exception)
00360 {
00361 #define ThresholdImageTag  "Threshold/Image"
00362 
00363   CacheView
00364     *image_view;
00365 
00366   MagickBooleanType
00367     status;
00368 
00369   MagickOffsetType
00370     progress;
00371 
00372   ssize_t
00373     y;
00374 
00375   assert(image != (Image *) NULL);
00376   assert(image->signature == MagickSignature);
00377   if (image->debug != MagickFalse)
00378     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00379   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
00380     return(MagickFalse);
00381   /*
00382     Bilevel threshold image.
00383   */
00384   status=MagickTrue;
00385   progress=0;
00386   image_view=AcquireCacheView(image);
00387 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00388   #pragma omp parallel for schedule(static,8) shared(progress,status)
00389 #endif
00390   for (y=0; y < (ssize_t) image->rows; y++)
00391   {
00392     register ssize_t
00393       x;
00394 
00395     register Quantum
00396       *restrict q;
00397 
00398     if (status == MagickFalse)
00399       continue;
00400     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
00401     if (q == (Quantum *) NULL)
00402       {
00403         status=MagickFalse;
00404         continue;
00405       }
00406     for (x=0; x < (ssize_t) image->columns; x++)
00407     {
00408       register ssize_t
00409         i;
00410 
00411       if (GetPixelMask(image,q) != 0)
00412         {
00413           q+=GetPixelChannels(image);
00414           continue;
00415         }
00416       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
00417       {
00418         PixelChannel
00419           channel;
00420 
00421         PixelTrait
00422           traits;
00423 
00424         channel=GetPixelChannelMapChannel(image,i);
00425         traits=GetPixelChannelMapTraits(image,channel);
00426         if ((traits & UpdatePixelTrait) == 0)
00427           continue;
00428         q[i]=(Quantum) ((MagickRealType) q[i] <= threshold ? 0 : QuantumRange);
00429       }
00430       q+=GetPixelChannels(image);
00431     }
00432     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
00433       status=MagickFalse;
00434     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00435       {
00436         MagickBooleanType
00437           proceed;
00438 
00439 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00440   #pragma omp critical (MagickCore_BilevelImage)
00441 #endif
00442         proceed=SetImageProgress(image,ThresholdImageTag,progress++,
00443           image->rows);
00444         if (proceed == MagickFalse)
00445           status=MagickFalse;
00446       }
00447   }
00448   image_view=DestroyCacheView(image_view);
00449   return(status);
00450 }
00451 
00452 /*
00453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00454 %                                                                             %
00455 %                                                                             %
00456 %                                                                             %
00457 %     B l a c k T h r e s h o l d I m a g e                                   %
00458 %                                                                             %
00459 %                                                                             %
00460 %                                                                             %
00461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00462 %
00463 %  BlackThresholdImage() is like ThresholdImage() but forces all pixels below
00464 %  the threshold into black while leaving all pixels at or above the threshold
00465 %  unchanged.
00466 %
00467 %  The format of the BlackThresholdImage method is:
00468 %
00469 %      MagickBooleanType BlackThresholdImage(Image *image,
00470 %        const char *threshold,ExceptionInfo *exception)
00471 %
00472 %  A description of each parameter follows:
00473 %
00474 %    o image: the image.
00475 %
00476 %    o threshold: define the threshold value.
00477 %
00478 %    o exception: return any errors or warnings in this structure.
00479 %
00480 */
00481 MagickExport MagickBooleanType BlackThresholdImage(Image *image,
00482   const char *thresholds,ExceptionInfo *exception)
00483 {
00484 #define ThresholdImageTag  "Threshold/Image"
00485 
00486   CacheView
00487     *image_view;
00488 
00489   GeometryInfo
00490     geometry_info;
00491 
00492   MagickBooleanType
00493     status;
00494 
00495   MagickOffsetType
00496     progress;
00497 
00498   MagickRealType
00499     threshold[5];
00500 
00501   MagickStatusType
00502     flags;
00503 
00504   register ssize_t
00505     i;
00506 
00507   ssize_t
00508     y;
00509 
00510   assert(image != (Image *) NULL);
00511   assert(image->signature == MagickSignature);
00512   if (image->debug != MagickFalse)
00513     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00514   if (thresholds == (const char *) NULL)
00515     return(MagickTrue);
00516   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
00517     return(MagickFalse);
00518   flags=ParseGeometry(thresholds,&geometry_info);
00519   for (i=0; i < 5; i++)
00520     threshold[i]=geometry_info.rho;
00521   if ((flags & SigmaValue) != 0)
00522     threshold[1]=geometry_info.sigma;
00523   if ((flags & XiValue) != 0)
00524     threshold[2]=geometry_info.xi;
00525   if ((flags & PsiValue) != 0)
00526     threshold[3]=geometry_info.psi;
00527   if ((flags & ChiValue) != 0)
00528     threshold[4]=geometry_info.chi;
00529   if ((flags & PercentValue) != 0)
00530     for (i=0; i < 5; i++)
00531       threshold[i]*=(QuantumRange/100.0);
00532   /*
00533     White threshold image.
00534   */
00535   status=MagickTrue;
00536   progress=0;
00537   image_view=AcquireCacheView(image);
00538 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00539   #pragma omp parallel for schedule(static,8) shared(progress,status)
00540 #endif
00541   for (y=0; y < (ssize_t) image->rows; y++)
00542   {
00543     register ssize_t
00544       x;
00545 
00546     register Quantum
00547       *restrict q;
00548 
00549     if (status == MagickFalse)
00550       continue;
00551     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
00552     if (q == (Quantum *) NULL)
00553       {
00554         status=MagickFalse;
00555         continue;
00556       }
00557     for (x=0; x < (ssize_t) image->columns; x++)
00558     {
00559       register ssize_t
00560         i;
00561 
00562       ssize_t
00563         n;
00564 
00565       if (GetPixelMask(image,q) != 0)
00566         {
00567           q+=GetPixelChannels(image);
00568           continue;
00569         }
00570       n=0;
00571       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
00572       {
00573         PixelChannel
00574           channel;
00575 
00576         PixelTrait
00577           traits;
00578 
00579         channel=GetPixelChannelMapChannel(image,i);
00580         traits=GetPixelChannelMapTraits(image,channel);
00581         if ((traits & UpdatePixelTrait) == 0)
00582           continue;
00583         if ((MagickRealType) q[i] < threshold[n++ % 5])
00584           q[i]=QuantumRange;
00585       }
00586       q+=GetPixelChannels(image);
00587     }
00588     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
00589       status=MagickFalse;
00590     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00591       {
00592         MagickBooleanType
00593           proceed;
00594 
00595 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00596   #pragma omp critical (MagickCore_WhiteThresholdImage)
00597 #endif
00598         proceed=SetImageProgress(image,ThresholdImageTag,progress++,
00599           image->rows);
00600         if (proceed == MagickFalse)
00601           status=MagickFalse;
00602       }
00603   }
00604   image_view=DestroyCacheView(image_view);
00605   return(status);
00606 }
00607 
00608 /*
00609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00610 %                                                                             %
00611 %                                                                             %
00612 %                                                                             %
00613 %     C l a m p I m a g e                                                     %
00614 %                                                                             %
00615 %                                                                             %
00616 %                                                                             %
00617 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00618 %
00619 %  ClampImage() restricts the color range from 0 to the quantum depth.
00620 %
00621 %  The format of the ClampImage method is:
00622 %
00623 %      MagickBooleanType ClampImage(Image *image,ExceptionInfo *exception)
00624 %
00625 %  A description of each parameter follows:
00626 %
00627 %    o image: the image.
00628 %
00629 %    o exception: return any errors or warnings in this structure.
00630 %
00631 */
00632 
00633 static inline Quantum ClampToUnsignedQuantum(const Quantum quantum)
00634 {
00635 #if defined(MAGICKCORE_HDRI_SUPPORT)
00636   if (quantum <= 0)
00637     return(0);
00638   if (quantum >= QuantumRange)
00639     return(QuantumRange);
00640   return(quantum);
00641 #else
00642   return(quantum);
00643 #endif
00644 }
00645 
00646 MagickExport MagickBooleanType ClampImage(Image *image,ExceptionInfo *exception)
00647 {
00648 #define ClampImageTag  "Clamp/Image"
00649 
00650   CacheView
00651     *image_view;
00652 
00653   MagickBooleanType
00654     status;
00655 
00656   MagickOffsetType
00657     progress;
00658 
00659   ssize_t
00660     y;
00661 
00662   assert(image != (Image *) NULL);
00663   assert(image->signature == MagickSignature);
00664   if (image->debug != MagickFalse)
00665     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00666   if (image->storage_class == PseudoClass)
00667     {
00668       register ssize_t
00669         i;
00670 
00671       register PixelInfo
00672         *restrict q;
00673 
00674       q=image->colormap;
00675       for (i=0; i < (ssize_t) image->colors; i++)
00676       {
00677         q->red=ClampToUnsignedQuantum(q->red);
00678         q->green=ClampToUnsignedQuantum(q->green);
00679         q->blue=ClampToUnsignedQuantum(q->blue);
00680         q->alpha=ClampToUnsignedQuantum(q->alpha);
00681         q++;
00682       }
00683       return(SyncImage(image,exception));
00684     }
00685   /*
00686     Clamp image.
00687   */
00688   status=MagickTrue;
00689   progress=0;
00690   image_view=AcquireCacheView(image);
00691 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00692   #pragma omp parallel for schedule(static,8) shared(progress,status)
00693 #endif
00694   for (y=0; y < (ssize_t) image->rows; y++)
00695   {
00696     register ssize_t
00697       x;
00698 
00699     register Quantum
00700       *restrict q;
00701 
00702     if (status == MagickFalse)
00703       continue;
00704     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
00705     if (q == (Quantum *) NULL)
00706       {
00707         status=MagickFalse;
00708         continue;
00709       }
00710     for (x=0; x < (ssize_t) image->columns; x++)
00711     {
00712       register ssize_t
00713         i;
00714 
00715       if (GetPixelMask(image,q) != 0)
00716         {
00717           q+=GetPixelChannels(image);
00718           continue;
00719         }
00720       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
00721       {
00722         PixelChannel
00723           channel;
00724 
00725         PixelTrait
00726           traits;
00727 
00728         channel=GetPixelChannelMapChannel(image,i);
00729         traits=GetPixelChannelMapTraits(image,channel);
00730         if (traits == UndefinedPixelTrait)
00731           continue;
00732         q[i]=ClampToUnsignedQuantum(q[i]);
00733       }
00734       q+=GetPixelChannels(image);
00735     }
00736     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
00737       status=MagickFalse;
00738     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00739       {
00740         MagickBooleanType
00741           proceed;
00742 
00743 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00744   #pragma omp critical (MagickCore_ClampImage)
00745 #endif
00746         proceed=SetImageProgress(image,ClampImageTag,progress++,
00747           image->rows);
00748         if (proceed == MagickFalse)
00749           status=MagickFalse;
00750       }
00751   }
00752   image_view=DestroyCacheView(image_view);
00753   return(status);
00754 }
00755 
00756 /*
00757 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00758 %                                                                             %
00759 %                                                                             %
00760 %                                                                             %
00761 %  D e s t r o y T h r e s h o l d M a p                                      %
00762 %                                                                             %
00763 %                                                                             %
00764 %                                                                             %
00765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00766 %
00767 %  DestroyThresholdMap() de-allocate the given ThresholdMap
00768 %
00769 %  The format of the ListThresholdMaps method is:
00770 %
00771 %      ThresholdMap *DestroyThresholdMap(Threshold *map)
00772 %
00773 %  A description of each parameter follows.
00774 %
00775 %    o map:    Pointer to the Threshold map to destroy
00776 %
00777 */
00778 MagickExport ThresholdMap *DestroyThresholdMap(ThresholdMap *map)
00779 {
00780   assert(map != (ThresholdMap *) NULL);
00781   if (map->map_id != (char *) NULL)
00782     map->map_id=DestroyString(map->map_id);
00783   if (map->description != (char *) NULL)
00784     map->description=DestroyString(map->description);
00785   if (map->levels != (ssize_t *) NULL)
00786     map->levels=(ssize_t *) RelinquishMagickMemory(map->levels);
00787   map=(ThresholdMap *) RelinquishMagickMemory(map);
00788   return(map);
00789 }
00790 
00791 /*
00792 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00793 %                                                                             %
00794 %                                                                             %
00795 %                                                                             %
00796 %  G e t T h r e s h o l d M a p                                              %
00797 %                                                                             %
00798 %                                                                             %
00799 %                                                                             %
00800 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00801 %
00802 %  GetThresholdMap() loads and searches one or more threshold map files for the
00803 %  map matching the given name or alias.
00804 %
00805 %  The format of the GetThresholdMap method is:
00806 %
00807 %      ThresholdMap *GetThresholdMap(const char *map_id,
00808 %        ExceptionInfo *exception)
00809 %
00810 %  A description of each parameter follows.
00811 %
00812 %    o map_id:  ID of the map to look for.
00813 %
00814 %    o exception: return any errors or warnings in this structure.
00815 %
00816 */
00817 MagickExport ThresholdMap *GetThresholdMap(const char *map_id,
00818   ExceptionInfo *exception)
00819 {
00820   const StringInfo
00821     *option;
00822 
00823   LinkedListInfo
00824     *options;
00825 
00826   ThresholdMap
00827     *map;
00828 
00829   map=(ThresholdMap *)NULL;
00830   options=GetConfigureOptions(ThresholdsFilename,exception);
00831   while ((option=(const StringInfo *) GetNextValueInLinkedList(options)) !=
00832          (const StringInfo *) NULL && (map == (ThresholdMap *) NULL))
00833     map=GetThresholdMapFile((const char *) GetStringInfoDatum(option),
00834       GetStringInfoPath(option),map_id,exception);
00835   options=DestroyConfigureOptions(options);
00836   return(map);
00837 }
00838 
00839 /*
00840 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00841 %                                                                             %
00842 %                                                                             %
00843 %                                                                             %
00844 +  G e t T h r e s h o l d M a p F i l e                                      %
00845 %                                                                             %
00846 %                                                                             %
00847 %                                                                             %
00848 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00849 %
00850 %  GetThresholdMapFile() look for a given threshold map name or alias in the
00851 %  given XML file data, and return the allocated the map when found.
00852 %
00853 %  The format of the ListThresholdMaps method is:
00854 %
00855 %      ThresholdMap *GetThresholdMap(const char *xml,const char *filename,
00856 %         const char *map_id,ExceptionInfo *exception)
00857 %
00858 %  A description of each parameter follows.
00859 %
00860 %    o xml:  The threshold map list in XML format.
00861 %
00862 %    o filename:  The threshold map XML filename.
00863 %
00864 %    o map_id:  ID of the map to look for in XML list.
00865 %
00866 %    o exception: return any errors or warnings in this structure.
00867 %
00868 */
00869 static ThresholdMap *GetThresholdMapFile(const char *xml,
00870   const char *filename,const char *map_id,ExceptionInfo *exception)
00871 {
00872   char
00873     *p;
00874 
00875   const char
00876     *attribute,
00877     *content;
00878 
00879   double
00880     value;
00881 
00882   register ssize_t
00883     i;
00884 
00885   ThresholdMap
00886     *map;
00887 
00888   XMLTreeInfo
00889     *description,
00890     *levels,
00891     *threshold,
00892     *thresholds;
00893 
00894   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
00895     "Loading threshold map file \"%s\" ...",filename);
00896   map=(ThresholdMap *) NULL;
00897   thresholds=NewXMLTree(xml,exception);
00898   if (thresholds == (XMLTreeInfo *) NULL)
00899     return(map);
00900   for (threshold=GetXMLTreeChild(thresholds,"threshold");
00901        threshold != (XMLTreeInfo *) NULL;
00902        threshold=GetNextXMLTreeTag(threshold))
00903   {
00904     attribute=GetXMLTreeAttribute(threshold,"map");
00905     if ((attribute != (char *) NULL) && (LocaleCompare(map_id,attribute) == 0))
00906       break;
00907     attribute=GetXMLTreeAttribute(threshold,"alias");
00908     if ((attribute != (char *) NULL) && (LocaleCompare(map_id,attribute) == 0))
00909       break;
00910   }
00911   if (threshold == (XMLTreeInfo *) NULL)
00912     return(map);
00913   description=GetXMLTreeChild(threshold,"description");
00914   if (description == (XMLTreeInfo *) NULL)
00915     {
00916       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00917         "XmlMissingElement", "<description>, map \"%s\"",map_id);
00918       thresholds=DestroyXMLTree(thresholds);
00919       return(map);
00920     }
00921   levels=GetXMLTreeChild(threshold,"levels");
00922   if (levels == (XMLTreeInfo *) NULL)
00923     {
00924       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00925         "XmlMissingElement", "<levels>, map \"%s\"", map_id);
00926       thresholds=DestroyXMLTree(thresholds);
00927       return(map);
00928     }
00929   map=(ThresholdMap *) AcquireMagickMemory(sizeof(ThresholdMap));
00930   if (map == (ThresholdMap *) NULL)
00931     ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireThresholdMap");
00932   map->map_id=(char *) NULL;
00933   map->description=(char *) NULL;
00934   map->levels=(ssize_t *) NULL;
00935   attribute=GetXMLTreeAttribute(threshold,"map");
00936   if (attribute != (char *) NULL)
00937     map->map_id=ConstantString(attribute);
00938   content=GetXMLTreeContent(description);
00939   if (content != (char *) NULL)
00940     map->description=ConstantString(content);
00941   attribute=GetXMLTreeAttribute(levels,"width");
00942   if (attribute == (char *) NULL)
00943     {
00944       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00945         "XmlMissingAttribute", "<levels width>, map \"%s\"",map_id);
00946       thresholds=DestroyXMLTree(thresholds);
00947       map=DestroyThresholdMap(map);
00948       return(map);
00949     }
00950   map->width=StringToUnsignedLong(attribute);
00951   if (map->width == 0)
00952     {
00953       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00954        "XmlInvalidAttribute", "<levels width>, map \"%s\"",map_id);
00955       thresholds=DestroyXMLTree(thresholds);
00956       map=DestroyThresholdMap(map);
00957       return(map);
00958     }
00959   attribute=GetXMLTreeAttribute(levels,"height");
00960   if (attribute == (char *) NULL)
00961     {
00962       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00963         "XmlMissingAttribute", "<levels height>, map \"%s\"",map_id);
00964       thresholds=DestroyXMLTree(thresholds);
00965       map=DestroyThresholdMap(map);
00966       return(map);
00967     }
00968   map->height=StringToUnsignedLong(attribute);
00969   if (map->height == 0)
00970     {
00971       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00972         "XmlInvalidAttribute", "<levels height>, map \"%s\"",map_id);
00973       thresholds=DestroyXMLTree(thresholds);
00974       map=DestroyThresholdMap(map);
00975       return(map);
00976     }
00977   attribute=GetXMLTreeAttribute(levels,"divisor");
00978   if (attribute == (char *) NULL)
00979     {
00980       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00981         "XmlMissingAttribute", "<levels divisor>, map \"%s\"",map_id);
00982       thresholds=DestroyXMLTree(thresholds);
00983       map=DestroyThresholdMap(map);
00984       return(map);
00985     }
00986   map->divisor=(ssize_t) StringToLong(attribute);
00987   if (map->divisor < 2)
00988     {
00989       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00990         "XmlInvalidAttribute", "<levels divisor>, map \"%s\"",map_id);
00991       thresholds=DestroyXMLTree(thresholds);
00992       map=DestroyThresholdMap(map);
00993       return(map);
00994     }
00995   content=GetXMLTreeContent(levels);
00996   if (content == (char *) NULL)
00997     {
00998       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00999         "XmlMissingContent", "<levels>, map \"%s\"",map_id);
01000       thresholds=DestroyXMLTree(thresholds);
01001       map=DestroyThresholdMap(map);
01002       return(map);
01003     }
01004   map->levels=(ssize_t *) AcquireQuantumMemory((size_t) map->width,map->height*
01005     sizeof(*map->levels));
01006   if (map->levels == (ssize_t *) NULL)
01007     ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireThresholdMap");
01008   for (i=0; i < (ssize_t) (map->width*map->height); i++)
01009   {
01010     map->levels[i]=(ssize_t) strtol(content,&p,10);
01011     if (p == content)
01012       {
01013         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01014           "XmlInvalidContent", "<level> too few values, map \"%s\"",map_id);
01015         thresholds=DestroyXMLTree(thresholds);
01016         map=DestroyThresholdMap(map);
01017         return(map);
01018       }
01019     if ((map->levels[i] < 0) || (map->levels[i] > map->divisor))
01020       {
01021         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01022           "XmlInvalidContent", "<level> %.20g out of range, map \"%s\"",
01023           (double) map->levels[i],map_id);
01024         thresholds=DestroyXMLTree(thresholds);
01025         map=DestroyThresholdMap(map);
01026         return(map);
01027       }
01028     content=p;
01029   }
01030   value=(double) strtol(content,&p,10);
01031   (void) value;
01032   if (p != content)
01033     {
01034       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01035         "XmlInvalidContent", "<level> too many values, map \"%s\"",map_id);
01036      thresholds=DestroyXMLTree(thresholds);
01037      map=DestroyThresholdMap(map);
01038      return(map);
01039    }
01040   thresholds=DestroyXMLTree(thresholds);
01041   return(map);
01042 }
01043 
01044 /*
01045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01046 %                                                                             %
01047 %                                                                             %
01048 %                                                                             %
01049 +  L i s t T h r e s h o l d M a p F i l e                                    %
01050 %                                                                             %
01051 %                                                                             %
01052 %                                                                             %
01053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01054 %
01055 %  ListThresholdMapFile() lists the threshold maps and their descriptions
01056 %  in the given XML file data.
01057 %
01058 %  The format of the ListThresholdMaps method is:
01059 %
01060 %      MagickBooleanType ListThresholdMaps(FILE *file,const char*xml,
01061 %         const char *filename,ExceptionInfo *exception)
01062 %
01063 %  A description of each parameter follows.
01064 %
01065 %    o file:  An pointer to the output FILE.
01066 %
01067 %    o xml:  The threshold map list in XML format.
01068 %
01069 %    o filename:  The threshold map XML filename.
01070 %
01071 %    o exception: return any errors or warnings in this structure.
01072 %
01073 */
01074 MagickBooleanType ListThresholdMapFile(FILE *file,const char *xml,
01075   const char *filename,ExceptionInfo *exception)
01076 {
01077   const char
01078     *alias,
01079     *content,
01080     *map;
01081 
01082   XMLTreeInfo
01083     *description,
01084     *threshold,
01085     *thresholds;
01086 
01087   assert( xml != (char *)NULL );
01088   assert( file != (FILE *)NULL );
01089   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
01090     "Loading threshold map file \"%s\" ...",filename);
01091   thresholds=NewXMLTree(xml,exception);
01092   if ( thresholds == (XMLTreeInfo *)NULL )
01093     return(MagickFalse);
01094   (void) FormatLocaleFile(file,"%-16s %-12s %s\n","Map","Alias","Description");
01095   (void) FormatLocaleFile(file,
01096     "----------------------------------------------------\n");
01097   threshold=GetXMLTreeChild(thresholds,"threshold");
01098   for ( ; threshold != (XMLTreeInfo *) NULL;
01099           threshold=GetNextXMLTreeTag(threshold))
01100   {
01101     map=GetXMLTreeAttribute(threshold,"map");
01102     if (map == (char *) NULL)
01103       {
01104         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01105           "XmlMissingAttribute", "<map>");
01106         thresholds=DestroyXMLTree(thresholds);
01107         return(MagickFalse);
01108       }
01109     alias=GetXMLTreeAttribute(threshold,"alias");
01110     description=GetXMLTreeChild(threshold,"description");
01111     if (description == (XMLTreeInfo *) NULL)
01112       {
01113         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01114           "XmlMissingElement", "<description>, map \"%s\"",map);
01115         thresholds=DestroyXMLTree(thresholds);
01116         return(MagickFalse);
01117       }
01118     content=GetXMLTreeContent(description);
01119     if (content == (char *) NULL)
01120       {
01121         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01122           "XmlMissingContent", "<description>, map \"%s\"", map);
01123         thresholds=DestroyXMLTree(thresholds);
01124         return(MagickFalse);
01125       }
01126     (void) FormatLocaleFile(file,"%-16s %-12s %s\n",map,alias ? alias : "",
01127       content);
01128   }
01129   thresholds=DestroyXMLTree(thresholds);
01130   return(MagickTrue);
01131 }
01132 
01133 /*
01134 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01135 %                                                                             %
01136 %                                                                             %
01137 %                                                                             %
01138 %  L i s t T h r e s h o l d M a p s                                          %
01139 %                                                                             %
01140 %                                                                             %
01141 %                                                                             %
01142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01143 %
01144 %  ListThresholdMaps() lists the threshold maps and their descriptions
01145 %  as defined by "threshold.xml" to a file.
01146 %
01147 %  The format of the ListThresholdMaps method is:
01148 %
01149 %      MagickBooleanType ListThresholdMaps(FILE *file,ExceptionInfo *exception)
01150 %
01151 %  A description of each parameter follows.
01152 %
01153 %    o file:  An pointer to the output FILE.
01154 %
01155 %    o exception: return any errors or warnings in this structure.
01156 %
01157 */
01158 MagickExport MagickBooleanType ListThresholdMaps(FILE *file,
01159   ExceptionInfo *exception)
01160 {
01161   const StringInfo
01162     *option;
01163 
01164   LinkedListInfo
01165     *options;
01166 
01167   MagickStatusType
01168     status;
01169 
01170   status=MagickFalse;
01171   if (file == (FILE *) NULL)
01172     file=stdout;
01173   options=GetConfigureOptions(ThresholdsFilename,exception);
01174   (void) FormatLocaleFile(file,
01175     "\n   Threshold Maps for Ordered Dither Operations\n");
01176   while ((option=(const StringInfo *) GetNextValueInLinkedList(options)) !=
01177          (const StringInfo *) NULL)
01178   {
01179     (void) FormatLocaleFile(file,"\nPATH: %s\n\n",GetStringInfoPath(option));
01180     status|=ListThresholdMapFile(file,(const char *) GetStringInfoDatum(option),
01181       GetStringInfoPath(option),exception);
01182   }
01183   options=DestroyConfigureOptions(options);
01184   return(status != 0 ? MagickTrue : MagickFalse);
01185 }
01186 
01187 /*
01188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01189 %                                                                             %
01190 %                                                                             %
01191 %                                                                             %
01192 %     O r d e r e d P o s t e r i z e I m a g e                               %
01193 %                                                                             %
01194 %                                                                             %
01195 %                                                                             %
01196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01197 %
01198 %  OrderedPosterizeImage() will perform a ordered dither based on a number
01199 %  of pre-defined dithering threshold maps, but over multiple intensity
01200 %  levels, which can be different for different channels, according to the
01201 %  input argument.
01202 %
01203 %  The format of the OrderedPosterizeImage method is:
01204 %
01205 %      MagickBooleanType OrderedPosterizeImage(Image *image,
01206 %        const char *threshold_map,ExceptionInfo *exception)
01207 %
01208 %  A description of each parameter follows:
01209 %
01210 %    o image: the image.
01211 %
01212 %    o threshold_map: A string containing the name of the threshold dither
01213 %      map to use, followed by zero or more numbers representing the number
01214 %      of color levels tho dither between.
01215 %
01216 %      Any level number less than 2 will be equivalent to 2, and means only
01217 %      binary dithering will be applied to each color channel.
01218 %
01219 %      No numbers also means a 2 level (bitmap) dither will be applied to all
01220 %      channels, while a single number is the number of levels applied to each
01221 %      channel in sequence.  More numbers will be applied in turn to each of
01222 %      the color channels.
01223 %
01224 %      For example: "o3x3,6" will generate a 6 level posterization of the
01225 %      image with a ordered 3x3 diffused pixel dither being applied between
01226 %      each level. While checker,8,8,4 will produce a 332 colormaped image
01227 %      with only a single checkerboard hash pattern (50% grey) between each
01228 %      color level, to basically double the number of color levels with
01229 %      a bare minimim of dithering.
01230 %
01231 %    o exception: return any errors or warnings in this structure.
01232 %
01233 */
01234 MagickExport MagickBooleanType OrderedPosterizeImage(Image *image,
01235   const char *threshold_map,ExceptionInfo *exception)
01236 {
01237 #define DitherImageTag  "Dither/Image"
01238 
01239   CacheView
01240     *image_view;
01241 
01242   char
01243     token[MaxTextExtent];
01244 
01245   const char
01246     *p;
01247 
01248   MagickBooleanType
01249     status;
01250 
01251   MagickOffsetType
01252     progress;
01253 
01254   MagickRealType
01255     levels[CompositePixelChannel];
01256 
01257   register ssize_t
01258     i;
01259 
01260   ssize_t
01261     y;
01262 
01263   ThresholdMap
01264     *map;
01265 
01266   assert(image != (Image *) NULL);
01267   assert(image->signature == MagickSignature);
01268   if (image->debug != MagickFalse)
01269     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01270   assert(exception != (ExceptionInfo *) NULL);
01271   assert(exception->signature == MagickSignature);
01272   if (threshold_map == (const char *) NULL)
01273     return(MagickTrue);
01274   p=(char *) threshold_map;
01275   while (((isspace((int) ((unsigned char) *p)) != 0) || (*p == ',')) &&
01276          (*p != '\0'))
01277     p++;
01278   threshold_map=p;
01279   while (((isspace((int) ((unsigned char) *p)) == 0) && (*p != ',')) &&
01280          (*p != '\0'))
01281   {
01282     if ((p-threshold_map) >= (MaxTextExtent-1))
01283       break;
01284     token[p-threshold_map]=(*p);
01285     p++;
01286   }
01287   token[p-threshold_map]='\0';
01288   map=GetThresholdMap(token,exception);
01289   if (map == (ThresholdMap *) NULL)
01290     {
01291       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01292         "InvalidArgument","%s : '%s'","ordered-dither",threshold_map);
01293       return(MagickFalse);
01294     }
01295   for (i=0; i < MaxPixelChannels; i++)
01296     levels[i]=2.0;
01297   p=strchr((char *) threshold_map,',');
01298   if ((p != (char *) NULL) && (isdigit((int) ((unsigned char) *(++p))) != 0))
01299     for (i=0; (*p != '\0') && (i < MaxPixelChannels); i++)
01300     {
01301       GetMagickToken(p,&p,token);
01302       if (*token == ',')
01303         GetMagickToken(p,&p,token);
01304       levels[i]=StringToDouble(token,(char **) NULL);
01305     }
01306   for (i=0; i < MaxPixelChannels; i++)
01307     if (fabs(levels[i]) >= 1)
01308       levels[i]-=1.0;
01309   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
01310     return(MagickFalse);
01311   status=MagickTrue;
01312   progress=0;
01313   image_view=AcquireCacheView(image);
01314 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01315   #pragma omp parallel for schedule(static,8) shared(progress,status)
01316 #endif
01317   for (y=0; y < (ssize_t) image->rows; y++)
01318   {
01319     register ssize_t
01320       x;
01321 
01322     register Quantum
01323       *restrict q;
01324 
01325     if (status == MagickFalse)
01326       continue;
01327     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
01328     if (q == (Quantum *) NULL)
01329       {
01330         status=MagickFalse;
01331         continue;
01332       }
01333     for (x=0; x < (ssize_t) image->columns; x++)
01334     {
01335       register ssize_t
01336         i;
01337 
01338       ssize_t
01339         n;
01340 
01341       n=0;
01342       if (GetPixelMask(image,q) != 0)
01343         {
01344           q+=GetPixelChannels(image);
01345           continue;
01346         }
01347       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
01348       {
01349         PixelChannel
01350           channel;
01351 
01352         PixelTrait
01353           traits;
01354 
01355         ssize_t
01356           level,
01357           threshold;
01358 
01359         channel=GetPixelChannelMapChannel(image,i);
01360         traits=GetPixelChannelMapTraits(image,channel);
01361         if ((traits & UpdatePixelTrait) == 0)
01362           continue;
01363         if (fabs(levels[n++]) < MagickEpsilon)
01364           continue;
01365         threshold=(ssize_t) (QuantumScale*q[i]*(levels[n]*(map->divisor-1)+1));
01366         level=threshold/(map->divisor-1);
01367         threshold-=level*(map->divisor-1);
01368         q[i]=RoundToQuantum((level+(threshold >= map->levels[(x % map->width)+
01369           map->width*(y % map->height)]))*QuantumRange/levels[n]);
01370         n++;
01371       }
01372       q+=GetPixelChannels(image);
01373     }
01374     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
01375       status=MagickFalse;
01376     if (image->progress_monitor != (MagickProgressMonitor) NULL)
01377       {
01378         MagickBooleanType
01379           proceed;
01380 
01381 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01382 #pragma omp critical (MagickCore_OrderedPosterizeImage)
01383 #endif
01384         proceed=SetImageProgress(image,DitherImageTag,progress++,image->rows);
01385         if (proceed == MagickFalse)
01386           status=MagickFalse;
01387       }
01388   }
01389   image_view=DestroyCacheView(image_view);
01390   map=DestroyThresholdMap(map);
01391   return(MagickTrue);
01392 }
01393 
01394 /*
01395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01396 %                                                                             %
01397 %                                                                             %
01398 %                                                                             %
01399 %     R a n d o m T h r e s h o l d I m a g e                                 %
01400 %                                                                             %
01401 %                                                                             %
01402 %                                                                             %
01403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01404 %
01405 %  RandomThresholdImage() changes the value of individual pixels based on the
01406 %  intensity of each pixel compared to a random threshold.  The result is a
01407 %  low-contrast, two color image.
01408 %
01409 %  The format of the RandomThresholdImage method is:
01410 %
01411 %      MagickBooleanType RandomThresholdImage(Image *image,
01412 %        const char *thresholds,ExceptionInfo *exception)
01413 %
01414 %  A description of each parameter follows:
01415 %
01416 %    o image: the image.
01417 %
01418 %    o thresholds: a geometry string containing low,high thresholds.  If the
01419 %      string contains 2x2, 3x3, or 4x4, an ordered dither of order 2, 3, or 4
01420 %      is performed instead.
01421 %
01422 %    o exception: return any errors or warnings in this structure.
01423 %
01424 */
01425 MagickExport MagickBooleanType RandomThresholdImage(Image *image,
01426   const char *thresholds,ExceptionInfo *exception)
01427 {
01428 #define ThresholdImageTag  "Threshold/Image"
01429 
01430   CacheView
01431     *image_view;
01432 
01433   GeometryInfo
01434     geometry_info;
01435 
01436   MagickStatusType
01437     flags;
01438 
01439   MagickBooleanType
01440     status;
01441 
01442   MagickOffsetType
01443     progress;
01444 
01445   PixelInfo
01446     threshold;
01447 
01448   MagickRealType
01449     min_threshold,
01450     max_threshold;
01451 
01452   RandomInfo
01453     **restrict random_info;
01454 
01455   ssize_t
01456     y;
01457 
01458   assert(image != (Image *) NULL);
01459   assert(image->signature == MagickSignature);
01460   if (image->debug != MagickFalse)
01461     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01462   assert(exception != (ExceptionInfo *) NULL);
01463   assert(exception->signature == MagickSignature);
01464   if (thresholds == (const char *) NULL)
01465     return(MagickTrue);
01466   GetPixelInfo(image,&threshold);
01467   min_threshold=0.0;
01468   max_threshold=(MagickRealType) QuantumRange;
01469   flags=ParseGeometry(thresholds,&geometry_info);
01470   min_threshold=geometry_info.rho;
01471   max_threshold=geometry_info.sigma;
01472   if ((flags & SigmaValue) == 0)
01473     max_threshold=min_threshold;
01474   if (strchr(thresholds,'%') != (char *) NULL)
01475     {
01476       max_threshold*=(MagickRealType) (0.01*QuantumRange);
01477       min_threshold*=(MagickRealType) (0.01*QuantumRange);
01478     }
01479   /*
01480     Random threshold image.
01481   */
01482   status=MagickTrue;
01483   progress=0;
01484   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
01485     return(MagickFalse);
01486   random_info=AcquireRandomInfoThreadSet();
01487   image_view=AcquireCacheView(image);
01488 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01489   #pragma omp parallel for schedule(static,8) shared(progress,status)
01490 #endif
01491   for (y=0; y < (ssize_t) image->rows; y++)
01492   {
01493     const int
01494       id = GetOpenMPThreadId();
01495 
01496     register Quantum
01497       *restrict q;
01498 
01499     register ssize_t
01500       x;
01501 
01502     if (status == MagickFalse)
01503       continue;
01504     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
01505     if (q == (Quantum *) NULL)
01506       {
01507         status=MagickFalse;
01508         continue;
01509       }
01510     for (x=0; x < (ssize_t) image->columns; x++)
01511     {
01512       register ssize_t
01513         i;
01514 
01515       if (GetPixelMask(image,q) != 0)
01516         {
01517           q+=GetPixelChannels(image);
01518           continue;
01519         }
01520       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
01521       {
01522         MagickRealType
01523           threshold;
01524 
01525         PixelChannel
01526           channel;
01527 
01528         PixelTrait
01529           traits;
01530 
01531         channel=GetPixelChannelMapChannel(image,i);
01532         traits=GetPixelChannelMapTraits(image,channel);
01533         if ((traits & UpdatePixelTrait) == 0)
01534           continue;
01535         if ((MagickRealType) q[i] < min_threshold)
01536           threshold=min_threshold;
01537         else
01538           if ((MagickRealType) q[i] > max_threshold)
01539             threshold=max_threshold;
01540           else
01541             threshold=(MagickRealType) (QuantumRange*
01542               GetPseudoRandomValue(random_info[id]));
01543           q[i]=(Quantum) ((MagickRealType) q[i] <= threshold ? 0 :
01544             QuantumRange);
01545       }
01546       q+=GetPixelChannels(image);
01547     }
01548     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
01549       status=MagickFalse;
01550     if (image->progress_monitor != (MagickProgressMonitor) NULL)
01551       {
01552         MagickBooleanType
01553           proceed;
01554 
01555 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01556   #pragma omp critical (MagickCore_RandomThresholdImage)
01557 #endif
01558         proceed=SetImageProgress(image,ThresholdImageTag,progress++,
01559           image->rows);
01560         if (proceed == MagickFalse)
01561           status=MagickFalse;
01562       }
01563   }
01564   image_view=DestroyCacheView(image_view);
01565   random_info=DestroyRandomInfoThreadSet(random_info);
01566   return(status);
01567 }
01568 
01569 /*
01570 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01571 %                                                                             %
01572 %                                                                             %
01573 %                                                                             %
01574 %     W h i t e T h r e s h o l d I m a g e                                   %
01575 %                                                                             %
01576 %                                                                             %
01577 %                                                                             %
01578 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01579 %
01580 %  WhiteThresholdImage() is like ThresholdImage() but forces all pixels above
01581 %  the threshold into white while leaving all pixels at or below the threshold
01582 %  unchanged.
01583 %
01584 %  The format of the WhiteThresholdImage method is:
01585 %
01586 %      MagickBooleanType WhiteThresholdImage(Image *image,
01587 %        const char *threshold,ExceptionInfo *exception)
01588 %
01589 %  A description of each parameter follows:
01590 %
01591 %    o image: the image.
01592 %
01593 %    o threshold: Define the threshold value.
01594 %
01595 %    o exception: return any errors or warnings in this structure.
01596 %
01597 */
01598 MagickExport MagickBooleanType WhiteThresholdImage(Image *image,
01599   const char *thresholds,ExceptionInfo *exception)
01600 {
01601 #define ThresholdImageTag  "Threshold/Image"
01602 
01603   CacheView
01604     *image_view;
01605 
01606   GeometryInfo
01607     geometry_info;
01608 
01609   MagickBooleanType
01610     status;
01611 
01612   MagickOffsetType
01613     progress;
01614 
01615   MagickRealType
01616     threshold[5];
01617 
01618   MagickStatusType
01619     flags;
01620 
01621   register ssize_t
01622     i;
01623 
01624   ssize_t
01625     y;
01626 
01627   assert(image != (Image *) NULL);
01628   assert(image->signature == MagickSignature);
01629   if (image->debug != MagickFalse)
01630     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01631   if (thresholds == (const char *) NULL)
01632     return(MagickTrue);
01633   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
01634     return(MagickFalse);
01635   flags=ParseGeometry(thresholds,&geometry_info);
01636   for (i=0; i < 5; i++)
01637     threshold[i]=geometry_info.rho;
01638   if ((flags & SigmaValue) != 0)
01639     threshold[1]=geometry_info.sigma;
01640   if ((flags & XiValue) != 0)
01641     threshold[2]=geometry_info.xi;
01642   if ((flags & PsiValue) != 0)
01643     threshold[3]=geometry_info.psi;
01644   if ((flags & ChiValue) != 0)
01645     threshold[4]=geometry_info.chi;
01646   if ((flags & PercentValue) != 0)
01647     for (i=0; i < 5; i++)
01648       threshold[i]*=(QuantumRange/100.0);
01649   /*
01650     White threshold image.
01651   */
01652   status=MagickTrue;
01653   progress=0;
01654   image_view=AcquireCacheView(image);
01655 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01656   #pragma omp parallel for schedule(static,8) shared(progress,status)
01657 #endif
01658   for (y=0; y < (ssize_t) image->rows; y++)
01659   {
01660     register ssize_t
01661       x;
01662 
01663     register Quantum
01664       *restrict q;
01665 
01666     if (status == MagickFalse)
01667       continue;
01668     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
01669     if (q == (Quantum *) NULL)
01670       {
01671         status=MagickFalse;
01672         continue;
01673       }
01674     for (x=0; x < (ssize_t) image->columns; x++)
01675     {
01676       register ssize_t
01677         i;
01678 
01679       ssize_t
01680         n;
01681 
01682       if (GetPixelMask(image,q) != 0)
01683         {
01684           q+=GetPixelChannels(image);
01685           continue;
01686         }
01687       n=0;
01688       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
01689       {
01690         PixelChannel
01691           channel;
01692 
01693         PixelTrait
01694           traits;
01695 
01696         channel=GetPixelChannelMapChannel(image,i);
01697         traits=GetPixelChannelMapTraits(image,channel);
01698         if ((traits & UpdatePixelTrait) == 0)
01699           continue;
01700         if ((MagickRealType) q[i] > threshold[n++ % 5])
01701           q[i]=QuantumRange;
01702       }
01703       q+=GetPixelChannels(image);
01704     }
01705     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
01706       status=MagickFalse;
01707     if (image->progress_monitor != (MagickProgressMonitor) NULL)
01708       {
01709         MagickBooleanType
01710           proceed;
01711 
01712 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01713   #pragma omp critical (MagickCore_WhiteThresholdImage)
01714 #endif
01715         proceed=SetImageProgress(image,ThresholdImageTag,progress++,
01716           image->rows);
01717         if (proceed == MagickFalse)
01718           status=MagickFalse;
01719       }
01720   }
01721   image_view=DestroyCacheView(image_view);
01722   return(status);
01723 }