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-2009 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 "magick/studio.h"
00044 #include "magick/property.h"
00045 #include "magick/blob.h"
00046 #include "magick/cache-view.h"
00047 #include "magick/color.h"
00048 #include "magick/color-private.h"
00049 #include "magick/colorspace.h"
00050 #include "magick/configure.h"
00051 #include "magick/constitute.h"
00052 #include "magick/decorate.h"
00053 #include "magick/draw.h"
00054 #include "magick/enhance.h"
00055 #include "magick/exception.h"
00056 #include "magick/exception-private.h"
00057 #include "magick/effect.h"
00058 #include "magick/fx.h"
00059 #include "magick/gem.h"
00060 #include "magick/geometry.h"
00061 #include "magick/image-private.h"
00062 #include "magick/list.h"
00063 #include "magick/log.h"
00064 #include "magick/memory_.h"
00065 #include "magick/monitor.h"
00066 #include "magick/monitor-private.h"
00067 #include "magick/montage.h"
00068 #include "magick/pixel-private.h"
00069 #include "magick/quantize.h"
00070 #include "magick/quantum.h"
00071 #include "magick/random_.h"
00072 #include "magick/random-private.h"
00073 #include "magick/resize.h"
00074 #include "magick/resource_.h"
00075 #include "magick/segment.h"
00076 #include "magick/shear.h"
00077 #include "magick/signature-private.h"
00078 #include "magick/string_.h"
00079 #include "magick/transform.h"
00080 #include "magick/threshold.h"
00081 #include "magick/option.h"
00082 #include "magick/xml-tree.h"
00083 
00084 /*
00085   Define declarations.
00086 */
00087 #define ThresholdsFilename  "thresholds.xml"
00088 
00089 /*
00090   Typedef declarations.
00091 */
00092 struct _ThresholdMap
00093 {
00094   char
00095     *map_id,
00096     *description;
00097 
00098   unsigned long
00099     width,
00100     height;
00101 
00102   long
00103     divisor,
00104     *levels;
00105 };
00106 
00107 /*
00108 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00109 %                                                                             %
00110 %                                                                             %
00111 %                                                                             %
00112 %     A d a p t i v e T h r e s h o l d I m a g e                             %
00113 %                                                                             %
00114 %                                                                             %
00115 %                                                                             %
00116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00117 %
00118 %  AdaptiveThresholdImage() selects an individual threshold for each pixel
00119 %  based on the range of intensity values in its local neighborhood.  This
00120 %  allows for thresholding of an image whose global intensity histogram
00121 %  doesn't contain distinctive peaks.
00122 %
00123 %  The format of the AdaptiveThresholdImage method is:
00124 %
00125 %      Image *AdaptiveThresholdImage(const Image *image,
00126 %        const unsigned long width,const unsigned long height,
00127 %        const long offset,ExceptionInfo *exception)
00128 %
00129 %  A description of each parameter follows:
00130 %
00131 %    o image: the image.
00132 %
00133 %    o width: the width of the local neighborhood.
00134 %
00135 %    o height: the height of the local neighborhood.
00136 %
00137 %    o offset: the mean offset.
00138 %
00139 %    o exception: return any errors or warnings in this structure.
00140 %
00141 */
00142 MagickExport Image *AdaptiveThresholdImage(const Image *image,
00143   const unsigned long width,const unsigned long height,const long offset,
00144   ExceptionInfo *exception)
00145 {
00146 #define ThresholdImageTag  "Threshold/Image"
00147 
00148   Image
00149     *threshold_image;
00150 
00151   long
00152     progress,
00153     y;
00154 
00155   MagickBooleanType
00156     status;
00157 
00158   MagickPixelPacket
00159     zero;
00160 
00161   MagickRealType
00162     number_pixels;
00163 
00164   CacheView
00165     *image_view,
00166     *threshold_view;
00167 
00168   assert(image != (const Image *) NULL);
00169   assert(image->signature == MagickSignature);
00170   if (image->debug != MagickFalse)
00171     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00172   assert(exception != (ExceptionInfo *) NULL);
00173   assert(exception->signature == MagickSignature);
00174   if ((image->columns < width) || (image->rows < height))
00175     ThrowImageException(OptionError,"ImageSmallerThanRadius");
00176   threshold_image=CloneImage(image,0,0,MagickTrue,exception);
00177   if (threshold_image == (Image *) NULL)
00178     return((Image *) NULL);
00179   if (SetImageStorageClass(threshold_image,DirectClass) == MagickFalse)
00180     {
00181       InheritException(exception,&threshold_image->exception);
00182       threshold_image=DestroyImage(threshold_image);
00183       return((Image *) NULL);
00184     }
00185   /*
00186     Local adaptive threshold.
00187   */
00188   status=MagickTrue;
00189   progress=0;
00190   GetMagickPixelPacket(image,&zero);
00191   number_pixels=(MagickRealType) width*height;
00192   image_view=AcquireCacheView(image);
00193   threshold_view=AcquireCacheView(threshold_image);
00194 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00195   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
00196 #endif
00197   for (y=0; y < (long) image->rows; y++)
00198   {
00199     MagickBooleanType
00200       sync;
00201 
00202     register const IndexPacket
00203       *__restrict indexes;
00204 
00205     register const PixelPacket
00206       *__restrict p;
00207 
00208     register IndexPacket
00209       *__restrict threshold_indexes;
00210 
00211     register long
00212       x;
00213 
00214     register PixelPacket
00215       *__restrict q;
00216 
00217     if (status == MagickFalse)
00218       continue;
00219     p=GetCacheViewVirtualPixels(image_view,-((long) width/2L),y-height/2L,
00220       image->columns+width,height,exception);
00221     q=GetCacheViewAuthenticPixels(threshold_view,0,y,threshold_image->columns,1,
00222       exception);
00223     if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
00224       {
00225         status=MagickFalse;
00226         continue;
00227       }
00228     indexes=GetCacheViewVirtualIndexQueue(image_view);
00229     threshold_indexes=GetCacheViewAuthenticIndexQueue(threshold_view);
00230     for (x=0; x < (long) image->columns; x++)
00231     {
00232       long
00233         v;
00234 
00235       MagickPixelPacket
00236         mean,
00237         pixel;
00238 
00239       register const PixelPacket
00240         *r;
00241 
00242       register long
00243         u;
00244 
00245       pixel=zero;
00246       mean=zero;
00247       r=p;
00248       for (v=0; v < (long) height; v++)
00249       {
00250         for (u=0; u < (long) width; u++)
00251         {
00252           pixel.red+=r[u].red;
00253           pixel.green+=r[u].green;
00254           pixel.blue+=r[u].blue;
00255           pixel.opacity+=r[u].opacity;
00256           if (image->colorspace == CMYKColorspace)
00257             pixel.index=(MagickRealType) indexes[x+(r-p)+u];
00258         }
00259         r+=image->columns+width;
00260       }
00261       mean.red=(MagickRealType) (pixel.red/number_pixels+offset);
00262       mean.green=(MagickRealType) (pixel.green/number_pixels+offset);
00263       mean.blue=(MagickRealType) (pixel.blue/number_pixels+offset);
00264       mean.opacity=(MagickRealType) (pixel.opacity/number_pixels+offset);
00265       if (image->colorspace == CMYKColorspace)
00266         mean.index=(MagickRealType) (pixel.index/number_pixels+offset);
00267       q->red=(Quantum) (((MagickRealType) q->red <= mean.red) ?
00268         0 : QuantumRange);
00269       q->green=(Quantum) (((MagickRealType) q->green <= mean.green) ?
00270         0 : QuantumRange);
00271       q->blue=(Quantum) (((MagickRealType) q->blue <= mean.blue) ?
00272         0 : QuantumRange);
00273       q->opacity=(Quantum) (((MagickRealType) q->opacity <= mean.opacity) ?
00274         0 : QuantumRange);
00275       if (image->colorspace == CMYKColorspace)
00276         threshold_indexes[x]=(IndexPacket) (((MagickRealType)
00277           threshold_indexes[x] <= mean.index) ? 0 : QuantumRange);
00278       p++;
00279       q++;
00280     }
00281     sync=SyncCacheViewAuthenticPixels(threshold_view,exception);
00282     if (sync == MagickFalse)
00283       status=MagickFalse;
00284     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00285       {
00286         MagickBooleanType
00287           proceed;
00288 
00289 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00290   #pragma omp critical (MagickCore_AdaptiveThresholdImage)
00291 #endif
00292         proceed=SetImageProgress(image,ThresholdImageTag,progress++,
00293           image->rows);
00294         if (proceed == MagickFalse)
00295           status=MagickFalse;
00296       }
00297   }
00298   threshold_view=DestroyCacheView(threshold_view);
00299   image_view=DestroyCacheView(image_view);
00300   if (status == MagickFalse)
00301     threshold_image=DestroyImage(threshold_image);
00302   return(threshold_image);
00303 }
00304 
00305 /*
00306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00307 %                                                                             %
00308 %                                                                             %
00309 %                                                                             %
00310 %     B i l e v e l I m a g e                                                 %
00311 %                                                                             %
00312 %                                                                             %
00313 %                                                                             %
00314 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00315 %
00316 %  BilevelImage() changes the value of individual pixels based on the
00317 %  intensity of each pixel channel.  The result is a high-contrast image.
00318 %
00319 %  More precisely each channel value of the image is 'thresholded' so that if
00320 %  it is equal to or less than the given value it is set to zero, while any
00321 %  value greater than that give is set to it maximum or QuantumRange.
00322 %
00323 %  This function is what is used to implement the "-threshold" operator for
00324 %  the command line API.
00325 %
00326 %  If the default channel setting is given the image is thresholded using just
00327 %  the gray 'intensity' of the image, rather than the individual channels.
00328 %
00329 %  The format of the BilevelImageChannel method is:
00330 %
00331 %      MagickBooleanType BilevelImage(Image *image,const double threshold)
00332 %      MagickBooleanType BilevelImageChannel(Image *image,
00333 %        const ChannelType channel,const double threshold)
00334 %
00335 %  A description of each parameter follows:
00336 %
00337 %    o image: the image.
00338 %
00339 %    o channel: the channel type.
00340 %
00341 %    o threshold: define the threshold values.
00342 %
00343 %  Aside: You can get the same results as operator using LevelImageChannels()
00344 %  with the 'threshold' value for both the black_point and the white_point.
00345 %
00346 */
00347 
00348 MagickExport MagickBooleanType BilevelImage(Image *image,const double threshold)
00349 {
00350   MagickBooleanType
00351     status;
00352 
00353   status=BilevelImageChannel(image,DefaultChannels,threshold);
00354   return(status);
00355 }
00356 
00357 MagickExport MagickBooleanType BilevelImageChannel(Image *image,
00358   const ChannelType channel,const double threshold)
00359 {
00360 #define ThresholdImageTag  "Threshold/Image"
00361 
00362   ExceptionInfo
00363     *exception;
00364 
00365   long
00366     progress,
00367     y;
00368 
00369   MagickBooleanType
00370     status;
00371 
00372   CacheView
00373     *image_view;
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) == MagickFalse)
00380     return(MagickFalse);
00381   /*
00382     Bilevel threshold image.
00383   */
00384   status=MagickTrue;
00385   progress=0;
00386   exception=(&image->exception);
00387   image_view=AcquireCacheView(image);
00388 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00389   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
00390 #endif
00391   for (y=0; y < (long) image->rows; y++)
00392   {
00393     register IndexPacket
00394       *__restrict indexes;
00395 
00396     register long
00397       x;
00398 
00399     register PixelPacket
00400       *__restrict q;
00401 
00402     if (status == MagickFalse)
00403       continue;
00404     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
00405     if (q == (PixelPacket *) NULL)
00406       {
00407         status=MagickFalse;
00408         continue;
00409       }
00410     indexes=GetCacheViewAuthenticIndexQueue(image_view);
00411     if (channel == DefaultChannels)
00412       {
00413         for (x=0; x < (long) image->columns; x++)
00414         {
00415           q->red=(Quantum) ((MagickRealType) PixelIntensityToQuantum(q) <=
00416             threshold ? 0 : QuantumRange);
00417           q->green=q->red;
00418           q->blue=q->red;
00419           q++;
00420         }
00421       }
00422     else
00423       for (x=0; x < (long) image->columns; x++)
00424       {
00425         if ((channel & RedChannel) != 0)
00426           q->red=(Quantum) ((MagickRealType) q->red <= threshold ? 0 :
00427             QuantumRange);
00428         if ((channel & GreenChannel) != 0)
00429           q->green=(Quantum) ((MagickRealType) q->green <= threshold ? 0 :
00430             QuantumRange);
00431         if ((channel & BlueChannel) != 0)
00432           q->blue=(Quantum) ((MagickRealType) q->blue <= threshold ? 0 :
00433             QuantumRange);
00434         if ((channel & OpacityChannel) != 0)
00435           {
00436             if (image->matte == MagickFalse)
00437               q->opacity=(Quantum) ((MagickRealType) q->opacity <= threshold ?
00438                 0 : QuantumRange);
00439             else
00440               q->opacity=(Quantum) ((MagickRealType) q->opacity <= threshold ?
00441                 OpaqueOpacity : TransparentOpacity);
00442           }
00443         if (((channel & IndexChannel) != 0) &&
00444             (image->colorspace == CMYKColorspace))
00445           indexes[x]=(IndexPacket) ((MagickRealType) indexes[x] <= threshold ?
00446             0 : QuantumRange);
00447         q++;
00448       }
00449     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
00450       status=MagickFalse;
00451     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00452       {
00453         MagickBooleanType
00454           proceed;
00455 
00456 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00457   #pragma omp critical (MagickCore_BilevelImageChannel)
00458 #endif
00459         proceed=SetImageProgress(image,ThresholdImageTag,progress++,
00460           image->rows);
00461         if (proceed == MagickFalse)
00462           status=MagickFalse;
00463       }
00464   }
00465   image_view=DestroyCacheView(image_view);
00466   return(status);
00467 }
00468 
00469 /*
00470 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00471 %                                                                             %
00472 %                                                                             %
00473 %                                                                             %
00474 %     B l a c k T h r e s h o l d I m a g e                                   %
00475 %                                                                             %
00476 %                                                                             %
00477 %                                                                             %
00478 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00479 %
00480 %  BlackThresholdImage() is like ThresholdImage() but forces all pixels below
00481 %  the threshold into black while leaving all pixels at or above the threshold
00482 %  unchanged.
00483 %
00484 %  The format of the BlackThresholdImage method is:
00485 %
00486 %      MagickBooleanType BlackThresholdImage(Image *image,const char *threshold)
00487 %      MagickBooleanType BlackThresholdImageChannel(Image *image,
00488 %        const ChannelType channel,const char *threshold,
00489 %        ExceptionInfo *exception)
00490 %
00491 %  A description of each parameter follows:
00492 %
00493 %    o image: the image.
00494 %
00495 %    o channel: the channel or channels to be thresholded.
00496 %
00497 %    o threshold: Define the threshold value.
00498 %
00499 %    o exception: return any errors or warnings in this structure.
00500 %
00501 */
00502 MagickExport MagickBooleanType BlackThresholdImage(Image *image,
00503   const char *threshold)
00504 {
00505   MagickBooleanType
00506     status;
00507 
00508   status=BlackThresholdImageChannel(image,DefaultChannels,threshold,
00509     &image->exception);
00510   return(status);
00511 }
00512 
00513 MagickExport MagickBooleanType BlackThresholdImageChannel(Image *image,
00514   const ChannelType channel,const char *thresholds,ExceptionInfo *exception)
00515 {
00516 #define ThresholdImageTag  "Threshold/Image"
00517 
00518   GeometryInfo
00519     geometry_info;
00520 
00521   long
00522     progress,
00523     y;
00524 
00525   MagickBooleanType
00526     status;
00527 
00528   MagickPixelPacket
00529     threshold;
00530 
00531   MagickStatusType
00532     flags;
00533 
00534   CacheView
00535     *image_view;
00536 
00537   assert(image != (Image *) NULL);
00538   assert(image->signature == MagickSignature);
00539   if (image->debug != MagickFalse)
00540     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00541   if (thresholds == (const char *) NULL)
00542     return(MagickTrue);
00543   if (SetImageStorageClass(image,DirectClass) == MagickFalse)
00544     return(MagickFalse);
00545   GetMagickPixelPacket(image,&threshold);
00546   flags=ParseGeometry(thresholds,&geometry_info);
00547   threshold.red=geometry_info.rho;
00548   threshold.green=geometry_info.sigma;
00549   if ((flags & SigmaValue) == 0)
00550     threshold.green=threshold.red;
00551   threshold.blue=geometry_info.xi;
00552   if ((flags & XiValue) == 0)
00553     threshold.blue=threshold.red;
00554   threshold.opacity=geometry_info.psi;
00555   if ((flags & PsiValue) == 0)
00556     threshold.opacity=threshold.red;
00557   threshold.index=geometry_info.chi;
00558   if ((flags & ChiValue) == 0)
00559     threshold.index=threshold.red;
00560   if ((flags & PercentValue) != 0)
00561     {
00562       threshold.red*=(QuantumRange/100.0);
00563       threshold.green*=(QuantumRange/100.0);
00564       threshold.blue*=(QuantumRange/100.0);
00565       threshold.opacity*=(QuantumRange/100.0);
00566       threshold.index*=(QuantumRange/100.0);
00567     }
00568   /*
00569     Black threshold image.
00570   */
00571   status=MagickTrue;
00572   progress=0;
00573   image_view=AcquireCacheView(image);
00574 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00575   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
00576 #endif
00577   for (y=0; y < (long) image->rows; y++)
00578   {
00579     register IndexPacket
00580       *__restrict indexes;
00581 
00582     register long
00583       x;
00584 
00585     register PixelPacket
00586       *__restrict q;
00587 
00588     if (status == MagickFalse)
00589       continue;
00590     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
00591     if (q == (PixelPacket *) NULL)
00592       {
00593         status=MagickFalse;
00594         continue;
00595       }
00596     indexes=GetCacheViewAuthenticIndexQueue(image_view);
00597     if (channel == DefaultChannels)
00598       for (x=0; x < (long) image->columns; x++)
00599       {
00600         if ((MagickRealType) q->red < threshold.red)
00601           q->red=(Quantum) 0;
00602         if ((MagickRealType) q->green < threshold.green)
00603           q->green=(Quantum) 0;
00604         if ((MagickRealType) q->blue < threshold.blue)
00605           q->blue=(Quantum) 0;
00606         if ((image->colorspace == CMYKColorspace) &&
00607             ((MagickRealType) indexes[x] < threshold.index))
00608           indexes[x]=(Quantum) 0;
00609         q++;
00610       }
00611     else
00612       for (x=0; x < (long) image->columns; x++)
00613       {
00614         if (((channel & RedChannel) != 0) &&
00615             ((MagickRealType) q->red < threshold.red))
00616           q->red=(Quantum) 0;
00617         if (((channel & GreenChannel) != 0) &&
00618             ((MagickRealType) q->green < threshold.green))
00619           q->green=(Quantum) 0;
00620         if (((channel & BlueChannel) != 0) &&
00621             ((MagickRealType) q->blue < threshold.blue))
00622           q->blue=(Quantum) 0;
00623         if (((channel & OpacityChannel) != 0) &&
00624             ((MagickRealType) q->opacity < threshold.opacity))
00625           q->opacity=(Quantum) 0;
00626         if (((channel & IndexChannel) != 0) &&
00627             (image->colorspace == CMYKColorspace) &&
00628             ((MagickRealType) indexes[x] < threshold.index))
00629           indexes[x]=(Quantum) 0;
00630         q++;
00631       }
00632     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
00633       status=MagickFalse;
00634     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00635       {
00636         MagickBooleanType
00637           proceed;
00638 
00639 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00640   #pragma omp critical (MagickCore_BlackThresholdImageChannel)
00641 #endif
00642         proceed=SetImageProgress(image,ThresholdImageTag,progress++,
00643           image->rows);
00644         if (proceed == MagickFalse)
00645           status=MagickFalse;
00646       }
00647   }
00648   image_view=DestroyCacheView(image_view);
00649   return(status);
00650 }
00651 
00652 /*
00653 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00654 %                                                                             %
00655 %                                                                             %
00656 %                                                                             %
00657 %     C l a m p I m a g e                                                     %
00658 %                                                                             %
00659 %                                                                             %
00660 %                                                                             %
00661 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00662 %
00663 %  ClampImage() restricts the color range from 0 to the quantum depth.
00664 %
00665 %  The format of the ClampImageChannel method is:
00666 %
00667 %      MagickBooleanType ClampImage(Image *image)
00668 %      MagickBooleanType ClampImageChannel(Image *image,
00669 %        const ChannelType channel)
00670 %
00671 %  A description of each parameter follows:
00672 %
00673 %    o image: the image.
00674 %
00675 %    o channel: the channel type.
00676 %
00677 */
00678 
00679 static inline Quantum ClampToQuantum(const Quantum quantum)
00680 {
00681 #if defined(MAGICKCORE_HDRI_SUPPORT)
00682   if (quantum <= 0)
00683     return(0);
00684   if (quantum >= QuantumRange)
00685     return(QuantumRange);
00686   return(quantum);
00687 #else
00688   return(quantum);
00689 #endif
00690 }
00691 
00692 MagickExport MagickBooleanType ClampImage(Image *image)
00693 {
00694   MagickBooleanType
00695     status;
00696 
00697   status=ClampImageChannel(image,DefaultChannels);
00698   return(status);
00699 }
00700 
00701 MagickExport MagickBooleanType ClampImageChannel(Image *image,
00702   const ChannelType channel)
00703 {
00704 #define ClampImageTag  "Clamp/Image"
00705 
00706   ExceptionInfo
00707     *exception;
00708 
00709   long
00710     progress,
00711     y;
00712 
00713   MagickBooleanType
00714     status;
00715 
00716   CacheView
00717     *image_view;
00718 
00719   assert(image != (Image *) NULL);
00720   assert(image->signature == MagickSignature);
00721   if (image->debug != MagickFalse)
00722     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
00723   if (image->storage_class == PseudoClass)
00724     {
00725       register long
00726         i;
00727 
00728       register PixelPacket
00729         *__restrict q;
00730 
00731       q=image->colormap;
00732       for (i=0; i < (long) image->colors; i++)
00733       {
00734         q->red=ClampToQuantum(q->red);
00735         q->green=ClampToQuantum(q->green);
00736         q->blue=ClampToQuantum(q->blue);
00737         q->opacity=ClampToQuantum(q->opacity);
00738         q++;
00739       }
00740       return(SyncImage(image));
00741     }
00742   /*
00743     Clamp image.
00744   */
00745   status=MagickTrue;
00746   progress=0;
00747   exception=(&image->exception);
00748   image_view=AcquireCacheView(image);
00749 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00750   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
00751 #endif
00752   for (y=0; y < (long) image->rows; y++)
00753   {
00754     register IndexPacket
00755       *__restrict indexes;
00756 
00757     register long
00758       x;
00759 
00760     register PixelPacket
00761       *__restrict q;
00762 
00763     if (status == MagickFalse)
00764       continue;
00765     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
00766     if (q == (PixelPacket *) NULL)
00767       {
00768         status=MagickFalse;
00769         continue;
00770       }
00771     indexes=GetCacheViewAuthenticIndexQueue(image_view);
00772     for (x=0; x < (long) image->columns; x++)
00773     {
00774       if ((channel & RedChannel) != 0)
00775         q->red=ClampToQuantum(q->red);
00776       if ((channel & GreenChannel) != 0)
00777         q->green=ClampToQuantum(q->green);
00778       if ((channel & BlueChannel) != 0)
00779         q->blue=ClampToQuantum(q->blue);
00780       if ((channel & OpacityChannel) != 0)
00781         q->opacity=ClampToQuantum(q->opacity);
00782       if (((channel & IndexChannel) != 0) &&
00783           (image->colorspace == CMYKColorspace))
00784         indexes[x]=(IndexPacket) ClampToQuantum(indexes[x]);
00785       q++;
00786     }
00787     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
00788       status=MagickFalse;
00789     if (image->progress_monitor != (MagickProgressMonitor) NULL)
00790       {
00791         MagickBooleanType
00792           proceed;
00793 
00794 #if defined(MAGICKCORE_OPENMP_SUPPORT)
00795   #pragma omp critical (MagickCore_ClampImageChannel)
00796 #endif
00797         proceed=SetImageProgress(image,ClampImageTag,progress++,
00798           image->rows);
00799         if (proceed == MagickFalse)
00800           status=MagickFalse;
00801       }
00802   }
00803   image_view=DestroyCacheView(image_view);
00804   return(status);
00805 }
00806 
00807 /*
00808 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00809 %                                                                             %
00810 %                                                                             %
00811 %                                                                             %
00812 %  D e s t r o y T h r e s h o l d M a p                                      %
00813 %                                                                             %
00814 %                                                                             %
00815 %                                                                             %
00816 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00817 %
00818 %  DestroyThresholdMap() de-allocate the given ThresholdMap
00819 %
00820 %  The format of the ListThresholdMaps method is:
00821 %
00822 %      ThresholdMap *DestroyThresholdMap(Threshold *map)
00823 %
00824 %  A description of each parameter follows.
00825 %
00826 %    o map:    Pointer to the Threshold map to destroy
00827 %
00828 */
00829 MagickExport ThresholdMap *DestroyThresholdMap(ThresholdMap *map)
00830 {
00831   assert(map != (ThresholdMap *) NULL);
00832   if (map->map_id != (char *) NULL)
00833     map->map_id=DestroyString(map->map_id);
00834   if (map->description != (char *) NULL)
00835     map->description=DestroyString(map->description);
00836   if (map->levels != (long *) NULL)
00837     map->levels=(long *) RelinquishMagickMemory(map->levels);
00838   map=(ThresholdMap *) RelinquishMagickMemory(map);
00839   return(map);
00840 }
00841 
00842 /*
00843 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00844 %                                                                             %
00845 %                                                                             %
00846 %                                                                             %
00847 +  G e t T h r e s h o l d M a p F i l e                                      %
00848 %                                                                             %
00849 %                                                                             %
00850 %                                                                             %
00851 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00852 %
00853 %  GetThresholdMapFile() look for a given threshold map name or alias in the
00854 %  given XML file data, and return the allocated the map when found.
00855 %
00856 %  The format of the ListThresholdMaps method is:
00857 %
00858 %      ThresholdMap *GetThresholdMap(const char *xml,const char *filename,
00859 %         const char *map_id,ExceptionInfo *exception)
00860 %
00861 %  A description of each parameter follows.
00862 %
00863 %    o xml:  The threshold map list in XML format.
00864 %
00865 %    o filename:  The threshold map XML filename.
00866 %
00867 %    o map_id:  ID of the map to look for in XML list.
00868 %
00869 %    o exception: return any errors or warnings in this structure.
00870 %
00871 */
00872 MagickExport ThresholdMap *GetThresholdMapFile(const char *xml,
00873   const char *filename,const char *map_id,ExceptionInfo *exception)
00874 {
00875   const char
00876     *attr,
00877     *content;
00878 
00879   double
00880     value;
00881 
00882  ThresholdMap
00883      *map;
00884 
00885   XMLTreeInfo
00886      *description,
00887      *levels,
00888      *threshold,
00889      *thresholds;
00890 
00891   map = (ThresholdMap *)NULL;
00892   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
00893     "Loading threshold map file \"%s\" ...",filename);
00894   thresholds=NewXMLTree(xml,exception);
00895   if ( thresholds == (XMLTreeInfo *)NULL )
00896     return(map);
00897 
00898   for( threshold = GetXMLTreeChild(thresholds,"threshold");
00899        threshold != (XMLTreeInfo *)NULL;
00900        threshold = GetNextXMLTreeTag(threshold) ) {
00901     attr = GetXMLTreeAttribute(threshold, "map");
00902     if ( (attr != (char *)NULL) && (LocaleCompare(map_id,attr) == 0) )
00903       break;
00904     attr = GetXMLTreeAttribute(threshold, "alias");
00905     if ( (attr != (char *)NULL) && (LocaleCompare(map_id,attr) == 0) )
00906       break;
00907   }
00908   if ( threshold == (XMLTreeInfo *)NULL ) {
00909     return(map);
00910   }
00911   description = GetXMLTreeChild(threshold,"description");
00912   if ( description == (XMLTreeInfo *)NULL ) {
00913     (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00914       "XmlMissingElement", "<description>, map \"%s\"", map_id);
00915     thresholds = DestroyXMLTree(thresholds);
00916     return(map);
00917   }
00918   levels = GetXMLTreeChild(threshold,"levels");
00919   if ( levels == (XMLTreeInfo *)NULL ) {
00920     (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00921       "XmlMissingElement", "<levels>, map \"%s\"", map_id);
00922     thresholds = DestroyXMLTree(thresholds);
00923     return(map);
00924   }
00925 
00926   /* The map has been found -- Allocate a Threshold Map to return */
00927   map = (ThresholdMap *)AcquireMagickMemory(sizeof(ThresholdMap));
00928   if ( map == (ThresholdMap *)NULL )
00929     ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireThresholdMap");
00930   map->map_id = (char *)NULL;
00931   map->description = (char *)NULL;
00932   map->levels = (long *) NULL;
00933 
00934   /* Assign Basic Attributes */
00935   attr = GetXMLTreeAttribute(threshold, "map");
00936   if ( attr != (char *)NULL )
00937     map->map_id = ConstantString(attr);
00938 
00939   content = GetXMLTreeContent(description);
00940   if ( content != (char *)NULL )
00941     map->description = ConstantString(content);
00942 
00943   attr = GetXMLTreeAttribute(levels, "width");
00944   if ( attr == (char *)NULL ) {
00945     (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00946       "XmlMissingAttribute", "<levels width>, map \"%s\"", map_id);
00947     thresholds = DestroyXMLTree(thresholds);
00948     map = DestroyThresholdMap(map);
00949     return(map);
00950   }
00951   map->width = (unsigned long) atoi(attr);
00952   if ( map->width == 0 ) {
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 
00960   attr = GetXMLTreeAttribute(levels, "height");
00961   if ( attr == (char *)NULL ) {
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 = (unsigned long) atoi(attr);
00969   if ( map->height == 0 ) {
00970     (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00971       "XmlInvalidAttribute", "<levels height>, map \"%s\"", map_id);
00972     thresholds = DestroyXMLTree(thresholds);
00973     map = DestroyThresholdMap(map);
00974     return(map);
00975   }
00976 
00977   attr = GetXMLTreeAttribute(levels, "divisor");
00978   if ( attr == (char *)NULL ) {
00979     (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00980       "XmlMissingAttribute", "<levels divisor>, map \"%s\"", map_id);
00981     thresholds = DestroyXMLTree(thresholds);
00982     map = DestroyThresholdMap(map);
00983     return(map);
00984   }
00985   map->divisor = atoi(attr);
00986   if ( map->divisor < 2 ) {
00987     (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00988       "XmlInvalidAttribute", "<levels divisor>, map \"%s\"", map_id);
00989     thresholds = DestroyXMLTree(thresholds);
00990     map = DestroyThresholdMap(map);
00991     return(map);
00992   }
00993 
00994   /* Allocate theshold levels array */
00995   content = GetXMLTreeContent(levels);
00996   if ( content == (char *)NULL ) {
00997     (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
00998       "XmlMissingContent", "<levels>, map \"%s\"", map_id);
00999     thresholds = DestroyXMLTree(thresholds);
01000     map = DestroyThresholdMap(map);
01001     return(map);
01002   }
01003   map->levels=(long *) AcquireQuantumMemory((size_t) map->width,map->height*
01004     sizeof(*map->levels));
01005   if ( map->levels == (long *)NULL )
01006     ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireThresholdMap");
01007   { /* parse levels into integer array */
01008     int i;
01009     char *p;
01010     for( i=0; i< (long) (map->width*map->height); i++) {
01011       map->levels[i] = (int)strtol(content, &p, 10);
01012       if ( p == content ) {
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         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01021           "XmlInvalidContent", "<level> %ld out of range, map \"%s\"",
01022           map->levels[i], map_id);
01023         thresholds = DestroyXMLTree(thresholds);
01024         map = DestroyThresholdMap(map);
01025         return(map);
01026       }
01027       content = p;
01028     }
01029     value=(double) strtol(content,&p,10);
01030     if (p != content)
01031       {
01032         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01033           "XmlInvalidContent", "<level> too many values, map \"%s\"", map_id);
01034        thresholds=DestroyXMLTree(thresholds);
01035        map=DestroyThresholdMap(map);
01036        return(map);
01037      }
01038   }
01039 
01040   thresholds = DestroyXMLTree(thresholds);
01041   return(map);
01042 }
01043 
01044 /*
01045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01046 %                                                                             %
01047 %                                                                             %
01048 %                                                                             %
01049 %  G e t T h r e s h o l d M a p                                              %
01050 %                                                                             %
01051 %                                                                             %
01052 %                                                                             %
01053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01054 %
01055 %  GetThresholdMap() load and search one or more threshold map files for the
01056 %  a map matching the given name or aliase.
01057 %
01058 %  The format of the GetThresholdMap method is:
01059 %
01060 %      ThresholdMap *GetThresholdMap(const char *map_id,
01061 %         ExceptionInfo *exception)
01062 %
01063 %  A description of each parameter follows.
01064 %
01065 %    o map_id:  ID of the map to look for.
01066 %
01067 %    o exception: return any errors or warnings in this structure.
01068 %
01069 */
01070 MagickExport ThresholdMap *GetThresholdMap(const char *map_id,
01071   ExceptionInfo *exception)
01072 {
01073   const StringInfo
01074     *option;
01075 
01076   LinkedListInfo
01077     *options;
01078 
01079   ThresholdMap
01080     *map;
01081 
01082   map=(ThresholdMap *)NULL;
01083   options=GetConfigureOptions(ThresholdsFilename,exception);
01084   while (( option=(const StringInfo *) GetNextValueInLinkedList(options) )
01085           != (const StringInfo *) NULL && map == (ThresholdMap *)NULL )
01086     map=GetThresholdMapFile((const char *) GetStringInfoDatum(option),
01087       GetStringInfoPath(option),map_id,exception);
01088   options=DestroyConfigureOptions(options);
01089   return(map);
01090 }
01091 
01092 /*
01093 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01094 %                                                                             %
01095 %                                                                             %
01096 %                                                                             %
01097 +  L i s t T h r e s h o l d M a p F i l e                                    %
01098 %                                                                             %
01099 %                                                                             %
01100 %                                                                             %
01101 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01102 %
01103 %  ListThresholdMapFile() lists the threshold maps and their descriptions
01104 %  in the given XML file data.
01105 %
01106 %  The format of the ListThresholdMaps method is:
01107 %
01108 %      MagickBooleanType ListThresholdMaps(FILE *file,const char*xml,
01109 %         const char *filename,ExceptionInfo *exception)
01110 %
01111 %  A description of each parameter follows.
01112 %
01113 %    o file:  An pointer to the output FILE.
01114 %
01115 %    o xml:  The threshold map list in XML format.
01116 %
01117 %    o filename:  The threshold map XML filename.
01118 %
01119 %    o exception: return any errors or warnings in this structure.
01120 %
01121 */
01122 MagickBooleanType ListThresholdMapFile(FILE *file,const char *xml,
01123   const char *filename,ExceptionInfo *exception)
01124 {
01125   XMLTreeInfo *thresholds,*threshold,*description;
01126   const char *map,*alias,*content;
01127 
01128   assert( xml != (char *)NULL );
01129   assert( file != (FILE *)NULL );
01130 
01131   (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
01132     "Loading threshold map file \"%s\" ...",filename);
01133   thresholds=NewXMLTree(xml,exception);
01134   if ( thresholds == (XMLTreeInfo *)NULL )
01135     return(MagickFalse);
01136 
01137   (void) fprintf(file,"%-16s %-12s %s\n", "Map", "Alias", "Description");
01138   (void) fprintf(file,"----------------------------------------------------\n");
01139 
01140   for( threshold = GetXMLTreeChild(thresholds,"threshold");
01141        threshold != (XMLTreeInfo *)NULL;
01142        threshold = GetNextXMLTreeTag(threshold) )
01143   {
01144     map = GetXMLTreeAttribute(threshold, "map");
01145     if (map == (char *) NULL) {
01146       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01147         "XmlMissingAttribute", "<map>");
01148       thresholds=DestroyXMLTree(thresholds);
01149       return(MagickFalse);
01150     }
01151     alias = GetXMLTreeAttribute(threshold, "alias");
01152     /* alias is optional, no if test needed */
01153     description=GetXMLTreeChild(threshold,"description");
01154     if ( description == (XMLTreeInfo *)NULL ) {
01155       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01156         "XmlMissingElement", "<description>, map \"%s\"", map);
01157       thresholds=DestroyXMLTree(thresholds);
01158       return(MagickFalse);
01159     }
01160     content=GetXMLTreeContent(description);
01161     if ( content == (char *)NULL ) {
01162       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01163         "XmlMissingContent", "<description>, map \"%s\"", map);
01164       thresholds=DestroyXMLTree(thresholds);
01165       return(MagickFalse);
01166     }
01167     (void) fprintf(file,"%-16s %-12s %s\n",map,alias ? alias : "", content);
01168   }
01169   thresholds=DestroyXMLTree(thresholds);
01170   return(MagickTrue);
01171 }
01172 
01173 /*
01174 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01175 %                                                                             %
01176 %                                                                             %
01177 %                                                                             %
01178 %  L i s t T h r e s h o l d M a p s                                          %
01179 %                                                                             %
01180 %                                                                             %
01181 %                                                                             %
01182 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01183 %
01184 %  ListThresholdMaps() lists the threshold maps and their descriptions
01185 %  as defined by "threshold.xml" to a file.
01186 %
01187 %  The format of the ListThresholdMaps method is:
01188 %
01189 %      MagickBooleanType ListThresholdMaps(FILE *file,ExceptionInfo *exception)
01190 %
01191 %  A description of each parameter follows.
01192 %
01193 %    o file:  An pointer to the output FILE.
01194 %
01195 %    o exception: return any errors or warnings in this structure.
01196 %
01197 */
01198 MagickExport MagickBooleanType ListThresholdMaps(FILE *file,
01199   ExceptionInfo *exception)
01200 {
01201   const StringInfo
01202     *option;
01203 
01204   LinkedListInfo
01205     *options;
01206 
01207   MagickStatusType
01208     status;
01209 
01210   status=MagickFalse;
01211   if ( file == (FILE *)NULL )
01212     file = stdout;
01213   options=GetConfigureOptions(ThresholdsFilename,exception);
01214 
01215   (void) fprintf(file, "\n   Threshold Maps for Ordered Dither Operations\n");
01216 
01217   while ( ( option=(const StringInfo *) GetNextValueInLinkedList(options) )
01218           != (const StringInfo *) NULL)
01219   {
01220     (void) fprintf(file,"\nPATH: %s\n\n",GetStringInfoPath(option));
01221     status|=ListThresholdMapFile(file,(const char *) GetStringInfoDatum(option),
01222       GetStringInfoPath(option),exception);
01223   }
01224   options=DestroyConfigureOptions(options);
01225   return(status != 0 ? MagickTrue : MagickFalse);
01226 }
01227 
01228 /*
01229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01230 %                                                                             %
01231 %                                                                             %
01232 %                                                                             %
01233 %   O r d e r e d D i t h e r I m a g e                                       %
01234 %                                                                             %
01235 %                                                                             %
01236 %                                                                             %
01237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01238 %
01239 %  OrderedDitherImage() uses the ordered dithering technique of reducing color
01240 %  images to monochrome using positional information to retain as much
01241 %  information as possible.
01242 %
01243 %  WARNING: This function is deprecated, and is now just a call to
01244 %  the more more powerful OrderedPosterizeImage(); function.
01245 %
01246 %  The format of the OrderedDitherImage method is:
01247 %
01248 %      MagickBooleanType OrderedDitherImage(Image *image)
01249 %      MagickBooleanType OrderedDitherImageChannel(Image *image,
01250 %        const ChannelType channel,ExceptionInfo *exception)
01251 %
01252 %  A description of each parameter follows:
01253 %
01254 %    o image: the image.
01255 %
01256 %    o channel: the channel or channels to be thresholded.
01257 %
01258 %    o exception: return any errors or warnings in this structure.
01259 %
01260 */
01261 
01262 MagickExport MagickBooleanType OrderedDitherImage(Image *image)
01263 {
01264   MagickBooleanType
01265     status;
01266 
01267   status=OrderedDitherImageChannel(image,DefaultChannels,&image->exception);
01268   return(status);
01269 }
01270 
01271 MagickExport MagickBooleanType OrderedDitherImageChannel(Image *image,
01272  const ChannelType channel,ExceptionInfo *exception)
01273 {
01274   MagickBooleanType
01275     status;
01276 
01277   /*
01278     Call the augumented function OrderedPosterizeImage()
01279   */
01280   status=OrderedPosterizeImageChannel(image,channel,"o8x8",exception);
01281   return(status);
01282 }
01283 
01284 /*
01285 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01286 %                                                                             %
01287 %                                                                             %
01288 %                                                                             %
01289 %     O r d e r e d P o s t e r i z e I m a g e                               %
01290 %                                                                             %
01291 %                                                                             %
01292 %                                                                             %
01293 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01294 %
01295 %  OrderedPosterizeImage() will perform a ordered dither based on a number
01296 %  of pre-defined dithering threshold maps, but over multiple intensity
01297 %  levels, which can be different for different channels, according to the
01298 %  input argument.
01299 %
01300 %  The format of the OrderedPosterizeImage method is:
01301 %
01302 %      MagickBooleanType OrderedPosterizeImage(Image *image,
01303 %        const char *threshold_map,ExceptionInfo *exception)
01304 %      MagickBooleanType OrderedPosterizeImageChannel(Image *image,
01305 %        const ChannelType channel,const char *threshold_map,
01306 %        ExceptionInfo *exception)
01307 %
01308 %  A description of each parameter follows:
01309 %
01310 %    o image: the image.
01311 %
01312 %    o channel: the channel or channels to be thresholded.
01313 %
01314 %    o threshold_map: A string containing the name of the threshold dither
01315 %      map to use, followed by zero or more numbers representing the number
01316 %      of color levels tho dither between.
01317 %
01318 %      Any level number less than 2 will be equivelent to 2, and means only
01319 %      binary dithering will be applied to each color channel.
01320 %
01321 %      No numbers also means a 2 level (bitmap) dither will be applied to all
01322 %      channels, while a single number is the number of levels applied to each
01323 %      channel in sequence.  More numbers will be applied in turn to each of
01324 %      the color channels.
01325 %
01326 %      For example: "o3x3,6" will generate a 6 level posterization of the
01327 %      image with a ordered 3x3 diffused pixel dither being applied between
01328 %      each level. While checker,8,8,4 will produce a 332 colormaped image
01329 %      with only a single checkerboard hash pattern (50% grey) between each
01330 %      color level, to basically double the number of color levels with
01331 %      a bare minimim of dithering.
01332 %
01333 %    o exception: return any errors or warnings in this structure.
01334 %
01335 */
01336 MagickExport MagickBooleanType OrderedPosterizeImage(Image *image,
01337   const char *threshold_map,ExceptionInfo *exception)
01338 {
01339   MagickBooleanType
01340     status;
01341 
01342   status=OrderedPosterizeImageChannel(image,DefaultChannels,threshold_map,
01343     exception);
01344   return(status);
01345 }
01346 
01347 MagickExport MagickBooleanType OrderedPosterizeImageChannel(Image *image,
01348   const ChannelType channel,const char *threshold_map,ExceptionInfo *exception)
01349 {
01350 #define DitherImageTag  "Dither/Image"
01351 
01352   long
01353     progress,
01354     y;
01355 
01356   LongPixelPacket
01357     levels;
01358 
01359   MagickBooleanType
01360     status;
01361 
01362   ThresholdMap
01363     *map;
01364 
01365   CacheView
01366     *image_view;
01367 
01368   assert(image != (Image *) NULL);
01369   assert(image->signature == MagickSignature);
01370   if (image->debug != MagickFalse)
01371     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01372   assert(exception != (ExceptionInfo *) NULL);
01373   assert(exception->signature == MagickSignature);
01374   if (threshold_map == (const char *) NULL)
01375     return(MagickTrue);
01376   {
01377     char
01378       token[MaxTextExtent];
01379 
01380     register const char
01381       *p;
01382 
01383     p=(char *)threshold_map;
01384     while (((isspace((int) ((unsigned char) *p)) != 0) || (*p == ',')) &&
01385                     (*p != '\0'))
01386       p++;
01387     threshold_map=p;
01388     while (((isspace((int) ((unsigned char) *p)) == 0) && (*p != ',')) &&
01389                     (*p != '\0')) {
01390       if ((p-threshold_map) >= MaxTextExtent)
01391         break;
01392       token[p-threshold_map] = *p;
01393       p++;
01394     }
01395     token[p-threshold_map] = '\0';
01396     map = GetThresholdMap(token, exception);
01397     if ( map == (ThresholdMap *)NULL ) {
01398       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
01399         "InvalidArgument","%s : '%s'","ordered-dither",threshold_map);
01400       return(MagickFalse);
01401     }
01402   }
01403   /* Set channel levels from extra comma seperated arguments
01404      Default to 2, the single value given, or individual channel values
01405   */
01406 #if 1
01407   { /* parse directly as a comma seperated list of integers */
01408     char *p;
01409 
01410     p = strchr((char *) threshold_map,',');
01411     if ( p != (char *)NULL && isdigit((int) ((unsigned char) *(++p))) )
01412       levels.index = (unsigned long) strtol(p, &p, 10);
01413     else
01414       levels.index = 2;
01415 
01416     levels.red     = ((channel & RedChannel  )   != 0) ? levels.index : 0;
01417     levels.green   = ((channel & GreenChannel)   != 0) ? levels.index : 0;
01418     levels.blue    = ((channel & BlueChannel)    != 0) ? levels.index : 0;
01419     levels.opacity = ((channel & OpacityChannel) != 0) ? levels.index : 0;
01420     levels.index   = ((channel & IndexChannel)   != 0
01421             && (image->colorspace == CMYKColorspace)) ? levels.index : 0;
01422 
01423     /* if more than a single number, each channel has a separate value */
01424     if ( p != (char *) NULL && *p == ',' ) {
01425       p=strchr((char *) threshold_map,',');
01426       p++;
01427       if ((channel & RedChannel) != 0)
01428         levels.red = (unsigned long) strtol(p, &p, 10),   (void)(*p == ',' && p++);
01429       if ((channel & GreenChannel) != 0)
01430         levels.green = (unsigned long) strtol(p, &p, 10), (void)(*p == ',' && p++);
01431       if ((channel & BlueChannel) != 0)
01432         levels.blue = (unsigned long) strtol(p, &p, 10),  (void)(*p == ',' && p++);
01433       if ((channel & IndexChannel) != 0 && image->colorspace == CMYKColorspace)
01434         levels.index=(unsigned long) strtol(p, &p, 10), (void)(*p == ',' && p++);
01435       if ((channel & OpacityChannel) != 0)
01436         levels.opacity = (unsigned long) strtol(p, &p, 10), (void)(*p == ',' && p++);
01437     }
01438   }
01439 #else
01440   /* Parse level values as a geometry */
01441   /* This difficult!
01442    * How to map   GeometryInfo structure elements into
01443    * LongPixelPacket structure elements, but according to channel?
01444    * Note the channels list may skip elements!!!!
01445    * EG  -channel BA  -ordered-dither map,2,3
01446    * will need to map  g.rho -> l.blue, and g.sigma -> l.opacity
01447    * A simpler way is needed, probably converting geometry to a temporary
01448    * array, then using channel to advance the index into long pixel packet.
01449    */
01450 #endif
01451 
01452 #if 0
01453 printf("DEBUG levels  r=%ld g=%ld b=%ld a=%ld i=%ld\n",
01454      levels.red, levels.green, levels.blue, levels.opacity, levels.index);
01455 #endif
01456 
01457   { /* Do the posterized ordered dithering of the image */
01458     int
01459       d;
01460 
01461     /* d = number of psuedo-level divisions added between color levels */
01462     d = map->divisor-1;
01463 
01464     /* reduce levels to levels - 1 */
01465     levels.red     = levels.red     ? levels.red-1     : 0;
01466     levels.green   = levels.green   ? levels.green-1   : 0;
01467     levels.blue    = levels.blue    ? levels.blue-1    : 0;
01468     levels.opacity = levels.opacity ? levels.opacity-1 : 0;
01469     levels.index   = levels.index   ? levels.index-1   : 0;
01470 
01471     if (SetImageStorageClass(image,DirectClass) == MagickFalse)
01472       {
01473         InheritException(exception,&image->exception);
01474         return(MagickFalse);
01475       }
01476     status=MagickTrue;
01477     progress=0;
01478     image_view=AcquireCacheView(image);
01479 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01480   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
01481 #endif
01482     for (y=0; y < (long) image->rows; y++)
01483     {
01484       register IndexPacket
01485         *__restrict indexes;
01486 
01487       register long
01488         x;
01489 
01490       register PixelPacket
01491         *__restrict q;
01492 
01493       if (status == MagickFalse)
01494         continue;
01495       q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
01496       if (q == (PixelPacket *) NULL)
01497         {
01498           status=MagickFalse;
01499           continue;
01500         }
01501       indexes=GetCacheViewAuthenticIndexQueue(image_view);
01502       for (x=0; x < (long) image->columns; x++)
01503       {
01504         register int
01505           threshold,
01506           t,
01507           l;
01508 
01509         /*
01510           Figure out the dither threshold for this pixel
01511           This must be a integer from 1 to map->divisor-1
01512         */
01513         threshold = map->levels[(x%map->width) +map->width*(y%map->height)];
01514 
01515         /* Dither each channel in the image as appropriate
01516           Notes on the integer Math...
01517               total number of divisions = (levels-1)*(divisor-1)+1)
01518               t1 = this colors psuedo_level =
01519                       q->red * total_divisions / (QuantumRange+1)
01520               l = posterization level       0..levels
01521               t = dither threshold level    0..divisor-1  NB: 0 only on last
01522               Each color_level is of size   QuantumRange / (levels-1)
01523               NB: All input levels and divisor are already had 1 subtracted
01524               Opacity is inverted so 'off' represents transparent.
01525         */
01526         if (levels.red) {
01527           t = (int) (QuantumScale*q->red*(levels.red*d+1));
01528           l = t/d;  t = t-l*d;
01529           q->red=(Quantum) ((l+(t >= threshold))*QuantumRange/levels.red);
01530         }
01531         if (levels.green) {
01532           t = (int) (QuantumScale*q->green*(levels.green*d+1));
01533           l = t/d;  t = t-l*d;
01534           q->green=(Quantum) ((l+(t >= threshold))*QuantumRange/levels.green);
01535         }
01536         if (levels.blue) {
01537           t = (int) (QuantumScale*q->blue*(levels.blue*d+1));
01538           l = t/d;  t = t-l*d;
01539           q->blue=(Quantum) ((l+(t >= threshold))*QuantumRange/levels.blue);
01540         }
01541         if (levels.opacity) {
01542           t = (int) ((1.0-QuantumScale*q->opacity)*(levels.opacity*d+1));
01543           l = t/d;  t = t-l*d;
01544           q->opacity=(Quantum) ((1.0-l-(t >= threshold))*QuantumRange/
01545             levels.opacity);
01546         }
01547         if (levels.index) {
01548           t = (int) (QuantumScale*indexes[x]*(levels.index*d+1));
01549           l = t/d;  t = t-l*d;
01550           indexes[x]=(IndexPacket) ((l+(t>=threshold))*QuantumRange/
01551             levels.index);
01552         }
01553         q++;
01554       }
01555       if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
01556         status=MagickFalse;
01557       if (image->progress_monitor != (MagickProgressMonitor) NULL)
01558         {
01559           MagickBooleanType
01560             proceed;
01561 
01562 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01563   #pragma omp critical (MagickCore_OrderedPosterizeImageChannel)
01564 #endif
01565           proceed=SetImageProgress(image,DitherImageTag,progress++,image->rows);
01566           if (proceed == MagickFalse)
01567             status=MagickFalse;
01568         }
01569     }
01570     image_view=DestroyCacheView(image_view);
01571   }
01572   map=DestroyThresholdMap(map);
01573   return(MagickTrue);
01574 }
01575 
01576 /*
01577 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01578 %                                                                             %
01579 %                                                                             %
01580 %                                                                             %
01581 %     R a n d o m T h r e s h o l d I m a g e                                 %
01582 %                                                                             %
01583 %                                                                             %
01584 %                                                                             %
01585 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01586 %
01587 %  RandomThresholdImage() changes the value of individual pixels based on the
01588 %  intensity of each pixel compared to a random threshold.  The result is a
01589 %  low-contrast, two color image.
01590 %
01591 %  The format of the RandomThresholdImage method is:
01592 %
01593 %      MagickBooleanType RandomThresholdImageChannel(Image *image,
01594 %        const char *thresholds,ExceptionInfo *exception)
01595 %      MagickBooleanType RandomThresholdImageChannel(Image *image,
01596 %        const ChannelType channel,const char *thresholds,
01597 %        ExceptionInfo *exception)
01598 %
01599 %  A description of each parameter follows:
01600 %
01601 %    o image: the image.
01602 %
01603 %    o channel: the channel or channels to be thresholded.
01604 %
01605 %    o thresholds: a geometry string containing low,high thresholds.  If the
01606 %      string contains 2x2, 3x3, or 4x4, an ordered dither of order 2, 3, or 4
01607 %      is performed instead.
01608 %
01609 %    o exception: return any errors or warnings in this structure.
01610 %
01611 */
01612 
01613 MagickExport MagickBooleanType RandomThresholdImage(Image *image,
01614   const char *thresholds,ExceptionInfo *exception)
01615 {
01616   MagickBooleanType
01617     status;
01618 
01619   status=RandomThresholdImageChannel(image,DefaultChannels,thresholds,
01620     exception);
01621   return(status);
01622 }
01623 
01624 MagickExport MagickBooleanType RandomThresholdImageChannel(Image *image,
01625   const ChannelType channel,const char *thresholds,ExceptionInfo *exception)
01626 {
01627 #define ThresholdImageTag  "Threshold/Image"
01628 
01629   GeometryInfo
01630     geometry_info;
01631 
01632   MagickStatusType
01633     flags;
01634 
01635   long
01636     progress,
01637     y;
01638 
01639   MagickBooleanType
01640     status;
01641 
01642   MagickPixelPacket
01643     threshold;
01644 
01645   MagickRealType
01646     min_threshold,
01647     max_threshold;
01648 
01649   RandomInfo
01650     **random_info;
01651 
01652   CacheView
01653     *image_view;
01654 
01655   assert(image != (Image *) NULL);
01656   assert(image->signature == MagickSignature);
01657   if (image->debug != MagickFalse)
01658     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01659   assert(exception != (ExceptionInfo *) NULL);
01660   assert(exception->signature == MagickSignature);
01661   if (thresholds == (const char *) NULL)
01662     return(MagickTrue);
01663   GetMagickPixelPacket(image,&threshold);
01664   min_threshold=0.0;
01665   max_threshold=(MagickRealType) QuantumRange;
01666   flags=ParseGeometry(thresholds,&geometry_info);
01667   min_threshold=geometry_info.rho;
01668   max_threshold=geometry_info.sigma;
01669   if ((flags & SigmaValue) == 0)
01670     max_threshold=min_threshold;
01671   if (strchr(thresholds,'%') != (char *) NULL)
01672     {
01673       max_threshold*=(MagickRealType) (0.01*QuantumRange);
01674       min_threshold*=(MagickRealType) (0.01*QuantumRange);
01675     }
01676   else
01677     if (((max_threshold == min_threshold) || (max_threshold == 1)) &&
01678         (min_threshold <= 8))
01679       {
01680         /*
01681           Backward Compatibility -- ordered-dither -- IM v 6.2.9-6.
01682         */
01683         status=OrderedPosterizeImageChannel(image,channel,thresholds,exception);
01684         return(status);
01685       }
01686   /*
01687     Random threshold image.
01688   */
01689   status=MagickTrue;
01690   progress=0;
01691   if (channel == AllChannels)
01692     {
01693       if (AcquireImageColormap(image,2) == MagickFalse)
01694         ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
01695           image->filename);
01696       random_info=AcquireRandomInfoThreadSet();
01697       image_view=AcquireCacheView(image);
01698 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01699   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
01700 #endif
01701       for (y=0; y < (long) image->rows; y++)
01702       {
01703         MagickBooleanType
01704           sync;
01705 
01706         register IndexPacket
01707           *__restrict indexes;
01708 
01709         register long
01710           id,
01711           x;
01712 
01713         register PixelPacket
01714           *__restrict q;
01715 
01716         if (status == MagickFalse)
01717           continue;
01718         q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
01719           exception);
01720         if (q == (PixelPacket *) NULL)
01721           {
01722             status=MagickFalse;
01723             continue;
01724           }
01725         indexes=GetCacheViewAuthenticIndexQueue(image_view);
01726         id=GetOpenMPThreadId();
01727         for (x=0; x < (long) image->columns; x++)
01728         {
01729           IndexPacket
01730             index;
01731 
01732           MagickRealType
01733             intensity;
01734 
01735           intensity=(MagickRealType) PixelIntensityToQuantum(q);
01736           if (intensity < min_threshold)
01737             threshold.index=min_threshold;
01738           else if (intensity > max_threshold)
01739             threshold.index=max_threshold;
01740           else
01741             threshold.index=(MagickRealType)(QuantumRange*
01742               GetPseudoRandomValue(random_info[id]));
01743           index=(IndexPacket) (intensity <= threshold.index ? 0 : 1);
01744           indexes[x]=index;
01745           *q++=image->colormap[(long) index];
01746         }
01747         sync=SyncCacheViewAuthenticPixels(image_view,exception);
01748         if (sync == MagickFalse)
01749           status=MagickFalse;
01750         if (image->progress_monitor != (MagickProgressMonitor) NULL)
01751           {
01752             MagickBooleanType
01753               proceed;
01754 
01755 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01756   #pragma omp critical (MagickCore_RandomThresholdImageChannel)
01757 #endif
01758             proceed=SetImageProgress(image,ThresholdImageTag,progress++,
01759               image->rows);
01760             if (proceed == MagickFalse)
01761               status=MagickFalse;
01762           }
01763       }
01764       image_view=DestroyCacheView(image_view);
01765       random_info=DestroyRandomInfoThreadSet(random_info);
01766       return(status);
01767     }
01768   if (SetImageStorageClass(image,DirectClass) == MagickFalse)
01769     {
01770       InheritException(exception,&image->exception);
01771       return(MagickFalse);
01772     }
01773   random_info=AcquireRandomInfoThreadSet();
01774   image_view=AcquireCacheView(image);
01775 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01776   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
01777 #endif
01778   for (y=0; y < (long) image->rows; y++)
01779   {
01780     register IndexPacket
01781       *__restrict indexes;
01782 
01783     register long
01784       id,
01785       x;
01786 
01787     register PixelPacket
01788       *__restrict q;
01789 
01790     if (status == MagickFalse)
01791       continue;
01792     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
01793     if (q == (PixelPacket *) NULL)
01794       {
01795         status=MagickFalse;
01796         continue;
01797       }
01798     indexes=GetCacheViewAuthenticIndexQueue(image_view);
01799     id=GetOpenMPThreadId();
01800     for (x=0; x < (long) image->columns; x++)
01801     {
01802       if ((channel & RedChannel) != 0)
01803         {
01804           if ((MagickRealType) q->red < min_threshold)
01805             threshold.red=min_threshold;
01806           else
01807             if ((MagickRealType) q->red > max_threshold)
01808               threshold.red=max_threshold;
01809             else
01810               threshold.red=(MagickRealType) (QuantumRange*
01811                 GetPseudoRandomValue(random_info[id]));
01812         }
01813       if ((channel & GreenChannel) != 0)
01814         {
01815           if ((MagickRealType) q->green < min_threshold)
01816             threshold.green=min_threshold;
01817           else
01818             if ((MagickRealType) q->green > max_threshold)
01819               threshold.green=max_threshold;
01820             else
01821               threshold.green=(MagickRealType) (QuantumRange*
01822                 GetPseudoRandomValue(random_info[id]));
01823         }
01824       if ((channel & BlueChannel) != 0)
01825         {
01826           if ((MagickRealType) q->blue < min_threshold)
01827             threshold.blue=min_threshold;
01828           else
01829             if ((MagickRealType) q->blue > max_threshold)
01830               threshold.blue=max_threshold;
01831             else
01832               threshold.blue=(MagickRealType) (QuantumRange*
01833                 GetPseudoRandomValue(random_info[id]));
01834         }
01835       if ((channel & OpacityChannel) != 0)
01836         {
01837           if ((MagickRealType) q->opacity < min_threshold)
01838             threshold.opacity=min_threshold;
01839           else
01840             if ((MagickRealType) q->opacity > max_threshold)
01841               threshold.opacity=max_threshold;
01842             else
01843               threshold.opacity=(MagickRealType) (QuantumRange*
01844                 GetPseudoRandomValue(random_info[id]));
01845         }
01846       if (((channel & IndexChannel) != 0) &&
01847           (image->colorspace == CMYKColorspace))
01848         {
01849           if ((MagickRealType) indexes[x] < min_threshold)
01850             threshold.index=min_threshold;
01851           else
01852             if ((MagickRealType) indexes[x] > max_threshold)
01853               threshold.index=max_threshold;
01854             else
01855               threshold.index=(MagickRealType) (QuantumRange*
01856                 GetPseudoRandomValue(random_info[id]));
01857         }
01858       if ((channel & RedChannel) != 0)
01859         q->red=(Quantum) ((MagickRealType) q->red <= threshold.red ? 0 :
01860           QuantumRange);
01861       if ((channel & GreenChannel) != 0)
01862         q->green=(Quantum) ((MagickRealType) q->green <= threshold.green ? 0 :
01863           QuantumRange);
01864       if ((channel & BlueChannel) != 0)
01865         q->blue=(Quantum) ((MagickRealType) q->blue <= threshold.blue ? 0 :
01866           QuantumRange);
01867       if ((channel & OpacityChannel) != 0)
01868         q->opacity=(Quantum) ((MagickRealType) q->opacity <= threshold.opacity ?
01869           0 : QuantumRange);
01870       if (((channel & IndexChannel) != 0) &&
01871           (image->colorspace == CMYKColorspace))
01872         indexes[x]=(IndexPacket) ((MagickRealType) indexes[x] <=
01873           threshold.index ? 0 : QuantumRange);
01874       q++;
01875     }
01876     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
01877       status=MagickFalse;
01878     if (image->progress_monitor != (MagickProgressMonitor) NULL)
01879       {
01880         MagickBooleanType
01881           proceed;
01882 
01883 #if defined(MAGICKCORE_OPENMP_SUPPORT)
01884   #pragma omp critical (MagickCore_RandomThresholdImageChannel)
01885 #endif
01886         proceed=SetImageProgress(image,ThresholdImageTag,progress++,
01887           image->rows);
01888         if (proceed == MagickFalse)
01889           status=MagickFalse;
01890       }
01891   }
01892   image_view=DestroyCacheView(image_view);
01893   random_info=DestroyRandomInfoThreadSet(random_info);
01894   return(status);
01895 }
01896 
01897 /*
01898 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01899 %                                                                             %
01900 %                                                                             %
01901 %                                                                             %
01902 %     W h i t e T h r e s h o l d I m a g e                                   %
01903 %                                                                             %
01904 %                                                                             %
01905 %                                                                             %
01906 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
01907 %
01908 %  WhiteThresholdImage() is like ThresholdImage() but forces all pixels above
01909 %  the threshold into white while leaving all pixels at or below the threshold
01910 %  unchanged.
01911 %
01912 %  The format of the WhiteThresholdImage method is:
01913 %
01914 %      MagickBooleanType WhiteThresholdImage(Image *image,const char *threshold)
01915 %      MagickBooleanType WhiteThresholdImageChannel(Image *image,
01916 %        const ChannelType channel,const char *threshold,
01917 %        ExceptionInfo *exception)
01918 %
01919 %  A description of each parameter follows:
01920 %
01921 %    o image: the image.
01922 %
01923 %    o channel: the channel or channels to be thresholded.
01924 %
01925 %    o threshold: Define the threshold value.
01926 %
01927 %    o exception: return any errors or warnings in this structure.
01928 %
01929 */
01930 MagickExport MagickBooleanType WhiteThresholdImage(Image *image,
01931   const char *threshold)
01932 {
01933   MagickBooleanType
01934     status;
01935 
01936   status=WhiteThresholdImageChannel(image,DefaultChannels,threshold,
01937     &image->exception);
01938   return(status);
01939 }
01940 
01941 MagickExport MagickBooleanType WhiteThresholdImageChannel(Image *image,
01942   const ChannelType channel,const char *thresholds,ExceptionInfo *exception)
01943 {
01944 #define ThresholdImageTag  "Threshold/Image"
01945 
01946   GeometryInfo
01947     geometry_info;
01948 
01949   long
01950     progress,
01951     y;
01952 
01953   MagickBooleanType
01954     status;
01955 
01956   MagickPixelPacket
01957     threshold;
01958 
01959   MagickStatusType
01960     flags;
01961 
01962   CacheView
01963     *image_view;
01964 
01965   assert(image != (Image *) NULL);
01966   assert(image->signature == MagickSignature);
01967   if (image->debug != MagickFalse)
01968     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
01969   if (thresholds == (const char *) NULL)
01970     return(MagickTrue);
01971   if (SetImageStorageClass(image,DirectClass) == MagickFalse)
01972     return(MagickFalse);
01973   flags=ParseGeometry(thresholds,&geometry_info);
01974   GetMagickPixelPacket(image,&threshold);
01975   threshold.red=geometry_info.rho;
01976   threshold.green=geometry_info.sigma;
01977   if ((flags & SigmaValue) == 0)
01978     threshold.green=threshold.red;
01979   threshold.blue=geometry_info.xi;
01980   if ((flags & XiValue) == 0)
01981     threshold.blue=threshold.red;
01982   threshold.opacity=geometry_info.psi;
01983   if ((flags & PsiValue) == 0)
01984     threshold.opacity=threshold.red;
01985   threshold.index=geometry_info.chi;
01986   if ((flags & ChiValue) == 0)
01987     threshold.index=threshold.red;
01988   if ((flags & PercentValue) != 0)
01989     {
01990       threshold.red*=(QuantumRange/100.0);
01991       threshold.green*=(QuantumRange/100.0);
01992       threshold.blue*=(QuantumRange/100.0);
01993       threshold.opacity*=(QuantumRange/100.0);
01994       threshold.index*=(QuantumRange/100.0);
01995     }
01996   /*
01997     White threshold image.
01998   */
01999   status=MagickTrue;
02000   progress=0;
02001   image_view=AcquireCacheView(image);
02002 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02003   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
02004 #endif
02005   for (y=0; y < (long) image->rows; y++)
02006   {
02007     register IndexPacket
02008       *__restrict indexes;
02009 
02010     register long
02011       x;
02012 
02013     register PixelPacket
02014       *__restrict q;
02015 
02016     if (status == MagickFalse)
02017       continue;
02018     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
02019     if (q == (PixelPacket *) NULL)
02020       {
02021         status=MagickFalse;
02022         continue;
02023       }
02024     indexes=GetCacheViewAuthenticIndexQueue(image_view);
02025     for (x=0; x < (long) image->columns; x++)
02026     {
02027       if (((channel & RedChannel) != 0) &&
02028           ((MagickRealType) q->red > threshold.red))
02029         q->red=(Quantum) QuantumRange;
02030       if (((channel & GreenChannel) != 0) &&
02031           ((MagickRealType) q->green > threshold.green))
02032         q->green=(Quantum) QuantumRange;
02033       if (((channel & BlueChannel) != 0) &&
02034           ((MagickRealType) q->blue > threshold.blue))
02035         q->blue=(Quantum) QuantumRange;
02036       if (((channel & OpacityChannel) != 0) &&
02037           ((MagickRealType) q->opacity > threshold.opacity))
02038         q->opacity=(Quantum) QuantumRange;
02039       if (((channel & IndexChannel) != 0) &&
02040           (image->colorspace == CMYKColorspace) &&
02041           ((MagickRealType) indexes[x] > threshold.index))
02042         indexes[x]=(Quantum) QuantumRange;
02043       q++;
02044     }
02045     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
02046       status=MagickFalse;
02047     if (image->progress_monitor != (MagickProgressMonitor) NULL)
02048       {
02049         MagickBooleanType
02050           proceed;
02051 
02052 #if defined(MAGICKCORE_OPENMP_SUPPORT)
02053   #pragma omp critical (MagickCore_WhiteThresholdImageChannel)
02054 #endif
02055         proceed=SetImageProgress(image,ThresholdImageTag,progress++,
02056           image->rows);
02057         if (proceed == MagickFalse)
02058           status=MagickFalse;
02059       }
02060   }
02061   image_view=DestroyCacheView(image_view);
02062   return(status);
02063 }

Generated on 19 Nov 2009 for MagickCore by  doxygen 1.6.1