2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 % MagickCore Image Special Effects Methods %
20 % Copyright 1999-2009 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 "magick/studio.h"
44 #include "magick/annotate.h"
45 #include "magick/artifact.h"
46 #include "magick/attribute.h"
47 #include "magick/cache.h"
48 #include "magick/cache-view.h"
49 #include "magick/color.h"
50 #include "magick/color-private.h"
51 #include "magick/composite.h"
52 #include "magick/decorate.h"
53 #include "magick/draw.h"
54 #include "magick/effect.h"
55 #include "magick/enhance.h"
56 #include "magick/exception.h"
57 #include "magick/exception-private.h"
58 #include "magick/fx.h"
59 #include "magick/fx-private.h"
60 #include "magick/gem.h"
61 #include "magick/geometry.h"
62 #include "magick/layer.h"
63 #include "magick/list.h"
64 #include "magick/log.h"
65 #include "magick/image.h"
66 #include "magick/image-private.h"
67 #include "magick/memory_.h"
68 #include "magick/monitor.h"
69 #include "magick/monitor-private.h"
70 #include "magick/option.h"
71 #include "magick/pixel-private.h"
72 #include "magick/property.h"
73 #include "magick/quantum.h"
74 #include "magick/random_.h"
75 #include "magick/random-private.h"
76 #include "magick/resample.h"
77 #include "magick/resample-private.h"
78 #include "magick/resize.h"
79 #include "magick/shear.h"
80 #include "magick/splay-tree.h"
81 #include "magick/statistic.h"
82 #include "magick/string_.h"
83 #include "magick/thread-private.h"
84 #include "magick/transform.h"
85 #include "magick/utility.h"
90 #define LeftShiftOperator 0xf5
91 #define RightShiftOperator 0xf6
92 #define LessThanEqualOperator 0xf7
93 #define GreaterThanEqualOperator 0xf8
94 #define EqualOperator 0xf9
95 #define NotEqualOperator 0xfa
96 #define LogicalAndOperator 0xfb
97 #define LogicalOrOperator 0xfc
128 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
132 + A c q u i r e F x I n f o %
136 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
138 % AcquireFxInfo() allocates the FxInfo structure.
140 % The format of the AcquireFxInfo method is:
142 % FxInfo *AcquireFxInfo(Image *image,const char *expression)
143 % A description of each parameter follows:
145 % o image: the image.
147 % o expression: the expression.
150 MagickExport FxInfo *AcquireFxInfo(const Image *image,const char *expression)
161 fx_info=(FxInfo *) AcquireMagickMemory(sizeof(*fx_info));
162 if (fx_info == (FxInfo *) NULL)
163 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
164 (void) ResetMagickMemory(fx_info,0,sizeof(*fx_info));
165 fx_info->exception=AcquireExceptionInfo();
166 fx_info->images=image;
167 fx_info->matte=image->matte;
168 fx_info->colors=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
169 RelinquishMagickMemory);
170 fx_info->symbols=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
171 RelinquishMagickMemory);
172 fx_info->resample_filter=(ResampleFilter **) AcquireQuantumMemory(
173 GetImageListLength(fx_info->images),sizeof(*fx_info->resample_filter));
174 if (fx_info->resample_filter == (ResampleFilter **) NULL)
175 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
176 for (i=0; i < (long) GetImageListLength(fx_info->images); i++)
178 fx_info->resample_filter[i]=AcquireResampleFilter(GetImageFromList(
179 fx_info->images,i),fx_info->exception);
180 SetResampleFilter(fx_info->resample_filter[i],PointFilter,1.0);
182 fx_info->random_info=AcquireRandomInfo();
183 fx_info->expression=ConstantString(expression);
184 fx_info->file=stderr;
185 (void) SubstituteString(&fx_info->expression," ",""); /* compact string */
186 if ((strstr(fx_info->expression,"e+") != (char *) NULL) ||
187 (strstr(fx_info->expression,"e-") != (char *) NULL))
190 Convert scientific notation.
192 (void) SubstituteString(&fx_info->expression,"0e+","0*10^");
193 (void) SubstituteString(&fx_info->expression,"1e+","1*10^");
194 (void) SubstituteString(&fx_info->expression,"2e+","2*10^");
195 (void) SubstituteString(&fx_info->expression,"3e+","3*10^");
196 (void) SubstituteString(&fx_info->expression,"4e+","4*10^");
197 (void) SubstituteString(&fx_info->expression,"5e+","5*10^");
198 (void) SubstituteString(&fx_info->expression,"6e+","6*10^");
199 (void) SubstituteString(&fx_info->expression,"7e+","7*10^");
200 (void) SubstituteString(&fx_info->expression,"8e+","8*10^");
201 (void) SubstituteString(&fx_info->expression,"9e+","9*10^");
202 (void) SubstituteString(&fx_info->expression,"0e-","0*10^-");
203 (void) SubstituteString(&fx_info->expression,"1e-","1*10^-");
204 (void) SubstituteString(&fx_info->expression,"2e-","2*10^-");
205 (void) SubstituteString(&fx_info->expression,"3e-","3*10^-");
206 (void) SubstituteString(&fx_info->expression,"4e-","4*10^-");
207 (void) SubstituteString(&fx_info->expression,"5e-","5*10^-");
208 (void) SubstituteString(&fx_info->expression,"6e-","6*10^-");
209 (void) SubstituteString(&fx_info->expression,"7e-","7*10^-");
210 (void) SubstituteString(&fx_info->expression,"8e-","8*10^-");
211 (void) SubstituteString(&fx_info->expression,"9e-","9*10^-");
214 Convert complex to simple operators.
217 *fx_op=(char) LeftShiftOperator;
218 (void) SubstituteString(&fx_info->expression,"<<",fx_op);
219 *fx_op=(char) RightShiftOperator;
220 (void) SubstituteString(&fx_info->expression,">>",fx_op);
221 *fx_op=(char) LessThanEqualOperator;
222 (void) SubstituteString(&fx_info->expression,"<=",fx_op);
223 *fx_op=(char) GreaterThanEqualOperator;
224 (void) SubstituteString(&fx_info->expression,">=",fx_op);
225 *fx_op=(char) EqualOperator;
226 (void) SubstituteString(&fx_info->expression,"==",fx_op);
227 *fx_op=(char) NotEqualOperator;
228 (void) SubstituteString(&fx_info->expression,"!=",fx_op);
229 *fx_op=(char) LogicalAndOperator;
230 (void) SubstituteString(&fx_info->expression,"&&",fx_op);
231 *fx_op=(char) LogicalOrOperator;
232 (void) SubstituteString(&fx_info->expression,"||",fx_op);
237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
241 % A d d N o i s e I m a g e %
245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
247 % AddNoiseImage() adds random noise to the image.
249 % The format of the AddNoiseImage method is:
251 % Image *AddNoiseImage(const Image *image,const NoiseType noise_type,
252 % ExceptionInfo *exception)
253 % Image *AddNoiseImageChannel(const Image *image,const ChannelType channel,
254 % const NoiseType noise_type,ExceptionInfo *exception)
256 % A description of each parameter follows:
258 % o image: the image.
260 % o channel: the channel type.
262 % o noise_type: The type of noise: Uniform, Gaussian, Multiplicative,
263 % Impulse, Laplacian, or Poisson.
265 % o exception: return any errors or warnings in this structure.
268 MagickExport Image *AddNoiseImage(const Image *image,const NoiseType noise_type,
269 ExceptionInfo *exception)
274 noise_image=AddNoiseImageChannel(image,DefaultChannels,noise_type,exception);
278 MagickExport Image *AddNoiseImageChannel(const Image *image,
279 const ChannelType channel,const NoiseType noise_type,ExceptionInfo *exception)
281 #define AddNoiseImageTag "AddNoise/Image"
307 Initialize noise image attributes.
309 assert(image != (const Image *) NULL);
310 assert(image->signature == MagickSignature);
311 if (image->debug != MagickFalse)
312 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
313 assert(exception != (ExceptionInfo *) NULL);
314 assert(exception->signature == MagickSignature);
315 noise_image=CloneImage(image,0,0,MagickTrue,exception);
316 if (noise_image == (Image *) NULL)
317 return((Image *) NULL);
318 if (SetImageStorageClass(noise_image,DirectClass) == MagickFalse)
320 InheritException(exception,&noise_image->exception);
321 noise_image=DestroyImage(noise_image);
322 return((Image *) NULL);
325 Add noise in each row.
328 option=GetImageArtifact(image,"attenuate");
329 if (option != (char *) NULL)
330 attenuate=atof(option);
333 random_info=AcquireRandomInfoThreadSet();
334 image_view=AcquireCacheView(image);
335 noise_view=AcquireCacheView(noise_image);
336 #if defined(MAGICKCOREMAGICKCORE_OPENMP_SUPPORT_SUPPORT_DEBUG)
337 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
339 for (y=0; y < (long) image->rows; y++)
344 register const IndexPacket
347 register const PixelPacket
351 *__restrict noise_indexes;
360 if (status == MagickFalse)
362 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
363 q=GetCacheViewAuthenticPixels(noise_view,0,y,noise_image->columns,1,
365 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
370 indexes=GetCacheViewVirtualIndexQueue(image_view);
371 noise_indexes=GetCacheViewAuthenticIndexQueue(noise_view);
372 id=GetOpenMPThreadId();
373 for (x=0; x < (long) image->columns; x++)
375 if ((channel & RedChannel) != 0)
376 q->red=RoundToQuantum(GenerateDifferentialNoise(random_info[id],
377 p->red,noise_type,attenuate));
378 if ((channel & GreenChannel) != 0)
379 q->green=RoundToQuantum(GenerateDifferentialNoise(random_info[id],
380 p->green,noise_type,attenuate));
381 if ((channel & BlueChannel) != 0)
382 q->blue=RoundToQuantum(GenerateDifferentialNoise(random_info[id],
383 p->blue,noise_type,attenuate));
384 if ((channel & OpacityChannel) != 0)
385 q->opacity=RoundToQuantum(GenerateDifferentialNoise(random_info[id],
386 p->opacity,noise_type,attenuate));
387 if (((channel & IndexChannel) != 0) &&
388 (image->colorspace == CMYKColorspace))
389 noise_indexes[x]=(IndexPacket) RoundToQuantum(GenerateDifferentialNoise(
390 random_info[id],indexes[x],noise_type,attenuate));
394 sync=SyncCacheViewAuthenticPixels(noise_view,exception);
395 if (sync == MagickFalse)
397 if (image->progress_monitor != (MagickProgressMonitor) NULL)
402 #if defined(MAGICKCORE_OPENMP_SUPPORT)
403 #pragma omp critical (MagickCore_AverageImages)
405 proceed=SetImageProgress(image,AddNoiseImageTag,progress++,
407 if (proceed == MagickFalse)
411 noise_view=DestroyCacheView(noise_view);
412 image_view=DestroyCacheView(image_view);
413 random_info=DestroyRandomInfoThreadSet(random_info);
414 if (status == MagickFalse)
415 noise_image=DestroyImage(noise_image);
420 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
424 % B l u e S h i f t I m a g e %
428 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
430 % BlueShiftImage() mutes the colors of the image to simulate a scene at
431 % nighttime in the moonlight.
433 % The format of the BlueShiftImage method is:
435 % Image *BlueShiftImage(const Image *image,const double factor,
436 % ExceptionInfo *exception)
438 % A description of each parameter follows:
440 % o image: the image.
442 % o factor: the shift factor.
444 % o exception: return any errors or warnings in this structure.
447 MagickExport Image *BlueShiftImage(const Image *image,const double factor,
448 ExceptionInfo *exception)
450 #define BlueShiftImageTag "BlueShift/Image"
467 Allocate blue shift image.
469 assert(image != (const Image *) NULL);
470 assert(image->signature == MagickSignature);
471 if (image->debug != MagickFalse)
472 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
473 assert(exception != (ExceptionInfo *) NULL);
474 assert(exception->signature == MagickSignature);
475 shift_image=CloneImage(image,image->columns,image->rows,MagickTrue,
477 if (shift_image == (Image *) NULL)
478 return((Image *) NULL);
479 if (SetImageStorageClass(shift_image,DirectClass) == MagickFalse)
481 InheritException(exception,&shift_image->exception);
482 shift_image=DestroyImage(shift_image);
483 return((Image *) NULL);
486 Blue-shift DirectClass image.
490 image_view=AcquireCacheView(image);
491 shift_view=AcquireCacheView(shift_image);
492 #if defined(MAGICKCOREMAGICKCORE_OPENMP_SUPPORT_SUPPORT_DEBUG)
493 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
495 for (y=0; y < (long) image->rows; y++)
506 register const PixelPacket
515 if (status == MagickFalse)
517 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
518 q=QueueCacheViewAuthenticPixels(shift_view,0,y,shift_image->columns,1,
520 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
525 for (x=0; x < (long) image->columns; x++)
528 if (p->green < quantum)
530 if (p->blue < quantum)
532 pixel.red=0.5*(p->red+factor*quantum);
533 pixel.green=0.5*(p->green+factor*quantum);
534 pixel.blue=0.5*(p->blue+factor*quantum);
536 if (p->green > quantum)
538 if (p->blue > quantum)
540 pixel.red=0.5*(pixel.red+factor*quantum);
541 pixel.green=0.5*(pixel.green+factor*quantum);
542 pixel.blue=0.5*(pixel.blue+factor*quantum);
543 q->red=RoundToQuantum(pixel.red);
544 q->green=RoundToQuantum(pixel.green);
545 q->blue=RoundToQuantum(pixel.blue);
549 sync=SyncCacheViewAuthenticPixels(shift_view,exception);
550 if (sync == MagickFalse)
552 if (image->progress_monitor != (MagickProgressMonitor) NULL)
557 #if defined(MAGICKCOREMAGICKCORE_OPENMP_SUPPORT_SUPPORT_DEBUG)
558 #pragma omp critical (MagickCore_BlueShiftImage)
560 proceed=SetImageProgress(image,BlueShiftImageTag,progress++,
562 if (proceed == MagickFalse)
566 image_view=DestroyCacheView(image_view);
567 shift_view=DestroyCacheView(shift_view);
568 if (status == MagickFalse)
569 shift_image=DestroyImage(shift_image);
574 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
578 % C h a r c o a l I m a g e %
582 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
584 % CharcoalImage() creates a new image that is a copy of an existing one with
585 % the edge highlighted. It allocates the memory necessary for the new Image
586 % structure and returns a pointer to the new image.
588 % The format of the CharcoalImage method is:
590 % Image *CharcoalImage(const Image *image,const double radius,
591 % const double sigma,ExceptionInfo *exception)
593 % A description of each parameter follows:
595 % o image: the image.
597 % o radius: the radius of the pixel neighborhood.
599 % o sigma: the standard deviation of the Gaussian, in pixels.
601 % o exception: return any errors or warnings in this structure.
604 MagickExport Image *CharcoalImage(const Image *image,const double radius,
605 const double sigma,ExceptionInfo *exception)
612 assert(image != (Image *) NULL);
613 assert(image->signature == MagickSignature);
614 if (image->debug != MagickFalse)
615 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
616 assert(exception != (ExceptionInfo *) NULL);
617 assert(exception->signature == MagickSignature);
618 clone_image=CloneImage(image,0,0,MagickTrue,exception);
619 if (clone_image == (Image *) NULL)
620 return((Image *) NULL);
621 (void) SetImageType(clone_image,GrayscaleType);
622 edge_image=EdgeImage(clone_image,radius,exception);
623 clone_image=DestroyImage(clone_image);
624 if (edge_image == (Image *) NULL)
625 return((Image *) NULL);
626 charcoal_image=BlurImage(edge_image,radius,sigma,exception);
627 edge_image=DestroyImage(edge_image);
628 if (charcoal_image == (Image *) NULL)
629 return((Image *) NULL);
630 (void) NormalizeImage(charcoal_image);
631 (void) NegateImage(charcoal_image,MagickFalse);
632 (void) SetImageType(charcoal_image,GrayscaleType);
633 return(charcoal_image);
637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
641 % C o l o r i z e I m a g e %
645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
647 % ColorizeImage() blends the fill color with each pixel in the image.
648 % A percentage blend is specified with opacity. Control the application
649 % of different color components by specifying a different percentage for
650 % each component (e.g. 90/100/10 is 90% red, 100% green, and 10% blue).
652 % The format of the ColorizeImage method is:
654 % Image *ColorizeImage(const Image *image,const char *opacity,
655 % const PixelPacket colorize,ExceptionInfo *exception)
657 % A description of each parameter follows:
659 % o image: the image.
661 % o opacity: A character string indicating the level of opacity as a
664 % o colorize: A color value.
666 % o exception: return any errors or warnings in this structure.
669 MagickExport Image *ColorizeImage(const Image *image,const char *opacity,
670 const PixelPacket colorize,ExceptionInfo *exception)
672 #define ColorizeImageTag "Colorize/Image"
698 Allocate colorized image.
700 assert(image != (const Image *) NULL);
701 assert(image->signature == MagickSignature);
702 if (image->debug != MagickFalse)
703 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
704 assert(exception != (ExceptionInfo *) NULL);
705 assert(exception->signature == MagickSignature);
706 colorize_image=CloneImage(image,image->columns,image->rows,MagickTrue,
708 if (colorize_image == (Image *) NULL)
709 return((Image *) NULL);
710 if (SetImageStorageClass(colorize_image,DirectClass) == MagickFalse)
712 InheritException(exception,&colorize_image->exception);
713 colorize_image=DestroyImage(colorize_image);
714 return((Image *) NULL);
716 if (opacity == (const char *) NULL)
717 return(colorize_image);
719 Determine RGB values of the pen color.
721 flags=ParseGeometry(opacity,&geometry_info);
722 pixel.red=geometry_info.rho;
723 pixel.green=geometry_info.rho;
724 pixel.blue=geometry_info.rho;
725 pixel.opacity=(MagickRealType) OpaqueOpacity;
726 if ((flags & SigmaValue) != 0)
727 pixel.green=geometry_info.sigma;
728 if ((flags & XiValue) != 0)
729 pixel.blue=geometry_info.xi;
730 if ((flags & PsiValue) != 0)
731 pixel.opacity=geometry_info.psi;
733 Colorize DirectClass image.
737 image_view=AcquireCacheView(image);
738 colorize_view=AcquireCacheView(colorize_image);
739 #if defined(MAGICKCOREMAGICKCORE_OPENMP_SUPPORT_SUPPORT_DEBUG)
740 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
742 for (y=0; y < (long) image->rows; y++)
747 register const PixelPacket
756 if (status == MagickFalse)
758 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
759 q=QueueCacheViewAuthenticPixels(colorize_view,0,y,colorize_image->columns,1,
761 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
766 for (x=0; x < (long) image->columns; x++)
768 q->red=(Quantum) ((p->red*(100.0-pixel.red)+
769 colorize.red*pixel.red)/100.0);
770 q->green=(Quantum) ((p->green*(100.0-pixel.green)+
771 colorize.green*pixel.green)/100.0);
772 q->blue=(Quantum) ((p->blue*(100.0-pixel.blue)+
773 colorize.blue*pixel.blue)/100.0);
774 q->opacity=(Quantum) ((p->opacity*(100.0-pixel.opacity)+
775 colorize.opacity*pixel.opacity)/100.0);
779 sync=SyncCacheViewAuthenticPixels(colorize_view,exception);
780 if (sync == MagickFalse)
782 if (image->progress_monitor != (MagickProgressMonitor) NULL)
787 #if defined(MAGICKCOREMAGICKCORE_OPENMP_SUPPORT_SUPPORT_DEBUG)
788 #pragma omp critical (MagickCore_ColorizeImage)
790 proceed=SetImageProgress(image,ColorizeImageTag,progress++,image->rows);
791 if (proceed == MagickFalse)
795 image_view=DestroyCacheView(image_view);
796 colorize_view=DestroyCacheView(colorize_view);
797 if (status == MagickFalse)
798 colorize_image=DestroyImage(colorize_image);
799 return(colorize_image);
803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
807 % C o n v o l v e I m a g e %
811 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
813 % ConvolveImage() applies a custom convolution kernel to the image.
815 % The format of the ConvolveImage method is:
817 % Image *ConvolveImage(const Image *image,const unsigned long order,
818 % const double *kernel,ExceptionInfo *exception)
819 % Image *ConvolveImageChannel(const Image *image,const ChannelType channel,
820 % const unsigned long order,const double *kernel,
821 % ExceptionInfo *exception)
823 % A description of each parameter follows:
825 % o image: the image.
827 % o channel: the channel type.
829 % o order: the number of columns and rows in the filter kernel.
831 % o kernel: An array of double representing the convolution kernel.
833 % o exception: return any errors or warnings in this structure.
837 MagickExport Image *ConvolveImage(const Image *image,const unsigned long order,
838 const double *kernel,ExceptionInfo *exception)
843 convolve_image=ConvolveImageChannel(image,DefaultChannels,order,kernel,
845 return(convolve_image);
848 MagickExport Image *ConvolveImageChannel(const Image *image,
849 const ChannelType channel,const unsigned long order,const double *kernel,
850 ExceptionInfo *exception)
852 #define ConvolveImageTag "Convolve/Image"
884 Initialize convolve image attributes.
886 assert(image != (Image *) NULL);
887 assert(image->signature == MagickSignature);
888 if (image->debug != MagickFalse)
889 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
890 assert(exception != (ExceptionInfo *) NULL);
891 assert(exception->signature == MagickSignature);
893 if ((width % 2) == 0)
894 ThrowImageException(OptionError,"KernelWidthMustBeAnOddNumber");
895 convolve_image=CloneImage(image,0,0,MagickTrue,exception);
896 if (convolve_image == (Image *) NULL)
897 return((Image *) NULL);
898 if (SetImageStorageClass(convolve_image,DirectClass) == MagickFalse)
900 InheritException(exception,&convolve_image->exception);
901 convolve_image=DestroyImage(convolve_image);
902 return((Image *) NULL);
904 if (image->debug != MagickFalse)
907 format[MaxTextExtent],
914 register const double
917 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
918 " ConvolveImage with %ldx%ld kernel:",width,width);
919 message=AcquireString("");
921 for (v=0; v < (long) width; v++)
924 (void) FormatMagickString(format,MaxTextExtent,"%ld: ",v);
925 (void) ConcatenateString(&message,format);
926 for (u=0; u < (long) width; u++)
928 (void) FormatMagickString(format,MaxTextExtent,"%+f ",*k++);
929 (void) ConcatenateString(&message,format);
931 (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
933 message=DestroyString(message);
938 normal_kernel=(double *) AcquireQuantumMemory(width*width,
939 sizeof(*normal_kernel));
940 if (normal_kernel == (double *) NULL)
942 convolve_image=DestroyImage(convolve_image);
943 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
946 for (i=0; i < (long) (width*width); i++)
948 gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
949 for (i=0; i < (long) (width*width); i++)
950 normal_kernel[i]=gamma*kernel[i];
956 GetMagickPixelPacket(image,&bias);
957 SetMagickPixelPacketBias(image,&bias);
958 image_view=AcquireCacheView(image);
959 convolve_view=AcquireCacheView(convolve_image);
960 #if defined(MAGICKCORE_OPENMP_SUPPORT)
961 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
963 for (y=0; y < (long) image->rows; y++)
968 register const IndexPacket
971 register const PixelPacket
975 *__restrict convolve_indexes;
983 if (status == MagickFalse)
985 p=GetCacheViewVirtualPixels(image_view,-((long) width/2L),y-(long) (width/
986 2L),image->columns+width,width,exception);
987 q=GetCacheViewAuthenticPixels(convolve_view,0,y,convolve_image->columns,1,
989 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
994 indexes=GetCacheViewVirtualIndexQueue(image_view);
995 convolve_indexes=GetCacheViewAuthenticIndexQueue(convolve_view);
996 for (x=0; x < (long) image->columns; x++)
1004 register const double
1007 register const PixelPacket
1008 *__restrict kernel_pixels;
1016 if (((channel & OpacityChannel) == 0) || (image->matte == MagickFalse))
1018 for (v=0; v < (long) width; v++)
1020 for (u=0; u < (long) width; u++)
1022 pixel.red+=(*k)*kernel_pixels[u].red;
1023 pixel.green+=(*k)*kernel_pixels[u].green;
1024 pixel.blue+=(*k)*kernel_pixels[u].blue;
1027 kernel_pixels+=image->columns+width;
1029 if ((channel & RedChannel) != 0)
1030 q->red=RoundToQuantum(pixel.red);
1031 if ((channel & GreenChannel) != 0)
1032 q->green=RoundToQuantum(pixel.green);
1033 if ((channel & BlueChannel) != 0)
1034 q->blue=RoundToQuantum(pixel.blue);
1035 if ((channel & OpacityChannel) != 0)
1039 for (v=0; v < (long) width; v++)
1041 for (u=0; u < (long) width; u++)
1043 pixel.opacity+=(*k)*kernel_pixels[u].opacity;
1046 kernel_pixels+=image->columns+width;
1048 q->opacity=RoundToQuantum(pixel.opacity);
1050 if (((channel & IndexChannel) != 0) &&
1051 (image->colorspace == CMYKColorspace))
1053 register const IndexPacket
1054 *__restrict kernel_indexes;
1057 kernel_indexes=indexes;
1058 for (v=0; v < (long) width; v++)
1060 for (u=0; u < (long) width; u++)
1062 pixel.index+=(*k)*kernel_indexes[u];
1065 kernel_indexes+=image->columns+width;
1067 convolve_indexes[x]=RoundToQuantum(pixel.index);
1077 for (v=0; v < (long) width; v++)
1079 for (u=0; u < (long) width; u++)
1081 alpha=(MagickRealType) (QuantumScale*(QuantumRange-
1082 kernel_pixels[u].opacity));
1083 pixel.red+=(*k)*alpha*kernel_pixels[u].red;
1084 pixel.green+=(*k)*alpha*kernel_pixels[u].green;
1085 pixel.blue+=(*k)*alpha*kernel_pixels[u].blue;
1086 pixel.opacity+=(*k)*kernel_pixels[u].opacity;
1090 kernel_pixels+=image->columns+width;
1092 gamma=1.0/(fabs((double) gamma) <= MagickEpsilon ? 1.0 : gamma);
1093 if ((channel & RedChannel) != 0)
1094 q->red=RoundToQuantum(gamma*pixel.red);
1095 if ((channel & GreenChannel) != 0)
1096 q->green=RoundToQuantum(gamma*pixel.green);
1097 if ((channel & BlueChannel) != 0)
1098 q->blue=RoundToQuantum(gamma*pixel.blue);
1099 if ((channel & OpacityChannel) != 0)
1103 for (v=0; v < (long) width; v++)
1105 for (u=0; u < (long) width; u++)
1107 pixel.opacity+=(*k)*kernel_pixels[u].opacity;
1110 kernel_pixels+=image->columns+width;
1112 q->opacity=RoundToQuantum(pixel.opacity);
1114 if (((channel & IndexChannel) != 0) &&
1115 (image->colorspace == CMYKColorspace))
1117 register const IndexPacket
1118 *__restrict kernel_indexes;
1122 kernel_indexes=indexes;
1123 for (v=0; v < (long) width; v++)
1125 for (u=0; u < (long) width; u++)
1127 alpha=(MagickRealType) (QuantumScale*(QuantumRange-
1128 kernel_pixels[u].opacity));
1129 pixel.index+=(*k)*alpha*kernel_indexes[u];
1132 kernel_pixels+=image->columns+width;
1133 kernel_indexes+=image->columns+width;
1135 convolve_indexes[x]=RoundToQuantum(gamma*pixel.index);
1141 sync=SyncCacheViewAuthenticPixels(convolve_view,exception);
1142 if (sync == MagickFalse)
1144 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1149 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1150 #pragma omp critical (MagickCore_ConvolveImageChannel)
1152 proceed=SetImageProgress(image,ConvolveImageTag,progress++,image->rows);
1153 if (proceed == MagickFalse)
1157 convolve_image->type=image->type;
1158 convolve_view=DestroyCacheView(convolve_view);
1159 image_view=DestroyCacheView(image_view);
1160 normal_kernel=(double *) RelinquishMagickMemory(normal_kernel);
1161 if (status == MagickFalse)
1162 convolve_image=DestroyImage(convolve_image);
1163 return(convolve_image);
1167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1171 + D e s t r o y F x I n f o %
1175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1177 % DestroyFxInfo() deallocates memory associated with an FxInfo structure.
1179 % The format of the DestroyFxInfo method is:
1181 % ImageInfo *DestroyFxInfo(ImageInfo *fx_info)
1183 % A description of each parameter follows:
1185 % o fx_info: the fx info.
1188 MagickExport FxInfo *DestroyFxInfo(FxInfo *fx_info)
1193 fx_info->exception=DestroyExceptionInfo(fx_info->exception);
1194 fx_info->expression=DestroyString(fx_info->expression);
1195 fx_info->symbols=DestroySplayTree(fx_info->symbols);
1196 fx_info->colors=DestroySplayTree(fx_info->colors);
1197 for (i=0; i < (long) GetImageListLength(fx_info->images); i++)
1198 fx_info->resample_filter[i]=DestroyResampleFilter(
1199 fx_info->resample_filter[i]);
1200 fx_info->resample_filter=(ResampleFilter **) RelinquishMagickMemory(
1201 fx_info->resample_filter);
1202 fx_info->random_info=DestroyRandomInfo(fx_info->random_info);
1203 fx_info=(FxInfo *) RelinquishMagickMemory(fx_info);
1208 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1212 % E v a l u a t e I m a g e %
1216 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1218 % EvaluateImage() applies a value to the image with an arithmetic, relational,
1219 % or logical operator to an image. Use these operations to lighten or darken
1220 % an image, to increase or decrease contrast in an image, or to produce the
1221 % "negative" of an image.
1223 % The format of the EvaluateImageChannel method is:
1225 % MagickBooleanType EvaluateImage(Image *image,
1226 % const MagickEvaluateOperator op,const double value,
1227 % ExceptionInfo *exception)
1228 % MagickBooleanType EvaluateImageChannel(Image *image,
1229 % const ChannelType channel,const MagickEvaluateOperator op,
1230 % const double value,ExceptionInfo *exception)
1232 % A description of each parameter follows:
1234 % o image: the image.
1236 % o channel: the channel.
1238 % o op: A channel op.
1240 % o value: A value value.
1242 % o exception: return any errors or warnings in this structure.
1246 static inline double MagickMax(const double x,const double y)
1253 static inline double MagickMin(const double x,const double y)
1260 static Quantum ApplyEvaluateOperator(RandomInfo *random_info,Quantum pixel,
1261 const MagickEvaluateOperator op,const MagickRealType value)
1269 case UndefinedEvaluateOperator:
1271 case AddEvaluateOperator:
1273 result=(MagickRealType) (pixel+value);
1276 case AddModulusEvaluateOperator:
1278 /* This will return a 'floored modulus' of the addition which will
1279 * always return a positive result, regardless of if the result is
1280 * positive or negative, and thus in the 0 to QuantumRange range.
1282 * WARNING: this is NOT the same as a % or fmod() which returns a
1283 * 'truncated modulus' result, where floor() is replaced by trunc()
1284 * and could return a negative result, which will be clipped.
1286 result = pixel+value;
1287 result -= (QuantumRange+1)*floor(result/(QuantumRange+1));
1290 case AndEvaluateOperator:
1292 result=(MagickRealType) ((unsigned long) pixel & (unsigned long)
1296 case CosineEvaluateOperator:
1298 result=(MagickRealType) (QuantumRange*(0.5*cos((double) (2.0*MagickPI*
1299 QuantumScale*pixel*value))+0.5));
1302 case DivideEvaluateOperator:
1304 result=pixel/(value == 0.0 ? 1.0 : value);
1307 case GaussianNoiseEvaluateOperator:
1309 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
1310 GaussianNoise,value);
1313 case ImpulseNoiseEvaluateOperator:
1315 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
1316 ImpulseNoise,value);
1319 case LaplacianNoiseEvaluateOperator:
1321 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
1322 LaplacianNoise,value);
1325 case LeftShiftEvaluateOperator:
1327 result=(MagickRealType) ((unsigned long) pixel << (unsigned long)
1331 case LogEvaluateOperator:
1333 result=(MagickRealType) (QuantumRange*log((double) (QuantumScale*value*
1334 pixel+1.0))/log((double) (value+1.0)));
1337 case MaxEvaluateOperator:
1339 result=(MagickRealType) MagickMax((double) pixel,value);
1342 case MinEvaluateOperator:
1344 result=(MagickRealType) MagickMin((double) pixel,value);
1347 case MultiplicativeNoiseEvaluateOperator:
1349 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
1350 MultiplicativeGaussianNoise,value);
1353 case MultiplyEvaluateOperator:
1355 result=(MagickRealType) (value*pixel);
1358 case OrEvaluateOperator:
1360 result=(MagickRealType) ((unsigned long) pixel | (unsigned long)
1364 case PoissonNoiseEvaluateOperator:
1366 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
1367 PoissonNoise,value);
1370 case PowEvaluateOperator:
1372 result=(MagickRealType) (QuantumRange*pow((double) (QuantumScale*pixel),
1376 case RightShiftEvaluateOperator:
1378 result=(MagickRealType) ((unsigned long) pixel >> (unsigned long)
1382 case SetEvaluateOperator:
1387 case SineEvaluateOperator:
1389 result=(MagickRealType) (QuantumRange*(0.5*sin((double) (2.0*MagickPI*
1390 QuantumScale*pixel*value))+0.5));
1393 case SubtractEvaluateOperator:
1395 result=(MagickRealType) (pixel-value);
1398 case ThresholdEvaluateOperator:
1400 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 :
1404 case ThresholdBlackEvaluateOperator:
1406 result=(MagickRealType) (((MagickRealType) pixel <= value) ? 0 : pixel);
1409 case ThresholdWhiteEvaluateOperator:
1411 result=(MagickRealType) (((MagickRealType) pixel > value) ? QuantumRange :
1415 case UniformNoiseEvaluateOperator:
1417 result=(MagickRealType) GenerateDifferentialNoise(random_info,pixel,
1418 UniformNoise,value);
1421 case XorEvaluateOperator:
1423 result=(MagickRealType) ((unsigned long) pixel ^ (unsigned long)
1428 return(RoundToQuantum(result));
1431 MagickExport MagickBooleanType EvaluateImage(Image *image,
1432 const MagickEvaluateOperator op,const double value,ExceptionInfo *exception)
1437 status=EvaluateImageChannel(image,AllChannels,op,value,exception);
1441 MagickExport MagickBooleanType EvaluateImageChannel(Image *image,
1442 const ChannelType channel,const MagickEvaluateOperator op,const double value,
1443 ExceptionInfo *exception)
1445 #define EvaluateImageTag "Evaluate/Image "
1460 assert(image != (Image *) NULL);
1461 assert(image->signature == MagickSignature);
1462 if (image->debug != MagickFalse)
1463 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1464 assert(exception != (ExceptionInfo *) NULL);
1465 assert(exception->signature == MagickSignature);
1466 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1468 InheritException(exception,&image->exception);
1469 return(MagickFalse);
1473 random_info=AcquireRandomInfoThreadSet();
1474 image_view=AcquireCacheView(image);
1475 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1476 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1478 for (y=0; y < (long) image->rows; y++)
1480 register IndexPacket
1481 *__restrict indexes;
1487 register PixelPacket
1490 if (status == MagickFalse)
1492 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1493 if (q == (PixelPacket *) NULL)
1498 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1499 id=GetOpenMPThreadId();
1500 for (x=0; x < (long) image->columns; x++)
1502 if ((channel & RedChannel) != 0)
1503 q->red=ApplyEvaluateOperator(random_info[id],q->red,op,value);
1504 if ((channel & GreenChannel) != 0)
1505 q->green=ApplyEvaluateOperator(random_info[id],q->green,op,value);
1506 if ((channel & BlueChannel) != 0)
1507 q->blue=ApplyEvaluateOperator(random_info[id],q->blue,op,value);
1508 if ((channel & OpacityChannel) != 0)
1510 if (image->matte == MagickFalse)
1511 q->opacity=ApplyEvaluateOperator(random_info[id],q->opacity,op,
1514 q->opacity=(Quantum) QuantumRange-ApplyEvaluateOperator(
1515 random_info[id],(Quantum) (QuantumRange-q->opacity),op,value);
1517 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
1518 indexes[x]=(IndexPacket) ApplyEvaluateOperator(random_info[id],
1519 indexes[x],op,value);
1522 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1524 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1529 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1530 #pragma omp critical (MagickCore_EvaluateImageChannel)
1532 proceed=SetImageProgress(image,EvaluateImageTag,progress++,image->rows);
1533 if (proceed == MagickFalse)
1537 image_view=DestroyCacheView(image_view);
1538 random_info=DestroyRandomInfoThreadSet(random_info);
1543 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1547 % F u n c t i o n I m a g e %
1551 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1553 % FunctionImage() applies a value to the image with an arithmetic, relational,
1554 % or logical operator to an image. Use these operations to lighten or darken
1555 % an image, to increase or decrease contrast in an image, or to produce the
1556 % "negative" of an image.
1558 % The format of the FunctionImageChannel method is:
1560 % MagickBooleanType FunctionImage(Image *image,
1561 % const MagickFunction function,const long number_parameters,
1562 % const double *parameters,ExceptionInfo *exception)
1563 % MagickBooleanType FunctionImageChannel(Image *image,
1564 % const ChannelType channel,const MagickFunction function,
1565 % const long number_parameters,const double *argument,
1566 % ExceptionInfo *exception)
1568 % A description of each parameter follows:
1570 % o image: the image.
1572 % o channel: the channel.
1574 % o function: A channel function.
1576 % o parameters: one or more parameters.
1578 % o exception: return any errors or warnings in this structure.
1582 static Quantum ApplyFunction(Quantum pixel,const MagickFunction function,
1583 const unsigned long number_parameters,const double *parameters,
1584 ExceptionInfo *exception)
1596 case PolynomialFunction:
1600 * Parameters: polynomial constants, highest to lowest order
1601 * For example: c0*x^3 + c1*x^2 + c2*x + c3
1604 for (i=0; i < (long) number_parameters; i++)
1605 result = result*QuantumScale*pixel + parameters[i];
1606 result *= QuantumRange;
1609 case SinusoidFunction:
1611 /* Sinusoid Function
1612 * Parameters: Freq, Phase, Ampl, bias
1614 double freq,phase,ampl,bias;
1615 freq = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
1616 phase = ( number_parameters >= 2 ) ? parameters[1] : 0.0;
1617 ampl = ( number_parameters >= 3 ) ? parameters[2] : 0.5;
1618 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
1619 result=(MagickRealType) (QuantumRange*(ampl*sin((double) (2.0*MagickPI*
1620 (freq*QuantumScale*pixel + phase/360.0) )) + bias ) );
1623 case ArcsinFunction:
1625 /* Arcsin Function (peged at range limits for invalid results)
1626 * Parameters: Width, Center, Range, Bias
1628 double width,range,center,bias;
1629 width = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
1630 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
1631 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
1632 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
1633 result = 2.0/width*(QuantumScale*pixel - center);
1634 if ( result <= -1.0 )
1635 result = bias - range/2.0;
1636 else if ( result >= 1.0 )
1637 result = bias + range/2.0;
1639 result=range/MagickPI*asin((double)result) + bias;
1640 result *= QuantumRange;
1643 case ArctanFunction:
1646 * Parameters: Slope, Center, Range, Bias
1648 double slope,range,center,bias;
1649 slope = ( number_parameters >= 1 ) ? parameters[0] : 1.0;
1650 center = ( number_parameters >= 2 ) ? parameters[1] : 0.5;
1651 range = ( number_parameters >= 3 ) ? parameters[2] : 1.0;
1652 bias = ( number_parameters >= 4 ) ? parameters[3] : 0.5;
1653 result = MagickPI*slope*(QuantumScale*pixel - center);
1654 result=(MagickRealType) (QuantumRange*(range/MagickPI*atan((double)
1658 case UndefinedFunction:
1661 return(RoundToQuantum(result));
1664 MagickExport MagickBooleanType FunctionImage(Image *image,
1665 const MagickFunction function,const unsigned long number_parameters,
1666 const double *parameters,ExceptionInfo *exception)
1671 status=FunctionImageChannel(image,AllChannels,function,number_parameters,
1672 parameters,exception);
1676 MagickExport MagickBooleanType FunctionImageChannel(Image *image,
1677 const ChannelType channel,const MagickFunction function,
1678 const unsigned long number_parameters,const double *parameters,
1679 ExceptionInfo *exception)
1681 #define FunctionImageTag "Function/Image "
1693 assert(image != (Image *) NULL);
1694 assert(image->signature == MagickSignature);
1695 if (image->debug != MagickFalse)
1696 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1697 assert(exception != (ExceptionInfo *) NULL);
1698 assert(exception->signature == MagickSignature);
1699 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
1701 InheritException(exception,&image->exception);
1702 return(MagickFalse);
1706 image_view=AcquireCacheView(image);
1707 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1708 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
1710 for (y=0; y < (long) image->rows; y++)
1712 register IndexPacket
1713 *__restrict indexes;
1718 register PixelPacket
1721 if (status == MagickFalse)
1723 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
1724 if (q == (PixelPacket *) NULL)
1729 indexes=GetCacheViewAuthenticIndexQueue(image_view);
1730 for (x=0; x < (long) image->columns; x++)
1732 if ((channel & RedChannel) != 0)
1733 q->red=ApplyFunction(q->red,function,number_parameters,parameters,
1735 if ((channel & GreenChannel) != 0)
1736 q->green=ApplyFunction(q->green,function,number_parameters,parameters,
1738 if ((channel & BlueChannel) != 0)
1739 q->blue=ApplyFunction(q->blue,function,number_parameters,parameters,
1741 if ((channel & OpacityChannel) != 0)
1743 if (image->matte == MagickFalse)
1744 q->opacity=ApplyFunction(q->opacity,function,number_parameters,
1745 parameters,exception);
1747 q->opacity=(Quantum) QuantumRange-ApplyFunction((Quantum) (
1748 QuantumRange-q->opacity),function,number_parameters,parameters,
1751 if (((channel & IndexChannel) != 0) && (indexes != (IndexPacket *) NULL))
1752 indexes[x]=(IndexPacket) ApplyFunction(indexes[x],function,
1753 number_parameters,parameters,exception);
1756 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
1758 if (image->progress_monitor != (MagickProgressMonitor) NULL)
1763 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1764 #pragma omp critical (MagickCore_FunctionImageChannel)
1766 proceed=SetImageProgress(image,FunctionImageTag,progress++,image->rows);
1767 if (proceed == MagickFalse)
1771 image_view=DestroyCacheView(image_view);
1776 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1780 + F x E v a l u a t e C h a n n e l E x p r e s s i o n %
1784 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1786 % FxEvaluateChannelExpression() evaluates an expression and returns the
1789 % The format of the FxEvaluateExpression method is:
1791 % MagickRealType FxEvaluateChannelExpression(FxInfo *fx_info,
1792 % const ChannelType channel,const long x,const long y,
1793 % MagickRealType *alpha,Exceptioninfo *exception)
1794 % MagickRealType FxEvaluateExpression(FxInfo *fx_info,
1795 % MagickRealType *alpha,Exceptioninfo *exception)
1797 % A description of each parameter follows:
1799 % o fx_info: the fx info.
1801 % o channel: the channel.
1803 % o x,y: the pixel position.
1805 % o alpha: the result.
1807 % o exception: return any errors or warnings in this structure.
1811 static MagickRealType FxChannelStatistics(FxInfo *fx_info,const Image *image,
1812 ChannelType channel,const char *symbol,ExceptionInfo *exception)
1816 statistic[MaxTextExtent];
1824 for (p=symbol; (*p != '.') && (*p != '\0'); p++) ;
1826 switch (*++p) /* e.g. depth.r */
1828 case 'r': channel=RedChannel; break;
1829 case 'g': channel=GreenChannel; break;
1830 case 'b': channel=BlueChannel; break;
1831 case 'c': channel=CyanChannel; break;
1832 case 'm': channel=MagentaChannel; break;
1833 case 'y': channel=YellowChannel; break;
1834 case 'k': channel=BlackChannel; break;
1837 (void) FormatMagickString(key,MaxTextExtent,"%p.%ld.%s",image,(long) channel,
1839 value=(const char *) GetValueFromSplayTree(fx_info->symbols,key);
1840 if (value != (const char *) NULL)
1841 return(QuantumScale*atof(value));
1842 (void) DeleteNodeFromSplayTree(fx_info->symbols,key);
1843 if (LocaleNCompare(symbol,"depth",5) == 0)
1848 depth=GetImageChannelDepth(image,channel,exception);
1849 (void) FormatMagickString(statistic,MaxTextExtent,"%lu",depth);
1851 if (LocaleNCompare(symbol,"kurtosis",8) == 0)
1857 (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
1859 (void) FormatMagickString(statistic,MaxTextExtent,"%g",kurtosis);
1861 if (LocaleNCompare(symbol,"maxima",6) == 0)
1867 (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
1868 (void) FormatMagickString(statistic,MaxTextExtent,"%g",maxima);
1870 if (LocaleNCompare(symbol,"mean",4) == 0)
1876 (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
1878 (void) FormatMagickString(statistic,MaxTextExtent,"%g",mean);
1880 if (LocaleNCompare(symbol,"minima",6) == 0)
1886 (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
1887 (void) FormatMagickString(statistic,MaxTextExtent,"%g",minima);
1889 if (LocaleNCompare(symbol,"skewness",8) == 0)
1895 (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
1897 (void) FormatMagickString(statistic,MaxTextExtent,"%g",skewness);
1899 if (LocaleNCompare(symbol,"standard_deviation",18) == 0)
1905 (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
1907 (void) FormatMagickString(statistic,MaxTextExtent,"%g",
1908 standard_deviation);
1910 (void) AddValueToSplayTree(fx_info->symbols,ConstantString(key),
1911 ConstantString(statistic));
1912 return(QuantumScale*atof(statistic));
1915 static MagickRealType
1916 FxEvaluateSubexpression(FxInfo *,const ChannelType,const long,const long,
1917 const char *,MagickRealType *,ExceptionInfo *);
1919 static inline MagickRealType FxMax(FxInfo *fx_info,const ChannelType channel,
1920 const long x,const long y,const char *expression,ExceptionInfo *exception)
1926 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression,&beta,exception);
1927 return((MagickRealType) MagickMax((double) alpha,(double) beta));
1930 static inline MagickRealType FxMin(FxInfo *fx_info,ChannelType channel,
1931 const long x,const long y,const char *expression,ExceptionInfo *exception)
1937 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression,&beta,exception);
1938 return((MagickRealType) MagickMin((double) alpha,(double) beta));
1941 static inline const char *FxSubexpression(const char *expression,
1942 ExceptionInfo *exception)
1951 subexpression=expression;
1952 while ((*subexpression != '\0') &&
1953 ((level != 1) || (strchr(")",(int) *subexpression) == (char *) NULL)))
1955 if (strchr("(",(int) *subexpression) != (char *) NULL)
1958 if (strchr(")",(int) *subexpression) != (char *) NULL)
1962 if (*subexpression == '\0')
1963 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1964 "UnbalancedParenthesis","`%s'",expression);
1965 return(subexpression);
1968 static MagickRealType FxGetSymbol(FxInfo *fx_info,const ChannelType channel,
1969 const long x,const long y,const char *expression,ExceptionInfo *exception)
1973 subexpression[MaxTextExtent],
1974 symbol[MaxTextExtent];
2003 i=GetImageIndexInList(fx_info->images);
2007 if (isalpha((int) *(p+1)) == 0)
2009 if (strchr("suv",(int) *p) != (char *) NULL)
2016 i=GetImageIndexInList(fx_info->images);
2019 case 'u': i=0; break;
2020 case 'v': i=1; break;
2027 for (p++; *p != '\0'; )
2041 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
2043 i=(long) (alpha+0.5);
2049 if ((isalpha((int) *(p+1)) == 0) && (*p == 'p'))
2056 for (p++; *p != '\0'; )
2070 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
2081 for (p++; *p != '\0'; )
2095 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
2105 length=GetImageListLength(fx_info->images);
2109 image=GetImageFromList(fx_info->images,i);
2110 if (image == (Image *) NULL)
2112 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2113 "NoSuchImage","`%s'",expression);
2116 (void) ResamplePixelColor(fx_info->resample_filter[i],point.x,point.y,&pixel);
2117 if ((strlen(p) > 2) &&
2118 (LocaleCompare(p,"intensity") != 0) &&
2119 (LocaleCompare(p,"luminance") != 0) &&
2120 (LocaleCompare(p,"hue") != 0) &&
2121 (LocaleCompare(p,"saturation") != 0) &&
2122 (LocaleCompare(p,"lightness") != 0))
2125 name[MaxTextExtent];
2127 (void) CopyMagickString(name,p,MaxTextExtent);
2128 for (q=name+(strlen(name)-1); q > name; q--)
2138 if ((strlen(name) > 2) &&
2139 (GetValueFromSplayTree(fx_info->symbols,name) == (const char *) NULL))
2144 color=(MagickPixelPacket *) GetValueFromSplayTree(fx_info->colors,
2146 if (color != (MagickPixelPacket *) NULL)
2152 if (QueryMagickColor(name,&pixel,fx_info->exception) != MagickFalse)
2154 (void) AddValueToSplayTree(fx_info->colors,ConstantString(name),
2155 CloneMagickPixelPacket(&pixel));
2160 (void) CopyMagickString(symbol,p,MaxTextExtent);
2161 StripString(symbol);
2162 if (*symbol == '\0')
2166 case RedChannel: return(QuantumScale*pixel.red);
2167 case GreenChannel: return(QuantumScale*pixel.green);
2168 case BlueChannel: return(QuantumScale*pixel.blue);
2169 case OpacityChannel:
2171 if (pixel.matte == MagickFalse)
2173 fx_info->matte=MagickFalse;
2176 return((MagickRealType) (QuantumScale*(QuantumRange-pixel.opacity)));
2180 if (image->colorspace != CMYKColorspace)
2182 (void) ThrowMagickException(exception,GetMagickModule(),
2183 OptionError,"ColorSeparatedImageRequired","`%s'",
2187 return(QuantumScale*pixel.index);
2192 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2193 "UnableToParseExpression","`%s'",p);
2201 if (LocaleCompare(symbol,"a") == 0)
2202 return((MagickRealType) (QuantumScale*(QuantumRange-pixel.opacity)));
2208 if (LocaleCompare(symbol,"b") == 0)
2209 return(QuantumScale*pixel.blue);
2215 if (LocaleNCompare(symbol,"channel",7) == 0)
2223 flags=ParseGeometry(symbol+7,&channel_info);
2224 if (image->colorspace == CMYKColorspace)
2229 if ((flags & RhoValue) == 0)
2231 return(channel_info.rho);
2233 case MagentaChannel:
2235 if ((flags & SigmaValue) == 0)
2237 return(channel_info.sigma);
2241 if ((flags & XiValue) == 0)
2243 return(channel_info.xi);
2247 if ((flags & PsiValue) == 0)
2249 return(channel_info.psi);
2251 case OpacityChannel:
2253 if ((flags & ChiValue) == 0)
2255 return(channel_info.chi);
2264 if ((flags & RhoValue) == 0)
2266 return(channel_info.rho);
2270 if ((flags & SigmaValue) == 0)
2272 return(channel_info.sigma);
2276 if ((flags & XiValue) == 0)
2278 return(channel_info.xi);
2280 case OpacityChannel:
2282 if ((flags & PsiValue) == 0)
2284 return(channel_info.psi);
2288 if ((flags & ChiValue) == 0)
2290 return(channel_info.chi);
2297 if (LocaleCompare(symbol,"c") == 0)
2298 return(QuantumScale*pixel.red);
2304 if (LocaleNCompare(symbol,"depth",5) == 0)
2305 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
2311 if (LocaleCompare(symbol,"g") == 0)
2312 return(QuantumScale*pixel.green);
2318 if (LocaleNCompare(symbol,"kurtosis",8) == 0)
2319 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
2320 if (LocaleCompare(symbol,"k") == 0)
2322 if (image->colorspace != CMYKColorspace)
2324 (void) ThrowMagickException(exception,GetMagickModule(),
2325 OptionError,"ColorSeparatedImageRequired","`%s'",
2329 return(QuantumScale*pixel.index);
2336 if (LocaleCompare(symbol,"h") == 0)
2337 return((MagickRealType) image->rows);
2338 if (LocaleCompare(symbol,"hue") == 0)
2345 ConvertRGBToHSL(RoundToQuantum(pixel.red),RoundToQuantum(pixel.green),
2346 RoundToQuantum(pixel.blue),&hue,&saturation,&lightness);
2354 if ((LocaleCompare(symbol,"image.depth") == 0) ||
2355 (LocaleCompare(symbol,"image.minima") == 0) ||
2356 (LocaleCompare(symbol,"image.maxima") == 0) ||
2357 (LocaleCompare(symbol,"image.mean") == 0) ||
2358 (LocaleCompare(symbol,"image.kurtosis") == 0) ||
2359 (LocaleCompare(symbol,"image.skewness") == 0) ||
2360 (LocaleCompare(symbol,"image.standard_deviation") == 0))
2361 return(FxChannelStatistics(fx_info,image,channel,symbol+6,exception));
2362 if (LocaleCompare(symbol,"image.resolution.x") == 0)
2363 return(image->x_resolution);
2364 if (LocaleCompare(symbol,"image.resolution.y") == 0)
2365 return(image->y_resolution);
2366 if (LocaleCompare(symbol,"intensity") == 0)
2367 return(QuantumScale*MagickPixelIntensityToQuantum(&pixel));
2368 if (LocaleCompare(symbol,"i") == 0)
2369 return((MagickRealType) x);
2375 if (LocaleCompare(symbol,"j") == 0)
2376 return((MagickRealType) y);
2382 if (LocaleCompare(symbol,"lightness") == 0)
2389 ConvertRGBToHSL(RoundToQuantum(pixel.red),RoundToQuantum(pixel.green),
2390 RoundToQuantum(pixel.blue),&hue,&saturation,&lightness);
2393 if (LocaleCompare(symbol,"luminance") == 0)
2398 luminence=0.2126*pixel.red+0.7152*pixel.green+0.0722*pixel.blue;
2399 return(QuantumScale*luminence);
2406 if (LocaleNCompare(symbol,"maxima",6) == 0)
2407 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
2408 if (LocaleNCompare(symbol,"mean",4) == 0)
2409 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
2410 if (LocaleNCompare(symbol,"minima",6) == 0)
2411 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
2412 if (LocaleCompare(symbol,"m") == 0)
2413 return(QuantumScale*pixel.blue);
2419 if (LocaleCompare(symbol,"n") == 0)
2420 return((MagickRealType) GetImageListLength(fx_info->images));
2426 if (LocaleCompare(symbol,"o") == 0)
2427 return(QuantumScale*pixel.opacity);
2433 if (LocaleCompare(symbol,"page.height") == 0)
2434 return((MagickRealType) image->page.height);
2435 if (LocaleCompare(symbol,"page.width") == 0)
2436 return((MagickRealType) image->page.width);
2437 if (LocaleCompare(symbol,"page.x") == 0)
2438 return((MagickRealType) image->page.x);
2439 if (LocaleCompare(symbol,"page.y") == 0)
2440 return((MagickRealType) image->page.y);
2446 if (LocaleCompare(symbol,"resolution.x") == 0)
2447 return(image->x_resolution);
2448 if (LocaleCompare(symbol,"resolution.y") == 0)
2449 return(image->y_resolution);
2450 if (LocaleCompare(symbol,"r") == 0)
2451 return(QuantumScale*pixel.red);
2457 if (LocaleCompare(symbol,"saturation") == 0)
2464 ConvertRGBToHSL(RoundToQuantum(pixel.red),RoundToQuantum(pixel.green),
2465 RoundToQuantum(pixel.blue),&hue,&saturation,&lightness);
2468 if (LocaleNCompare(symbol,"skewness",8) == 0)
2469 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
2470 if (LocaleNCompare(symbol,"standard_deviation",18) == 0)
2471 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
2477 if (LocaleCompare(symbol,"t") == 0)
2478 return((MagickRealType) fx_info->images->scene);
2484 if (LocaleCompare(symbol,"w") == 0)
2485 return((MagickRealType) image->columns);
2491 if (LocaleCompare(symbol,"y") == 0)
2492 return(QuantumScale*pixel.green);
2498 if (LocaleCompare(symbol,"z") == 0)
2503 depth=(MagickRealType) GetImageChannelDepth(image,channel,
2504 fx_info->exception);
2512 value=(const char *) GetValueFromSplayTree(fx_info->symbols,symbol);
2513 if (value != (const char *) NULL)
2514 return((MagickRealType) atof(value));
2515 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2516 "UnableToParseExpression","`%s'",symbol);
2520 static const char *FxOperatorPrecedence(const char *expression,
2521 ExceptionInfo *exception)
2525 UndefinedPrecedence,
2527 BitwiseComplementPrecedence,
2532 RelationalPrecedence,
2533 EquivalencyPrecedence,
2534 BitwiseAndPrecedence,
2535 BitwiseOrPrecedence,
2536 LogicalAndPrecedence,
2537 LogicalOrPrecedence,
2539 AssignmentPrecedence,
2559 subexpression=(const char *) NULL;
2560 target=NullPrecedence;
2561 while (*expression != '\0')
2563 precedence=UndefinedPrecedence;
2564 if ((isspace((int) ((char) *expression)) != 0) || (c == (int) '@'))
2569 if (LocaleNCompare(expression,"atan2",5) == 0)
2574 if ((c == (int) '{') || (c == (int) '['))
2577 if ((c == (int) '}') || (c == (int) ']'))
2580 switch ((unsigned char) *expression)
2585 precedence=BitwiseComplementPrecedence;
2590 precedence=ExponentPrecedence;
2595 if (((c != 0) && ((isdigit((int) ((char) c)) != 0) ||
2596 (strchr(")",c) != (char *) NULL))) &&
2597 (((islower((int) ((char) *expression)) != 0) ||
2598 (strchr("(",(int) *expression) != (char *) NULL)) ||
2599 ((isdigit((int) ((char) c)) == 0) &&
2600 (isdigit((int) ((char) *expression)) != 0))) &&
2601 (strchr("xy",(int) *expression) == (char *) NULL))
2602 precedence=MultiplyPrecedence;
2609 precedence=MultiplyPrecedence;
2615 if ((strchr("(+-/*%:&^|<>~,",c) == (char *) NULL) ||
2617 precedence=AdditionPrecedence;
2620 case LeftShiftOperator:
2621 case RightShiftOperator:
2623 precedence=ShiftPrecedence;
2627 case LessThanEqualOperator:
2628 case GreaterThanEqualOperator:
2631 precedence=RelationalPrecedence;
2635 case NotEqualOperator:
2637 precedence=EquivalencyPrecedence;
2642 precedence=BitwiseAndPrecedence;
2647 precedence=BitwiseOrPrecedence;
2650 case LogicalAndOperator:
2652 precedence=LogicalAndPrecedence;
2655 case LogicalOrOperator:
2657 precedence=LogicalOrPrecedence;
2663 precedence=TernaryPrecedence;
2668 precedence=AssignmentPrecedence;
2673 precedence=CommaPrecedence;
2678 precedence=SeparatorPrecedence;
2682 if ((precedence == BitwiseComplementPrecedence) ||
2683 (precedence == TernaryPrecedence) ||
2684 (precedence == AssignmentPrecedence))
2686 if (precedence > target)
2689 Right-to-left associativity.
2692 subexpression=expression;
2696 if (precedence >= target)
2699 Left-to-right associativity.
2702 subexpression=expression;
2704 if (strchr("(",(int) *expression) != (char *) NULL)
2705 expression=FxSubexpression(expression,exception);
2706 c=(int) (*expression++);
2708 return(subexpression);
2711 static MagickRealType FxEvaluateSubexpression(FxInfo *fx_info,
2712 const ChannelType channel,const long x,const long y,const char *expression,
2713 MagickRealType *beta,ExceptionInfo *exception)
2717 subexpression[MaxTextExtent];
2727 if (exception->severity != UndefinedException)
2729 while (isspace((int) *expression) != 0)
2731 if (*expression == '\0')
2733 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2734 "MissingExpression","`%s'",expression);
2737 p=FxOperatorPrecedence(expression,exception);
2738 if (p != (const char *) NULL)
2740 (void) CopyMagickString(subexpression,expression,(size_t)
2742 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,beta,
2744 switch ((unsigned char) *p)
2748 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2749 *beta=(MagickRealType) (~(unsigned long) *beta);
2754 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2755 return(*beta == 0.0 ? 1.0 : 0.0);
2759 *beta=pow((double) alpha,(double) FxEvaluateSubexpression(fx_info,
2760 channel,x,y,++p,beta,exception));
2765 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2766 return(alpha*(*beta));
2770 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2773 if (exception->severity == UndefinedException)
2774 (void) ThrowMagickException(exception,GetMagickModule(),
2775 OptionError,"DivideByZero","`%s'",expression);
2778 return(alpha/(*beta));
2782 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2783 *beta=fabs(floor(((double) *beta)+0.5));
2786 (void) ThrowMagickException(exception,GetMagickModule(),
2787 OptionError,"DivideByZero","`%s'",expression);
2790 return(fmod((double) alpha,(double) *beta));
2794 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2795 return(alpha+(*beta));
2799 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2800 return(alpha-(*beta));
2802 case LeftShiftOperator:
2804 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2805 *beta=(MagickRealType) ((unsigned long) (alpha+0.5) << (unsigned long)
2809 case RightShiftOperator:
2811 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2812 *beta=(MagickRealType) ((unsigned long) (alpha+0.5) >> (unsigned long)
2818 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2819 return(alpha < *beta ? 1.0 : 0.0);
2821 case LessThanEqualOperator:
2823 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2824 return(alpha <= *beta ? 1.0 : 0.0);
2828 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2829 return(alpha > *beta ? 1.0 : 0.0);
2831 case GreaterThanEqualOperator:
2833 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2834 return(alpha >= *beta ? 1.0 : 0.0);
2838 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2839 return(fabs(alpha-(*beta)) <= MagickEpsilon ? 1.0 : 0.0);
2841 case NotEqualOperator:
2843 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2844 return(fabs(alpha-(*beta)) > MagickEpsilon ? 1.0 : 0.0);
2848 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2849 *beta=(MagickRealType) ((unsigned long) (alpha+0.5) & (unsigned long)
2855 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2856 *beta=(MagickRealType) ((unsigned long) (alpha+0.5) | (unsigned long)
2860 case LogicalAndOperator:
2862 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2863 *beta=(alpha > 0.0) && (gamma > 0.0) ? 1.0 : 0.0;
2866 case LogicalOrOperator:
2868 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2869 *beta=(alpha > 0.0) || (gamma > 0.0) ? 1.0 : 0.0;
2877 (void) CopyMagickString(subexpression,++p,MaxTextExtent);
2879 p=StringToken(":",&q);
2880 if (q == (char *) NULL)
2882 (void) ThrowMagickException(exception,GetMagickModule(),
2883 OptionError,"UnableToParseExpression","`%s'",subexpression);
2886 if (fabs((double) alpha) > MagickEpsilon)
2887 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,beta,exception);
2889 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,q,beta,exception);
2895 numeric[MaxTextExtent];
2898 while (isalpha((int) ((unsigned char) *q)) != 0)
2902 (void) ThrowMagickException(exception,GetMagickModule(),
2903 OptionError,"UnableToParseExpression","`%s'",subexpression);
2906 ClearMagickException(exception);
2907 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2908 (void) FormatMagickString(numeric,MaxTextExtent,"%g",(double) *beta);
2909 (void) DeleteNodeFromSplayTree(fx_info->symbols,subexpression);
2910 (void) AddValueToSplayTree(fx_info->symbols,ConstantString(
2911 subexpression),ConstantString(numeric));
2916 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2921 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2926 gamma=alpha*FxEvaluateSubexpression(fx_info,channel,x,y,p,beta,
2932 if (strchr("(",(int) *expression) != (char *) NULL)
2934 (void) CopyMagickString(subexpression,expression+1,MaxTextExtent);
2935 subexpression[strlen(subexpression)-1]='\0';
2936 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,beta,
2940 switch (*expression)
2944 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta,
2950 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta,
2956 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta,
2958 return((MagickRealType) (~(unsigned long) (gamma+0.5)));
2963 if (LocaleNCompare(expression,"abs",3) == 0)
2965 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2967 return((MagickRealType) fabs((double) alpha));
2969 if (LocaleNCompare(expression,"acos",4) == 0)
2971 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2973 return((MagickRealType) acos((double) alpha));
2975 if (LocaleNCompare(expression,"asin",4) == 0)
2977 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2979 return((MagickRealType) asin((double) alpha));
2981 if (LocaleNCompare(expression,"alt",3) == 0)
2983 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2985 return(((long) alpha) & 0x01 ? -1.0 : 1.0);
2987 if (LocaleNCompare(expression,"atan2",5) == 0)
2989 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2991 return((MagickRealType) atan2((double) alpha,(double) *beta));
2993 if (LocaleNCompare(expression,"atan",4) == 0)
2995 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2997 return((MagickRealType) atan((double) alpha));
2999 if (LocaleCompare(expression,"a") == 0)
3000 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3006 if (LocaleCompare(expression,"b") == 0)
3007 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3013 if (LocaleNCompare(expression,"ceil",4) == 0)
3015 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
3017 return((MagickRealType) ceil((double) alpha));
3019 if (LocaleNCompare(expression,"cosh",4) == 0)
3021 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
3023 return((MagickRealType) cosh((double) alpha));
3025 if (LocaleNCompare(expression,"cos",3) == 0)
3027 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
3029 return((MagickRealType) cos((double) alpha));
3031 if (LocaleCompare(expression,"c") == 0)
3032 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3038 if (LocaleNCompare(expression,"debug",5) == 0)
3043 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
3045 if (fx_info->images->colorspace == CMYKColorspace)
3048 case CyanChannel: type="cyan"; break;
3049 case MagentaChannel: type="magenta"; break;
3050 case YellowChannel: type="yellow"; break;
3051 case OpacityChannel: type="opacity"; break;
3052 case BlackChannel: type="black"; break;
3053 default: type="unknown"; break;
3058 case RedChannel: type="red"; break;
3059 case GreenChannel: type="green"; break;
3060 case BlueChannel: type="blue"; break;
3061 case OpacityChannel: type="opacity"; break;
3062 default: type="unknown"; break;
3064 (void) CopyMagickString(subexpression,expression+6,MaxTextExtent);
3065 if (strlen(subexpression) > 1)
3066 subexpression[strlen(subexpression)-1]='\0';
3067 if (fx_info->file != (FILE *) NULL)
3068 (void) fprintf(fx_info->file,"%s[%ld,%ld].%s: %s=%g\n",
3069 fx_info->images->filename,x,y,type,subexpression,(double) alpha);
3077 if (LocaleCompare(expression,"epsilon") == 0)
3078 return((MagickRealType) MagickEpsilon);
3079 if (LocaleNCompare(expression,"exp",3) == 0)
3081 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
3083 return((MagickRealType) exp((double) alpha));
3085 if (LocaleCompare(expression,"e") == 0)
3086 return((MagickRealType) 2.7182818284590452354);
3092 if (LocaleNCompare(expression,"floor",5) == 0)
3094 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
3096 return((MagickRealType) floor((double) alpha));
3103 if (LocaleCompare(expression,"g") == 0)
3104 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3110 if (LocaleCompare(expression,"h") == 0)
3111 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3112 if (LocaleCompare(expression,"hue") == 0)
3113 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3114 if (LocaleNCompare(expression,"hypot",5) == 0)
3116 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
3118 return((MagickRealType) hypot((double) alpha,(double) *beta));
3125 if (LocaleCompare(expression,"k") == 0)
3126 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3132 if (LocaleCompare(expression,"intensity") == 0)
3133 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3134 if (LocaleNCompare(expression,"int",3) == 0)
3136 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
3138 return((MagickRealType) floor(alpha+0.5));
3140 if (LocaleCompare(expression,"i") == 0)
3141 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3147 if (LocaleCompare(expression,"j") == 0)
3148 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3154 if (LocaleNCompare(expression,"ln",2) == 0)
3156 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,beta,
3158 return((MagickRealType) log((double) alpha));
3160 if (LocaleNCompare(expression,"logtwo",4) == 0)
3162 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
3164 return((MagickRealType) log10((double) alpha))/log10(2.0);
3166 if (LocaleNCompare(expression,"log",3) == 0)
3168 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
3170 return((MagickRealType) log10((double) alpha));
3172 if (LocaleCompare(expression,"lightness") == 0)
3173 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3179 if (LocaleCompare(expression,"MaxRGB") == 0)
3180 return((MagickRealType) QuantumRange);
3181 if (LocaleNCompare(expression,"maxima",6) == 0)
3183 if (LocaleNCompare(expression,"max",3) == 0)
3184 return(FxMax(fx_info,channel,x,y,expression+3,exception));
3185 if (LocaleNCompare(expression,"minima",6) == 0)
3187 if (LocaleNCompare(expression,"min",3) == 0)
3188 return(FxMin(fx_info,channel,x,y,expression+3,exception));
3189 if (LocaleNCompare(expression,"mod",3) == 0)
3191 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
3193 return((MagickRealType) fmod((double) alpha,(double) *beta));
3195 if (LocaleCompare(expression,"m") == 0)
3196 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3202 if (LocaleCompare(expression,"n") == 0)
3203 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3209 if (LocaleCompare(expression,"Opaque") == 0)
3211 if (LocaleCompare(expression,"o") == 0)
3212 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3218 if (LocaleCompare(expression,"pi") == 0)
3219 return((MagickRealType) MagickPI);
3220 if (LocaleNCompare(expression,"pow",3) == 0)
3222 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
3224 return((MagickRealType) pow((double) alpha,(double) *beta));
3226 if (LocaleCompare(expression,"p") == 0)
3227 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3233 if (LocaleCompare(expression,"QuantumRange") == 0)
3234 return((MagickRealType) QuantumRange);
3235 if (LocaleCompare(expression,"QuantumScale") == 0)
3236 return((MagickRealType) QuantumScale);
3242 if (LocaleNCompare(expression,"rand",4) == 0)
3243 return((MagickRealType) GetPseudoRandomValue(fx_info->random_info));
3244 if (LocaleNCompare(expression,"round",5) == 0)
3246 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
3249 return((MagickRealType) floor((double) alpha+0.5));
3250 return((MagickRealType) ceil((double) alpha-0.5));
3252 if (LocaleCompare(expression,"r") == 0)
3253 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3259 if (LocaleCompare(expression,"saturation") == 0)
3260 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3261 if (LocaleNCompare(expression,"sign",4) == 0)
3263 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
3265 return(alpha < 0.0 ? -1.0 : 1.0);
3267 if (LocaleNCompare(expression,"sinh",4) == 0)
3269 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
3271 return((MagickRealType) sinh((double) alpha));
3273 if (LocaleNCompare(expression,"sin",3) == 0)
3275 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
3277 return((MagickRealType) sin((double) alpha));
3279 if (LocaleNCompare(expression,"sqrt",4) == 0)
3281 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
3283 return((MagickRealType) sqrt((double) alpha));
3285 if (LocaleCompare(expression,"s") == 0)
3286 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3292 if (LocaleNCompare(expression,"tanh",4) == 0)
3294 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
3296 return((MagickRealType) tanh((double) alpha));
3298 if (LocaleNCompare(expression,"tan",3) == 0)
3300 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
3302 return((MagickRealType) tan((double) alpha));
3304 if (LocaleCompare(expression,"Transparent") == 0)
3306 if (LocaleCompare(expression,"t") == 0)
3307 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3313 if (LocaleCompare(expression,"u") == 0)
3314 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3320 if (LocaleCompare(expression,"v") == 0)
3321 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3327 if (LocaleCompare(expression,"w") == 0)
3328 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3334 if (LocaleCompare(expression,"y") == 0)
3335 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3341 if (LocaleCompare(expression,"z") == 0)
3342 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3348 q=(char *) expression;
3349 alpha=strtod(expression,&q);
3350 if (q == expression)
3351 return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
3355 MagickExport MagickBooleanType FxEvaluateExpression(FxInfo *fx_info,
3356 MagickRealType *alpha,ExceptionInfo *exception)
3361 status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
3365 MagickExport MagickBooleanType FxPreprocessExpression(FxInfo *fx_info,
3366 MagickRealType *alpha,ExceptionInfo *exception)
3375 fx_info->file=(FILE *) NULL;
3376 status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
3381 MagickExport MagickBooleanType FxEvaluateChannelExpression(FxInfo *fx_info,
3382 const ChannelType channel,const long x,const long y,MagickRealType *alpha,
3383 ExceptionInfo *exception)
3389 *alpha=FxEvaluateSubexpression(fx_info,channel,x,y,fx_info->expression,&beta,
3391 return(exception->severity == OptionError ? MagickFalse : MagickTrue);
3395 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3403 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3405 % FxImage() applies a mathematical expression to the specified image.
3407 % The format of the FxImage method is:
3409 % Image *FxImage(const Image *image,const char *expression,
3410 % ExceptionInfo *exception)
3411 % Image *FxImageChannel(const Image *image,const ChannelType channel,
3412 % const char *expression,ExceptionInfo *exception)
3414 % A description of each parameter follows:
3416 % o image: the image.
3418 % o channel: the channel.
3420 % o expression: A mathematical expression.
3422 % o exception: return any errors or warnings in this structure.
3426 static FxInfo **DestroyFxThreadSet(FxInfo **fx_info)
3431 assert(fx_info != (FxInfo **) NULL);
3432 for (i=0; i < (long) GetOpenMPMaximumThreads(); i++)
3433 if (fx_info[i] != (FxInfo *) NULL)
3434 fx_info[i]=DestroyFxInfo(fx_info[i]);
3435 fx_info=(FxInfo **) RelinquishAlignedMemory(fx_info);
3439 static FxInfo **AcquireFxThreadSet(const Image *image,const char *expression,
3440 ExceptionInfo *exception)
3457 number_threads=GetOpenMPMaximumThreads();
3458 fx_info=(FxInfo **) AcquireAlignedMemory(number_threads,sizeof(*fx_info));
3459 if (fx_info == (FxInfo **) NULL)
3460 return((FxInfo **) NULL);
3461 (void) ResetMagickMemory(fx_info,0,number_threads*sizeof(*fx_info));
3462 if (*expression != '@')
3463 fx_expression=ConstantString(expression);
3465 fx_expression=FileToString(expression+1,~0,exception);
3466 for (i=0; i < (long) number_threads; i++)
3468 fx_info[i]=AcquireFxInfo(image,fx_expression);
3469 if (fx_info[i] == (FxInfo *) NULL)
3470 return(DestroyFxThreadSet(fx_info));
3471 (void) FxPreprocessExpression(fx_info[i],&alpha,fx_info[i]->exception);
3473 fx_expression=DestroyString(fx_expression);
3477 MagickExport Image *FxImage(const Image *image,const char *expression,
3478 ExceptionInfo *exception)
3483 fx_image=FxImageChannel(image,GrayChannel,expression,exception);
3487 MagickExport Image *FxImageChannel(const Image *image,const ChannelType channel,
3488 const char *expression,ExceptionInfo *exception)
3490 #define FxImageTag "Fx/Image"
3511 assert(image != (Image *) NULL);
3512 assert(image->signature == MagickSignature);
3513 if (image->debug != MagickFalse)
3514 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3515 fx_image=CloneImage(image,0,0,MagickTrue,exception);
3516 if (fx_image == (Image *) NULL)
3517 return((Image *) NULL);
3518 if (SetImageStorageClass(fx_image,DirectClass) == MagickFalse)
3520 InheritException(exception,&fx_image->exception);
3521 fx_image=DestroyImage(fx_image);
3522 return((Image *) NULL);
3524 fx_info=AcquireFxThreadSet(image,expression,exception);
3525 if (fx_info == (FxInfo **) NULL)
3527 fx_image=DestroyImage(fx_image);
3528 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
3530 status=FxPreprocessExpression(fx_info[0],&alpha,exception);
3531 if (status == MagickFalse)
3533 fx_image=DestroyImage(fx_image);
3534 fx_info=DestroyFxThreadSet(fx_info);
3535 return((Image *) NULL);
3542 fx_view=AcquireCacheView(fx_image);
3543 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3544 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
3546 for (y=0; y < (long) fx_image->rows; y++)
3551 register IndexPacket
3552 *__restrict fx_indexes;
3558 register PixelPacket
3561 if (status == MagickFalse)
3563 q=GetCacheViewAuthenticPixels(fx_view,0,y,fx_image->columns,1,exception);
3564 if (q == (PixelPacket *) NULL)
3569 fx_indexes=GetCacheViewAuthenticIndexQueue(fx_view);
3570 id=GetOpenMPThreadId();
3572 for (x=0; x < (long) fx_image->columns; x++)
3574 if ((channel & RedChannel) != 0)
3576 (void) FxEvaluateChannelExpression(fx_info[id],RedChannel,x,y,
3578 q->red=RoundToQuantum((MagickRealType) QuantumRange*alpha);
3580 if ((channel & GreenChannel) != 0)
3582 (void) FxEvaluateChannelExpression(fx_info[id],GreenChannel,x,y,
3584 q->green=RoundToQuantum((MagickRealType) QuantumRange*alpha);
3586 if ((channel & BlueChannel) != 0)
3588 (void) FxEvaluateChannelExpression(fx_info[id],BlueChannel,x,y,
3590 q->blue=RoundToQuantum((MagickRealType) QuantumRange*alpha);
3592 if ((channel & OpacityChannel) != 0)
3594 (void) FxEvaluateChannelExpression(fx_info[id],OpacityChannel,x,y,
3596 if (image->matte == MagickFalse)
3597 q->opacity=RoundToQuantum((MagickRealType) QuantumRange*alpha);
3599 q->opacity=RoundToQuantum((MagickRealType) (QuantumRange-
3600 QuantumRange*alpha));
3602 if (((channel & IndexChannel) != 0) &&
3603 (fx_image->colorspace == CMYKColorspace))
3605 (void) FxEvaluateChannelExpression(fx_info[id],IndexChannel,x,y,
3607 fx_indexes[x]=(IndexPacket) RoundToQuantum((MagickRealType)
3608 QuantumRange*alpha);
3612 if (SyncCacheViewAuthenticPixels(fx_view,exception) == MagickFalse)
3614 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3619 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3620 #pragma omp critical (MagickCore_FxImageChannel)
3622 proceed=SetImageProgress(image,FxImageTag,progress++,image->rows);
3623 if (proceed == MagickFalse)
3627 fx_image->matte=fx_info[0]->matte;
3628 fx_view=DestroyCacheView(fx_view);
3629 fx_info=DestroyFxThreadSet(fx_info);
3630 if (status == MagickFalse)
3631 fx_image=DestroyImage(fx_image);
3636 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3640 % I m p l o d e I m a g e %
3644 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3646 % ImplodeImage() creates a new image that is a copy of an existing
3647 % one with the image pixels "implode" by the specified percentage. It
3648 % allocates the memory necessary for the new Image structure and returns a
3649 % pointer to the new image.
3651 % The format of the ImplodeImage method is:
3653 % Image *ImplodeImage(const Image *image,const double amount,
3654 % ExceptionInfo *exception)
3656 % A description of each parameter follows:
3658 % o implode_image: Method ImplodeImage returns a pointer to the image
3659 % after it is implode. A null image is returned if there is a memory
3662 % o image: the image.
3664 % o amount: Define the extent of the implosion.
3666 % o exception: return any errors or warnings in this structure.
3669 MagickExport Image *ImplodeImage(const Image *image,const double amount,
3670 ExceptionInfo *exception)
3672 #define ImplodeImageTag "Implode/Image"
3702 Initialize implode image attributes.
3704 assert(image != (Image *) NULL);
3705 assert(image->signature == MagickSignature);
3706 if (image->debug != MagickFalse)
3707 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3708 assert(exception != (ExceptionInfo *) NULL);
3709 assert(exception->signature == MagickSignature);
3710 implode_image=CloneImage(image,0,0,MagickTrue,exception);
3711 if (implode_image == (Image *) NULL)
3712 return((Image *) NULL);
3713 if (SetImageStorageClass(implode_image,DirectClass) == MagickFalse)
3715 InheritException(exception,&implode_image->exception);
3716 implode_image=DestroyImage(implode_image);
3717 return((Image *) NULL);
3719 if (implode_image->background_color.opacity != OpaqueOpacity)
3720 implode_image->matte=MagickTrue;
3722 Compute scaling factor.
3726 center.x=0.5*image->columns;
3727 center.y=0.5*image->rows;
3729 if (image->columns > image->rows)
3730 scale.y=(double) image->columns/(double) image->rows;
3732 if (image->columns < image->rows)
3734 scale.x=(double) image->rows/(double) image->columns;
3742 GetMagickPixelPacket(implode_image,&zero);
3743 resample_filter=AcquireResampleFilterThreadSet(image,MagickTrue,exception);
3744 image_view=AcquireCacheView(image);
3745 implode_view=AcquireCacheView(implode_image);
3746 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3747 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
3749 for (y=0; y < (long) image->rows; y++)
3760 register IndexPacket
3761 *__restrict implode_indexes;
3767 register PixelPacket
3770 if (status == MagickFalse)
3772 q=GetCacheViewAuthenticPixels(implode_view,0,y,implode_image->columns,1,
3774 if (q == (PixelPacket *) NULL)
3779 implode_indexes=GetCacheViewAuthenticIndexQueue(implode_view);
3780 delta.y=scale.y*(double) (y-center.y);
3782 id=GetOpenMPThreadId();
3783 for (x=0; x < (long) image->columns; x++)
3786 Determine if the pixel is within an ellipse.
3788 delta.x=scale.x*(double) (x-center.x);
3789 distance=delta.x*delta.x+delta.y*delta.y;
3790 if (distance < (radius*radius))
3800 factor=pow(sin((double) (MagickPI*sqrt((double) distance)/
3801 radius/2)),-amount);
3802 (void) ResamplePixelColor(resample_filter[id],(double)
3803 (factor*delta.x/scale.x+center.x),(double) (factor*delta.y/
3804 scale.y+center.y),&pixel);
3805 SetPixelPacket(implode_image,&pixel,q,implode_indexes+x);
3809 if (SyncCacheViewAuthenticPixels(implode_view,exception) == MagickFalse)
3811 if (image->progress_monitor != (MagickProgressMonitor) NULL)
3816 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3817 #pragma omp critical (MagickCore_ImplodeImage)
3819 proceed=SetImageProgress(image,ImplodeImageTag,progress++,image->rows);
3820 if (proceed == MagickFalse)
3824 implode_view=DestroyCacheView(implode_view);
3825 image_view=DestroyCacheView(image_view);
3826 resample_filter=DestroyResampleFilterThreadSet(resample_filter);
3827 if (status == MagickFalse)
3828 implode_image=DestroyImage(implode_image);
3829 return(implode_image);
3833 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3837 % M o r p h I m a g e s %
3841 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3843 % The MorphImages() method requires a minimum of two images. The first
3844 % image is transformed into the second by a number of intervening images
3845 % as specified by frames.
3847 % The format of the MorphImage method is:
3849 % Image *MorphImages(const Image *image,const unsigned long number_frames,
3850 % ExceptionInfo *exception)
3852 % A description of each parameter follows:
3854 % o image: the image.
3856 % o number_frames: Define the number of in-between image to generate.
3857 % The more in-between frames, the smoother the morph.
3859 % o exception: return any errors or warnings in this structure.
3862 MagickExport Image *MorphImages(const Image *image,
3863 const unsigned long number_frames,ExceptionInfo *exception)
3865 #define MorphImageTag "Morph/Image"
3881 register const Image
3891 Clone first frame in sequence.
3893 assert(image != (Image *) NULL);
3894 assert(image->signature == MagickSignature);
3895 if (image->debug != MagickFalse)
3896 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3897 assert(exception != (ExceptionInfo *) NULL);
3898 assert(exception->signature == MagickSignature);
3899 morph_images=CloneImage(image,0,0,MagickTrue,exception);
3900 if (morph_images == (Image *) NULL)
3901 return((Image *) NULL);
3902 if (GetNextImageInList(image) == (Image *) NULL)
3907 for (i=1; i < (long) number_frames; i++)
3909 morph_image=CloneImage(image,0,0,MagickTrue,exception);
3910 if (morph_image == (Image *) NULL)
3912 morph_images=DestroyImageList(morph_images);
3913 return((Image *) NULL);
3915 AppendImageToList(&morph_images,morph_image);
3916 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
3917 (QuantumTick(i,number_frames) != MagickFalse))
3919 status=image->progress_monitor(MorphImageTag,i,number_frames,
3920 image->client_data);
3921 if (status == MagickFalse)
3925 return(GetFirstImageInList(morph_images));
3928 Morph image sequence.
3933 for ( ; GetNextImageInList(next) != (Image *) NULL; next=GetNextImageInList(next))
3935 for (i=0; i < (long) number_frames; i++)
3941 beta=(MagickRealType) (i+1.0)/(MagickRealType) (number_frames+1.0);
3943 morph_image=ZoomImage(next,(unsigned long) (alpha*next->columns+beta*
3944 GetNextImageInList(next)->columns+0.5),(unsigned long) (alpha*
3945 next->rows+beta*GetNextImageInList(next)->rows+0.5),exception);
3946 if (morph_image == (Image *) NULL)
3948 morph_images=DestroyImageList(morph_images);
3949 return((Image *) NULL);
3951 if (SetImageStorageClass(morph_image,DirectClass) == MagickFalse)
3953 InheritException(exception,&morph_image->exception);
3954 morph_image=DestroyImage(morph_image);
3955 return((Image *) NULL);
3957 AppendImageToList(&morph_images,morph_image);
3958 morph_images=GetLastImageInList(morph_images);
3959 morph_image=ZoomImage(GetNextImageInList(next),morph_images->columns,
3960 morph_images->rows,exception);
3961 if (morph_image == (Image *) NULL)
3963 morph_images=DestroyImageList(morph_images);
3964 return((Image *) NULL);
3966 image_view=AcquireCacheView(morph_image);
3967 morph_view=AcquireCacheView(morph_images);
3968 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3969 #pragma omp parallel for schedule(dynamic,4) shared(status)
3971 for (y=0; y < (long) morph_images->rows; y++)
3976 register const PixelPacket
3982 register PixelPacket
3985 if (status == MagickFalse)
3987 p=GetCacheViewVirtualPixels(image_view,0,y,morph_image->columns,1,
3989 q=GetCacheViewAuthenticPixels(morph_view,0,y,morph_images->columns,1,
3991 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
3996 for (x=0; x < (long) morph_images->columns; x++)
3998 q->red=RoundToQuantum(alpha*q->red+beta*p->red);
3999 q->green=RoundToQuantum(alpha*q->green+beta*p->green);
4000 q->blue=RoundToQuantum(alpha*q->blue+beta*p->blue);
4001 q->opacity=RoundToQuantum(alpha*q->opacity+beta*p->opacity);
4005 sync=SyncCacheViewAuthenticPixels(morph_view,exception);
4006 if (sync == MagickFalse)
4009 morph_view=DestroyCacheView(morph_view);
4010 image_view=DestroyCacheView(image_view);
4011 morph_image=DestroyImage(morph_image);
4013 if (i < (long) number_frames)
4016 Clone last frame in sequence.
4018 morph_image=CloneImage(GetNextImageInList(next),0,0,MagickTrue,exception);
4019 if (morph_image == (Image *) NULL)
4021 morph_images=DestroyImageList(morph_images);
4022 return((Image *) NULL);
4024 AppendImageToList(&morph_images,morph_image);
4025 morph_images=GetLastImageInList(morph_images);
4026 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4031 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4032 #pragma omp critical (MagickCore_MorphImages)
4034 proceed=SetImageProgress(image,MorphImageTag,scene,
4035 GetImageListLength(image));
4036 if (proceed == MagickFalse)
4041 if (GetNextImageInList(next) != (Image *) NULL)
4043 morph_images=DestroyImageList(morph_images);
4044 return((Image *) NULL);
4046 return(GetFirstImageInList(morph_images));
4050 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4054 % P l a s m a I m a g e %
4058 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4060 % PlasmaImage() initializes an image with plasma fractal values. The image
4061 % must be initialized with a base color and the random number generator
4062 % seeded before this method is called.
4064 % The format of the PlasmaImage method is:
4066 % MagickBooleanType PlasmaImage(Image *image,const SegmentInfo *segment,
4067 % unsigned long attenuate,unsigned long depth)
4069 % A description of each parameter follows:
4071 % o image: the image.
4073 % o segment: Define the region to apply plasma fractals values.
4075 % o attenuate: Define the plasmattenuation factor.
4077 % o depth: Limit the plasma recursion depth.
4081 static inline Quantum PlasmaPixel(RandomInfo *random_info,
4082 const MagickRealType pixel,const MagickRealType noise)
4087 plasma=RoundToQuantum(pixel+noise*GetPseudoRandomValue(random_info)-
4092 MagickExport MagickBooleanType PlasmaImageProxy(Image *image,
4093 RandomInfo *random_info,const SegmentInfo *segment,unsigned long attenuate,
4094 unsigned long depth)
4112 if (((segment->x2-segment->x1) == 0.0) && ((segment->y2-segment->y1) == 0.0))
4120 Divide the area into quadrants and recurse.
4124 x_mid=(long) (segment->x1+segment->x2+0.5)/2;
4125 y_mid=(long) (segment->y1+segment->y2+0.5)/2;
4126 local_info=(*segment);
4127 local_info.x2=(double) x_mid;
4128 local_info.y2=(double) y_mid;
4129 (void) PlasmaImageProxy(image,random_info,&local_info,attenuate,depth);
4130 local_info=(*segment);
4131 local_info.y1=(double) y_mid;
4132 local_info.x2=(double) x_mid;
4133 (void) PlasmaImageProxy(image,random_info,&local_info,attenuate,depth);
4134 local_info=(*segment);
4135 local_info.x1=(double) x_mid;
4136 local_info.y2=(double) y_mid;
4137 (void) PlasmaImageProxy(image,random_info,&local_info,attenuate,depth);
4138 local_info=(*segment);
4139 local_info.x1=(double) x_mid;
4140 local_info.y1=(double) y_mid;
4141 return(PlasmaImageProxy(image,random_info,&local_info,attenuate,depth));
4143 if (SetImageStorageClass(image,DirectClass) == MagickFalse)
4144 return(MagickFalse);
4145 x_mid=(long) (segment->x1+segment->x2+0.5)/2;
4146 y_mid=(long) (segment->y1+segment->y2+0.5)/2;
4147 if ((segment->x1 == (double) x_mid) && (segment->x2 == (double) x_mid) &&
4148 (segment->y1 == (double) y_mid) && (segment->y2 == (double) y_mid))
4149 return(MagickFalse);
4151 Average pixels and apply plasma.
4153 exception=(&image->exception);
4154 plasma=(MagickRealType) QuantumRange/(2.0*attenuate);
4155 if ((segment->x1 != (double) x_mid) || (segment->x2 != (double) x_mid))
4157 register PixelPacket
4163 x=(long) (segment->x1+0.5);
4164 (void) GetOneVirtualPixel(image,x,(long) (segment->y1+0.5),&u,exception);
4165 (void) GetOneVirtualPixel(image,x,(long) (segment->y2+0.5),&v,exception);
4166 q=QueueAuthenticPixels(image,x,y_mid,1,1,exception);
4167 if (q == (PixelPacket *) NULL)
4169 q->red=PlasmaPixel(random_info,(MagickRealType) (u.red+v.red)/2.0,
4171 q->green=PlasmaPixel(random_info,(MagickRealType) (u.green+v.green)/2.0,
4173 q->blue=PlasmaPixel(random_info,(MagickRealType) (u.blue+v.blue)/2.0,
4175 (void) SyncAuthenticPixels(image,exception);
4176 if (segment->x1 != segment->x2)
4181 x=(long) (segment->x2+0.5);
4182 (void) GetOneVirtualPixel(image,x,(long) (segment->y1+0.5),&u,
4184 (void) GetOneVirtualPixel(image,x,(long) (segment->y2+0.5),&v,
4186 q=QueueAuthenticPixels(image,x,y_mid,1,1,exception);
4187 if (q == (PixelPacket *) NULL)
4189 q->red=PlasmaPixel(random_info,(MagickRealType) (u.red+v.red)/2.0,
4191 q->green=PlasmaPixel(random_info,(MagickRealType) (u.green+v.green)/
4193 q->blue=PlasmaPixel(random_info,(MagickRealType) (u.blue+v.blue)/2.0,
4195 (void) SyncAuthenticPixels(image,exception);
4198 if ((segment->y1 != (double) y_mid) || (segment->y2 != (double) y_mid))
4200 if ((segment->x1 != (double) x_mid) || (segment->y2 != (double) y_mid))
4202 register PixelPacket
4208 y=(long) (segment->y2+0.5);
4209 (void) GetOneVirtualPixel(image,(long) (segment->x1+0.5),y,&u,
4211 (void) GetOneVirtualPixel(image,(long) (segment->x2+0.5),y,&v,
4213 q=QueueAuthenticPixels(image,x_mid,y,1,1,exception);
4214 if (q == (PixelPacket *) NULL)
4216 q->red=PlasmaPixel(random_info,(MagickRealType) (u.red+v.red)/2.0,
4218 q->green=PlasmaPixel(random_info,(MagickRealType) (u.green+v.green)/
4220 q->blue=PlasmaPixel(random_info,(MagickRealType) (u.blue+v.blue)/2.0,
4222 (void) SyncAuthenticPixels(image,exception);
4224 if (segment->y1 != segment->y2)
4226 register PixelPacket
4232 y=(long) (segment->y1+0.5);
4233 (void) GetOneVirtualPixel(image,(long) (segment->x1+0.5),y,&u,
4235 (void) GetOneVirtualPixel(image,(long) (segment->x2+0.5),y,&v,
4237 q=QueueAuthenticPixels(image,x_mid,y,1,1,exception);
4238 if (q == (PixelPacket *) NULL)
4240 q->red=PlasmaPixel(random_info,(MagickRealType) (u.red+v.red)/2.0,
4242 q->green=PlasmaPixel(random_info,(MagickRealType) (u.green+v.green)/
4244 q->blue=PlasmaPixel(random_info,(MagickRealType) (u.blue+v.blue)/2.0,
4246 (void) SyncAuthenticPixels(image,exception);
4249 if ((segment->x1 != segment->x2) || (segment->y1 != segment->y2))
4251 register PixelPacket
4257 x=(long) (segment->x1+0.5);
4258 y=(long) (segment->y1+0.5);
4259 (void) GetOneVirtualPixel(image,x,y,&u,exception);
4260 x=(long) (segment->x2+0.5);
4261 y=(long) (segment->y2+0.5);
4262 (void) GetOneVirtualPixel(image,x,y,&v,exception);
4263 q=QueueAuthenticPixels(image,x_mid,y_mid,1,1,exception);
4264 if (q == (PixelPacket *) NULL)
4266 q->red=PlasmaPixel(random_info,(MagickRealType) (u.red+v.red)/2.0,
4268 q->green=PlasmaPixel(random_info,(MagickRealType) (u.green+v.green)/2.0,
4270 q->blue=PlasmaPixel(random_info,(MagickRealType) (u.blue+v.blue)/2.0,
4272 (void) SyncAuthenticPixels(image,exception);
4274 if (((segment->x2-segment->x1) < 3.0) && ((segment->y2-segment->y1) < 3.0))
4276 return(MagickFalse);
4279 MagickExport MagickBooleanType PlasmaImage(Image *image,
4280 const SegmentInfo *segment,unsigned long attenuate,unsigned long depth)
4288 if (image->debug != MagickFalse)
4289 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4290 assert(image != (Image *) NULL);
4291 assert(image->signature == MagickSignature);
4292 if (image->debug != MagickFalse)
4293 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
4294 random_info=AcquireRandomInfo();
4295 status=PlasmaImageProxy(image,random_info,segment,attenuate,depth);
4296 random_info=DestroyRandomInfo(random_info);
4301 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4305 % P o l a r o i d I m a g e %
4309 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4311 % PolaroidImage() simulates a Polaroid picture.
4313 % The format of the AnnotateImage method is:
4315 % Image *PolaroidImage(const Image *image,const DrawInfo *draw_info,
4316 % const double angle,ExceptionInfo exception)
4318 % A description of each parameter follows:
4320 % o image: the image.
4322 % o draw_info: the draw info.
4324 % o angle: Apply the effect along this angle.
4326 % o exception: return any errors or warnings in this structure.
4329 MagickExport Image *PolaroidImage(const Image *image,const DrawInfo *draw_info,
4330 const double angle,ExceptionInfo *exception)
4351 Simulate a Polaroid picture.
4353 assert(image != (Image *) NULL);
4354 assert(image->signature == MagickSignature);
4355 if (image->debug != MagickFalse)
4356 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4357 assert(exception != (ExceptionInfo *) NULL);
4358 assert(exception->signature == MagickSignature);
4359 quantum=(long) MagickMax(MagickMax((double) image->columns,(double)
4360 image->rows)/25.0,10.0);
4361 height=image->rows+2*quantum;
4362 caption_image=(Image *) NULL;
4363 value=GetImageProperty(image,"Caption");
4364 if (value != (const char *) NULL)
4368 geometry[MaxTextExtent];
4383 Generate caption image.
4385 caption_image=CloneImage(image,image->columns,1,MagickTrue,exception);
4386 if (caption_image == (Image *) NULL)
4387 return((Image *) NULL);
4388 annotate_info=CloneDrawInfo((const ImageInfo *) NULL,draw_info);
4389 caption=InterpretImageProperties((ImageInfo *) NULL,(Image *) image,
4391 (void) CloneString(&annotate_info->text,caption);
4392 count=FormatMagickCaption(caption_image,annotate_info,&metrics,&caption);
4393 status=SetImageExtent(caption_image,image->columns,(unsigned long)
4394 ((count+1)*(metrics.ascent-metrics.descent)+0.5));
4395 if (status == MagickFalse)
4396 caption_image=DestroyImage(caption_image);
4399 caption_image->background_color=image->border_color;
4400 (void) SetImageBackgroundColor(caption_image);
4401 (void) CloneString(&annotate_info->text,caption);
4402 (void) FormatMagickString(geometry,MaxTextExtent,"+0+%g",
4404 if (annotate_info->gravity == UndefinedGravity)
4405 (void) CloneString(&annotate_info->geometry,AcquireString(
4407 (void) AnnotateImage(caption_image,annotate_info);
4408 height+=caption_image->rows;
4410 annotate_info=DestroyDrawInfo(annotate_info);
4411 caption=DestroyString(caption);
4413 picture_image=CloneImage(image,image->columns+2*quantum,height,MagickTrue,
4415 if (picture_image == (Image *) NULL)
4417 if (caption_image != (Image *) NULL)
4418 caption_image=DestroyImage(caption_image);
4419 return((Image *) NULL);
4421 picture_image->background_color=image->border_color;
4422 (void) SetImageBackgroundColor(picture_image);
4423 (void) CompositeImage(picture_image,OverCompositeOp,image,quantum,quantum);
4424 if (caption_image != (Image *) NULL)
4426 (void) CompositeImage(picture_image,OverCompositeOp,caption_image,
4427 quantum,(long) (image->rows+3*quantum/2));
4428 caption_image=DestroyImage(caption_image);
4430 (void) QueryColorDatabase("none",&picture_image->background_color,exception);
4431 (void) SetImageAlphaChannel(picture_image,OpaqueAlphaChannel);
4432 rotate_image=RotateImage(picture_image,90.0,exception);
4433 picture_image=DestroyImage(picture_image);
4434 if (rotate_image == (Image *) NULL)
4435 return((Image *) NULL);
4436 picture_image=rotate_image;
4437 bend_image=WaveImage(picture_image,0.01*picture_image->rows,2.0*
4438 picture_image->columns,exception);
4439 picture_image=DestroyImage(picture_image);
4440 if (bend_image == (Image *) NULL)
4441 return((Image *) NULL);
4442 InheritException(&bend_image->exception,exception);
4443 picture_image=bend_image;
4444 rotate_image=RotateImage(picture_image,-90.0,exception);
4445 picture_image=DestroyImage(picture_image);
4446 if (rotate_image == (Image *) NULL)
4447 return((Image *) NULL);
4448 picture_image=rotate_image;
4449 picture_image->background_color=image->background_color;
4450 polaroid_image=ShadowImage(picture_image,80.0,2.0,quantum/3,quantum/3,
4452 if (polaroid_image == (Image *) NULL)
4454 picture_image=DestroyImage(picture_image);
4455 return(picture_image);
4457 flop_image=FlopImage(polaroid_image,exception);
4458 polaroid_image=DestroyImage(polaroid_image);
4459 if (flop_image == (Image *) NULL)
4461 picture_image=DestroyImage(picture_image);
4462 return(picture_image);
4464 polaroid_image=flop_image;
4465 (void) CompositeImage(polaroid_image,OverCompositeOp,picture_image,
4466 (long) (-0.01*picture_image->columns/2.0),0L);
4467 picture_image=DestroyImage(picture_image);
4468 (void) QueryColorDatabase("none",&polaroid_image->background_color,exception);
4469 rotate_image=RotateImage(polaroid_image,angle,exception);
4470 polaroid_image=DestroyImage(polaroid_image);
4471 if (rotate_image == (Image *) NULL)
4472 return((Image *) NULL);
4473 polaroid_image=rotate_image;
4474 trim_image=TrimImage(polaroid_image,exception);
4475 polaroid_image=DestroyImage(polaroid_image);
4476 if (trim_image == (Image *) NULL)
4477 return((Image *) NULL);
4478 polaroid_image=trim_image;
4479 return(polaroid_image);
4483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4487 % R e c o l o r I m a g e %
4491 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4493 % RecolorImage() translate, scale, shear, or rotate image colors. Although
4494 % you can use variable sized matrices, typically you use a 5 x 5 for an RGBA
4495 % image and a 6x6 for CMYKA. Populate the last row with normalized values to
4498 % The format of the RecolorImage method is:
4500 % Image *RecolorImage(const Image *image,const unsigned long order,
4501 % const double *color_matrix,ExceptionInfo *exception)
4503 % A description of each parameter follows:
4505 % o image: the image.
4507 % o order: the number of columns and rows in the recolor matrix.
4509 % o color_matrix: An array of double representing the recolor matrix.
4511 % o exception: return any errors or warnings in this structure.
4514 MagickExport Image *RecolorImage(const Image *image,const unsigned long order,
4515 const double *color_matrix,ExceptionInfo *exception)
4517 #define RecolorImageTag "Recolor/Image"
4534 Initialize image attributes.
4536 assert(image != (Image *) NULL);
4537 assert(image->signature == MagickSignature);
4538 if (image->debug != MagickFalse)
4539 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4540 assert(exception != (ExceptionInfo *) NULL);
4541 assert(exception->signature == MagickSignature);
4542 recolor_image=CloneImage(image,0,0,MagickTrue,exception);
4543 if (recolor_image == (Image *) NULL)
4544 return((Image *) NULL);
4545 if (SetImageStorageClass(recolor_image,DirectClass) == MagickFalse)
4547 InheritException(exception,&recolor_image->exception);
4548 recolor_image=DestroyImage(recolor_image);
4549 return((Image *) NULL);
4551 if (image->debug != MagickFalse)
4554 format[MaxTextExtent],
4561 register const double
4564 (void) LogMagickEvent(TransformEvent,GetMagickModule(),
4565 " Recolor image with %ldx%ld color matrix:",order,order);
4566 message=AcquireString("");
4568 for (v=0; v < (long) order; v++)
4571 (void) FormatMagickString(format,MaxTextExtent,"%ld: ",v);
4572 (void) ConcatenateString(&message,format);
4573 for (u=0; u < (long) order; u++)
4575 (void) FormatMagickString(format,MaxTextExtent,"%+f ",*k++);
4576 (void) ConcatenateString(&message,format);
4578 (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
4580 message=DestroyString(message);
4587 image_view=AcquireCacheView(image);
4588 recolor_view=AcquireCacheView(recolor_image);
4589 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4590 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
4592 for (y=0; y < (long) image->rows; y++)
4594 register const double
4597 register const IndexPacket
4598 *__restrict indexes;
4600 register const PixelPacket
4606 register IndexPacket
4607 *__restrict recolor_indexes;
4609 register PixelPacket
4612 if (status == MagickFalse)
4614 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
4615 q=GetCacheViewAuthenticPixels(recolor_view,0,y,recolor_image->columns,1,
4617 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
4622 indexes=GetCacheViewAuthenticIndexQueue(image_view);
4623 recolor_indexes=GetCacheViewAuthenticIndexQueue(recolor_view);
4631 for (x=0; x < (long) image->columns; x++)
4633 q->red=RoundToQuantum(k[0]*p->red);
4641 for (x=0; x < (long) image->columns; x++)
4643 q->red=RoundToQuantum(k[0]*p->red+k[1]*p->green);
4644 q->green=RoundToQuantum(k[2]*p->red+k[3]*p->green);
4652 for (x=0; x < (long) image->columns; x++)
4654 q->red=RoundToQuantum(k[0]*p->red+k[1]*p->green+k[2]*p->blue);
4655 q->green=RoundToQuantum(k[3]*p->red+k[4]*p->green+k[5]*p->blue);
4656 q->blue=RoundToQuantum(k[6]*p->red+k[7]*p->green+k[8]*p->blue);
4664 for (x=0; x < (long) image->columns; x++)
4666 q->red=RoundToQuantum(k[0]*p->red+k[1]*p->green+k[2]*p->blue+
4667 k[12]*QuantumRange);
4668 q->green=RoundToQuantum(k[4]*p->red+k[5]*p->green+k[6]*p->blue+
4669 k[13]*QuantumRange);
4670 q->blue=RoundToQuantum(k[8]*p->red+k[9]*p->green+k[10]*p->blue+
4671 k[14]*QuantumRange);
4679 for (x=0; x < (long) image->columns; x++)
4681 q->red=RoundToQuantum(k[0]*p->red+k[1]*p->green+k[2]*p->blue+
4682 k[3]*(QuantumRange-p->opacity)+k[20]*QuantumRange);
4683 q->green=RoundToQuantum(k[5]*p->red+k[6]*p->green+k[7]*p->blue+
4684 k[8]*(QuantumRange-p->opacity)+k[21]*QuantumRange);
4685 q->blue=RoundToQuantum(k[10]*p->red+k[11]*p->green+k[12]*p->blue+
4686 k[13]*(QuantumRange-p->opacity)+k[22]*QuantumRange);
4687 if (image->matte != MagickFalse)
4688 q->opacity=RoundToQuantum((MagickRealType) QuantumRange-(k[15]*
4689 p->red+k[16]*p->green+k[17]*p->blue+k[18]*(QuantumRange-
4690 p->opacity)+k[23]*QuantumRange));
4698 for (x=0; x < (long) image->columns; x++)
4700 q->red=RoundToQuantum(k[0]*p->red+k[1]*p->green+k[2]*p->blue+
4701 k[3]*indexes[x]+k[4]*((Quantum) QuantumRange-p->opacity)+
4702 k[30]*QuantumRange);
4703 q->green=RoundToQuantum(k[6]*p->red+k[7]*p->green+k[8]*p->blue+
4704 k[9]*indexes[x]+k[10]*((Quantum) QuantumRange-p->opacity)+
4705 k[31]*QuantumRange);
4706 q->blue=RoundToQuantum(k[12]*p->red+k[13]*p->green+k[14]*p->blue+
4707 k[15]*indexes[x]+k[16]*((Quantum) QuantumRange-p->opacity)+
4708 k[32]*QuantumRange);
4709 if (image->matte != MagickFalse)
4710 q->opacity=RoundToQuantum((MagickRealType) QuantumRange-(k[24]*
4711 p->red+k[25]*p->green+k[26]*p->blue+k[27]*indexes[x]+
4712 k[28]*(QuantumRange-p->opacity)+k[34]*QuantumRange));
4713 if (image->colorspace == CMYKColorspace)
4714 recolor_indexes[x]=RoundToQuantum(k[18]*p->red+k[19]*p->green+k[20]*
4715 p->blue+k[21]*indexes[x]+k[22]*((Quantum) QuantumRange-
4716 p->opacity)+k[33]*QuantumRange);
4723 if (SyncCacheViewAuthenticPixels(recolor_view,exception) == MagickFalse)
4725 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4730 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4731 #pragma omp critical (MagickCore_RecolorImage)
4733 proceed=SetImageProgress(image,RecolorImageTag,progress++,image->rows);
4734 if (proceed == MagickFalse)
4738 recolor_view=DestroyCacheView(recolor_view);
4739 image_view=DestroyCacheView(image_view);
4740 if (status == MagickFalse)
4741 recolor_image=DestroyImage(recolor_image);
4742 return(recolor_image);
4746 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4750 % S e p i a T o n e I m a g e %
4754 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4756 % MagickSepiaToneImage() applies a special effect to the image, similar to the
4757 % effect achieved in a photo darkroom by sepia toning. Threshold ranges from
4758 % 0 to QuantumRange and is a measure of the extent of the sepia toning. A
4759 % threshold of 80% is a good starting point for a reasonable tone.
4761 % The format of the SepiaToneImage method is:
4763 % Image *SepiaToneImage(const Image *image,const double threshold,
4764 % ExceptionInfo *exception)
4766 % A description of each parameter follows:
4768 % o image: the image.
4770 % o threshold: the tone threshold.
4772 % o exception: return any errors or warnings in this structure.
4775 MagickExport Image *SepiaToneImage(const Image *image,const double threshold,
4776 ExceptionInfo *exception)
4778 #define SepiaToneImageTag "SepiaTone/Image"
4795 Initialize sepia-toned image attributes.
4797 assert(image != (const Image *) NULL);
4798 assert(image->signature == MagickSignature);
4799 if (image->debug != MagickFalse)
4800 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4801 assert(exception != (ExceptionInfo *) NULL);
4802 assert(exception->signature == MagickSignature);
4803 sepia_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
4804 if (sepia_image == (Image *) NULL)
4805 return((Image *) NULL);
4806 if (SetImageStorageClass(sepia_image,DirectClass) == MagickFalse)
4808 InheritException(exception,&sepia_image->exception);
4809 sepia_image=DestroyImage(sepia_image);
4810 return((Image *) NULL);
4813 Tone each row of the image.
4817 image_view=AcquireCacheView(image);
4818 sepia_view=AcquireCacheView(sepia_image);
4819 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4820 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
4822 for (y=0; y < (long) image->rows; y++)
4824 register const PixelPacket
4830 register PixelPacket
4833 if (status == MagickFalse)
4835 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
4836 q=QueueCacheViewAuthenticPixels(sepia_view,0,y,sepia_image->columns,1,
4838 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
4843 for (x=0; x < (long) image->columns; x++)
4849 intensity=(MagickRealType) PixelIntensityToQuantum(p);
4850 tone=intensity > threshold ? (MagickRealType) QuantumRange : intensity+
4851 (MagickRealType) QuantumRange-threshold;
4852 q->red=RoundToQuantum(tone);
4853 tone=intensity > (7.0*threshold/6.0) ? (MagickRealType) QuantumRange :
4854 intensity+(MagickRealType) QuantumRange-7.0*threshold/6.0;
4855 q->green=RoundToQuantum(tone);
4856 tone=intensity < (threshold/6.0) ? 0 : intensity-threshold/6.0;
4857 q->blue=RoundToQuantum(tone);
4859 if ((MagickRealType) q->green < tone)
4860 q->green=RoundToQuantum(tone);
4861 if ((MagickRealType) q->blue < tone)
4862 q->blue=RoundToQuantum(tone);
4866 if (SyncCacheViewAuthenticPixels(sepia_view,exception) == MagickFalse)
4868 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4873 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4874 #pragma omp critical (MagickCore_SepiaToneImage)
4876 proceed=SetImageProgress(image,SepiaToneImageTag,progress++,
4878 if (proceed == MagickFalse)
4882 sepia_view=DestroyCacheView(sepia_view);
4883 image_view=DestroyCacheView(image_view);
4884 (void) NormalizeImage(sepia_image);
4885 (void) ContrastImage(sepia_image,MagickTrue);
4886 if (status == MagickFalse)
4887 sepia_image=DestroyImage(sepia_image);
4888 return(sepia_image);
4892 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4896 % S h a d o w I m a g e %
4900 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4902 % ShadowImage() simulates a shadow from the specified image and returns it.
4904 % The format of the ShadowImage method is:
4906 % Image *ShadowImage(const Image *image,const double opacity,
4907 % const double sigma,const long x_offset,const long y_offset,
4908 % ExceptionInfo *exception)
4910 % A description of each parameter follows:
4912 % o image: the image.
4914 % o opacity: percentage transparency.
4916 % o sigma: the standard deviation of the Gaussian, in pixels.
4918 % o x_offset: the shadow x-offset.
4920 % o y_offset: the shadow y-offset.
4922 % o exception: return any errors or warnings in this structure.
4925 MagickExport Image *ShadowImage(const Image *image,const double opacity,
4926 const double sigma,const long x_offset,const long y_offset,
4927 ExceptionInfo *exception)
4929 #define ShadowImageTag "Shadow/Image"
4949 assert(image != (Image *) NULL);
4950 assert(image->signature == MagickSignature);
4951 if (image->debug != MagickFalse)
4952 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4953 assert(exception != (ExceptionInfo *) NULL);
4954 assert(exception->signature == MagickSignature);
4955 clone_image=CloneImage(image,0,0,MagickTrue,exception);
4956 if (clone_image == (Image *) NULL)
4957 return((Image *) NULL);
4958 (void) SetImageVirtualPixelMethod(clone_image,EdgeVirtualPixelMethod);
4959 clone_image->compose=OverCompositeOp;
4960 border_info.width=(unsigned long) (2.0*sigma+0.5);
4961 border_info.height=(unsigned long) (2.0*sigma+0.5);
4964 (void) QueryColorDatabase("none",&clone_image->border_color,exception);
4965 border_image=BorderImage(clone_image,&border_info,exception);
4966 clone_image=DestroyImage(clone_image);
4967 if (border_image == (Image *) NULL)
4968 return((Image *) NULL);
4969 if (border_image->matte == MagickFalse)
4970 (void) SetImageAlphaChannel(border_image,OpaqueAlphaChannel);
4976 image_view=AcquireCacheView(border_image);
4977 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4978 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
4980 for (y=0; y < (long) border_image->rows; y++)
4985 register PixelPacket
4988 if (status == MagickFalse)
4990 q=GetCacheViewAuthenticPixels(image_view,0,y,border_image->columns,1,
4992 if (q == (PixelPacket *) NULL)
4997 for (x=0; x < (long) border_image->columns; x++)
4999 q->red=border_image->background_color.red;
5000 q->green=border_image->background_color.green;
5001 q->blue=border_image->background_color.blue;
5002 if (border_image->matte == MagickFalse)
5003 q->opacity=border_image->background_color.opacity;
5005 q->opacity=RoundToQuantum((MagickRealType) (QuantumRange-(QuantumRange-
5006 q->opacity)*opacity/100.0));
5009 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
5011 if (image->progress_monitor != (MagickProgressMonitor) NULL)
5016 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5017 #pragma omp critical (MagickCore_ShadowImage)
5019 proceed=SetImageProgress(image,ShadowImageTag,progress++,
5020 border_image->rows);
5021 if (proceed == MagickFalse)
5025 image_view=DestroyCacheView(image_view);
5026 shadow_image=BlurImageChannel(border_image,AlphaChannel,0.0,sigma,exception);
5027 border_image=DestroyImage(border_image);
5028 if (shadow_image == (Image *) NULL)
5029 return((Image *) NULL);
5030 if (shadow_image->page.width == 0)
5031 shadow_image->page.width=shadow_image->columns;
5032 if (shadow_image->page.height == 0)
5033 shadow_image->page.height=shadow_image->rows;
5034 shadow_image->page.width+=x_offset-(long) border_info.width;
5035 shadow_image->page.height+=y_offset-(long) border_info.height;
5036 shadow_image->page.x+=x_offset-(long) border_info.width;
5037 shadow_image->page.y+=y_offset-(long) border_info.height;
5038 return(shadow_image);
5042 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5046 % S k e t c h I m a g e %
5050 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5052 % SketchImage() simulates a pencil sketch. We convolve the image with a
5053 % Gaussian operator of the given radius and standard deviation (sigma). For
5054 % reasonable results, radius should be larger than sigma. Use a radius of 0
5055 % and SketchImage() selects a suitable radius for you. Angle gives the angle
5058 % The format of the SketchImage method is:
5060 % Image *SketchImage(const Image *image,const double radius,
5061 % const double sigma,const double angle,ExceptionInfo *exception)
5063 % A description of each parameter follows:
5065 % o image: the image.
5067 % o radius: the radius of the Gaussian, in pixels, not counting
5070 % o sigma: the standard deviation of the Gaussian, in pixels.
5072 % o angle: Apply the effect along this angle.
5074 % o exception: return any errors or warnings in this structure.
5077 MagickExport Image *SketchImage(const Image *image,const double radius,
5078 const double sigma,const double angle,ExceptionInfo *exception)
5105 random_image=CloneImage(image,image->columns << 1,image->rows << 1,
5106 MagickTrue,exception);
5107 if (random_image == (Image *) NULL)
5108 return((Image *) NULL);
5110 GetMagickPixelPacket(random_image,&zero);
5111 random_info=AcquireRandomInfo();
5112 random_view=AcquireCacheView(random_image);
5113 for (y=0; y < (long) random_image->rows; y++)
5118 register IndexPacket
5119 *__restrict indexes;
5124 register PixelPacket
5127 q=QueueCacheViewAuthenticPixels(random_view,0,y,random_image->columns,1,
5129 if (q == (PixelPacket *) NULL)
5134 indexes=GetCacheViewAuthenticIndexQueue(random_view);
5136 for (x=0; x < (long) random_image->columns; x++)
5138 pixel.red=(MagickRealType) (QuantumRange*
5139 GetPseudoRandomValue(random_info));
5140 pixel.green=pixel.red;
5141 pixel.blue=pixel.red;
5142 if (image->colorspace == CMYKColorspace)
5143 pixel.index=pixel.red;
5144 SetPixelPacket(random_image,&pixel,q,indexes+x);
5147 if (SyncCacheViewAuthenticPixels(random_view,exception) == MagickFalse)
5149 if (status == MagickFalse)
5152 random_view=DestroyCacheView(random_view);
5153 random_info=DestroyRandomInfo(random_info);
5154 if (status == MagickFalse)
5156 random_image=DestroyImage(random_image);
5157 return(random_image);
5159 blur_image=MotionBlurImage(random_image,radius,sigma,angle,exception);
5160 random_image=DestroyImage(random_image);
5161 if (blur_image == (Image *) NULL)
5162 return((Image *) NULL);
5163 dodge_image=EdgeImage(blur_image,radius,exception);
5164 blur_image=DestroyImage(blur_image);
5165 if (dodge_image == (Image *) NULL)
5166 return((Image *) NULL);
5167 (void) NormalizeImage(dodge_image);
5168 (void) NegateImage(dodge_image,MagickFalse);
5169 (void) TransformImage(&dodge_image,(char *) NULL,"50%");
5170 sketch_image=CloneImage(image,0,0,MagickTrue,exception);
5171 if (sketch_image == (Image *) NULL)
5173 dodge_image=DestroyImage(dodge_image);
5174 return((Image *) NULL);
5176 (void) CompositeImage(sketch_image,ColorDodgeCompositeOp,dodge_image,0,0);
5177 dodge_image=DestroyImage(dodge_image);
5178 blend_image=CloneImage(image,0,0,MagickTrue,exception);
5179 if (blend_image == (Image *) NULL)
5181 sketch_image=DestroyImage(sketch_image);
5182 return((Image *) NULL);
5184 (void) SetImageArtifact(blend_image,"compose:args","20x80");
5185 (void) CompositeImage(sketch_image,BlendCompositeOp,blend_image,0,0);
5186 blend_image=DestroyImage(blend_image);
5187 return(sketch_image);
5191 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5195 % S o l a r i z e I m a g e %
5199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5201 % SolarizeImage() applies a special effect to the image, similar to the effect
5202 % achieved in a photo darkroom by selectively exposing areas of photo
5203 % sensitive paper to light. Threshold ranges from 0 to QuantumRange and is a
5204 % measure of the extent of the solarization.
5206 % The format of the SolarizeImage method is:
5208 % MagickBooleanType SolarizeImage(Image *image,const double threshold)
5210 % A description of each parameter follows:
5212 % o image: the image.
5214 % o threshold: Define the extent of the solarization.
5217 MagickExport MagickBooleanType SolarizeImage(Image *image,
5218 const double threshold)
5220 #define SolarizeImageTag "Solarize/Image"
5235 assert(image != (Image *) NULL);
5236 assert(image->signature == MagickSignature);
5237 if (image->debug != MagickFalse)
5238 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5239 if (image->storage_class == PseudoClass)
5247 for (i=0; i < (long) image->colors; i++)
5249 if ((MagickRealType) image->colormap[i].red > threshold)
5250 image->colormap[i].red=(Quantum) QuantumRange-image->colormap[i].red;
5251 if ((MagickRealType) image->colormap[i].green > threshold)
5252 image->colormap[i].green=(Quantum) QuantumRange-
5253 image->colormap[i].green;
5254 if ((MagickRealType) image->colormap[i].blue > threshold)
5255 image->colormap[i].blue=(Quantum) QuantumRange-
5256 image->colormap[i].blue;
5264 exception=(&image->exception);
5265 image_view=AcquireCacheView(image);
5266 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5267 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
5269 for (y=0; y < (long) image->rows; y++)
5274 register PixelPacket
5277 if (status == MagickFalse)
5279 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
5281 if (q == (PixelPacket *) NULL)
5286 for (x=0; x < (long) image->columns; x++)
5288 if ((MagickRealType) q->red > threshold)
5289 q->red=(Quantum) QuantumRange-q->red;
5290 if ((MagickRealType) q->green > threshold)
5291 q->green=(Quantum) QuantumRange-q->green;
5292 if ((MagickRealType) q->blue > threshold)
5293 q->blue=(Quantum) QuantumRange-q->blue;
5296 if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
5298 if (image->progress_monitor != (MagickProgressMonitor) NULL)
5303 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5304 #pragma omp critical (MagickCore_SolarizeImage)
5306 proceed=SetImageProgress(image,SolarizeImageTag,progress++,image->rows);
5307 if (proceed == MagickFalse)
5311 image_view=DestroyCacheView(image_view);
5316 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5320 % S t e g a n o I m a g e %
5324 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5326 % SteganoImage() hides a digital watermark within the image. Recover
5327 % the hidden watermark later to prove that the authenticity of an image.
5328 % Offset defines the start position within the image to hide the watermark.
5330 % The format of the SteganoImage method is:
5332 % Image *SteganoImage(const Image *image,Image *watermark,
5333 % ExceptionInfo *exception)
5335 % A description of each parameter follows:
5337 % o image: the image.
5339 % o watermark: the watermark image.
5341 % o exception: return any errors or warnings in this structure.
5344 MagickExport Image *SteganoImage(const Image *image,const Image *watermark,
5345 ExceptionInfo *exception)
5347 #define GetBit(alpha,i) ((((unsigned long) (alpha) >> (unsigned long) \
5349 #define SetBit(alpha,i,set) (alpha)=(Quantum) ((set) ? (unsigned long) (alpha) \
5350 | (1UL << (unsigned long) (i)) : (unsigned long) (alpha) & \
5351 ~(1UL << (unsigned long) (i)))
5352 #define SteganoImageTag "Stegano/Image"
5375 register PixelPacket
5382 Initialize steganographic image attributes.
5384 assert(image != (const Image *) NULL);
5385 assert(image->signature == MagickSignature);
5386 if (image->debug != MagickFalse)
5387 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5388 assert(watermark != (const Image *) NULL);
5389 assert(watermark->signature == MagickSignature);
5390 assert(exception != (ExceptionInfo *) NULL);
5391 assert(exception->signature == MagickSignature);
5392 stegano_image=CloneImage(image,0,0,MagickTrue,exception);
5393 if (stegano_image == (Image *) NULL)
5394 return((Image *) NULL);
5395 if (SetImageStorageClass(stegano_image,DirectClass) == MagickFalse)
5397 InheritException(exception,&stegano_image->exception);
5398 stegano_image=DestroyImage(stegano_image);
5399 return((Image *) NULL);
5401 stegano_image->depth=MAGICKCORE_QUANTUM_DEPTH;
5403 Hide watermark in low-order bits of image.
5408 depth=stegano_image->depth;
5410 for (i=(long) depth-1; (i >= 0) && (j < (long) depth); i--)
5412 for (y=0; (y < (long) watermark->rows) && (j < (long) depth); y++)
5414 for (x=0; (x < (long) watermark->columns) && (j < (long) depth); x++)
5416 (void) GetOneVirtualPixel(watermark,x,y,&pixel,exception);
5417 if ((k/(long) stegano_image->columns) >= (long) stegano_image->rows)
5419 q=GetAuthenticPixels(stegano_image,k % (long) stegano_image->columns,
5420 k/(long) stegano_image->columns,1,1,exception);
5421 if (q == (PixelPacket *) NULL)
5427 SetBit(q->red,j,GetBit(PixelIntensityToQuantum(&pixel),i));
5432 SetBit(q->green,j,GetBit(PixelIntensityToQuantum(&pixel),i));
5437 SetBit(q->blue,j,GetBit(PixelIntensityToQuantum(&pixel),i));
5441 if (SyncAuthenticPixels(stegano_image,exception) == MagickFalse)
5447 if (k == (long) (stegano_image->columns*stegano_image->columns))
5449 if (k == image->offset)
5453 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
5454 (QuantumTick((MagickOffsetType) depth-i,depth) != MagickFalse))
5456 status=image->progress_monitor(SteganoImageTag,(MagickOffsetType) depth-
5457 i,depth,image->client_data);
5458 if (status == MagickFalse)
5462 if (stegano_image->storage_class == PseudoClass)
5463 (void) SyncImage(stegano_image);
5464 return(stegano_image);
5468 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5472 % S t e r e o A n a g l y p h I m a g e %
5476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5478 % StereoAnaglyphImage() combines two images and produces a single image that
5479 % is the composite of a left and right image of a stereo pair. Special
5480 % red-green stereo glasses are required to view this effect.
5482 % The format of the StereoAnaglyphImage method is:
5484 % Image *StereoImage(const Image *left_image,const Image *right_image,
5485 % ExceptionInfo *exception)
5486 % Image *StereoAnaglyphImage(const Image *left_image,
5487 % const Image *right_image,const long x_offset,const long y_offset,
5488 % ExceptionInfo *exception)
5490 % A description of each parameter follows:
5492 % o left_image: the left image.
5494 % o right_image: the right image.
5496 % o exception: return any errors or warnings in this structure.
5498 % o x_offset: amount, in pixels, by which the left image is offset to the
5499 % right of the right image.
5501 % o y_offset: amount, in pixels, by which the left image is offset to the
5502 % bottom of the right image.
5506 MagickExport Image *StereoImage(const Image *left_image,
5507 const Image *right_image,ExceptionInfo *exception)
5509 return(StereoAnaglyphImage(left_image,right_image,0,0,exception));
5512 MagickExport Image *StereoAnaglyphImage(const Image *left_image,
5513 const Image *right_image,const long x_offset,const long y_offset,
5514 ExceptionInfo *exception)
5516 #define StereoImageTag "Stereo/Image"
5530 assert(left_image != (const Image *) NULL);
5531 assert(left_image->signature == MagickSignature);
5532 if (left_image->debug != MagickFalse)
5533 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
5534 left_image->filename);
5535 assert(right_image != (const Image *) NULL);
5536 assert(right_image->signature == MagickSignature);
5537 assert(exception != (ExceptionInfo *) NULL);
5538 assert(exception->signature == MagickSignature);
5539 assert(right_image != (const Image *) NULL);
5541 if ((left_image->columns != right_image->columns) ||
5542 (left_image->rows != right_image->rows))
5543 ThrowImageException(ImageError,"LeftAndRightImageSizesDiffer");
5545 Initialize stereo image attributes.
5547 stereo_image=CloneImage(left_image,left_image->columns,left_image->rows,
5548 MagickTrue,exception);
5549 if (stereo_image == (Image *) NULL)
5550 return((Image *) NULL);
5551 if (SetImageStorageClass(stereo_image,DirectClass) == MagickFalse)
5553 InheritException(exception,&stereo_image->exception);
5554 stereo_image=DestroyImage(stereo_image);
5555 return((Image *) NULL);
5558 Copy left image to red channel and right image to blue channel.
5560 for (y=0; y < (long) stereo_image->rows; y++)
5562 register const PixelPacket
5569 register PixelPacket
5572 p=GetVirtualPixels(left_image,-x_offset,y-y_offset,image->columns,1,
5574 q=GetVirtualPixels(right_image,0,y,right_image->columns,1,exception);
5575 r=QueueAuthenticPixels(stereo_image,0,y,stereo_image->columns,1,exception);
5576 if ((p == (PixelPacket *) NULL) || (q == (PixelPacket *) NULL) ||
5577 (r == (PixelPacket *) NULL))
5579 for (x=0; x < (long) stereo_image->columns; x++)
5584 r->opacity=(Quantum) ((p->opacity+q->opacity)/2);
5589 if (SyncAuthenticPixels(stereo_image,exception) == MagickFalse)
5591 if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
5592 (QuantumTick(y,image->rows) != MagickFalse))
5594 status=image->progress_monitor(StereoImageTag,y,stereo_image->rows,
5595 stereo_image->client_data);
5596 if (status == MagickFalse)
5600 return(stereo_image);
5604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5608 % S w i r l I m a g e %
5612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5614 % SwirlImage() swirls the pixels about the center of the image, where
5615 % degrees indicates the sweep of the arc through which each pixel is moved.
5616 % You get a more dramatic effect as the degrees move from 1 to 360.
5618 % The format of the SwirlImage method is:
5620 % Image *SwirlImage(const Image *image,double degrees,
5621 % ExceptionInfo *exception)
5623 % A description of each parameter follows:
5625 % o image: the image.
5627 % o degrees: Define the tightness of the swirling effect.
5629 % o exception: return any errors or warnings in this structure.
5632 MagickExport Image *SwirlImage(const Image *image,double degrees,
5633 ExceptionInfo *exception)
5635 #define SwirlImageTag "Swirl/Image"
5665 Initialize swirl image attributes.
5667 assert(image != (const Image *) NULL);
5668 assert(image->signature == MagickSignature);
5669 if (image->debug != MagickFalse)
5670 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5671 assert(exception != (ExceptionInfo *) NULL);
5672 assert(exception->signature == MagickSignature);
5673 swirl_image=CloneImage(image,0,0,MagickTrue,exception);
5674 if (swirl_image == (Image *) NULL)
5675 return((Image *) NULL);
5676 if (SetImageStorageClass(swirl_image,DirectClass) == MagickFalse)
5678 InheritException(exception,&swirl_image->exception);
5679 swirl_image=DestroyImage(swirl_image);
5680 return((Image *) NULL);
5682 if (swirl_image->background_color.opacity != OpaqueOpacity)
5683 swirl_image->matte=MagickTrue;
5685 Compute scaling factor.
5687 center.x=(double) image->columns/2.0;
5688 center.y=(double) image->rows/2.0;
5689 radius=MagickMax(center.x,center.y);
5692 if (image->columns > image->rows)
5693 scale.y=(double) image->columns/(double) image->rows;
5695 if (image->columns < image->rows)
5696 scale.x=(double) image->rows/(double) image->columns;
5697 degrees=(double) DegreesToRadians(degrees);
5703 GetMagickPixelPacket(swirl_image,&zero);
5704 resample_filter=AcquireResampleFilterThreadSet(image,MagickTrue,exception);
5705 image_view=AcquireCacheView(image);
5706 swirl_view=AcquireCacheView(swirl_image);
5707 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5708 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
5710 for (y=0; y < (long) image->rows; y++)
5721 register IndexPacket
5722 *__restrict swirl_indexes;
5728 register PixelPacket
5731 if (status == MagickFalse)
5733 q=GetCacheViewAuthenticPixels(swirl_view,0,y,swirl_image->columns,1,
5735 if (q == (PixelPacket *) NULL)
5740 swirl_indexes=GetCacheViewAuthenticIndexQueue(swirl_view);
5741 delta.y=scale.y*(double) (y-center.y);
5743 id=GetOpenMPThreadId();
5744 for (x=0; x < (long) image->columns; x++)
5747 Determine if the pixel is within an ellipse.
5749 delta.x=scale.x*(double) (x-center.x);
5750 distance=delta.x*delta.x+delta.y*delta.y;
5751 if (distance < (radius*radius))
5761 factor=1.0-sqrt((double) distance)/radius;
5762 sine=sin((double) (degrees*factor*factor));
5763 cosine=cos((double) (degrees*factor*factor));
5764 (void) ResamplePixelColor(resample_filter[id],(double) ((cosine*
5765 delta.x-sine*delta.y)/scale.x+center.x),(double) ((sine*delta.x+
5766 cosine*delta.y)/scale.y+center.y),&pixel);
5767 SetPixelPacket(swirl_image,&pixel,q,swirl_indexes+x);
5771 if (SyncCacheViewAuthenticPixels(swirl_view,exception) == MagickFalse)
5773 if (image->progress_monitor != (MagickProgressMonitor) NULL)
5778 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5779 #pragma omp critical (MagickCore_SwirlImage)
5781 proceed=SetImageProgress(image,SwirlImageTag,progress++,image->rows);
5782 if (proceed == MagickFalse)
5786 swirl_view=DestroyCacheView(swirl_view);
5787 image_view=DestroyCacheView(image_view);
5788 resample_filter=DestroyResampleFilterThreadSet(resample_filter);
5789 if (status == MagickFalse)
5790 swirl_image=DestroyImage(swirl_image);
5791 return(swirl_image);
5795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5799 % T i n t I m a g e %
5803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5805 % TintImage() applies a color vector to each pixel in the image. The length
5806 % of the vector is 0 for black and white and at its maximum for the midtones.
5807 % The vector weighting function is f(x)=(1-(4.0*((x-0.5)*(x-0.5))))
5809 % The format of the TintImage method is:
5811 % Image *TintImage(const Image *image,const char *opacity,
5812 % const PixelPacket tint,ExceptionInfo *exception)
5814 % A description of each parameter follows:
5816 % o image: the image.
5818 % o opacity: A color value used for tinting.
5820 % o tint: A color value used for tinting.
5822 % o exception: return any errors or warnings in this structure.
5825 MagickExport Image *TintImage(const Image *image,const char *opacity,
5826 const PixelPacket tint,ExceptionInfo *exception)
5828 #define TintImageTag "Tint/Image"
5855 Allocate tint image.
5857 assert(image != (const Image *) NULL);
5858 assert(image->signature == MagickSignature);
5859 if (image->debug != MagickFalse)
5860 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5861 assert(exception != (ExceptionInfo *) NULL);
5862 assert(exception->signature == MagickSignature);
5863 tint_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
5864 if (tint_image == (Image *) NULL)
5865 return((Image *) NULL);
5866 if (SetImageStorageClass(tint_image,DirectClass) == MagickFalse)
5868 InheritException(exception,&tint_image->exception);
5869 tint_image=DestroyImage(tint_image);
5870 return((Image *) NULL);
5872 if (opacity == (const char *) NULL)
5875 Determine RGB values of the color.
5877 flags=ParseGeometry(opacity,&geometry_info);
5878 pixel.red=geometry_info.rho;
5879 if ((flags & SigmaValue) != 0)
5880 pixel.green=geometry_info.sigma;
5882 pixel.green=pixel.red;
5883 if ((flags & XiValue) != 0)
5884 pixel.blue=geometry_info.xi;
5886 pixel.blue=pixel.red;
5887 if ((flags & PsiValue) != 0)
5888 pixel.opacity=geometry_info.psi;
5890 pixel.opacity=(MagickRealType) OpaqueOpacity;
5891 color_vector.red=(MagickRealType) (pixel.red*tint.red/100.0-
5892 PixelIntensity(&tint));
5893 color_vector.green=(MagickRealType) (pixel.green*tint.green/100.0-
5894 PixelIntensity(&tint));
5895 color_vector.blue=(MagickRealType) (pixel.blue*tint.blue/100.0-
5896 PixelIntensity(&tint));
5902 image_view=AcquireCacheView(image);
5903 tint_view=AcquireCacheView(tint_image);
5904 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5905 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
5907 for (y=0; y < (long) image->rows; y++)
5909 register const PixelPacket
5915 register PixelPacket
5918 if (status == MagickFalse)
5920 p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
5921 q=QueueCacheViewAuthenticPixels(tint_view,0,y,tint_image->columns,1,
5923 if ((p == (const PixelPacket *) NULL) || (q == (PixelPacket *) NULL))
5928 for (x=0; x < (long) image->columns; x++)
5936 weight=QuantumScale*p->red-0.5;
5937 pixel.red=(MagickRealType) p->red+color_vector.red*(1.0-(4.0*
5939 q->red=RoundToQuantum(pixel.red);
5940 weight=QuantumScale*p->green-0.5;
5941 pixel.green=(MagickRealType) p->green+color_vector.green*(1.0-(4.0*
5943 q->green=RoundToQuantum(pixel.green);
5944 weight=QuantumScale*p->blue-0.5;
5945 pixel.blue=(MagickRealType) p->blue+color_vector.blue*(1.0-(4.0*
5947 q->blue=RoundToQuantum(pixel.blue);
5948 q->opacity=p->opacity;
5952 if (SyncCacheViewAuthenticPixels(tint_view,exception) == MagickFalse)
5954 if (image->progress_monitor != (MagickProgressMonitor) NULL)
5959 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5960 #pragma omp critical (MagickCore_TintImage)
5962 proceed=SetImageProgress(image,TintImageTag,progress++,image->rows);
5963 if (proceed == MagickFalse)
5967 tint_view=DestroyCacheView(tint_view);
5968 image_view=DestroyCacheView(image_view);
5969 if (status == MagickFalse)
5970 tint_image=DestroyImage(tint_image);
5975 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5979 % V i g n e t t e I m a g e %
5983 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5985 % VignetteImage() softens the edges of the image in vignette style.
5987 % The format of the VignetteImage method is:
5989 % Image *VignetteImage(const Image *image,const double radius,
5990 % const double sigma,const long x,const long y,ExceptionInfo *exception)
5992 % A description of each parameter follows:
5994 % o image: the image.
5996 % o radius: the radius of the pixel neighborhood.
5998 % o sigma: the standard deviation of the Gaussian, in pixels.
6000 % o x, y: Define the x and y ellipse offset.
6002 % o exception: return any errors or warnings in this structure.
6005 MagickExport Image *VignetteImage(const Image *image,const double radius,
6006 const double sigma,const long x,const long y,ExceptionInfo *exception)
6009 ellipse[MaxTextExtent];
6020 assert(image != (Image *) NULL);
6021 assert(image->signature == MagickSignature);
6022 if (image->debug != MagickFalse)
6023 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
6024 assert(exception != (ExceptionInfo *) NULL);
6025 assert(exception->signature == MagickSignature);
6026 canvas_image=CloneImage(image,0,0,MagickTrue,exception);
6027 if (canvas_image == (Image *) NULL)
6028 return((Image *) NULL);
6029 if (SetImageStorageClass(canvas_image,DirectClass) == MagickFalse)
6031 InheritException(exception,&canvas_image->exception);
6032 canvas_image=DestroyImage(canvas_image);
6033 return((Image *) NULL);
6035 canvas_image->matte=MagickTrue;
6036 oval_image=CloneImage(canvas_image,canvas_image->columns,
6037 canvas_image->rows,MagickTrue,exception);
6038 if (oval_image == (Image *) NULL)
6040 canvas_image=DestroyImage(canvas_image);
6041 return((Image *) NULL);
6043 (void) QueryColorDatabase("#000000",&oval_image->background_color,exception);
6044 (void) SetImageBackgroundColor(oval_image);
6045 draw_info=CloneDrawInfo((const ImageInfo *) NULL,(const DrawInfo *) NULL);
6046 (void) QueryColorDatabase("#ffffff",&draw_info->fill,exception);
6047 (void) QueryColorDatabase("#ffffff",&draw_info->stroke,exception);
6048 (void) FormatMagickString(ellipse,MaxTextExtent,
6049 "ellipse %g,%g,%g,%g,0.0,360.0",image->columns/2.0,image->rows/2.0,
6050 image->columns/2.0-x,image->rows/2.0-y);
6051 draw_info->primitive=AcquireString(ellipse);
6052 (void) DrawImage(oval_image,draw_info);
6053 draw_info=DestroyDrawInfo(draw_info);
6054 blur_image=BlurImage(oval_image,radius,sigma,exception);
6055 oval_image=DestroyImage(oval_image);
6056 if (blur_image == (Image *) NULL)
6058 canvas_image=DestroyImage(canvas_image);
6059 return((Image *) NULL);
6061 blur_image->matte=MagickFalse;
6062 (void) CompositeImage(canvas_image,CopyOpacityCompositeOp,blur_image,0,0);
6063 blur_image=DestroyImage(blur_image);
6064 vignette_image=MergeImageLayers(canvas_image,FlattenLayer,exception);
6065 canvas_image=DestroyImage(canvas_image);
6066 return(vignette_image);
6070 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6074 % W a v e I m a g e %
6078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6080 % WaveImage() creates a "ripple" effect in the image by shifting the pixels
6081 % vertically along a sine wave whose amplitude and wavelength is specified
6082 % by the given parameters.
6084 % The format of the WaveImage method is:
6086 % Image *WaveImage(const Image *image,const double amplitude,
6087 % const double wave_length,ExceptionInfo *exception)
6089 % A description of each parameter follows:
6091 % o image: the image.
6093 % o amplitude, wave_length: Define the amplitude and wave length of the
6096 % o exception: return any errors or warnings in this structure.
6099 MagickExport Image *WaveImage(const Image *image,const double amplitude,
6100 const double wave_length,ExceptionInfo *exception)
6102 #define WaveImageTag "Wave/Image"
6130 Initialize wave image attributes.
6132 assert(image != (Image *) NULL);
6133 assert(image->signature == MagickSignature);
6134 if (image->debug != MagickFalse)
6135 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
6136 assert(exception != (ExceptionInfo *) NULL);
6137 assert(exception->signature == MagickSignature);
6138 wave_image=CloneImage(image,image->columns,(unsigned long) (image->rows+2.0*
6139 fabs(amplitude)),MagickTrue,exception);
6140 if (wave_image == (Image *) NULL)
6141 return((Image *) NULL);
6142 if (SetImageStorageClass(wave_image,DirectClass) == MagickFalse)
6144 InheritException(exception,&wave_image->exception);
6145 wave_image=DestroyImage(wave_image);
6146 return((Image *) NULL);
6148 if (wave_image->background_color.opacity != OpaqueOpacity)
6149 wave_image->matte=MagickTrue;
6153 sine_map=(MagickRealType *) AcquireQuantumMemory((size_t) wave_image->columns,
6155 if (sine_map == (MagickRealType *) NULL)
6157 wave_image=DestroyImage(wave_image);
6158 ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
6160 for (i=0; i < (long) wave_image->columns; i++)
6161 sine_map[i]=fabs(amplitude)+amplitude*sin((2*MagickPI*i)/wave_length);
6167 GetMagickPixelPacket(wave_image,&zero);
6168 resample_filter=AcquireResampleFilterThreadSet(image,MagickTrue,exception);
6169 wave_view=AcquireCacheView(wave_image);
6170 #if defined(MAGICKCORE_OPENMP_SUPPORT)
6171 #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
6173 for (y=0; y < (long) wave_image->rows; y++)
6178 register IndexPacket
6179 *__restrict indexes;
6185 register PixelPacket
6188 if (status == MagickFalse)
6190 q=QueueCacheViewAuthenticPixels(wave_view,0,y,wave_image->columns,1,
6192 if (q == (PixelPacket *) NULL)
6197 indexes=GetCacheViewAuthenticIndexQueue(wave_view);
6199 id=GetOpenMPThreadId();
6200 (void) SetResampleFilterVirtualPixelMethod(resample_filter[id],
6201 BackgroundVirtualPixelMethod);
6202 for (x=0; x < (long) wave_image->columns; x++)
6204 (void) ResamplePixelColor(resample_filter[id],(double) x,(double) (y-
6205 sine_map[x]),&pixel);
6206 SetPixelPacket(wave_image,&pixel,q,indexes+x);
6209 if (SyncCacheViewAuthenticPixels(wave_view,exception) == MagickFalse)
6211 if (image->progress_monitor != (MagickProgressMonitor) NULL)
6216 #if defined(MAGICKCORE_OPENMP_SUPPORT)
6217 #pragma omp critical (MagickCore_WaveImage)
6219 proceed=SetImageProgress(image,WaveImageTag,progress++,image->rows);
6220 if (proceed == MagickFalse)
6224 wave_view=DestroyCacheView(wave_view);
6225 resample_filter=DestroyResampleFilterThreadSet(resample_filter);
6226 sine_map=(MagickRealType *) RelinquishMagickMemory(sine_map);
6227 if (status == MagickFalse)
6228 wave_image=DestroyImage(wave_image);