2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6 % TTTTT H H RRRR EEEEE SSSSS H H OOO L DDDD %
7 % T H H R R E SS H H O O L D D %
8 % T HHHHH RRRR EEE SSS HHHHH O O L D D %
9 % T H H R R E SS H H O O L D D %
10 % T H H R R EEEEE SSSSS H H OOO LLLLL DDDD %
13 % MagickCore Image Threshold Methods %
20 % Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization %
21 % dedicated to making software imaging solutions freely available. %
23 % You may not use this file except in compliance with the License. You may %
24 % obtain a copy of the License at %
26 % http://www.imagemagick.org/script/license.php %
28 % Unless required by applicable law or agreed to in writing, software %
29 % distributed under the License is distributed on an "AS IS" BASIS, %
30 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31 % See the License for the specific language governing permissions and %
32 % limitations under the License. %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 #include "MagickCore/studio.h"
44 #include "MagickCore/property.h"
45 #include "MagickCore/blob.h"
46 #include "MagickCore/cache-view.h"
47 #include "MagickCore/color.h"
48 #include "MagickCore/color-private.h"
49 #include "MagickCore/colormap.h"
50 #include "MagickCore/colorspace.h"
51 #include "MagickCore/colorspace-private.h"
52 #include "MagickCore/configure.h"
53 #include "MagickCore/constitute.h"
54 #include "MagickCore/decorate.h"
55 #include "MagickCore/draw.h"
56 #include "MagickCore/enhance.h"
57 #include "MagickCore/exception.h"
58 #include "MagickCore/exception-private.h"
59 #include "MagickCore/effect.h"
60 #include "MagickCore/fx.h"
61 #include "MagickCore/gem.h"
62 #include "MagickCore/geometry.h"
63 #include "MagickCore/image-private.h"
64 #include "MagickCore/list.h"
65 #include "MagickCore/log.h"
66 #include "MagickCore/memory_.h"
67 #include "MagickCore/monitor.h"
68 #include "MagickCore/monitor-private.h"
69 #include "MagickCore/montage.h"
70 #include "MagickCore/option.h"
71 #include "MagickCore/pixel-accessor.h"
72 #include "MagickCore/quantize.h"
73 #include "MagickCore/quantum.h"
74 #include "MagickCore/random_.h"
75 #include "MagickCore/random-private.h"
76 #include "MagickCore/resize.h"
77 #include "MagickCore/resource_.h"
78 #include "MagickCore/segment.h"
79 #include "MagickCore/shear.h"
80 #include "MagickCore/signature-private.h"
81 #include "MagickCore/string_.h"
82 #include "MagickCore/string-private.h"
83 #include "MagickCore/thread-private.h"
84 #include "MagickCore/threshold.h"
85 #include "MagickCore/token.h"
86 #include "MagickCore/transform.h"
87 #include "MagickCore/xml-tree.h"
88 #include "MagickCore/xml-tree-private.h"
93 #define ThresholdsFilename "thresholds.xml"
114 Forward declarations.
117 *GetThresholdMapFile(const char *,const char *,const char *,ExceptionInfo *);
120 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
124 % A d a p t i v e T h r e s h o l d I m a g e %
128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130 % AdaptiveThresholdImage() selects an individual threshold for each pixel
131 % based on the range of intensity values in its local neighborhood. This
132 % allows for thresholding of an image whose global intensity histogram
133 % doesn't contain distinctive peaks.
135 % The format of the AdaptiveThresholdImage method is:
137 % Image *AdaptiveThresholdImage(const Image *image,const size_t width,
138 % const size_t height,const double bias,ExceptionInfo *exception)
140 % A description of each parameter follows:
142 % o image: the image.
144 % o width: the width of the local neighborhood.
146 % o height: the height of the local neighborhood.
148 % o bias: the mean bias.
150 % o exception: return any errors or warnings in this structure.
153 MagickExport Image *AdaptiveThresholdImage(const Image *image,
154 const size_t width,const size_t height,const double bias,
155 ExceptionInfo *exception)
157 #define AdaptiveThresholdImageTag "AdaptiveThreshold/Image"
179 Initialize threshold image attributes.
181 assert(image != (Image *) NULL);
182 assert(image->signature == MagickSignature);
183 if (image->debug != MagickFalse)
184 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
185 assert(exception != (ExceptionInfo *) NULL);
186 assert(exception->signature == MagickSignature);
187 if ((width % 2) == 0)
188 ThrowImageException(OptionError,"KernelWidthMustBeAnOddNumber");
189 threshold_image=CloneImage(image,image->columns,image->rows,MagickTrue,
191 if (threshold_image == (Image *) NULL)
192 return((Image *) NULL);
193 status=SetImageStorageClass(threshold_image,DirectClass,exception);
194 if (status == MagickFalse)
196 threshold_image=DestroyImage(threshold_image);
197 return((Image *) NULL);
204 number_pixels=(MagickSizeType) width*height;
205 image_view=AcquireVirtualCacheView(image,exception);
206 threshold_view=AcquireAuthenticCacheView(threshold_image,exception);
207 #if defined(MAGICKCORE_OPENMP_SUPPORT)
208 #pragma omp parallel for schedule(static,4) shared(progress,status) \
209 dynamic_number_threads(image->columns,image->rows,1)
211 for (y=0; y < (ssize_t) image->rows; y++)
213 register const Quantum
225 if (status == MagickFalse)
227 p=GetCacheViewVirtualPixels(image_view,-((ssize_t) width/2L),y-(ssize_t)
228 (height/2L),image->columns+width,height,exception);
229 q=QueueCacheViewAuthenticPixels(threshold_view,0,y,threshold_image->columns,
231 if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
236 center=(ssize_t) GetPixelChannels(image)*(image->columns+width)*(height/2L)+
237 GetPixelChannels(image)*(width/2);
238 for (x=0; x < (ssize_t) image->columns; x++)
243 if (GetPixelMask(image,p) != 0)
245 p+=GetPixelChannels(image);
246 q+=GetPixelChannels(threshold_image);
249 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
262 register const Quantum
271 channel=GetPixelChannelMapChannel(image,i);
272 traits=GetPixelChannelMapTraits(image,channel);
273 threshold_traits=GetPixelChannelMapTraits(threshold_image,channel);
274 if ((traits == UndefinedPixelTrait) ||
275 (threshold_traits == UndefinedPixelTrait))
277 if ((threshold_traits & CopyPixelTrait) != 0)
279 SetPixelChannel(threshold_image,channel,p[center+i],q);
284 for (v=0; v < (ssize_t) height; v++)
286 for (u=0; u < (ssize_t) width; u++)
289 pixels+=GetPixelChannels(image);
291 pixels+=image->columns*GetPixelChannels(image);
293 mean=(MagickRealType) (pixel/number_pixels+bias);
294 SetPixelChannel(threshold_image,channel,(Quantum) ((MagickRealType)
295 p[center+i] <= mean ? 0 : QuantumRange),q);
297 p+=GetPixelChannels(image);
298 q+=GetPixelChannels(threshold_image);
300 if (SyncCacheViewAuthenticPixels(threshold_view,exception) == MagickFalse)
302 if (image->progress_monitor != (MagickProgressMonitor) NULL)
307 #if defined(MAGICKCORE_OPENMP_SUPPORT)
308 #pragma omp critical (MagickCore_AdaptiveThresholdImage)
310 proceed=SetImageProgress(image,AdaptiveThresholdImageTag,progress++,
312 if (proceed == MagickFalse)
316 threshold_image->type=image->type;
317 threshold_view=DestroyCacheView(threshold_view);
318 image_view=DestroyCacheView(image_view);
319 if (status == MagickFalse)
320 threshold_image=DestroyImage(threshold_image);
321 return(threshold_image);
325 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
329 % B i l e v e l I m a g e %
333 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
335 % BilevelImage() changes the value of individual pixels based on the
336 % intensity of each pixel channel. The result is a high-contrast image.
338 % More precisely each channel value of the image is 'thresholded' so that if
339 % it is equal to or less than the given value it is set to zero, while any
340 % value greater than that give is set to it maximum or QuantumRange.
342 % This function is what is used to implement the "-threshold" operator for
343 % the command line API.
345 % If the default channel setting is given the image is thresholded using just
346 % the gray 'intensity' of the image, rather than the individual channels.
348 % The format of the BilevelImage method is:
350 % MagickBooleanType BilevelImage(Image *image,const double threshold,
351 % ExceptionInfo *exception)
353 % A description of each parameter follows:
355 % o image: the image.
357 % o threshold: define the threshold values.
359 % o exception: return any errors or warnings in this structure.
361 % Aside: You can get the same results as operator using LevelImages()
362 % with the 'threshold' value for both the black_point and the white_point.
365 MagickExport MagickBooleanType BilevelImage(Image *image,const double threshold,
366 ExceptionInfo *exception)
368 #define ThresholdImageTag "Threshold/Image"
382 assert(image != (Image *) NULL);
383 assert(image->signature == MagickSignature);
384 if (image->debug != MagickFalse)
385 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
386 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
389 Bilevel threshold image.
393 image_view=AcquireAuthenticCacheView(image,exception);
394 #if defined(MAGICKCORE_OPENMP_SUPPORT)
395 #pragma omp parallel for schedule(static,8) shared(progress,status) \
396 dynamic_number_threads(image->columns,image->rows,1)
398 for (y=0; y < (ssize_t) image->rows; y++)
406 if (status == MagickFalse)
408 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
409 if (q == (Quantum *) NULL)
414 for (x=0; x < (ssize_t) image->columns; x++)
419 if (GetPixelMask(image,q) != 0)
421 q+=GetPixelChannels(image);
424 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
432 channel=GetPixelChannelMapChannel(image,i);
433 traits=GetPixelChannelMapTraits(image,channel);
434 if ((traits & UpdatePixelTrait) == 0)
436 q[i]=(Quantum) ((MagickRealType) q[i] <= threshold ? 0 : QuantumRange);
438 q+=GetPixelChannels(image);
440 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
442 if (image->progress_monitor != (MagickProgressMonitor) NULL)
447 #if defined(MAGICKCORE_OPENMP_SUPPORT)
448 #pragma omp critical (MagickCore_BilevelImage)
450 proceed=SetImageProgress(image,ThresholdImageTag,progress++,
452 if (proceed == MagickFalse)
456 image_view=DestroyCacheView(image_view);
461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
465 % B l a c k T h r e s h o l d I m a g e %
469 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
471 % BlackThresholdImage() is like ThresholdImage() but forces all pixels below
472 % the threshold into black while leaving all pixels at or above the threshold
475 % The format of the BlackThresholdImage method is:
477 % MagickBooleanType BlackThresholdImage(Image *image,
478 % const char *threshold,ExceptionInfo *exception)
480 % A description of each parameter follows:
482 % o image: the image.
484 % o threshold: define the threshold value.
486 % o exception: return any errors or warnings in this structure.
489 MagickExport MagickBooleanType BlackThresholdImage(Image *image,
490 const char *thresholds,ExceptionInfo *exception)
492 #define ThresholdImageTag "Threshold/Image"
493 #define BlackThreshold(pixel,threshold) \
494 if (pixel <= threshold) pixel=0;
517 assert(image != (Image *) NULL);
518 assert(image->signature == MagickSignature);
519 if (image->debug != MagickFalse)
520 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
521 if (thresholds == (const char *) NULL)
523 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
525 if (IsGrayColorspace(image->colorspace) != MagickFalse)
526 (void) TransformImageColorspace(image,sRGBColorspace,exception);
527 GetPixelInfo(image,&threshold);
528 flags=ParseGeometry(thresholds,&geometry_info);
529 threshold.red=geometry_info.rho;
530 threshold.green=geometry_info.rho;
531 threshold.blue=geometry_info.rho;
532 threshold.black=geometry_info.rho;
533 threshold.alpha=100.0;
534 if ((flags & SigmaValue) != 0)
535 threshold.green=geometry_info.sigma;
536 if ((flags & XiValue) != 0)
537 threshold.blue=geometry_info.xi;
538 if ((flags & PsiValue) != 0)
539 threshold.alpha=geometry_info.psi;
540 if (threshold.colorspace == CMYKColorspace)
542 if ((flags & PsiValue) != 0)
543 threshold.black=geometry_info.psi;
544 if ((flags & ChiValue) != 0)
545 threshold.alpha=geometry_info.chi;
547 if ((flags & PercentValue) != 0)
549 threshold.red*=(QuantumRange/100.0);
550 threshold.green*=(QuantumRange/100.0);
551 threshold.blue*=(QuantumRange/100.0);
552 threshold.black*=(QuantumRange/100.0);
553 threshold.alpha*=(QuantumRange/100.0);
556 White threshold image.
560 image_view=AcquireAuthenticCacheView(image,exception);
561 #if defined(MAGICKCORE_OPENMP_SUPPORT)
562 #pragma omp parallel for schedule(static,8) shared(progress,status) \
563 dynamic_number_threads(image->columns,image->rows,1)
565 for (y=0; y < (ssize_t) image->rows; y++)
576 if (status == MagickFalse)
578 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
579 if (q == (Quantum *) NULL)
584 GetPixelInfo(image,&pixel);
585 for (x=0; x < (ssize_t) image->columns; x++)
587 if (GetPixelMask(image,q) != 0)
589 q+=GetPixelChannels(image);
592 GetPixelInfoPixel(image,q,&pixel);
593 BlackThreshold(pixel.red,threshold.red);
594 BlackThreshold(pixel.green,threshold.green);
595 BlackThreshold(pixel.blue,threshold.blue);
596 BlackThreshold(pixel.black,threshold.black);
597 BlackThreshold(pixel.alpha,threshold.alpha);
598 SetPixelInfoPixel(image,&pixel,q);
599 q+=GetPixelChannels(image);
601 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
603 if (image->progress_monitor != (MagickProgressMonitor) NULL)
608 #if defined(MAGICKCORE_OPENMP_SUPPORT)
609 #pragma omp critical (MagickCore_BlackThresholdImage)
611 proceed=SetImageProgress(image,ThresholdImageTag,progress++,
613 if (proceed == MagickFalse)
617 image_view=DestroyCacheView(image_view);
622 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
626 % C l a m p I m a g e %
630 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
632 % ClampImage() restricts the color range from 0 to the quantum depth.
634 % The format of the ClampImage method is:
636 % MagickBooleanType ClampImage(Image *image,ExceptionInfo *exception)
638 % A description of each parameter follows:
640 % o image: the image.
642 % o exception: return any errors or warnings in this structure.
646 static inline Quantum ClampToUnsignedQuantum(const Quantum quantum)
648 #if defined(MAGICKCORE_HDRI_SUPPORT)
651 if (quantum >= QuantumRange)
652 return(QuantumRange);
659 MagickExport MagickBooleanType ClampImage(Image *image,ExceptionInfo *exception)
661 #define ClampImageTag "Clamp/Image"
675 assert(image != (Image *) NULL);
676 assert(image->signature == MagickSignature);
677 if (image->debug != MagickFalse)
678 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
679 if (image->storage_class == PseudoClass)
688 for (i=0; i < (ssize_t) image->colors; i++)
690 q->red=(double) ClampToUnsignedQuantum(ClampToQuantum(q->red));
691 q->green=(double) ClampToUnsignedQuantum(ClampToQuantum(q->green));
692 q->blue=(double) ClampToUnsignedQuantum(ClampToQuantum(q->blue));
693 q->alpha=(double) ClampToUnsignedQuantum(ClampToQuantum(q->alpha));
696 return(SyncImage(image,exception));
703 image_view=AcquireAuthenticCacheView(image,exception);
704 #if defined(MAGICKCORE_OPENMP_SUPPORT)
705 #pragma omp parallel for schedule(static,8) shared(progress,status) \
706 dynamic_number_threads(image->columns,image->rows,1)
708 for (y=0; y < (ssize_t) image->rows; y++)
716 if (status == MagickFalse)
718 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
719 if (q == (Quantum *) NULL)
724 for (x=0; x < (ssize_t) image->columns; x++)
729 if (GetPixelMask(image,q) != 0)
731 q+=GetPixelChannels(image);
734 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
742 channel=GetPixelChannelMapChannel(image,i);
743 traits=GetPixelChannelMapTraits(image,channel);
744 if (traits == UndefinedPixelTrait)
746 q[i]=ClampToUnsignedQuantum(q[i]);
748 q+=GetPixelChannels(image);
750 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
752 if (image->progress_monitor != (MagickProgressMonitor) NULL)
757 #if defined(MAGICKCORE_OPENMP_SUPPORT)
758 #pragma omp critical (MagickCore_ClampImage)
760 proceed=SetImageProgress(image,ClampImageTag,progress++,
762 if (proceed == MagickFalse)
766 image_view=DestroyCacheView(image_view);
771 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
775 % D e s t r o y T h r e s h o l d M a p %
779 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
781 % DestroyThresholdMap() de-allocate the given ThresholdMap
783 % The format of the ListThresholdMaps method is:
785 % ThresholdMap *DestroyThresholdMap(Threshold *map)
787 % A description of each parameter follows.
789 % o map: Pointer to the Threshold map to destroy
792 MagickExport ThresholdMap *DestroyThresholdMap(ThresholdMap *map)
794 assert(map != (ThresholdMap *) NULL);
795 if (map->map_id != (char *) NULL)
796 map->map_id=DestroyString(map->map_id);
797 if (map->description != (char *) NULL)
798 map->description=DestroyString(map->description);
799 if (map->levels != (ssize_t *) NULL)
800 map->levels=(ssize_t *) RelinquishMagickMemory(map->levels);
801 map=(ThresholdMap *) RelinquishMagickMemory(map);
806 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
810 % G e t T h r e s h o l d M a p %
814 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
816 % GetThresholdMap() loads and searches one or more threshold map files for the
817 % map matching the given name or alias.
819 % The format of the GetThresholdMap method is:
821 % ThresholdMap *GetThresholdMap(const char *map_id,
822 % ExceptionInfo *exception)
824 % A description of each parameter follows.
826 % o map_id: ID of the map to look for.
828 % o exception: return any errors or warnings in this structure.
831 MagickExport ThresholdMap *GetThresholdMap(const char *map_id,
832 ExceptionInfo *exception)
843 map=(ThresholdMap *)NULL;
844 options=GetConfigureOptions(ThresholdsFilename,exception);
845 while ((option=(const StringInfo *) GetNextValueInLinkedList(options)) !=
846 (const StringInfo *) NULL && (map == (ThresholdMap *) NULL))
847 map=GetThresholdMapFile((const char *) GetStringInfoDatum(option),
848 GetStringInfoPath(option),map_id,exception);
849 options=DestroyConfigureOptions(options);
854 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
858 + G e t T h r e s h o l d M a p F i l e %
862 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
864 % GetThresholdMapFile() look for a given threshold map name or alias in the
865 % given XML file data, and return the allocated the map when found.
867 % The format of the ListThresholdMaps method is:
869 % ThresholdMap *GetThresholdMap(const char *xml,const char *filename,
870 % const char *map_id,ExceptionInfo *exception)
872 % A description of each parameter follows.
874 % o xml: The threshold map list in XML format.
876 % o filename: The threshold map XML filename.
878 % o map_id: ID of the map to look for in XML list.
880 % o exception: return any errors or warnings in this structure.
883 static ThresholdMap *GetThresholdMapFile(const char *xml,
884 const char *filename,const char *map_id,ExceptionInfo *exception)
908 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
909 "Loading threshold map file \"%s\" ...",filename);
910 map=(ThresholdMap *) NULL;
911 thresholds=NewXMLTree(xml,exception);
912 if (thresholds == (XMLTreeInfo *) NULL)
914 for (threshold=GetXMLTreeChild(thresholds,"threshold");
915 threshold != (XMLTreeInfo *) NULL;
916 threshold=GetNextXMLTreeTag(threshold))
918 attribute=GetXMLTreeAttribute(threshold,"map");
919 if ((attribute != (char *) NULL) && (LocaleCompare(map_id,attribute) == 0))
921 attribute=GetXMLTreeAttribute(threshold,"alias");
922 if ((attribute != (char *) NULL) && (LocaleCompare(map_id,attribute) == 0))
925 if (threshold == (XMLTreeInfo *) NULL)
927 description=GetXMLTreeChild(threshold,"description");
928 if (description == (XMLTreeInfo *) NULL)
930 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
931 "XmlMissingElement", "<description>, map \"%s\"",map_id);
932 thresholds=DestroyXMLTree(thresholds);
935 levels=GetXMLTreeChild(threshold,"levels");
936 if (levels == (XMLTreeInfo *) NULL)
938 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
939 "XmlMissingElement", "<levels>, map \"%s\"", map_id);
940 thresholds=DestroyXMLTree(thresholds);
943 map=(ThresholdMap *) AcquireMagickMemory(sizeof(ThresholdMap));
944 if (map == (ThresholdMap *) NULL)
945 ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireThresholdMap");
946 map->map_id=(char *) NULL;
947 map->description=(char *) NULL;
948 map->levels=(ssize_t *) NULL;
949 attribute=GetXMLTreeAttribute(threshold,"map");
950 if (attribute != (char *) NULL)
951 map->map_id=ConstantString(attribute);
952 content=GetXMLTreeContent(description);
953 if (content != (char *) NULL)
954 map->description=ConstantString(content);
955 attribute=GetXMLTreeAttribute(levels,"width");
956 if (attribute == (char *) NULL)
958 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
959 "XmlMissingAttribute", "<levels width>, map \"%s\"",map_id);
960 thresholds=DestroyXMLTree(thresholds);
961 map=DestroyThresholdMap(map);
964 map->width=StringToUnsignedLong(attribute);
967 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
968 "XmlInvalidAttribute", "<levels width>, map \"%s\"",map_id);
969 thresholds=DestroyXMLTree(thresholds);
970 map=DestroyThresholdMap(map);
973 attribute=GetXMLTreeAttribute(levels,"height");
974 if (attribute == (char *) NULL)
976 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
977 "XmlMissingAttribute", "<levels height>, map \"%s\"",map_id);
978 thresholds=DestroyXMLTree(thresholds);
979 map=DestroyThresholdMap(map);
982 map->height=StringToUnsignedLong(attribute);
983 if (map->height == 0)
985 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
986 "XmlInvalidAttribute", "<levels height>, map \"%s\"",map_id);
987 thresholds=DestroyXMLTree(thresholds);
988 map=DestroyThresholdMap(map);
991 attribute=GetXMLTreeAttribute(levels,"divisor");
992 if (attribute == (char *) NULL)
994 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
995 "XmlMissingAttribute", "<levels divisor>, map \"%s\"",map_id);
996 thresholds=DestroyXMLTree(thresholds);
997 map=DestroyThresholdMap(map);
1000 map->divisor=(ssize_t) StringToLong(attribute);
1001 if (map->divisor < 2)
1003 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1004 "XmlInvalidAttribute", "<levels divisor>, map \"%s\"",map_id);
1005 thresholds=DestroyXMLTree(thresholds);
1006 map=DestroyThresholdMap(map);
1009 content=GetXMLTreeContent(levels);
1010 if (content == (char *) NULL)
1012 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1013 "XmlMissingContent", "<levels>, map \"%s\"",map_id);
1014 thresholds=DestroyXMLTree(thresholds);
1015 map=DestroyThresholdMap(map);
1018 map->levels=(ssize_t *) AcquireQuantumMemory((size_t) map->width,map->height*
1019 sizeof(*map->levels));
1020 if (map->levels == (ssize_t *) NULL)
1021 ThrowFatalException(ResourceLimitFatalError,"UnableToAcquireThresholdMap");
1022 for (i=0; i < (ssize_t) (map->width*map->height); i++)
1024 map->levels[i]=(ssize_t) strtol(content,&p,10);
1027 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1028 "XmlInvalidContent", "<level> too few values, map \"%s\"",map_id);
1029 thresholds=DestroyXMLTree(thresholds);
1030 map=DestroyThresholdMap(map);
1033 if ((map->levels[i] < 0) || (map->levels[i] > map->divisor))
1035 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1036 "XmlInvalidContent", "<level> %.20g out of range, map \"%s\"",
1037 (double) map->levels[i],map_id);
1038 thresholds=DestroyXMLTree(thresholds);
1039 map=DestroyThresholdMap(map);
1044 value=(double) strtol(content,&p,10);
1048 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1049 "XmlInvalidContent", "<level> too many values, map \"%s\"",map_id);
1050 thresholds=DestroyXMLTree(thresholds);
1051 map=DestroyThresholdMap(map);
1054 thresholds=DestroyXMLTree(thresholds);
1059 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1063 + L i s t T h r e s h o l d M a p F i l e %
1067 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1069 % ListThresholdMapFile() lists the threshold maps and their descriptions
1070 % in the given XML file data.
1072 % The format of the ListThresholdMaps method is:
1074 % MagickBooleanType ListThresholdMaps(FILE *file,const char*xml,
1075 % const char *filename,ExceptionInfo *exception)
1077 % A description of each parameter follows.
1079 % o file: An pointer to the output FILE.
1081 % o xml: The threshold map list in XML format.
1083 % o filename: The threshold map XML filename.
1085 % o exception: return any errors or warnings in this structure.
1088 MagickBooleanType ListThresholdMapFile(FILE *file,const char *xml,
1089 const char *filename,ExceptionInfo *exception)
1101 assert( xml != (char *)NULL );
1102 assert( file != (FILE *)NULL );
1103 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(),
1104 "Loading threshold map file \"%s\" ...",filename);
1105 thresholds=NewXMLTree(xml,exception);
1106 if ( thresholds == (XMLTreeInfo *)NULL )
1107 return(MagickFalse);
1108 (void) FormatLocaleFile(file,"%-16s %-12s %s\n","Map","Alias","Description");
1109 (void) FormatLocaleFile(file,
1110 "----------------------------------------------------\n");
1111 threshold=GetXMLTreeChild(thresholds,"threshold");
1112 for ( ; threshold != (XMLTreeInfo *) NULL;
1113 threshold=GetNextXMLTreeTag(threshold))
1115 map=GetXMLTreeAttribute(threshold,"map");
1116 if (map == (char *) NULL)
1118 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1119 "XmlMissingAttribute", "<map>");
1120 thresholds=DestroyXMLTree(thresholds);
1121 return(MagickFalse);
1123 alias=GetXMLTreeAttribute(threshold,"alias");
1124 description=GetXMLTreeChild(threshold,"description");
1125 if (description == (XMLTreeInfo *) NULL)
1127 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1128 "XmlMissingElement", "<description>, map \"%s\"",map);
1129 thresholds=DestroyXMLTree(thresholds);
1130 return(MagickFalse);
1132 content=GetXMLTreeContent(description);
1133 if (content == (char *) NULL)
1135 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1136 "XmlMissingContent", "<description>, map \"%s\"", map);
1137 thresholds=DestroyXMLTree(thresholds);
1138 return(MagickFalse);
1140 (void) FormatLocaleFile(file,"%-16s %-12s %s\n",map,alias ? alias : "",
1143 thresholds=DestroyXMLTree(thresholds);
1148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1152 % L i s t T h r e s h o l d M a p s %
1156 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1158 % ListThresholdMaps() lists the threshold maps and their descriptions
1159 % as defined by "threshold.xml" to a file.
1161 % The format of the ListThresholdMaps method is:
1163 % MagickBooleanType ListThresholdMaps(FILE *file,ExceptionInfo *exception)
1165 % A description of each parameter follows.
1167 % o file: An pointer to the output FILE.
1169 % o exception: return any errors or warnings in this structure.
1172 MagickExport MagickBooleanType ListThresholdMaps(FILE *file,
1173 ExceptionInfo *exception)
1185 if (file == (FILE *) NULL)
1187 options=GetConfigureOptions(ThresholdsFilename,exception);
1188 (void) FormatLocaleFile(file,
1189 "\n Threshold Maps for Ordered Dither Operations\n");
1190 while ((option=(const StringInfo *) GetNextValueInLinkedList(options)) !=
1191 (const StringInfo *) NULL)
1193 (void) FormatLocaleFile(file,"\nPATH: %s\n\n",GetStringInfoPath(option));
1194 status|=ListThresholdMapFile(file,(const char *) GetStringInfoDatum(option),
1195 GetStringInfoPath(option),exception);
1197 options=DestroyConfigureOptions(options);
1198 return(status != 0 ? MagickTrue : MagickFalse);
1202 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1206 % O r d e r e d P o s t e r i z e I m a g e %
1210 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1212 % OrderedPosterizeImage() will perform a ordered dither based on a number
1213 % of pre-defined dithering threshold maps, but over multiple intensity
1214 % levels, which can be different for different channels, according to the
1217 % The format of the OrderedPosterizeImage method is:
1219 % MagickBooleanType OrderedPosterizeImage(Image *image,
1220 % const char *threshold_map,ExceptionInfo *exception)
1222 % A description of each parameter follows:
1224 % o image: the image.
1226 % o threshold_map: A string containing the name of the threshold dither
1227 % map to use, followed by zero or more numbers representing the number
1228 % of color levels tho dither between.
1230 % Any level number less than 2 will be equivalent to 2, and means only
1231 % binary dithering will be applied to each color channel.
1233 % No numbers also means a 2 level (bitmap) dither will be applied to all
1234 % channels, while a single number is the number of levels applied to each
1235 % channel in sequence. More numbers will be applied in turn to each of
1236 % the color channels.
1238 % For example: "o3x3,6" will generate a 6 level posterization of the
1239 % image with a ordered 3x3 diffused pixel dither being applied between
1240 % each level. While checker,8,8,4 will produce a 332 colormaped image
1241 % with only a single checkerboard hash pattern (50% grey) between each
1242 % color level, to basically double the number of color levels with
1243 % a bare minimim of dithering.
1245 % o exception: return any errors or warnings in this structure.
1248 MagickExport MagickBooleanType OrderedPosterizeImage(Image *image,
1249 const char *threshold_map,ExceptionInfo *exception)
1251 #define DitherImageTag "Dither/Image"
1257 token[MaxTextExtent];
1269 levels[CompositePixelChannel];
1280 assert(image != (Image *) NULL);
1281 assert(image->signature == MagickSignature);
1282 if (image->debug != MagickFalse)
1283 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1284 assert(exception != (ExceptionInfo *) NULL);
1285 assert(exception->signature == MagickSignature);
1286 if (threshold_map == (const char *) NULL)
1288 p=(char *) threshold_map;
1289 while (((isspace((int) ((unsigned char) *p)) != 0) || (*p == ',')) &&
1293 while (((isspace((int) ((unsigned char) *p)) == 0) && (*p != ',')) &&
1296 if ((p-threshold_map) >= (MaxTextExtent-1))
1298 token[p-threshold_map]=(*p);
1301 token[p-threshold_map]='\0';
1302 map=GetThresholdMap(token,exception);
1303 if (map == (ThresholdMap *) NULL)
1305 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1306 "InvalidArgument","%s : '%s'","ordered-dither",threshold_map);
1307 return(MagickFalse);
1309 for (i=0; i < MaxPixelChannels; i++)
1311 p=strchr((char *) threshold_map,',');
1312 if ((p != (char *) NULL) && (isdigit((int) ((unsigned char) *(++p))) != 0))
1313 for (i=0; (*p != '\0') && (i < MaxPixelChannels); i++)
1315 GetMagickToken(p,&p,token);
1317 GetMagickToken(p,&p,token);
1318 levels[i]=StringToDouble(token,(char **) NULL);
1320 for (i=0; i < MaxPixelChannels; i++)
1321 if (fabs(levels[i]) >= 1)
1323 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1324 return(MagickFalse);
1327 image_view=AcquireAuthenticCacheView(image,exception);
1328 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1329 #pragma omp parallel for schedule(static,8) shared(progress,status) \
1330 dynamic_number_threads(image->columns,image->rows,1)
1332 for (y=0; y < (ssize_t) image->rows; y++)
1340 if (status == MagickFalse)
1342 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1343 if (q == (Quantum *) NULL)
1348 for (x=0; x < (ssize_t) image->columns; x++)
1357 if (GetPixelMask(image,q) != 0)
1359 q+=GetPixelChannels(image);
1362 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1374 channel=GetPixelChannelMapChannel(image,i);
1375 traits=GetPixelChannelMapTraits(image,channel);
1376 if ((traits & UpdatePixelTrait) == 0)
1378 if (fabs(levels[n++]) < MagickEpsilon)
1380 threshold=(ssize_t) (QuantumScale*q[i]*(levels[n]*(map->divisor-1)+1));
1381 level=threshold/(map->divisor-1);
1382 threshold-=level*(map->divisor-1);
1383 q[i]=RoundToQuantum((MagickRealType) (level+(threshold >=
1384 map->levels[(x % map->width)+map->width*(y % map->height)]))*
1385 QuantumRange/levels[n]);
1388 q+=GetPixelChannels(image);
1390 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1392 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1397 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1398 #pragma omp critical (MagickCore_OrderedPosterizeImage)
1400 proceed=SetImageProgress(image,DitherImageTag,progress++,image->rows);
1401 if (proceed == MagickFalse)
1405 image_view=DestroyCacheView(image_view);
1406 map=DestroyThresholdMap(map);
1411 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1415 % R a n d o m T h r e s h o l d I m a g e %
1419 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1421 % RandomThresholdImage() changes the value of individual pixels based on the
1422 % intensity of each pixel compared to a random threshold. The result is a
1423 % low-contrast, two color image.
1425 % The format of the RandomThresholdImage method is:
1427 % MagickBooleanType RandomThresholdImage(Image *image,
1428 % const char *thresholds,ExceptionInfo *exception)
1430 % A description of each parameter follows:
1432 % o image: the image.
1434 % o thresholds: a geometry string containing low,high thresholds. If the
1435 % string contains 2x2, 3x3, or 4x4, an ordered dither of order 2, 3, or 4
1436 % is performed instead.
1438 % o exception: return any errors or warnings in this structure.
1441 MagickExport MagickBooleanType RandomThresholdImage(Image *image,
1442 const char *thresholds,ExceptionInfo *exception)
1444 #define ThresholdImageTag "Threshold/Image"
1469 **restrict random_info;
1477 assert(image != (Image *) NULL);
1478 assert(image->signature == MagickSignature);
1479 if (image->debug != MagickFalse)
1480 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1481 assert(exception != (ExceptionInfo *) NULL);
1482 assert(exception->signature == MagickSignature);
1483 if (thresholds == (const char *) NULL)
1485 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1486 return(MagickFalse);
1487 GetPixelInfo(image,&threshold);
1489 max_threshold=(MagickRealType) QuantumRange;
1490 flags=ParseGeometry(thresholds,&geometry_info);
1491 min_threshold=geometry_info.rho;
1492 max_threshold=geometry_info.sigma;
1493 if ((flags & SigmaValue) == 0)
1494 max_threshold=min_threshold;
1495 if (strchr(thresholds,'%') != (char *) NULL)
1497 max_threshold*=(MagickRealType) (0.01*QuantumRange);
1498 min_threshold*=(MagickRealType) (0.01*QuantumRange);
1501 Random threshold image.
1505 random_info=AcquireRandomInfoThreadSet();
1506 key=GetRandomSecretKey(random_info[0]);
1507 image_view=AcquireAuthenticCacheView(image,exception);
1508 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1509 #pragma omp parallel for schedule(static,8) shared(progress,status) \
1510 dynamic_number_threads(image->columns,image->rows,key == ~0UL)
1512 for (y=0; y < (ssize_t) image->rows; y++)
1515 id = GetOpenMPThreadId();
1523 if (status == MagickFalse)
1525 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1526 if (q == (Quantum *) NULL)
1531 for (x=0; x < (ssize_t) image->columns; x++)
1536 if (GetPixelMask(image,q) != 0)
1538 q+=GetPixelChannels(image);
1541 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
1552 channel=GetPixelChannelMapChannel(image,i);
1553 traits=GetPixelChannelMapTraits(image,channel);
1554 if ((traits & UpdatePixelTrait) == 0)
1556 if ((MagickRealType) q[i] < min_threshold)
1557 threshold=min_threshold;
1559 if ((MagickRealType) q[i] > max_threshold)
1560 threshold=max_threshold;
1562 threshold=(MagickRealType) (QuantumRange*
1563 GetPseudoRandomValue(random_info[id]));
1564 q[i]=(Quantum) ((MagickRealType) q[i] <= threshold ? 0 :
1567 q+=GetPixelChannels(image);
1569 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1571 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1576 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1577 #pragma omp critical (MagickCore_RandomThresholdImage)
1579 proceed=SetImageProgress(image,ThresholdImageTag,progress++,
1581 if (proceed == MagickFalse)
1585 image_view=DestroyCacheView(image_view);
1586 random_info=DestroyRandomInfoThreadSet(random_info);
1591 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1595 % W h i t e T h r e s h o l d I m a g e %
1599 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1601 % WhiteThresholdImage() is like ThresholdImage() but forces all pixels above
1602 % the threshold into white while leaving all pixels at or below the threshold
1605 % The format of the WhiteThresholdImage method is:
1607 % MagickBooleanType WhiteThresholdImage(Image *image,
1608 % const char *threshold,ExceptionInfo *exception)
1610 % A description of each parameter follows:
1612 % o image: the image.
1614 % o threshold: Define the threshold value.
1616 % o exception: return any errors or warnings in this structure.
1619 MagickExport MagickBooleanType WhiteThresholdImage(Image *image,
1620 const char *thresholds,ExceptionInfo *exception)
1622 #define ThresholdImageTag "Threshold/Image"
1623 #define WhiteThreshold(pixel,threshold) \
1624 if (pixel > threshold) pixel=QuantumRange;
1647 assert(image != (Image *) NULL);
1648 assert(image->signature == MagickSignature);
1649 if (image->debug != MagickFalse)
1650 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1651 if (thresholds == (const char *) NULL)
1653 if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
1654 return(MagickFalse);
1655 if (IsGrayColorspace(image->colorspace) != MagickFalse)
1656 (void) TransformImageColorspace(image,sRGBColorspace,exception);
1657 GetPixelInfo(image,&threshold);
1658 flags=ParseGeometry(thresholds,&geometry_info);
1659 threshold.red=geometry_info.rho;
1660 threshold.green=geometry_info.rho;
1661 threshold.blue=geometry_info.rho;
1662 threshold.black=geometry_info.rho;
1663 threshold.alpha=100.0;
1664 if ((flags & SigmaValue) != 0)
1665 threshold.green=geometry_info.sigma;
1666 if ((flags & XiValue) != 0)
1667 threshold.blue=geometry_info.xi;
1668 if ((flags & PsiValue) != 0)
1669 threshold.alpha=geometry_info.psi;
1670 if (threshold.colorspace == CMYKColorspace)
1672 if ((flags & PsiValue) != 0)
1673 threshold.black=geometry_info.psi;
1674 if ((flags & ChiValue) != 0)
1675 threshold.alpha=geometry_info.chi;
1677 if ((flags & PercentValue) != 0)
1679 threshold.red*=(QuantumRange/100.0);
1680 threshold.green*=(QuantumRange/100.0);
1681 threshold.blue*=(QuantumRange/100.0);
1682 threshold.black*=(QuantumRange/100.0);
1683 threshold.alpha*=(QuantumRange/100.0);
1686 White threshold image.
1690 image_view=AcquireAuthenticCacheView(image,exception);
1691 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1692 #pragma omp parallel for schedule(static,8) shared(progress,status) \
1693 dynamic_number_threads(image->columns,image->rows,1)
1695 for (y=0; y < (ssize_t) image->rows; y++)
1706 if (status == MagickFalse)
1708 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1709 if (q == (Quantum *) NULL)
1714 GetPixelInfo(image,&pixel);
1715 for (x=0; x < (ssize_t) image->columns; x++)
1717 if (GetPixelMask(image,q) != 0)
1719 q+=GetPixelChannels(image);
1722 GetPixelInfoPixel(image,q,&pixel);
1723 WhiteThreshold(pixel.red,threshold.red);
1724 WhiteThreshold(pixel.green,threshold.green);
1725 WhiteThreshold(pixel.blue,threshold.blue);
1726 WhiteThreshold(pixel.black,threshold.black);
1727 WhiteThreshold(pixel.alpha,threshold.alpha);
1728 SetPixelInfoPixel(image,&pixel,q);
1729 q+=GetPixelChannels(image);
1731 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1733 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1738 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1739 #pragma omp critical (MagickCore_WhiteThresholdImage)
1741 proceed=SetImageProgress(image,ThresholdImageTag,progress++,
1743 if (proceed == MagickFalse)
1747 image_view=DestroyCacheView(image_view);