]> granicus.if.org Git - imagemagick/blob - MagickCore/fx.c
(no commit message)
[imagemagick] / MagickCore / fx.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                                 FFFFF  X   X                                %
7 %                                 F       X X                                 %
8 %                                 FFF      X                                  %
9 %                                 F       X X                                 %
10 %                                 F      X   X                                %
11 %                                                                             %
12 %                                                                             %
13 %                   MagickCore Image Special Effects Methods                  %
14 %                                                                             %
15 %                               Software Design                               %
16 %                                 John Cristy                                 %
17 %                                 October 1996                                %
18 %                                                                             %
19 %                                                                             %
20 %  Copyright 1999-2012 ImageMagick Studio LLC, a non-profit organization      %
21 %  dedicated to making software imaging solutions freely available.           %
22 %                                                                             %
23 %  You may not use this file except in compliance with the License.  You may  %
24 %  obtain a copy of the License at                                            %
25 %                                                                             %
26 %    http://www.imagemagick.org/script/license.php                            %
27 %                                                                             %
28 %  Unless required by applicable law or agreed to in writing, software        %
29 %  distributed under the License is distributed on an "AS IS" BASIS,          %
30 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31 %  See the License for the specific language governing permissions and        %
32 %  limitations under the License.                                             %
33 %                                                                             %
34 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35 %
36 %
37 %
38 */
39 \f
40 /*
41   Include declarations.
42 */
43 #include "MagickCore/studio.h"
44 #include "MagickCore/annotate.h"
45 #include "MagickCore/artifact.h"
46 #include "MagickCore/attribute.h"
47 #include "MagickCore/cache.h"
48 #include "MagickCore/cache-view.h"
49 #include "MagickCore/color.h"
50 #include "MagickCore/color-private.h"
51 #include "MagickCore/colorspace-private.h"
52 #include "MagickCore/composite.h"
53 #include "MagickCore/decorate.h"
54 #include "MagickCore/distort.h"
55 #include "MagickCore/draw.h"
56 #include "MagickCore/effect.h"
57 #include "MagickCore/enhance.h"
58 #include "MagickCore/exception.h"
59 #include "MagickCore/exception-private.h"
60 #include "MagickCore/fx.h"
61 #include "MagickCore/fx-private.h"
62 #include "MagickCore/gem.h"
63 #include "MagickCore/gem-private.h"
64 #include "MagickCore/geometry.h"
65 #include "MagickCore/layer.h"
66 #include "MagickCore/list.h"
67 #include "MagickCore/log.h"
68 #include "MagickCore/image.h"
69 #include "MagickCore/image-private.h"
70 #include "MagickCore/magick.h"
71 #include "MagickCore/memory_.h"
72 #include "MagickCore/monitor.h"
73 #include "MagickCore/monitor-private.h"
74 #include "MagickCore/option.h"
75 #include "MagickCore/pixel.h"
76 #include "MagickCore/pixel-accessor.h"
77 #include "MagickCore/property.h"
78 #include "MagickCore/quantum.h"
79 #include "MagickCore/quantum-private.h"
80 #include "MagickCore/random_.h"
81 #include "MagickCore/random-private.h"
82 #include "MagickCore/resample.h"
83 #include "MagickCore/resample-private.h"
84 #include "MagickCore/resize.h"
85 #include "MagickCore/resource_.h"
86 #include "MagickCore/splay-tree.h"
87 #include "MagickCore/statistic.h"
88 #include "MagickCore/string_.h"
89 #include "MagickCore/string-private.h"
90 #include "MagickCore/thread-private.h"
91 #include "MagickCore/transform.h"
92 #include "MagickCore/utility.h"
93 \f
94 /*
95   Define declarations.
96 */
97 #define LeftShiftOperator 0xf5
98 #define RightShiftOperator 0xf6
99 #define LessThanEqualOperator 0xf7
100 #define GreaterThanEqualOperator 0xf8
101 #define EqualOperator 0xf9
102 #define NotEqualOperator 0xfa
103 #define LogicalAndOperator 0xfb
104 #define LogicalOrOperator 0xfc
105 #define ExponentialNotation 0xfd
106
107 struct _FxInfo
108 {
109   const Image
110     *images;
111
112   char
113     *expression;
114
115   FILE
116     *file;
117
118   SplayTreeInfo
119     *colors,
120     *symbols;
121
122   CacheView
123     **view;
124
125   RandomInfo
126     *random_info;
127
128   ExceptionInfo
129     *exception;
130 };
131 \f
132 /*
133 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
134 %                                                                             %
135 %                                                                             %
136 %                                                                             %
137 +   A c q u i r e F x I n f o                                                 %
138 %                                                                             %
139 %                                                                             %
140 %                                                                             %
141 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
142 %
143 %  AcquireFxInfo() allocates the FxInfo structure.
144 %
145 %  The format of the AcquireFxInfo method is:
146 %
147 %      FxInfo *AcquireFxInfo(Image *image,const char *expression,
148 %        ExceptionInfo *exception)
149 %
150 %  A description of each parameter follows:
151 %
152 %    o image: the image.
153 %
154 %    o expression: the expression.
155 %
156 %    o exception: return any errors or warnings in this structure.
157 %
158 */
159 MagickPrivate FxInfo *AcquireFxInfo(const Image *image,const char *expression,
160   ExceptionInfo *exception)
161 {
162   char
163     fx_op[2];
164
165   const Image
166     *next;
167
168   FxInfo
169     *fx_info;
170
171   register ssize_t
172     i;
173
174   fx_info=(FxInfo *) AcquireMagickMemory(sizeof(*fx_info));
175   if (fx_info == (FxInfo *) NULL)
176     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
177   (void) ResetMagickMemory(fx_info,0,sizeof(*fx_info));
178   fx_info->exception=AcquireExceptionInfo();
179   fx_info->images=image;
180   fx_info->colors=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
181     RelinquishMagickMemory);
182   fx_info->symbols=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
183     RelinquishMagickMemory);
184   fx_info->view=(CacheView **) AcquireQuantumMemory(GetImageListLength(
185     fx_info->images),sizeof(*fx_info->view));
186   if (fx_info->view == (CacheView **) NULL)
187     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
188   i=0;
189   next=GetFirstImageInList(fx_info->images);
190   for ( ; next != (Image *) NULL; next=next->next)
191   {
192     fx_info->view[i]=AcquireVirtualCacheView(next,exception);
193     i++;
194   }
195   fx_info->random_info=AcquireRandomInfo();
196   fx_info->expression=ConstantString(expression);
197   fx_info->file=stderr;
198   (void) SubstituteString(&fx_info->expression," ","");  /* compact string */
199   /*
200     Force right-to-left associativity for unary negation.
201   */
202   (void) SubstituteString(&fx_info->expression,"-","-1.0*");
203   (void) SubstituteString(&fx_info->expression,"E-1.0*","E-");
204   (void) SubstituteString(&fx_info->expression,"e-1.0*","e-");
205   /*
206     Convert complex to simple operators.
207   */
208   fx_op[1]='\0';
209   *fx_op=(char) LeftShiftOperator;
210   (void) SubstituteString(&fx_info->expression,"<<",fx_op);
211   *fx_op=(char) RightShiftOperator;
212   (void) SubstituteString(&fx_info->expression,">>",fx_op);
213   *fx_op=(char) LessThanEqualOperator;
214   (void) SubstituteString(&fx_info->expression,"<=",fx_op);
215   *fx_op=(char) GreaterThanEqualOperator;
216   (void) SubstituteString(&fx_info->expression,">=",fx_op);
217   *fx_op=(char) EqualOperator;
218   (void) SubstituteString(&fx_info->expression,"==",fx_op);
219   *fx_op=(char) NotEqualOperator;
220   (void) SubstituteString(&fx_info->expression,"!=",fx_op);
221   *fx_op=(char) LogicalAndOperator;
222   (void) SubstituteString(&fx_info->expression,"&&",fx_op);
223   *fx_op=(char) LogicalOrOperator;
224   (void) SubstituteString(&fx_info->expression,"||",fx_op);
225   *fx_op=(char) ExponentialNotation;
226   (void) SubstituteString(&fx_info->expression,"**",fx_op);
227   return(fx_info);
228 }
229 \f
230 /*
231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
232 %                                                                             %
233 %                                                                             %
234 %                                                                             %
235 %     A d d N o i s e I m a g e                                               %
236 %                                                                             %
237 %                                                                             %
238 %                                                                             %
239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
240 %
241 %  AddNoiseImage() adds random noise to the image.
242 %
243 %  The format of the AddNoiseImage method is:
244 %
245 %      Image *AddNoiseImage(const Image *image,const NoiseType noise_type,
246 %        const double attenuate,ExceptionInfo *exception)
247 %
248 %  A description of each parameter follows:
249 %
250 %    o image: the image.
251 %
252 %    o channel: the channel type.
253 %
254 %    o noise_type:  The type of noise: Uniform, Gaussian, Multiplicative,
255 %      Impulse, Laplacian, or Poisson.
256 %
257 %    o attenuate:  attenuate the random distribution.
258 %
259 %    o exception: return any errors or warnings in this structure.
260 %
261 */
262 MagickExport Image *AddNoiseImage(const Image *image,const NoiseType noise_type,
263   const double attenuate,ExceptionInfo *exception)
264 {
265 #define AddNoiseImageTag  "AddNoise/Image"
266
267   CacheView
268     *image_view,
269     *noise_view;
270
271   Image
272     *noise_image;
273
274   MagickBooleanType
275     status;
276
277   MagickOffsetType
278     progress;
279
280   RandomInfo
281     **restrict random_info;
282
283   ssize_t
284     y;
285
286 #if defined(MAGICKCORE_OPENMP_SUPPORT)
287   unsigned long
288     key;
289 #endif
290
291   /*
292     Initialize noise image attributes.
293   */
294   assert(image != (const Image *) NULL);
295   assert(image->signature == MagickSignature);
296   if (image->debug != MagickFalse)
297     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
298   assert(exception != (ExceptionInfo *) NULL);
299   assert(exception->signature == MagickSignature);
300   noise_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
301   if (noise_image == (Image *) NULL)
302     return((Image *) NULL);
303   if (SetImageStorageClass(noise_image,DirectClass,exception) == MagickFalse)
304     {
305       noise_image=DestroyImage(noise_image);
306       return((Image *) NULL);
307     }
308   if (IsGrayColorspace(image->colorspace) != MagickFalse)
309     (void) TransformImageColorspace(noise_image,RGBColorspace,exception);
310   /*
311     Add noise in each row.
312   */
313   status=MagickTrue;
314   progress=0;
315   random_info=AcquireRandomInfoThreadSet();
316   image_view=AcquireVirtualCacheView(image,exception);
317   noise_view=AcquireAuthenticCacheView(noise_image,exception);
318 #if defined(MAGICKCORE_OPENMP_SUPPORT)
319   key=GetRandomSecretKey(random_info[0]);
320   #pragma omp parallel for schedule(static,4) shared(progress,status) \
321     dynamic_number_threads(image,image->columns,image->rows,key == ~0UL)
322 #endif
323   for (y=0; y < (ssize_t) image->rows; y++)
324   {
325     const int
326       id = GetOpenMPThreadId();
327
328     MagickBooleanType
329       sync;
330
331     register const Quantum
332       *restrict p;
333
334     register ssize_t
335       x;
336
337     register Quantum
338       *restrict q;
339
340     if (status == MagickFalse)
341       continue;
342     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
343     q=QueueCacheViewAuthenticPixels(noise_view,0,y,noise_image->columns,1,
344       exception);
345     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
346       {
347         status=MagickFalse;
348         continue;
349       }
350     for (x=0; x < (ssize_t) image->columns; x++)
351     {
352       register ssize_t
353         i;
354
355       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
356       {
357         PixelChannel
358           channel;
359
360         PixelTrait
361           noise_traits,
362           traits;
363
364         channel=GetPixelChannelChannel(image,i);
365         traits=GetPixelChannelTraits(image,channel);
366         noise_traits=GetPixelChannelTraits(noise_image,channel);
367         if ((traits == UndefinedPixelTrait) ||
368             (noise_traits == UndefinedPixelTrait))
369           continue;
370         if (((noise_traits & CopyPixelTrait) != 0) ||
371             (GetPixelMask(image,p) != 0))
372           {
373             SetPixelChannel(noise_image,channel,p[i],q);
374             continue;
375           }
376         SetPixelChannel(noise_image,channel,ClampToQuantum(
377           GenerateDifferentialNoise(random_info[id],p[i],noise_type,attenuate)),
378           q);
379       }
380       p+=GetPixelChannels(image);
381       q+=GetPixelChannels(noise_image);
382     }
383     sync=SyncCacheViewAuthenticPixels(noise_view,exception);
384     if (sync == MagickFalse)
385       status=MagickFalse;
386     if (image->progress_monitor != (MagickProgressMonitor) NULL)
387       {
388         MagickBooleanType
389           proceed;
390
391 #if defined(MAGICKCORE_OPENMP_SUPPORT)
392         #pragma omp critical (MagickCore_AddNoiseImage)
393 #endif
394         proceed=SetImageProgress(image,AddNoiseImageTag,progress++,
395           image->rows);
396         if (proceed == MagickFalse)
397           status=MagickFalse;
398       }
399   }
400   noise_view=DestroyCacheView(noise_view);
401   image_view=DestroyCacheView(image_view);
402   random_info=DestroyRandomInfoThreadSet(random_info);
403   if (status == MagickFalse)
404     noise_image=DestroyImage(noise_image);
405   return(noise_image);
406 }
407 \f
408 /*
409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
410 %                                                                             %
411 %                                                                             %
412 %                                                                             %
413 %     B l u e S h i f t I m a g e                                             %
414 %                                                                             %
415 %                                                                             %
416 %                                                                             %
417 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
418 %
419 %  BlueShiftImage() mutes the colors of the image to simulate a scene at
420 %  nighttime in the moonlight.
421 %
422 %  The format of the BlueShiftImage method is:
423 %
424 %      Image *BlueShiftImage(const Image *image,const double factor,
425 %        ExceptionInfo *exception)
426 %
427 %  A description of each parameter follows:
428 %
429 %    o image: the image.
430 %
431 %    o factor: the shift factor.
432 %
433 %    o exception: return any errors or warnings in this structure.
434 %
435 */
436 MagickExport Image *BlueShiftImage(const Image *image,const double factor,
437   ExceptionInfo *exception)
438 {
439 #define BlueShiftImageTag  "BlueShift/Image"
440
441   CacheView
442     *image_view,
443     *shift_view;
444
445   Image
446     *shift_image;
447
448   MagickBooleanType
449     status;
450
451   MagickOffsetType
452     progress;
453
454   ssize_t
455     y;
456
457   /*
458     Allocate blue shift image.
459   */
460   assert(image != (const Image *) NULL);
461   assert(image->signature == MagickSignature);
462   if (image->debug != MagickFalse)
463     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
464   assert(exception != (ExceptionInfo *) NULL);
465   assert(exception->signature == MagickSignature);
466   shift_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
467   if (shift_image == (Image *) NULL)
468     return((Image *) NULL);
469   if (SetImageStorageClass(shift_image,DirectClass,exception) == MagickFalse)
470     {
471       shift_image=DestroyImage(shift_image);
472       return((Image *) NULL);
473     }
474   /*
475     Blue-shift DirectClass image.
476   */
477   status=MagickTrue;
478   progress=0;
479   image_view=AcquireVirtualCacheView(image,exception);
480   shift_view=AcquireAuthenticCacheView(shift_image,exception);
481 #if defined(MAGICKCORE_OPENMP_SUPPORT)
482   #pragma omp parallel for schedule(static,4) shared(progress,status) \
483     dynamic_number_threads(image,image->columns,image->rows,1)
484 #endif
485   for (y=0; y < (ssize_t) image->rows; y++)
486   {
487     MagickBooleanType
488       sync;
489
490     PixelInfo
491       pixel;
492
493     Quantum
494       quantum;
495
496     register const Quantum
497       *restrict p;
498
499     register ssize_t
500       x;
501
502     register Quantum
503       *restrict q;
504
505     if (status == MagickFalse)
506       continue;
507     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
508     q=QueueCacheViewAuthenticPixels(shift_view,0,y,shift_image->columns,1,
509       exception);
510     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
511       {
512         status=MagickFalse;
513         continue;
514       }
515     for (x=0; x < (ssize_t) image->columns; x++)
516     {
517       quantum=GetPixelRed(image,p);
518       if (GetPixelGreen(image,p) < quantum)
519         quantum=GetPixelGreen(image,p);
520       if (GetPixelBlue(image,p) < quantum)
521         quantum=GetPixelBlue(image,p);
522       pixel.red=0.5*(GetPixelRed(image,p)+factor*quantum);
523       pixel.green=0.5*(GetPixelGreen(image,p)+factor*quantum);
524       pixel.blue=0.5*(GetPixelBlue(image,p)+factor*quantum);
525       quantum=GetPixelRed(image,p);
526       if (GetPixelGreen(image,p) > quantum)
527         quantum=GetPixelGreen(image,p);
528       if (GetPixelBlue(image,p) > quantum)
529         quantum=GetPixelBlue(image,p);
530       pixel.red=0.5*(pixel.red+factor*quantum);
531       pixel.green=0.5*(pixel.green+factor*quantum);
532       pixel.blue=0.5*(pixel.blue+factor*quantum);
533       SetPixelRed(shift_image,ClampToQuantum(pixel.red),q);
534       SetPixelGreen(shift_image,ClampToQuantum(pixel.green),q);
535       SetPixelBlue(shift_image,ClampToQuantum(pixel.blue),q);
536       p+=GetPixelChannels(image);
537       q+=GetPixelChannels(shift_image);
538     }
539     sync=SyncCacheViewAuthenticPixels(shift_view,exception);
540     if (sync == MagickFalse)
541       status=MagickFalse;
542     if (image->progress_monitor != (MagickProgressMonitor) NULL)
543       {
544         MagickBooleanType
545           proceed;
546
547 #if defined(MAGICKCORE_OPENMP_SUPPORT)
548         #pragma omp critical (MagickCore_BlueShiftImage)
549 #endif
550         proceed=SetImageProgress(image,BlueShiftImageTag,progress++,
551           image->rows);
552         if (proceed == MagickFalse)
553           status=MagickFalse;
554       }
555   }
556   image_view=DestroyCacheView(image_view);
557   shift_view=DestroyCacheView(shift_view);
558   if (status == MagickFalse)
559     shift_image=DestroyImage(shift_image);
560   return(shift_image);
561 }
562 \f
563 /*
564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
565 %                                                                             %
566 %                                                                             %
567 %                                                                             %
568 %     C h a r c o a l I m a g e                                               %
569 %                                                                             %
570 %                                                                             %
571 %                                                                             %
572 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
573 %
574 %  CharcoalImage() creates a new image that is a copy of an existing one with
575 %  the edge highlighted.  It allocates the memory necessary for the new Image
576 %  structure and returns a pointer to the new image.
577 %
578 %  The format of the CharcoalImage method is:
579 %
580 %      Image *CharcoalImage(const Image *image,const double radius,
581 %        const double sigma,ExceptionInfo *exception)
582 %
583 %  A description of each parameter follows:
584 %
585 %    o image: the image.
586 %
587 %    o radius: the radius of the pixel neighborhood.
588 %
589 %    o sigma: the standard deviation of the Gaussian, in pixels.
590 %
591 %    o exception: return any errors or warnings in this structure.
592 %
593 */
594 MagickExport Image *CharcoalImage(const Image *image,const double radius,
595   const double sigma,ExceptionInfo *exception)
596 {
597   Image
598     *charcoal_image,
599     *clone_image,
600     *edge_image;
601
602   assert(image != (Image *) NULL);
603   assert(image->signature == MagickSignature);
604   if (image->debug != MagickFalse)
605     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
606   assert(exception != (ExceptionInfo *) NULL);
607   assert(exception->signature == MagickSignature);
608   clone_image=CloneImage(image,0,0,MagickTrue,exception);
609   if (clone_image == (Image *) NULL)
610     return((Image *) NULL);
611   (void) SetImageType(clone_image,GrayscaleType,exception);
612   edge_image=EdgeImage(clone_image,radius,sigma,exception);
613   clone_image=DestroyImage(clone_image);
614   if (edge_image == (Image *) NULL)
615     return((Image *) NULL);
616   charcoal_image=BlurImage(edge_image,radius,sigma,exception);
617   edge_image=DestroyImage(edge_image);
618   if (charcoal_image == (Image *) NULL)
619     return((Image *) NULL);
620   (void) NormalizeImage(charcoal_image,exception);
621   (void) NegateImage(charcoal_image,MagickFalse,exception);
622   (void) SetImageType(charcoal_image,GrayscaleType,exception);
623   return(charcoal_image);
624 }
625 \f
626 /*
627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
628 %                                                                             %
629 %                                                                             %
630 %                                                                             %
631 %     C o l o r i z e I m a g e                                               %
632 %                                                                             %
633 %                                                                             %
634 %                                                                             %
635 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636 %
637 %  ColorizeImage() blends the fill color with each pixel in the image.
638 %  A percentage blend is specified with opacity.  Control the application
639 %  of different color components by specifying a different percentage for
640 %  each component (e.g. 90/100/10 is 90% red, 100% green, and 10% blue).
641 %
642 %  The format of the ColorizeImage method is:
643 %
644 %      Image *ColorizeImage(const Image *image,const char *blend,
645 %        const PixelInfo *colorize,ExceptionInfo *exception)
646 %
647 %  A description of each parameter follows:
648 %
649 %    o image: the image.
650 %
651 %    o blend:  A character string indicating the level of blending as a
652 %      percentage.
653 %
654 %    o colorize: A color value.
655 %
656 %    o exception: return any errors or warnings in this structure.
657 %
658 */
659 MagickExport Image *ColorizeImage(const Image *image,const char *blend,
660   const PixelInfo *colorize,ExceptionInfo *exception)
661 {
662 #define ColorizeImageTag  "Colorize/Image"
663 #define Colorize(pixel,blend_percentage,colorize)  \
664   (((pixel)*(100.0-(blend_percentage))+(colorize)*(blend_percentage))/100.0)
665
666   CacheView
667     *colorize_view,
668     *image_view;
669
670   GeometryInfo
671     geometry_info;
672
673   Image
674     *colorize_image;
675
676   MagickBooleanType
677     status;
678
679   MagickOffsetType
680     progress;
681
682   MagickStatusType
683     flags;
684
685   PixelInfo
686     blend_percentage;
687
688   ssize_t
689     y;
690
691   /*
692     Allocate colorized image.
693   */
694   assert(image != (const Image *) NULL);
695   assert(image->signature == MagickSignature);
696   if (image->debug != MagickFalse)
697     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
698   assert(exception != (ExceptionInfo *) NULL);
699   assert(exception->signature == MagickSignature);
700   colorize_image=CloneImage(image,image->columns,image->rows,MagickTrue,
701     exception);
702   if (colorize_image == (Image *) NULL)
703     return((Image *) NULL);
704   if (SetImageStorageClass(colorize_image,DirectClass,exception) == MagickFalse)
705     {
706       colorize_image=DestroyImage(colorize_image);
707       return((Image *) NULL);
708     }
709   if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
710       (IsPixelInfoGray(colorize) != MagickFalse))
711     (void) SetImageColorspace(colorize_image,RGBColorspace,exception);
712   if ((colorize_image->alpha_trait != BlendPixelTrait) &&
713       (colorize->alpha_trait == BlendPixelTrait))
714     (void) SetImageAlpha(colorize_image,OpaqueAlpha,exception);
715   if (blend == (const char *) NULL)
716     return(colorize_image);
717   GetPixelInfo(image,&blend_percentage);
718   flags=ParseGeometry(blend,&geometry_info);
719   blend_percentage.red=geometry_info.rho;
720   blend_percentage.green=geometry_info.rho;
721   blend_percentage.blue=geometry_info.rho;
722   blend_percentage.black=geometry_info.rho;
723   blend_percentage.alpha=geometry_info.rho;
724   if ((flags & SigmaValue) != 0)
725     blend_percentage.green=geometry_info.sigma;
726   if ((flags & XiValue) != 0)
727     blend_percentage.blue=geometry_info.xi;
728   if ((flags & PsiValue) != 0)
729     blend_percentage.alpha=geometry_info.psi;
730   if (blend_percentage.colorspace == CMYKColorspace)
731     {
732       if ((flags & PsiValue) != 0)
733         blend_percentage.black=geometry_info.psi;
734       if ((flags & ChiValue) != 0)
735         blend_percentage.alpha=geometry_info.chi;
736     }
737   /*
738     Colorize DirectClass image.
739   */
740   status=MagickTrue;
741   progress=0;
742   image_view=AcquireVirtualCacheView(image,exception);
743   colorize_view=AcquireAuthenticCacheView(colorize_image,exception);
744 #if defined(MAGICKCORE_OPENMP_SUPPORT)
745   #pragma omp parallel for schedule(static,4) shared(progress,status) \
746     dynamic_number_threads(image,image->columns,image->rows,1)
747 #endif
748   for (y=0; y < (ssize_t) image->rows; y++)
749   {
750     MagickBooleanType
751       sync;
752
753     register const Quantum
754       *restrict p;
755
756     register Quantum
757       *restrict q;
758
759     register ssize_t
760       x;
761
762     if (status == MagickFalse)
763       continue;
764     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
765     q=QueueCacheViewAuthenticPixels(colorize_view,0,y,colorize_image->columns,1,
766       exception);
767     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
768       {
769         status=MagickFalse;
770         continue;
771       }
772     for (x=0; x < (ssize_t) image->columns; x++)
773     {
774       register ssize_t
775         i;
776
777       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
778       {
779         PixelChannel
780           channel;
781
782         PixelTrait
783           colorize_traits,
784           traits;
785
786         channel=GetPixelChannelChannel(image,i);
787         traits=GetPixelChannelTraits(image,channel);
788         colorize_traits=GetPixelChannelTraits(colorize_image,channel);
789         if ((traits == UndefinedPixelTrait) ||
790             (colorize_traits == UndefinedPixelTrait))
791           continue;
792         if (((colorize_traits & CopyPixelTrait) != 0) ||
793             (GetPixelMask(image,p) != 0))
794           {
795             SetPixelChannel(colorize_image,channel,p[i],q);
796             continue;
797           }
798         SetPixelChannel(colorize_image,channel,
799           ClampToQuantum(Colorize(p[i],GetPixelInfoChannel(&blend_percentage,
800           channel),GetPixelInfoChannel(colorize,channel))),q);
801       }
802       p+=GetPixelChannels(image);
803       q+=GetPixelChannels(colorize_image);
804     }
805     sync=SyncCacheViewAuthenticPixels(colorize_view,exception);
806     if (sync == MagickFalse)
807       status=MagickFalse;
808     if (image->progress_monitor != (MagickProgressMonitor) NULL)
809       {
810         MagickBooleanType
811           proceed;
812
813 #if defined(MAGICKCORE_OPENMP_SUPPORT)
814         #pragma omp critical (MagickCore_ColorizeImage)
815 #endif
816         proceed=SetImageProgress(image,ColorizeImageTag,progress++,image->rows);
817         if (proceed == MagickFalse)
818           status=MagickFalse;
819       }
820   }
821   image_view=DestroyCacheView(image_view);
822   colorize_view=DestroyCacheView(colorize_view);
823   if (status == MagickFalse)
824     colorize_image=DestroyImage(colorize_image);
825   return(colorize_image);
826 }
827 \f
828 /*
829 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
830 %                                                                             %
831 %                                                                             %
832 %                                                                             %
833 %     C o l o r M a t r i x I m a g e                                         %
834 %                                                                             %
835 %                                                                             %
836 %                                                                             %
837 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
838 %
839 %  ColorMatrixImage() applies color transformation to an image. This method
840 %  permits saturation changes, hue rotation, luminance to alpha, and various
841 %  other effects.  Although variable-sized transformation matrices can be used,
842 %  typically one uses a 5x5 matrix for an RGBA image and a 6x6 for CMYKA
843 %  (or RGBA with offsets).  The matrix is similar to those used by Adobe Flash
844 %  except offsets are in column 6 rather than 5 (in support of CMYKA images)
845 %  and offsets are normalized (divide Flash offset by 255).
846 %
847 %  The format of the ColorMatrixImage method is:
848 %
849 %      Image *ColorMatrixImage(const Image *image,
850 %        const KernelInfo *color_matrix,ExceptionInfo *exception)
851 %
852 %  A description of each parameter follows:
853 %
854 %    o image: the image.
855 %
856 %    o color_matrix:  the color matrix.
857 %
858 %    o exception: return any errors or warnings in this structure.
859 %
860 */
861 /* FUTURE: modify to make use of a MagickMatrix Mutliply function
862    That should be provided in "matrix.c"
863    (ASIDE: actually distorts should do this too but currently doesn't)
864 */
865
866 MagickExport Image *ColorMatrixImage(const Image *image,
867   const KernelInfo *color_matrix,ExceptionInfo *exception)
868 {
869 #define ColorMatrixImageTag  "ColorMatrix/Image"
870
871   CacheView
872     *color_view,
873     *image_view;
874
875   double
876     ColorMatrix[6][6] =
877     {
878       { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0 },
879       { 0.0, 1.0, 0.0, 0.0, 0.0, 0.0 },
880       { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 },
881       { 0.0, 0.0, 0.0, 1.0, 0.0, 0.0 },
882       { 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 },
883       { 0.0, 0.0, 0.0, 0.0, 0.0, 1.0 }
884     };
885
886   Image
887     *color_image;
888
889   MagickBooleanType
890     status;
891
892   MagickOffsetType
893     progress;
894
895   register ssize_t
896     i;
897
898   ssize_t
899     u,
900     v,
901     y;
902
903   /*
904     Map given color_matrix, into a 6x6 matrix   RGBKA and a constant
905   */
906   assert(image != (Image *) NULL);
907   assert(image->signature == MagickSignature);
908   if (image->debug != MagickFalse)
909     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
910   assert(exception != (ExceptionInfo *) NULL);
911   assert(exception->signature == MagickSignature);
912   i=0;
913   for (v=0; v < (ssize_t) color_matrix->height; v++)
914     for (u=0; u < (ssize_t) color_matrix->width; u++)
915     {
916       if ((v < 6) && (u < 6))
917         ColorMatrix[v][u]=color_matrix->values[i];
918       i++;
919     }
920   /*
921     Initialize color image.
922   */
923   color_image=CloneImage(image,0,0,MagickTrue,exception);
924   if (color_image == (Image *) NULL)
925     return((Image *) NULL);
926   if (SetImageStorageClass(color_image,DirectClass,exception) == MagickFalse)
927     {
928       color_image=DestroyImage(color_image);
929       return((Image *) NULL);
930     }
931   if (image->debug != MagickFalse)
932     {
933       char
934         format[MaxTextExtent],
935         *message;
936
937       (void) LogMagickEvent(TransformEvent,GetMagickModule(),
938         "  ColorMatrix image with color matrix:");
939       message=AcquireString("");
940       for (v=0; v < 6; v++)
941       {
942         *message='\0';
943         (void) FormatLocaleString(format,MaxTextExtent,"%.20g: ",(double) v);
944         (void) ConcatenateString(&message,format);
945         for (u=0; u < 6; u++)
946         {
947           (void) FormatLocaleString(format,MaxTextExtent,"%+f ",
948             ColorMatrix[v][u]);
949           (void) ConcatenateString(&message,format);
950         }
951         (void) LogMagickEvent(TransformEvent,GetMagickModule(),"%s",message);
952       }
953       message=DestroyString(message);
954     }
955   /*
956     Apply the ColorMatrix to image.
957   */
958   status=MagickTrue;
959   progress=0;
960   image_view=AcquireVirtualCacheView(image,exception);
961   color_view=AcquireAuthenticCacheView(color_image,exception);
962 #if defined(MAGICKCORE_OPENMP_SUPPORT)
963   #pragma omp parallel for schedule(static,4) shared(progress,status) \
964     dynamic_number_threads(image,image->columns,image->rows,1)
965 #endif
966   for (y=0; y < (ssize_t) image->rows; y++)
967   {
968     PixelInfo
969       pixel;
970
971     register const Quantum
972       *restrict p;
973
974     register Quantum
975       *restrict q;
976
977     register ssize_t
978       x;
979
980     if (status == MagickFalse)
981       continue;
982     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
983     q=GetCacheViewAuthenticPixels(color_view,0,y,color_image->columns,1,
984       exception);
985     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
986       {
987         status=MagickFalse;
988         continue;
989       }
990     GetPixelInfo(image,&pixel);
991     for (x=0; x < (ssize_t) image->columns; x++)
992     {
993       register ssize_t
994         v;
995
996       size_t
997         height;
998
999       GetPixelInfoPixel(image,p,&pixel);
1000       height=color_matrix->height > 6 ? 6UL : color_matrix->height;
1001       for (v=0; v < (ssize_t) height; v++)
1002       {
1003         double
1004           sum;
1005
1006         sum=ColorMatrix[v][0]*GetPixelRed(image,p)+ColorMatrix[v][1]*
1007           GetPixelGreen(image,p)+ColorMatrix[v][2]*GetPixelBlue(image,p);
1008         if (image->colorspace == CMYKColorspace)
1009           sum+=ColorMatrix[v][3]*GetPixelBlack(image,p);
1010         if (image->alpha_trait == BlendPixelTrait)
1011           sum+=ColorMatrix[v][4]*GetPixelAlpha(image,p);
1012         sum+=QuantumRange*ColorMatrix[v][5];
1013         switch (v)
1014         {
1015           case 0: pixel.red=sum; break;
1016           case 1: pixel.green=sum; break;
1017           case 2: pixel.blue=sum; break;
1018           case 3: pixel.black=sum; break;
1019           case 4: pixel.alpha=sum; break;
1020           default: break;
1021         }
1022       }
1023       SetPixelInfoPixel(color_image,&pixel,q);
1024       p+=GetPixelChannels(image);
1025       q+=GetPixelChannels(color_image);
1026     }
1027     if (SyncCacheViewAuthenticPixels(color_view,exception) == MagickFalse)
1028       status=MagickFalse;
1029     if (image->progress_monitor != (MagickProgressMonitor) NULL)
1030       {
1031         MagickBooleanType
1032           proceed;
1033
1034 #if defined(MAGICKCORE_OPENMP_SUPPORT)
1035         #pragma omp critical (MagickCore_ColorMatrixImage)
1036 #endif
1037         proceed=SetImageProgress(image,ColorMatrixImageTag,progress++,
1038           image->rows);
1039         if (proceed == MagickFalse)
1040           status=MagickFalse;
1041       }
1042   }
1043   color_view=DestroyCacheView(color_view);
1044   image_view=DestroyCacheView(image_view);
1045   if (status == MagickFalse)
1046     color_image=DestroyImage(color_image);
1047   return(color_image);
1048 }
1049 \f
1050 /*
1051 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1052 %                                                                             %
1053 %                                                                             %
1054 %                                                                             %
1055 +   D e s t r o y F x I n f o                                                 %
1056 %                                                                             %
1057 %                                                                             %
1058 %                                                                             %
1059 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1060 %
1061 %  DestroyFxInfo() deallocates memory associated with an FxInfo structure.
1062 %
1063 %  The format of the DestroyFxInfo method is:
1064 %
1065 %      ImageInfo *DestroyFxInfo(ImageInfo *fx_info)
1066 %
1067 %  A description of each parameter follows:
1068 %
1069 %    o fx_info: the fx info.
1070 %
1071 */
1072 MagickPrivate FxInfo *DestroyFxInfo(FxInfo *fx_info)
1073 {
1074   register ssize_t
1075     i;
1076
1077   fx_info->exception=DestroyExceptionInfo(fx_info->exception);
1078   fx_info->expression=DestroyString(fx_info->expression);
1079   fx_info->symbols=DestroySplayTree(fx_info->symbols);
1080   fx_info->colors=DestroySplayTree(fx_info->colors);
1081   for (i=(ssize_t) GetImageListLength(fx_info->images)-1; i >= 0; i--)
1082     fx_info->view[i]=DestroyCacheView(fx_info->view[i]);
1083   fx_info->view=(CacheView **) RelinquishMagickMemory(fx_info->view);
1084   fx_info->random_info=DestroyRandomInfo(fx_info->random_info);
1085   fx_info=(FxInfo *) RelinquishMagickMemory(fx_info);
1086   return(fx_info);
1087 }
1088 \f
1089 /*
1090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1091 %                                                                             %
1092 %                                                                             %
1093 %                                                                             %
1094 +     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                   %
1095 %                                                                             %
1096 %                                                                             %
1097 %                                                                             %
1098 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1099 %
1100 %  FxEvaluateChannelExpression() evaluates an expression and returns the
1101 %  results.
1102 %
1103 %  The format of the FxEvaluateExpression method is:
1104 %
1105 %      double FxEvaluateChannelExpression(FxInfo *fx_info,
1106 %        const PixelChannel channel,const ssize_t x,const ssize_t y,
1107 %        double *alpha,Exceptioninfo *exception)
1108 %      double FxEvaluateExpression(FxInfo *fx_info,
1109 %        double *alpha,Exceptioninfo *exception)
1110 %
1111 %  A description of each parameter follows:
1112 %
1113 %    o fx_info: the fx info.
1114 %
1115 %    o channel: the channel.
1116 %
1117 %    o x,y: the pixel position.
1118 %
1119 %    o alpha: the result.
1120 %
1121 %    o exception: return any errors or warnings in this structure.
1122 %
1123 */
1124
1125 static inline double MagickMax(const double x,const double y)
1126 {
1127   if (x > y)
1128     return(x);
1129   return(y);
1130 }
1131
1132 static inline double MagickMin(const double x,const double y)
1133 {
1134   if (x < y)
1135     return(x);
1136   return(y);
1137 }
1138
1139 static double FxChannelStatistics(FxInfo *fx_info,Image *image,
1140   PixelChannel channel,const char *symbol,ExceptionInfo *exception)
1141 {
1142   ChannelType
1143     channel_mask;
1144
1145   char
1146     key[MaxTextExtent],
1147     statistic[MaxTextExtent];
1148
1149   const char
1150     *value;
1151
1152   register const char
1153     *p;
1154
1155   channel_mask=UndefinedChannel;
1156   for (p=symbol; (*p != '.') && (*p != '\0'); p++) ;
1157   if (*p == '.')
1158     {
1159       ssize_t
1160         option;
1161
1162       option=ParseCommandOption(MagickPixelChannelOptions,MagickTrue,p+1);
1163       if (option >= 0)
1164         {
1165           channel=(PixelChannel) option;
1166           channel_mask=(ChannelType) (channel_mask | (1 << channel));
1167           SetPixelChannelMask(image,channel_mask);
1168         }
1169     }
1170   (void) FormatLocaleString(key,MaxTextExtent,"%p.%.20g.%s",(void *) image,
1171     (double) channel,symbol);
1172   value=(const char *) GetValueFromSplayTree(fx_info->symbols,key);
1173   if (value != (const char *) NULL)
1174     {
1175       if (channel_mask != UndefinedChannel)
1176         SetPixelChannelMask(image,channel_mask);
1177       return(QuantumScale*StringToDouble(value,(char **) NULL));
1178     }
1179   (void) DeleteNodeFromSplayTree(fx_info->symbols,key);
1180   if (LocaleNCompare(symbol,"depth",5) == 0)
1181     {
1182       size_t
1183         depth;
1184
1185       depth=GetImageDepth(image,exception);
1186       (void) FormatLocaleString(statistic,MaxTextExtent,"%.20g",(double) depth);
1187     }
1188   if (LocaleNCompare(symbol,"kurtosis",8) == 0)
1189     {
1190       double
1191         kurtosis,
1192         skewness;
1193
1194       (void) GetImageKurtosis(image,&kurtosis,&skewness,exception);
1195       (void) FormatLocaleString(statistic,MaxTextExtent,"%g",kurtosis);
1196     }
1197   if (LocaleNCompare(symbol,"maxima",6) == 0)
1198     {
1199       double
1200         maxima,
1201         minima;
1202
1203       (void) GetImageRange(image,&minima,&maxima,exception);
1204       (void) FormatLocaleString(statistic,MaxTextExtent,"%g",maxima);
1205     }
1206   if (LocaleNCompare(symbol,"mean",4) == 0)
1207     {
1208       double
1209         mean,
1210         standard_deviation;
1211
1212       (void) GetImageMean(image,&mean,&standard_deviation,exception);
1213       (void) FormatLocaleString(statistic,MaxTextExtent,"%g",mean);
1214     }
1215   if (LocaleNCompare(symbol,"minima",6) == 0)
1216     {
1217       double
1218         maxima,
1219         minima;
1220
1221       (void) GetImageRange(image,&minima,&maxima,exception);
1222       (void) FormatLocaleString(statistic,MaxTextExtent,"%g",minima);
1223     }
1224   if (LocaleNCompare(symbol,"skewness",8) == 0)
1225     {
1226       double
1227         kurtosis,
1228         skewness;
1229
1230       (void) GetImageKurtosis(image,&kurtosis,&skewness,exception);
1231       (void) FormatLocaleString(statistic,MaxTextExtent,"%g",skewness);
1232     }
1233   if (LocaleNCompare(symbol,"standard_deviation",18) == 0)
1234     {
1235       double
1236         mean,
1237         standard_deviation;
1238
1239       (void) GetImageMean(image,&mean,&standard_deviation,exception);
1240       (void) FormatLocaleString(statistic,MaxTextExtent,"%g",
1241         standard_deviation);
1242     }
1243   if (channel_mask != UndefinedChannel)
1244     SetPixelChannelMask(image,channel_mask);
1245   (void) AddValueToSplayTree(fx_info->symbols,ConstantString(key),
1246     ConstantString(statistic));
1247   return(QuantumScale*StringToDouble(statistic,(char **) NULL));
1248 }
1249
1250 static double
1251   FxEvaluateSubexpression(FxInfo *,const PixelChannel,const ssize_t,
1252     const ssize_t,const char *,double *,ExceptionInfo *);
1253
1254 static MagickOffsetType FxGCD(MagickOffsetType alpha,MagickOffsetType beta)
1255 {
1256   if (beta != 0)
1257     return(FxGCD(beta,alpha % beta));
1258   return(alpha);
1259 }
1260
1261 static inline const char *FxSubexpression(const char *expression,
1262   ExceptionInfo *exception)
1263 {
1264   const char
1265     *subexpression;
1266
1267   register ssize_t
1268     level;
1269
1270   level=0;
1271   subexpression=expression;
1272   while ((*subexpression != '\0') &&
1273          ((level != 1) || (strchr(")",(int) *subexpression) == (char *) NULL)))
1274   {
1275     if (strchr("(",(int) *subexpression) != (char *) NULL)
1276       level++;
1277     else
1278       if (strchr(")",(int) *subexpression) != (char *) NULL)
1279         level--;
1280     subexpression++;
1281   }
1282   if (*subexpression == '\0')
1283     (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1284       "UnbalancedParenthesis","'%s'",expression);
1285   return(subexpression);
1286 }
1287
1288 static double FxGetSymbol(FxInfo *fx_info,const PixelChannel channel,
1289   const ssize_t x,const ssize_t y,const char *expression,
1290   ExceptionInfo *exception)
1291 {
1292   char
1293     *q,
1294     subexpression[MaxTextExtent],
1295     symbol[MaxTextExtent];
1296
1297   const char
1298     *p,
1299     *value;
1300
1301   Image
1302     *image;
1303
1304   PixelInfo
1305     pixel;
1306
1307   double
1308     alpha,
1309     beta;
1310
1311   PointInfo
1312     point;
1313
1314   register ssize_t
1315     i;
1316
1317   size_t
1318     length,
1319     level;
1320
1321   p=expression;
1322   i=GetImageIndexInList(fx_info->images);
1323   level=0;
1324   point.x=(double) x;
1325   point.y=(double) y;
1326   if (isalpha((int) *(p+1)) == 0)
1327     {
1328       if (strchr("suv",(int) *p) != (char *) NULL)
1329         {
1330           switch (*p)
1331           {
1332             case 's':
1333             default:
1334             {
1335               i=GetImageIndexInList(fx_info->images);
1336               break;
1337             }
1338             case 'u': i=0; break;
1339             case 'v': i=1; break;
1340           }
1341           p++;
1342           if (*p == '[')
1343             {
1344               level++;
1345               q=subexpression;
1346               for (p++; *p != '\0'; )
1347               {
1348                 if (*p == '[')
1349                   level++;
1350                 else
1351                   if (*p == ']')
1352                     {
1353                       level--;
1354                       if (level == 0)
1355                         break;
1356                     }
1357                 *q++=(*p++);
1358               }
1359               *q='\0';
1360               alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
1361                 &beta,exception);
1362               i=(ssize_t) (alpha+0.5);
1363               p++;
1364             }
1365           if (*p == '.')
1366             p++;
1367         }
1368       if ((isalpha((int) *(p+1)) == 0) && (*p == 'p'))
1369         {
1370           p++;
1371           if (*p == '{')
1372             {
1373               level++;
1374               q=subexpression;
1375               for (p++; *p != '\0'; )
1376               {
1377                 if (*p == '{')
1378                   level++;
1379                 else
1380                   if (*p == '}')
1381                     {
1382                       level--;
1383                       if (level == 0)
1384                         break;
1385                     }
1386                 *q++=(*p++);
1387               }
1388               *q='\0';
1389               alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
1390                 &beta,exception);
1391               point.x=alpha;
1392               point.y=beta;
1393               p++;
1394             }
1395           else
1396             if (*p == '[')
1397               {
1398                 level++;
1399                 q=subexpression;
1400                 for (p++; *p != '\0'; )
1401                 {
1402                   if (*p == '[')
1403                     level++;
1404                   else
1405                     if (*p == ']')
1406                       {
1407                         level--;
1408                         if (level == 0)
1409                           break;
1410                       }
1411                   *q++=(*p++);
1412                 }
1413                 *q='\0';
1414                 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
1415                   &beta,exception);
1416                 point.x+=alpha;
1417                 point.y+=beta;
1418                 p++;
1419               }
1420           if (*p == '.')
1421             p++;
1422         }
1423     }
1424   length=GetImageListLength(fx_info->images);
1425   while (i < 0)
1426     i+=(ssize_t) length;
1427   i%=length;
1428   image=GetImageFromList(fx_info->images,i);
1429   if (image == (Image *) NULL)
1430     {
1431       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1432         "NoSuchImage","'%s'",expression);
1433       return(0.0);
1434     }
1435   GetPixelInfo(image,&pixel);
1436   (void) InterpolatePixelInfo(image,fx_info->view[i],image->interpolate,
1437     point.x,point.y,&pixel,exception);
1438   if ((strlen(p) > 2) && (LocaleCompare(p,"intensity") != 0) &&
1439       (LocaleCompare(p,"luminance") != 0) && (LocaleCompare(p,"hue") != 0) &&
1440       (LocaleCompare(p,"saturation") != 0) &&
1441       (LocaleCompare(p,"lightness") != 0))
1442     {
1443       char
1444         name[MaxTextExtent];
1445
1446       (void) CopyMagickString(name,p,MaxTextExtent);
1447       for (q=name+(strlen(name)-1); q > name; q--)
1448       {
1449         if (*q == ')')
1450           break;
1451         if (*q == '.')
1452           {
1453             *q='\0';
1454             break;
1455           }
1456       }
1457       if ((strlen(name) > 2) &&
1458           (GetValueFromSplayTree(fx_info->symbols,name) == (const char *) NULL))
1459         {
1460           PixelInfo
1461             *color;
1462
1463           color=(PixelInfo *) GetValueFromSplayTree(fx_info->colors,name);
1464           if (color != (PixelInfo *) NULL)
1465             {
1466               pixel=(*color);
1467               p+=strlen(name);
1468             }
1469           else
1470             {
1471               MagickBooleanType
1472                 status;
1473
1474               status=QueryColorCompliance(name,AllCompliance,&pixel,
1475                 fx_info->exception);
1476               if (status != MagickFalse)
1477                 {
1478                   (void) AddValueToSplayTree(fx_info->colors,ConstantString(
1479                     name),ClonePixelInfo(&pixel));
1480                   p+=strlen(name);
1481                 }
1482             }
1483         }
1484     }
1485   (void) CopyMagickString(symbol,p,MaxTextExtent);
1486   StripString(symbol);
1487   if (*symbol == '\0')
1488     {
1489       switch (channel)
1490       {
1491         case RedPixelChannel: return(QuantumScale*pixel.red);
1492         case GreenPixelChannel: return(QuantumScale*pixel.green);
1493         case BluePixelChannel: return(QuantumScale*pixel.blue);
1494         case BlackPixelChannel:
1495         {
1496           if (image->colorspace != CMYKColorspace)
1497             {
1498               (void) ThrowMagickException(exception,GetMagickModule(),
1499                 ImageError,"ColorSeparatedImageRequired","'%s'",
1500                 image->filename);
1501               return(0.0);
1502             }
1503           return(QuantumScale*pixel.black);
1504         }
1505         case AlphaPixelChannel:
1506         {
1507           double
1508             alpha;
1509
1510           if (pixel.alpha_trait != BlendPixelTrait)
1511             return(1.0);
1512           alpha=(double) (QuantumScale*pixel.alpha);
1513           return(alpha);
1514         }
1515         case IndexPixelChannel:
1516           return(0.0);
1517         case IntensityPixelChannel:
1518         {
1519           return(QuantumScale*GetPixelInfoIntensity(&pixel));
1520         }
1521         default:
1522           break;
1523       }
1524       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1525         "UnableToParseExpression","'%s'",p);
1526       return(0.0);
1527     }
1528   switch (*symbol)
1529   {
1530     case 'A':
1531     case 'a':
1532     {
1533       if (LocaleCompare(symbol,"a") == 0)
1534         return((double) (QuantumScale*pixel.alpha));
1535       break;
1536     }
1537     case 'B':
1538     case 'b':
1539     {
1540       if (LocaleCompare(symbol,"b") == 0)
1541         return(QuantumScale*pixel.blue);
1542       break;
1543     }
1544     case 'C':
1545     case 'c':
1546     {
1547       if (LocaleNCompare(symbol,"channel",7) == 0)
1548         {
1549           GeometryInfo
1550             channel_info;
1551
1552           MagickStatusType
1553             flags;
1554
1555           flags=ParseGeometry(symbol+7,&channel_info);
1556           if (image->colorspace == CMYKColorspace)
1557             switch (channel)
1558             {
1559               case CyanPixelChannel:
1560               {
1561                 if ((flags & RhoValue) == 0)
1562                   return(0.0);
1563                 return(channel_info.rho);
1564               }
1565               case MagentaPixelChannel:
1566               {
1567                 if ((flags & SigmaValue) == 0)
1568                   return(0.0);
1569                 return(channel_info.sigma);
1570               }
1571               case YellowPixelChannel:
1572               {
1573                 if ((flags & XiValue) == 0)
1574                   return(0.0);
1575                 return(channel_info.xi);
1576               }
1577               case BlackPixelChannel:
1578               {
1579                 if ((flags & PsiValue) == 0)
1580                   return(0.0);
1581                 return(channel_info.psi);
1582               }
1583               case AlphaPixelChannel:
1584               {
1585                 if ((flags & ChiValue) == 0)
1586                   return(0.0);
1587                 return(channel_info.chi);
1588               }
1589               default:
1590                 return(0.0);
1591             }
1592           switch (channel)
1593           {
1594             case RedPixelChannel:
1595             {
1596               if ((flags & RhoValue) == 0)
1597                 return(0.0);
1598               return(channel_info.rho);
1599             }
1600             case GreenPixelChannel:
1601             {
1602               if ((flags & SigmaValue) == 0)
1603                 return(0.0);
1604               return(channel_info.sigma);
1605             }
1606             case BluePixelChannel:
1607             {
1608               if ((flags & XiValue) == 0)
1609                 return(0.0);
1610               return(channel_info.xi);
1611             }
1612             case BlackPixelChannel:
1613             {
1614               if ((flags & ChiValue) == 0)
1615                 return(0.0);
1616               return(channel_info.chi);
1617             }
1618             case AlphaPixelChannel:
1619             {
1620               if ((flags & PsiValue) == 0)
1621                 return(0.0);
1622               return(channel_info.psi);
1623             }
1624             default:
1625               return(0.0);
1626           }
1627           return(0.0);
1628         }
1629       if (LocaleCompare(symbol,"c") == 0)
1630         return(QuantumScale*pixel.red);
1631       break;
1632     }
1633     case 'D':
1634     case 'd':
1635     {
1636       if (LocaleNCompare(symbol,"depth",5) == 0)
1637         return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1638       break;
1639     }
1640     case 'G':
1641     case 'g':
1642     {
1643       if (LocaleCompare(symbol,"g") == 0)
1644         return(QuantumScale*pixel.green);
1645       break;
1646     }
1647     case 'K':
1648     case 'k':
1649     {
1650       if (LocaleNCompare(symbol,"kurtosis",8) == 0)
1651         return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1652       if (LocaleCompare(symbol,"k") == 0)
1653         {
1654           if (image->colorspace != CMYKColorspace)
1655             {
1656               (void) ThrowMagickException(exception,GetMagickModule(),
1657                 OptionError,"ColorSeparatedImageRequired","'%s'",
1658                 image->filename);
1659               return(0.0);
1660             }
1661           return(QuantumScale*pixel.black);
1662         }
1663       break;
1664     }
1665     case 'H':
1666     case 'h':
1667     {
1668       if (LocaleCompare(symbol,"h") == 0)
1669         return((double) image->rows);
1670       if (LocaleCompare(symbol,"hue") == 0)
1671         {
1672           double
1673             hue,
1674             lightness,
1675             saturation;
1676
1677           ConvertRGBToHSL(pixel.red,pixel.green,pixel.blue,&hue,&saturation,
1678             &lightness);
1679           return(hue);
1680         }
1681       break;
1682     }
1683     case 'I':
1684     case 'i':
1685     {
1686       if ((LocaleCompare(symbol,"image.depth") == 0) ||
1687           (LocaleCompare(symbol,"image.minima") == 0) ||
1688           (LocaleCompare(symbol,"image.maxima") == 0) ||
1689           (LocaleCompare(symbol,"image.mean") == 0) ||
1690           (LocaleCompare(symbol,"image.kurtosis") == 0) ||
1691           (LocaleCompare(symbol,"image.skewness") == 0) ||
1692           (LocaleCompare(symbol,"image.standard_deviation") == 0))
1693         return(FxChannelStatistics(fx_info,image,channel,symbol+6,exception));
1694       if (LocaleCompare(symbol,"image.resolution.x") == 0)
1695         return(image->resolution.x);
1696       if (LocaleCompare(symbol,"image.resolution.y") == 0)
1697         return(image->resolution.y);
1698       if (LocaleCompare(symbol,"intensity") == 0)
1699         return(QuantumScale*GetPixelInfoIntensity(&pixel));
1700       if (LocaleCompare(symbol,"i") == 0)
1701         return((double) x);
1702       break;
1703     }
1704     case 'J':
1705     case 'j':
1706     {
1707       if (LocaleCompare(symbol,"j") == 0)
1708         return((double) y);
1709       break;
1710     }
1711     case 'L':
1712     case 'l':
1713     {
1714       if (LocaleCompare(symbol,"lightness") == 0)
1715         {
1716           double
1717             hue,
1718             lightness,
1719             saturation;
1720
1721           ConvertRGBToHSL(pixel.red,pixel.green,pixel.blue,&hue,&saturation,
1722             &lightness);
1723           return(lightness);
1724         }
1725       if (LocaleCompare(symbol,"luminance") == 0)
1726         {
1727           double
1728             luminence;
1729
1730           luminence=0.21267*pixel.red+0.71516*pixel.green+0.07217*pixel.blue;
1731           return(QuantumScale*luminence);
1732         }
1733       break;
1734     }
1735     case 'M':
1736     case 'm':
1737     {
1738       if (LocaleNCompare(symbol,"maxima",6) == 0)
1739         return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1740       if (LocaleNCompare(symbol,"mean",4) == 0)
1741         return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1742       if (LocaleNCompare(symbol,"minima",6) == 0)
1743         return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1744       if (LocaleCompare(symbol,"m") == 0)
1745         return(QuantumScale*pixel.blue);
1746       break;
1747     }
1748     case 'N':
1749     case 'n':
1750     {
1751       if (LocaleCompare(symbol,"n") == 0)
1752         return((double) GetImageListLength(fx_info->images));
1753       break;
1754     }
1755     case 'O':
1756     case 'o':
1757     {
1758       if (LocaleCompare(symbol,"o") == 0)
1759         return(QuantumScale*pixel.alpha);
1760       break;
1761     }
1762     case 'P':
1763     case 'p':
1764     {
1765       if (LocaleCompare(symbol,"page.height") == 0)
1766         return((double) image->page.height);
1767       if (LocaleCompare(symbol,"page.width") == 0)
1768         return((double) image->page.width);
1769       if (LocaleCompare(symbol,"page.x") == 0)
1770         return((double) image->page.x);
1771       if (LocaleCompare(symbol,"page.y") == 0)
1772         return((double) image->page.y);
1773       break;
1774     }
1775     case 'R':
1776     case 'r':
1777     {
1778       if (LocaleCompare(symbol,"resolution.x") == 0)
1779         return(image->resolution.x);
1780       if (LocaleCompare(symbol,"resolution.y") == 0)
1781         return(image->resolution.y);
1782       if (LocaleCompare(symbol,"r") == 0)
1783         return(QuantumScale*pixel.red);
1784       break;
1785     }
1786     case 'S':
1787     case 's':
1788     {
1789       if (LocaleCompare(symbol,"saturation") == 0)
1790         {
1791           double
1792             hue,
1793             lightness,
1794             saturation;
1795
1796           ConvertRGBToHSL(pixel.red,pixel.green,pixel.blue,&hue,&saturation,
1797             &lightness);
1798           return(saturation);
1799         }
1800       if (LocaleNCompare(symbol,"skewness",8) == 0)
1801         return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1802       if (LocaleNCompare(symbol,"standard_deviation",18) == 0)
1803         return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1804       break;
1805     }
1806     case 'T':
1807     case 't':
1808     {
1809       if (LocaleCompare(symbol,"t") == 0)
1810         return((double) GetImageIndexInList(fx_info->images));
1811       break;
1812     }
1813     case 'W':
1814     case 'w':
1815     {
1816       if (LocaleCompare(symbol,"w") == 0)
1817         return((double) image->columns);
1818       break;
1819     }
1820     case 'Y':
1821     case 'y':
1822     {
1823       if (LocaleCompare(symbol,"y") == 0)
1824         return(QuantumScale*pixel.green);
1825       break;
1826     }
1827     case 'Z':
1828     case 'z':
1829     {
1830       if (LocaleCompare(symbol,"z") == 0)
1831         {
1832           double
1833             depth;
1834
1835           depth=(double) GetImageDepth(image,fx_info->exception);
1836           return(depth);
1837         }
1838       break;
1839     }
1840     default:
1841       break;
1842   }
1843   value=(const char *) GetValueFromSplayTree(fx_info->symbols,symbol);
1844   if (value != (const char *) NULL)
1845     return((double) StringToDouble(value,(char **) NULL));
1846   (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1847     "UnableToParseExpression","'%s'",symbol);
1848   return(0.0);
1849 }
1850
1851 static const char *FxOperatorPrecedence(const char *expression,
1852   ExceptionInfo *exception)
1853 {
1854   typedef enum
1855   {
1856     UndefinedPrecedence,
1857     NullPrecedence,
1858     BitwiseComplementPrecedence,
1859     ExponentPrecedence,
1860     ExponentialNotationPrecedence,
1861     MultiplyPrecedence,
1862     AdditionPrecedence,
1863     ShiftPrecedence,
1864     RelationalPrecedence,
1865     EquivalencyPrecedence,
1866     BitwiseAndPrecedence,
1867     BitwiseOrPrecedence,
1868     LogicalAndPrecedence,
1869     LogicalOrPrecedence,
1870     TernaryPrecedence,
1871     AssignmentPrecedence,
1872     CommaPrecedence,
1873     SeparatorPrecedence
1874   } FxPrecedence;
1875
1876   FxPrecedence
1877     precedence,
1878     target;
1879
1880   register const char
1881     *subexpression;
1882
1883   register int
1884     c;
1885
1886   size_t
1887     level;
1888
1889   c=0;
1890   level=0;
1891   subexpression=(const char *) NULL;
1892   target=NullPrecedence;
1893   while (*expression != '\0')
1894   {
1895     precedence=UndefinedPrecedence;
1896     if ((isspace((int) ((char) *expression)) != 0) || (c == (int) '@'))
1897       {
1898         expression++;
1899         continue;
1900       }
1901     switch (*expression)
1902     {
1903       case 'A':
1904       case 'a':
1905       {
1906 #if defined(MAGICKCORE_HAVE_ACOSH)
1907         if (LocaleNCompare(expression,"acosh",5) == 0)
1908           {
1909             expression+=5;
1910             break;
1911           }
1912 #endif
1913 #if defined(MAGICKCORE_HAVE_ASINH)
1914         if (LocaleNCompare(expression,"asinh",5) == 0)
1915           {
1916             expression+=5;
1917             break;
1918           }
1919 #endif
1920 #if defined(MAGICKCORE_HAVE_ATANH)
1921         if (LocaleNCompare(expression,"atanh",5) == 0)
1922           {
1923             expression+=5;
1924             break;
1925           }
1926 #endif
1927         if (LocaleNCompare(expression,"atan2",5) == 0)
1928           {
1929             expression+=5;
1930             break;
1931           }
1932         break;
1933       }
1934       case 'E':
1935       case 'e':
1936       {
1937         if ((LocaleNCompare(expression,"E+",2) == 0) ||
1938             (LocaleNCompare(expression,"E-",2) == 0))
1939           {
1940             expression+=2;  /* scientific notation */
1941             break;
1942           }
1943       }
1944       case 'J':
1945       case 'j':
1946       {
1947         if ((LocaleNCompare(expression,"j0",2) == 0) ||
1948             (LocaleNCompare(expression,"j1",2) == 0))
1949           {
1950             expression+=2;
1951             break;
1952           }
1953         break;
1954       }
1955       case '#':
1956       {
1957         while (isxdigit((int) ((unsigned char) *(expression+1))) != 0)
1958           expression++;
1959         break;
1960       }
1961       default:
1962         break;
1963     }
1964     if ((c == (int) '{') || (c == (int) '['))
1965       level++;
1966     else
1967       if ((c == (int) '}') || (c == (int) ']'))
1968         level--;
1969     if (level == 0)
1970       switch ((unsigned char) *expression)
1971       {
1972         case '~':
1973         case '!':
1974         {
1975           precedence=BitwiseComplementPrecedence;
1976           break;
1977         }
1978         case '^':
1979         case '@':
1980         {
1981           precedence=ExponentPrecedence;
1982           break;
1983         }
1984         default:
1985         {
1986           if (((c != 0) && ((isdigit((int) ((char) c)) != 0) ||
1987                (strchr(")",c) != (char *) NULL))) &&
1988               (((islower((int) ((char) *expression)) != 0) ||
1989                (strchr("(",(int) *expression) != (char *) NULL)) ||
1990                ((isdigit((int) ((char) c)) == 0) &&
1991                 (isdigit((int) ((char) *expression)) != 0))) &&
1992               (strchr("xy",(int) *expression) == (char *) NULL))
1993             precedence=MultiplyPrecedence;
1994           break;
1995         }
1996         case '*':
1997         case '/':
1998         case '%':
1999         {
2000           precedence=MultiplyPrecedence;
2001           break;
2002         }
2003         case '+':
2004         case '-':
2005         {
2006           if ((strchr("(+-/*%:&^|<>~,",c) == (char *) NULL) ||
2007               (isalpha(c) != 0))
2008             precedence=AdditionPrecedence;
2009           break;
2010         }
2011         case LeftShiftOperator:
2012         case RightShiftOperator:
2013         {
2014           precedence=ShiftPrecedence;
2015           break;
2016         }
2017         case '<':
2018         case LessThanEqualOperator:
2019         case GreaterThanEqualOperator:
2020         case '>':
2021         {
2022           precedence=RelationalPrecedence;
2023           break;
2024         }
2025         case EqualOperator:
2026         case NotEqualOperator:
2027         {
2028           precedence=EquivalencyPrecedence;
2029           break;
2030         }
2031         case '&':
2032         {
2033           precedence=BitwiseAndPrecedence;
2034           break;
2035         }
2036         case '|':
2037         {
2038           precedence=BitwiseOrPrecedence;
2039           break;
2040         }
2041         case LogicalAndOperator:
2042         {
2043           precedence=LogicalAndPrecedence;
2044           break;
2045         }
2046         case LogicalOrOperator:
2047         {
2048           precedence=LogicalOrPrecedence;
2049           break;
2050         }
2051         case ExponentialNotation:
2052         {
2053           precedence=ExponentialNotationPrecedence;
2054           break;
2055         }
2056         case ':':
2057         case '?':
2058         {
2059           precedence=TernaryPrecedence;
2060           break;
2061         }
2062         case '=':
2063         {
2064           precedence=AssignmentPrecedence;
2065           break;
2066         }
2067         case ',':
2068         {
2069           precedence=CommaPrecedence;
2070           break;
2071         }
2072         case ';':
2073         {
2074           precedence=SeparatorPrecedence;
2075           break;
2076         }
2077       }
2078     if ((precedence == BitwiseComplementPrecedence) ||
2079         (precedence == TernaryPrecedence) ||
2080         (precedence == AssignmentPrecedence))
2081       {
2082         if (precedence > target)
2083           {
2084             /*
2085               Right-to-left associativity.
2086             */
2087             target=precedence;
2088             subexpression=expression;
2089           }
2090       }
2091     else
2092       if (precedence >= target)
2093         {
2094           /*
2095             Left-to-right associativity.
2096           */
2097           target=precedence;
2098           subexpression=expression;
2099         }
2100     if (strchr("(",(int) *expression) != (char *) NULL)
2101       expression=FxSubexpression(expression,exception);
2102     c=(int) (*expression++);
2103   }
2104   return(subexpression);
2105 }
2106
2107 static double FxEvaluateSubexpression(FxInfo *fx_info,
2108   const PixelChannel channel,const ssize_t x,const ssize_t y,
2109   const char *expression,double *beta,ExceptionInfo *exception)
2110 {
2111   char
2112     *q,
2113     subexpression[MaxTextExtent];
2114
2115   double
2116     alpha,
2117     gamma;
2118
2119   register const char
2120     *p;
2121
2122   *beta=0.0;
2123   if (exception->severity != UndefinedException)
2124     return(0.0);
2125   while (isspace((int) *expression) != 0)
2126     expression++;
2127   if (*expression == '\0')
2128     {
2129       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2130         "MissingExpression","'%s'",expression);
2131       return(0.0);
2132     }
2133   *subexpression='\0';
2134   p=FxOperatorPrecedence(expression,exception);
2135   if (p != (const char *) NULL)
2136     {
2137       (void) CopyMagickString(subexpression,expression,(size_t)
2138         (p-expression+1));
2139       alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,beta,
2140         exception);
2141       switch ((unsigned char) *p)
2142       {
2143         case '~':
2144         {
2145           *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2146           *beta=(double) (~(size_t) *beta);
2147           return(*beta);
2148         }
2149         case '!':
2150         {
2151           *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2152           return(*beta == 0.0 ? 1.0 : 0.0);
2153         }
2154         case '^':
2155         {
2156           *beta=pow((double) alpha,(double) FxEvaluateSubexpression(fx_info,
2157             channel,x,y,++p,beta,exception));
2158           return(*beta);
2159         }
2160         case '*':
2161         case ExponentialNotation:
2162         {
2163           *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2164           return(alpha*(*beta));
2165         }
2166         case '/':
2167         {
2168           *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2169           if (*beta == 0.0)
2170             {
2171               if (exception->severity == UndefinedException)
2172                 (void) ThrowMagickException(exception,GetMagickModule(),
2173                   OptionError,"DivideByZero","'%s'",expression);
2174               return(0.0);
2175             }
2176           return(alpha/(*beta));
2177         }
2178         case '%':
2179         {
2180           *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2181           *beta=fabs(floor(((double) *beta)+0.5));
2182           if (*beta == 0.0)
2183             {
2184               (void) ThrowMagickException(exception,GetMagickModule(),
2185                 OptionError,"DivideByZero","'%s'",expression);
2186               return(0.0);
2187             }
2188           return(fmod((double) alpha,(double) *beta));
2189         }
2190         case '+':
2191         {
2192           *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2193           return(alpha+(*beta));
2194         }
2195         case '-':
2196         {
2197           *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2198           return(alpha-(*beta));
2199         }
2200         case LeftShiftOperator:
2201         {
2202           gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2203           *beta=(double) ((size_t) (alpha+0.5) << (size_t) (gamma+0.5));
2204           return(*beta);
2205         }
2206         case RightShiftOperator:
2207         {
2208           gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2209           *beta=(double) ((size_t) (alpha+0.5) >> (size_t) (gamma+0.5));
2210           return(*beta);
2211         }
2212         case '<':
2213         {
2214           *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2215           return(alpha < *beta ? 1.0 : 0.0);
2216         }
2217         case LessThanEqualOperator:
2218         {
2219           *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2220           return(alpha <= *beta ? 1.0 : 0.0);
2221         }
2222         case '>':
2223         {
2224           *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2225           return(alpha > *beta ? 1.0 : 0.0);
2226         }
2227         case GreaterThanEqualOperator:
2228         {
2229           *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2230           return(alpha >= *beta ? 1.0 : 0.0);
2231         }
2232         case EqualOperator:
2233         {
2234           *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2235           return(fabs(alpha-(*beta)) < MagickEpsilon ? MagickEpsilon : 0.0);
2236         }
2237         case NotEqualOperator:
2238         {
2239           *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2240           return(fabs(alpha-(*beta)) >= MagickEpsilon ? 1.0 : 0.0);
2241         }
2242         case '&':
2243         {
2244           gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2245           *beta=(double) ((size_t) (alpha+0.5) & (size_t) (gamma+0.5));
2246           return(*beta);
2247         }
2248         case '|':
2249         {
2250           gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2251           *beta=(double) ((size_t) (alpha+0.5) | (size_t) (gamma+0.5));
2252           return(*beta);
2253         }
2254         case LogicalAndOperator:
2255         {
2256           gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2257           *beta=(alpha > 0.0) && (gamma > 0.0) ? 1.0 : 0.0;
2258           return(*beta);
2259         }
2260         case LogicalOrOperator:
2261         {
2262           gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2263           *beta=(alpha > 0.0) || (gamma > 0.0) ? 1.0 : 0.0;
2264           return(*beta);
2265         }
2266         case '?':
2267         {
2268           double
2269             gamma;
2270
2271           (void) CopyMagickString(subexpression,++p,MaxTextExtent);
2272           q=subexpression;
2273           p=StringToken(":",&q);
2274           if (q == (char *) NULL)
2275             {
2276               (void) ThrowMagickException(exception,GetMagickModule(),
2277                 OptionError,"UnableToParseExpression","'%s'",subexpression);
2278               return(0.0);
2279             }
2280           if (fabs((double) alpha) >= MagickEpsilon)
2281             gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,beta,exception);
2282           else
2283             gamma=FxEvaluateSubexpression(fx_info,channel,x,y,q,beta,exception);
2284           return(gamma);
2285         }
2286         case '=':
2287         {
2288           char
2289             numeric[MaxTextExtent];
2290
2291           q=subexpression;
2292           while (isalpha((int) ((unsigned char) *q)) != 0)
2293             q++;
2294           if (*q != '\0')
2295             {
2296               (void) ThrowMagickException(exception,GetMagickModule(),
2297                 OptionError,"UnableToParseExpression","'%s'",subexpression);
2298               return(0.0);
2299             }
2300           ClearMagickException(exception);
2301           *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2302           (void) FormatLocaleString(numeric,MaxTextExtent,"%g",(double)
2303             *beta);
2304           (void) DeleteNodeFromSplayTree(fx_info->symbols,subexpression);
2305           (void) AddValueToSplayTree(fx_info->symbols,ConstantString(
2306             subexpression),ConstantString(numeric));
2307           return(*beta);
2308         }
2309         case ',':
2310         {
2311           *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2312           return(alpha);
2313         }
2314         case ';':
2315         {
2316           *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,beta,exception);
2317           return(*beta);
2318         }
2319         default:
2320         {
2321           gamma=alpha*FxEvaluateSubexpression(fx_info,channel,x,y,p,beta,
2322             exception);
2323           return(gamma);
2324         }
2325       }
2326     }
2327   if (strchr("(",(int) *expression) != (char *) NULL)
2328     {
2329       (void) CopyMagickString(subexpression,expression+1,MaxTextExtent);
2330       subexpression[strlen(subexpression)-1]='\0';
2331       gamma=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,beta,
2332         exception);
2333       return(gamma);
2334     }
2335   switch (*expression)
2336   {
2337     case '+':
2338     {
2339       gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta,
2340         exception);
2341       return(1.0*gamma);
2342     }
2343     case '-':
2344     {
2345       gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta,
2346         exception);
2347       return(-1.0*gamma);
2348     }
2349     case '~':
2350     {
2351       gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,beta,
2352         exception);
2353       return((double) (~(size_t) (gamma+0.5)));
2354     }
2355     case 'A':
2356     case 'a':
2357     {
2358       if (LocaleNCompare(expression,"abs",3) == 0)
2359         {
2360           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2361             exception);
2362           return((double) fabs((double) alpha));
2363         }
2364 #if defined(MAGICKCORE_HAVE_ACOSH)
2365       if (LocaleNCompare(expression,"acosh",5) == 0)
2366         {
2367           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2368             exception);
2369           return((double) acosh((double) alpha));
2370         }
2371 #endif
2372       if (LocaleNCompare(expression,"acos",4) == 0)
2373         {
2374           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2375             exception);
2376           return((double) acos((double) alpha));
2377         }
2378 #if defined(MAGICKCORE_HAVE_J1)
2379       if (LocaleNCompare(expression,"airy",4) == 0)
2380         {
2381           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2382             exception);
2383           if (alpha == 0.0)
2384             return(1.0);
2385           gamma=2.0*j1((double) (MagickPI*alpha))/(MagickPI*alpha);
2386           return(gamma*gamma);
2387         }
2388 #endif
2389 #if defined(MAGICKCORE_HAVE_ASINH)
2390       if (LocaleNCompare(expression,"asinh",5) == 0)
2391         {
2392           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2393             exception);
2394           return((double) asinh((double) alpha));
2395         }
2396 #endif
2397       if (LocaleNCompare(expression,"asin",4) == 0)
2398         {
2399           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2400             exception);
2401           return((double) asin((double) alpha));
2402         }
2403       if (LocaleNCompare(expression,"alt",3) == 0)
2404         {
2405           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2406             exception);
2407           return(((ssize_t) alpha) & 0x01 ? -1.0 : 1.0);
2408         }
2409       if (LocaleNCompare(expression,"atan2",5) == 0)
2410         {
2411           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2412             exception);
2413           return((double) atan2((double) alpha,(double) *beta));
2414         }
2415 #if defined(MAGICKCORE_HAVE_ATANH)
2416       if (LocaleNCompare(expression,"atanh",5) == 0)
2417         {
2418           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2419             exception);
2420           return((double) atanh((double) alpha));
2421         }
2422 #endif
2423       if (LocaleNCompare(expression,"atan",4) == 0)
2424         {
2425           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2426             exception);
2427           return((double) atan((double) alpha));
2428         }
2429       if (LocaleCompare(expression,"a") == 0)
2430         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2431       break;
2432     }
2433     case 'B':
2434     case 'b':
2435     {
2436       if (LocaleCompare(expression,"b") == 0)
2437         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2438       break;
2439     }
2440     case 'C':
2441     case 'c':
2442     {
2443       if (LocaleNCompare(expression,"ceil",4) == 0)
2444         {
2445           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2446             exception);
2447           return((double) ceil((double) alpha));
2448         }
2449       if (LocaleNCompare(expression,"cosh",4) == 0)
2450         {
2451           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2452             exception);
2453           return((double) cosh((double) alpha));
2454         }
2455       if (LocaleNCompare(expression,"cos",3) == 0)
2456         {
2457           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2458             exception);
2459           return((double) cos((double) alpha));
2460         }
2461       if (LocaleCompare(expression,"c") == 0)
2462         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2463       break;
2464     }
2465     case 'D':
2466     case 'd':
2467     {
2468       if (LocaleNCompare(expression,"debug",5) == 0)
2469         {
2470           const char
2471             *type;
2472
2473           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2474             exception);
2475           if (fx_info->images->colorspace == CMYKColorspace)
2476             switch (channel)
2477             {
2478               case CyanPixelChannel: type="cyan"; break;
2479               case MagentaPixelChannel: type="magenta"; break;
2480               case YellowPixelChannel: type="yellow"; break;
2481               case AlphaPixelChannel: type="opacity"; break;
2482               case BlackPixelChannel: type="black"; break;
2483               default: type="unknown"; break;
2484             }
2485           else
2486             switch (channel)
2487             {
2488               case RedPixelChannel: type="red"; break;
2489               case GreenPixelChannel: type="green"; break;
2490               case BluePixelChannel: type="blue"; break;
2491               case AlphaPixelChannel: type="opacity"; break;
2492               default: type="unknown"; break;
2493             }
2494           (void) CopyMagickString(subexpression,expression+6,MaxTextExtent);
2495           if (strlen(subexpression) > 1)
2496             subexpression[strlen(subexpression)-1]='\0';
2497           if (fx_info->file != (FILE *) NULL)
2498             (void) FormatLocaleFile(fx_info->file,"%s[%.20g,%.20g].%s: "
2499                "%s=%.*g\n",fx_info->images->filename,(double) x,(double) y,type,
2500                subexpression,GetMagickPrecision(),(double) alpha);
2501           return(0.0);
2502         }
2503       if (LocaleNCompare(expression,"drc",3) == 0)
2504         {
2505           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2506             exception);
2507           return((double) (alpha/(*beta*(alpha-1.0)+1.0)));
2508         }
2509       break;
2510     }
2511     case 'E':
2512     case 'e':
2513     {
2514       if (LocaleCompare(expression,"epsilon") == 0)
2515         return((double) MagickEpsilon);
2516       if (LocaleNCompare(expression,"exp",3) == 0)
2517         {
2518           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2519             exception);
2520           return((double) exp((double) alpha));
2521         }
2522       if (LocaleCompare(expression,"e") == 0)
2523         return((double) 2.7182818284590452354);
2524       break;
2525     }
2526     case 'F':
2527     case 'f':
2528     {
2529       if (LocaleNCompare(expression,"floor",5) == 0)
2530         {
2531           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2532             exception);
2533           return((double) floor((double) alpha));
2534         }
2535       break;
2536     }
2537     case 'G':
2538     case 'g':
2539     {
2540       if (LocaleNCompare(expression,"gauss",5) == 0)
2541         {
2542           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2543             exception);
2544           gamma=exp((double) (-alpha*alpha/2.0))/sqrt(2.0*MagickPI);
2545           return((double) gamma);
2546         }
2547       if (LocaleNCompare(expression,"gcd",3) == 0)
2548         {
2549           MagickOffsetType
2550             gcd;
2551
2552           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2553             exception);
2554           gcd=FxGCD((MagickOffsetType) (alpha+0.5),(MagickOffsetType) (*beta+
2555             0.5));
2556           return((double) gcd);
2557         }
2558       if (LocaleCompare(expression,"g") == 0)
2559         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2560       break;
2561     }
2562     case 'H':
2563     case 'h':
2564     {
2565       if (LocaleCompare(expression,"h") == 0)
2566         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2567       if (LocaleCompare(expression,"hue") == 0)
2568         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2569       if (LocaleNCompare(expression,"hypot",5) == 0)
2570         {
2571           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2572             exception);
2573           return((double) hypot((double) alpha,(double) *beta));
2574         }
2575       break;
2576     }
2577     case 'K':
2578     case 'k':
2579     {
2580       if (LocaleCompare(expression,"k") == 0)
2581         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2582       break;
2583     }
2584     case 'I':
2585     case 'i':
2586     {
2587       if (LocaleCompare(expression,"intensity") == 0)
2588         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2589       if (LocaleNCompare(expression,"int",3) == 0)
2590         {
2591           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2592             exception);
2593           return((double) floor(alpha));
2594         }
2595 #if defined(MAGICKCORE_HAVE_ISNAN)
2596       if (LocaleNCompare(expression,"isnan",5) == 0)
2597         {
2598           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2599             exception);
2600           return((double) !!isnan((double) alpha));
2601         }
2602 #endif
2603       if (LocaleCompare(expression,"i") == 0)
2604         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2605       break;
2606     }
2607     case 'J':
2608     case 'j':
2609     {
2610       if (LocaleCompare(expression,"j") == 0)
2611         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2612 #if defined(MAGICKCORE_HAVE_J0)
2613       if (LocaleNCompare(expression,"j0",2) == 0)
2614         {
2615           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,beta,
2616             exception);
2617           return((double) j0((double) alpha));
2618         }
2619 #endif
2620 #if defined(MAGICKCORE_HAVE_J1)
2621       if (LocaleNCompare(expression,"j1",2) == 0)
2622         {
2623           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,beta,
2624             exception);
2625           return((double) j1((double) alpha));
2626         }
2627 #endif
2628 #if defined(MAGICKCORE_HAVE_J1)
2629       if (LocaleNCompare(expression,"jinc",4) == 0)
2630         {
2631           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2632             exception);
2633           if (alpha == 0.0)
2634             return(1.0);
2635           gamma=(double) (2.0*j1((double) (MagickPI*alpha))/(MagickPI*
2636             alpha));
2637           return(gamma);
2638         }
2639 #endif
2640       break;
2641     }
2642     case 'L':
2643     case 'l':
2644     {
2645       if (LocaleNCompare(expression,"ln",2) == 0)
2646         {
2647           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,beta,
2648             exception);
2649           return((double) log((double) alpha));
2650         }
2651       if (LocaleNCompare(expression,"logtwo",6) == 0)
2652         {
2653           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,beta,
2654             exception);
2655           return((double) log10((double) alpha))/log10(2.0);
2656         }
2657       if (LocaleNCompare(expression,"log",3) == 0)
2658         {
2659           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2660             exception);
2661           return((double) log10((double) alpha));
2662         }
2663       if (LocaleCompare(expression,"lightness") == 0)
2664         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2665       break;
2666     }
2667     case 'M':
2668     case 'm':
2669     {
2670       if (LocaleCompare(expression,"MaxRGB") == 0)
2671         return((double) QuantumRange);
2672       if (LocaleNCompare(expression,"maxima",6) == 0)
2673         break;
2674       if (LocaleNCompare(expression,"max",3) == 0)
2675         {
2676           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2677             exception);
2678           return(alpha > *beta ? alpha : *beta);
2679         }
2680       if (LocaleNCompare(expression,"minima",6) == 0)
2681         break;
2682       if (LocaleNCompare(expression,"min",3) == 0)
2683         {
2684           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2685             exception);
2686           return(alpha < *beta ? alpha : *beta);
2687         }
2688       if (LocaleNCompare(expression,"mod",3) == 0)
2689         {
2690           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2691             exception);
2692           gamma=alpha-floor((double) (alpha/(*beta)))*(*beta);
2693           return(gamma);
2694         }
2695       if (LocaleCompare(expression,"m") == 0)
2696         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2697       break;
2698     }
2699     case 'N':
2700     case 'n':
2701     {
2702       if (LocaleNCompare(expression,"not",3) == 0)
2703         {
2704           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2705             exception);
2706           return((double) (alpha < MagickEpsilon));
2707         }
2708       if (LocaleCompare(expression,"n") == 0)
2709         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2710       break;
2711     }
2712     case 'O':
2713     case 'o':
2714     {
2715       if (LocaleCompare(expression,"Opaque") == 0)
2716         return(1.0);
2717       if (LocaleCompare(expression,"o") == 0)
2718         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2719       break;
2720     }
2721     case 'P':
2722     case 'p':
2723     {
2724       if (LocaleCompare(expression,"phi") == 0)
2725         return((double) MagickPHI);
2726       if (LocaleCompare(expression,"pi") == 0)
2727         return((double) MagickPI);
2728       if (LocaleNCompare(expression,"pow",3) == 0)
2729         {
2730           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2731             exception);
2732           return((double) pow((double) alpha,(double) *beta));
2733         }
2734       if (LocaleCompare(expression,"p") == 0)
2735         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2736       break;
2737     }
2738     case 'Q':
2739     case 'q':
2740     {
2741       if (LocaleCompare(expression,"QuantumRange") == 0)
2742         return((double) QuantumRange);
2743       if (LocaleCompare(expression,"QuantumScale") == 0)
2744         return((double) QuantumScale);
2745       break;
2746     }
2747     case 'R':
2748     case 'r':
2749     {
2750       if (LocaleNCompare(expression,"rand",4) == 0)
2751         return((double) GetPseudoRandomValue(fx_info->random_info));
2752       if (LocaleNCompare(expression,"round",5) == 0)
2753         {
2754           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2755             exception);
2756           return((double) floor((double) alpha+0.5));
2757         }
2758       if (LocaleCompare(expression,"r") == 0)
2759         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2760       break;
2761     }
2762     case 'S':
2763     case 's':
2764     {
2765       if (LocaleCompare(expression,"saturation") == 0)
2766         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2767       if (LocaleNCompare(expression,"sign",4) == 0)
2768         {
2769           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2770             exception);
2771           return(alpha < 0.0 ? -1.0 : 1.0);
2772         }
2773       if (LocaleNCompare(expression,"sinc",4) == 0)
2774         {
2775           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2776             exception);
2777           if (alpha == 0)
2778             return(1.0);
2779           gamma=(double) (sin((double) (MagickPI*alpha))/
2780             (MagickPI*alpha));
2781           return(gamma);
2782         }
2783       if (LocaleNCompare(expression,"sinh",4) == 0)
2784         {
2785           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2786             exception);
2787           return((double) sinh((double) alpha));
2788         }
2789       if (LocaleNCompare(expression,"sin",3) == 0)
2790         {
2791           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2792             exception);
2793           return((double) sin((double) alpha));
2794         }
2795       if (LocaleNCompare(expression,"sqrt",4) == 0)
2796         {
2797           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2798             exception);
2799           return((double) sqrt((double) alpha));
2800         }
2801       if (LocaleNCompare(expression,"squish",6) == 0)
2802         {
2803           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,beta,
2804             exception);
2805           return((double) (1.0/(1.0+exp((double) (-alpha)))));
2806         }
2807       if (LocaleCompare(expression,"s") == 0)
2808         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2809       break;
2810     }
2811     case 'T':
2812     case 't':
2813     {
2814       if (LocaleNCompare(expression,"tanh",4) == 0)
2815         {
2816           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,beta,
2817             exception);
2818           return((double) tanh((double) alpha));
2819         }
2820       if (LocaleNCompare(expression,"tan",3) == 0)
2821         {
2822           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,beta,
2823             exception);
2824           return((double) tan((double) alpha));
2825         }
2826       if (LocaleCompare(expression,"Transparent") == 0)
2827         return(0.0);
2828       if (LocaleNCompare(expression,"trunc",5) == 0)
2829         {
2830           alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2831             exception);
2832           if (alpha >= 0.0)
2833             return((double) floor((double) alpha));
2834           return((double) ceil((double) alpha));
2835         }
2836       if (LocaleCompare(expression,"t") == 0)
2837         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2838       break;
2839     }
2840     case 'U':
2841     case 'u':
2842     {
2843       if (LocaleCompare(expression,"u") == 0)
2844         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2845       break;
2846     }
2847     case 'V':
2848     case 'v':
2849     {
2850       if (LocaleCompare(expression,"v") == 0)
2851         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2852       break;
2853     }
2854     case 'W':
2855     case 'w':
2856     {
2857       if (LocaleNCompare(expression,"while",5) == 0)
2858         {
2859           do
2860           {
2861             alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,beta,
2862               exception);
2863           } while (fabs((double) alpha) >= MagickEpsilon);
2864           return((double) *beta);
2865         }
2866       if (LocaleCompare(expression,"w") == 0)
2867         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2868       break;
2869     }
2870     case 'Y':
2871     case 'y':
2872     {
2873       if (LocaleCompare(expression,"y") == 0)
2874         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2875       break;
2876     }
2877     case 'Z':
2878     case 'z':
2879     {
2880       if (LocaleCompare(expression,"z") == 0)
2881         return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2882       break;
2883     }
2884     default:
2885       break;
2886   }
2887   q=(char *) expression;
2888   alpha=InterpretSiPrefixValue(expression,&q);
2889   if (q == expression)
2890     return(FxGetSymbol(fx_info,channel,x,y,expression,exception));
2891   return(alpha);
2892 }
2893
2894 MagickPrivate MagickBooleanType FxEvaluateExpression(FxInfo *fx_info,
2895   double *alpha,ExceptionInfo *exception)
2896 {
2897   MagickBooleanType
2898     status;
2899
2900   status=FxEvaluateChannelExpression(fx_info,GrayPixelChannel,0,0,alpha,
2901     exception);
2902   return(status);
2903 }
2904
2905 MagickExport MagickBooleanType FxPreprocessExpression(FxInfo *fx_info,
2906   double *alpha,ExceptionInfo *exception)
2907 {
2908   FILE
2909     *file;
2910
2911   MagickBooleanType
2912     status;
2913
2914   file=fx_info->file;
2915   fx_info->file=(FILE *) NULL;
2916   status=FxEvaluateChannelExpression(fx_info,GrayPixelChannel,0,0,alpha,
2917     exception);
2918   fx_info->file=file;
2919   return(status);
2920 }
2921
2922 MagickPrivate MagickBooleanType FxEvaluateChannelExpression(FxInfo *fx_info,
2923   const PixelChannel channel,const ssize_t x,const ssize_t y,
2924   double *alpha,ExceptionInfo *exception)
2925 {
2926   double
2927     beta;
2928
2929   beta=0.0;
2930   *alpha=FxEvaluateSubexpression(fx_info,channel,x,y,fx_info->expression,&beta,
2931     exception);
2932   return(exception->severity == OptionError ? MagickFalse : MagickTrue);
2933 }
2934 \f
2935 /*
2936 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2937 %                                                                             %
2938 %                                                                             %
2939 %                                                                             %
2940 %     F x I m a g e                                                           %
2941 %                                                                             %
2942 %                                                                             %
2943 %                                                                             %
2944 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2945 %
2946 %  FxImage() applies a mathematical expression to the specified image.
2947 %
2948 %  The format of the FxImage method is:
2949 %
2950 %      Image *FxImage(const Image *image,const char *expression,
2951 %        ExceptionInfo *exception)
2952 %
2953 %  A description of each parameter follows:
2954 %
2955 %    o image: the image.
2956 %
2957 %    o expression: A mathematical expression.
2958 %
2959 %    o exception: return any errors or warnings in this structure.
2960 %
2961 */
2962
2963 static FxInfo **DestroyFxThreadSet(FxInfo **fx_info)
2964 {
2965   register ssize_t
2966     i;
2967
2968   assert(fx_info != (FxInfo **) NULL);
2969   for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
2970     if (fx_info[i] != (FxInfo *) NULL)
2971       fx_info[i]=DestroyFxInfo(fx_info[i]);
2972   fx_info=(FxInfo **) RelinquishMagickMemory(fx_info);
2973   return(fx_info);
2974 }
2975
2976 static FxInfo **AcquireFxThreadSet(const Image *image,const char *expression,
2977   ExceptionInfo *exception)
2978 {
2979   char
2980     *fx_expression;
2981
2982   FxInfo
2983     **fx_info;
2984
2985   double
2986     alpha;
2987
2988   register ssize_t
2989     i;
2990
2991   size_t
2992     number_threads;
2993
2994   number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
2995   fx_info=(FxInfo **) AcquireQuantumMemory(number_threads,sizeof(*fx_info));
2996   if (fx_info == (FxInfo **) NULL)
2997     {
2998       (void) ThrowMagickException(exception,GetMagickModule(),
2999         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
3000       return((FxInfo **) NULL);
3001     }
3002   (void) ResetMagickMemory(fx_info,0,number_threads*sizeof(*fx_info));
3003   if (*expression != '@')
3004     fx_expression=ConstantString(expression);
3005   else
3006     fx_expression=FileToString(expression+1,~0,exception);
3007   for (i=0; i < (ssize_t) number_threads; i++)
3008   {
3009     MagickBooleanType
3010       status;
3011
3012     fx_info[i]=AcquireFxInfo(image,fx_expression,exception);
3013     if (fx_info[i] == (FxInfo *) NULL)
3014       break;
3015     status=FxPreprocessExpression(fx_info[i],&alpha,exception);
3016     if (status == MagickFalse)
3017       break;
3018   }
3019   fx_expression=DestroyString(fx_expression);
3020   if (i < (ssize_t) number_threads)
3021     fx_info=DestroyFxThreadSet(fx_info);
3022   return(fx_info);
3023 }
3024
3025 MagickExport Image *FxImage(const Image *image,const char *expression,
3026   ExceptionInfo *exception)
3027 {
3028 #define FxImageTag  "Fx/Image"
3029
3030   CacheView
3031     *fx_view,
3032     *image_view;
3033
3034   FxInfo
3035     **restrict fx_info;
3036
3037   Image
3038     *fx_image;
3039
3040   MagickBooleanType
3041     status;
3042
3043   MagickOffsetType
3044     progress;
3045
3046   ssize_t
3047     y;
3048
3049   assert(image != (Image *) NULL);
3050   assert(image->signature == MagickSignature);
3051   if (image->debug != MagickFalse)
3052     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3053   fx_info=AcquireFxThreadSet(image,expression,exception);
3054   if (fx_info == (FxInfo **) NULL)
3055     return((Image *) NULL);
3056   fx_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
3057   if (fx_image == (Image *) NULL)
3058     {
3059       fx_info=DestroyFxThreadSet(fx_info);
3060       return((Image *) NULL);
3061     }
3062   if (SetImageStorageClass(fx_image,DirectClass,exception) == MagickFalse)
3063     {
3064       fx_info=DestroyFxThreadSet(fx_info);
3065       fx_image=DestroyImage(fx_image);
3066       return((Image *) NULL);
3067     }
3068   /*
3069     Fx image.
3070   */
3071   status=MagickTrue;
3072   progress=0;
3073   image_view=AcquireVirtualCacheView(image,exception);
3074   fx_view=AcquireAuthenticCacheView(fx_image,exception);
3075 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3076   #pragma omp parallel for schedule(static,4) shared(progress,status) \
3077     dynamic_number_threads(image,image->columns,image->rows,1)
3078 #endif
3079   for (y=0; y < (ssize_t) fx_image->rows; y++)
3080   {
3081     const int
3082       id = GetOpenMPThreadId();
3083
3084     register const Quantum
3085       *restrict p;
3086
3087     register Quantum
3088       *restrict q;
3089
3090     register ssize_t
3091       x;
3092
3093     if (status == MagickFalse)
3094       continue;
3095     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
3096     q=QueueCacheViewAuthenticPixels(fx_view,0,y,fx_image->columns,1,exception);
3097     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3098       {
3099         status=MagickFalse;
3100         continue;
3101       }
3102     for (x=0; x < (ssize_t) fx_image->columns; x++)
3103     {
3104       register ssize_t
3105         i;
3106
3107       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3108       {
3109         double
3110           alpha;
3111
3112         PixelChannel
3113           channel;
3114
3115         PixelTrait
3116           fx_traits,
3117           traits;
3118
3119         channel=GetPixelChannelChannel(image,i);
3120         traits=GetPixelChannelTraits(image,channel);
3121         fx_traits=GetPixelChannelTraits(fx_image,channel);
3122         if ((traits == UndefinedPixelTrait) ||
3123             (fx_traits == UndefinedPixelTrait))
3124           continue;
3125         if (((fx_traits & CopyPixelTrait) != 0) ||
3126             (GetPixelMask(image,p) != 0))
3127           {
3128             SetPixelChannel(fx_image,channel,p[i],q);
3129             continue;
3130           }
3131         alpha=0.0;
3132         (void) FxEvaluateChannelExpression(fx_info[id],channel,x,y,&alpha,
3133           exception);
3134         q[i]=ClampToQuantum(QuantumRange*alpha);
3135       }
3136       p+=GetPixelChannels(image);
3137       q+=GetPixelChannels(fx_image);
3138     }
3139     if (SyncCacheViewAuthenticPixels(fx_view,exception) == MagickFalse)
3140       status=MagickFalse;
3141     if (image->progress_monitor != (MagickProgressMonitor) NULL)
3142       {
3143         MagickBooleanType
3144           proceed;
3145
3146 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3147         #pragma omp critical (MagickCore_FxImage)
3148 #endif
3149         proceed=SetImageProgress(image,FxImageTag,progress++,image->rows);
3150         if (proceed == MagickFalse)
3151           status=MagickFalse;
3152       }
3153   }
3154   fx_view=DestroyCacheView(fx_view);
3155   image_view=DestroyCacheView(image_view);
3156   fx_info=DestroyFxThreadSet(fx_info);
3157   if (status == MagickFalse)
3158     fx_image=DestroyImage(fx_image);
3159   return(fx_image);
3160 }
3161 \f
3162 /*
3163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3164 %                                                                             %
3165 %                                                                             %
3166 %                                                                             %
3167 %     I m p l o d e I m a g e                                                 %
3168 %                                                                             %
3169 %                                                                             %
3170 %                                                                             %
3171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3172 %
3173 %  ImplodeImage() creates a new image that is a copy of an existing
3174 %  one with the image pixels "implode" by the specified percentage.  It
3175 %  allocates the memory necessary for the new Image structure and returns a
3176 %  pointer to the new image.
3177 %
3178 %  The format of the ImplodeImage method is:
3179 %
3180 %      Image *ImplodeImage(const Image *image,const double amount,
3181 %        const PixelInterpolateMethod method,ExceptionInfo *exception)
3182 %
3183 %  A description of each parameter follows:
3184 %
3185 %    o implode_image: Method ImplodeImage returns a pointer to the image
3186 %      after it is implode.  A null image is returned if there is a memory
3187 %      shortage.
3188 %
3189 %    o image: the image.
3190 %
3191 %    o amount:  Define the extent of the implosion.
3192 %
3193 %    o method: the pixel interpolation method.
3194 %
3195 %    o exception: return any errors or warnings in this structure.
3196 %
3197 */
3198 MagickExport Image *ImplodeImage(const Image *image,const double amount,
3199   const PixelInterpolateMethod method,ExceptionInfo *exception)
3200 {
3201 #define ImplodeImageTag  "Implode/Image"
3202
3203   CacheView
3204     *image_view,
3205     *implode_view;
3206
3207   Image
3208     *implode_image;
3209
3210   MagickBooleanType
3211     status;
3212
3213   MagickOffsetType
3214     progress;
3215
3216   double
3217     radius;
3218
3219   PointInfo
3220     center,
3221     scale;
3222
3223   ssize_t
3224     y;
3225
3226   /*
3227     Initialize implode image attributes.
3228   */
3229   assert(image != (Image *) NULL);
3230   assert(image->signature == MagickSignature);
3231   if (image->debug != MagickFalse)
3232     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3233   assert(exception != (ExceptionInfo *) NULL);
3234   assert(exception->signature == MagickSignature);
3235   implode_image=CloneImage(image,image->columns,image->rows,MagickTrue,
3236     exception);
3237   if (implode_image == (Image *) NULL)
3238     return((Image *) NULL);
3239   if (SetImageStorageClass(implode_image,DirectClass,exception) == MagickFalse)
3240     {
3241       implode_image=DestroyImage(implode_image);
3242       return((Image *) NULL);
3243     }
3244   if (implode_image->background_color.alpha != OpaqueAlpha)
3245     implode_image->alpha_trait=BlendPixelTrait;
3246   /*
3247     Compute scaling factor.
3248   */
3249   scale.x=1.0;
3250   scale.y=1.0;
3251   center.x=0.5*image->columns;
3252   center.y=0.5*image->rows;
3253   radius=center.x;
3254   if (image->columns > image->rows)
3255     scale.y=(double) image->columns/(double) image->rows;
3256   else
3257     if (image->columns < image->rows)
3258       {
3259         scale.x=(double) image->rows/(double) image->columns;
3260         radius=center.y;
3261       }
3262   /*
3263     Implode image.
3264   */
3265   status=MagickTrue;
3266   progress=0;
3267   image_view=AcquireVirtualCacheView(image,exception);
3268   implode_view=AcquireAuthenticCacheView(implode_image,exception);
3269 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3270   #pragma omp parallel for schedule(static,4) shared(progress,status) \
3271     dynamic_number_threads(image,image->columns,image->rows,1)
3272 #endif
3273   for (y=0; y < (ssize_t) image->rows; y++)
3274   {
3275     double
3276       distance;
3277
3278     PointInfo
3279       delta;
3280
3281     register const Quantum
3282       *restrict p;
3283
3284     register ssize_t
3285       x;
3286
3287     register Quantum
3288       *restrict q;
3289
3290     if (status == MagickFalse)
3291       continue;
3292     p=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3293     q=QueueCacheViewAuthenticPixels(implode_view,0,y,implode_image->columns,1,
3294       exception);
3295     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3296       {
3297         status=MagickFalse;
3298         continue;
3299       }
3300     delta.y=scale.y*(double) (y-center.y);
3301     for (x=0; x < (ssize_t) image->columns; x++)
3302     {
3303       register ssize_t
3304         i;
3305
3306       /*
3307         Determine if the pixel is within an ellipse.
3308       */
3309       if (GetPixelMask(image,p) != 0)
3310         {
3311           p+=GetPixelChannels(image);
3312           q+=GetPixelChannels(implode_image);
3313           continue;
3314         }
3315       delta.x=scale.x*(double) (x-center.x);
3316       distance=delta.x*delta.x+delta.y*delta.y;
3317       if (distance >= (radius*radius))
3318         for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3319         {
3320           PixelChannel
3321             channel;
3322
3323           PixelTrait
3324             implode_traits,
3325             traits;
3326
3327           channel=GetPixelChannelChannel(image,i);
3328           traits=GetPixelChannelTraits(image,channel);
3329           implode_traits=GetPixelChannelTraits(implode_image,channel);
3330           if ((traits == UndefinedPixelTrait) ||
3331               (implode_traits == UndefinedPixelTrait))
3332             continue;
3333           SetPixelChannel(implode_image,channel,p[i],q);
3334         }
3335       else
3336         {
3337           double
3338             factor;
3339
3340           /*
3341             Implode the pixel.
3342           */
3343           factor=1.0;
3344           if (distance > 0.0)
3345             factor=pow(sin((double) (MagickPI*sqrt((double) distance)/radius/
3346               2)),-amount);
3347           status=InterpolatePixelChannels(image,image_view,implode_image,method,
3348             (double) (factor*delta.x/scale.x+center.x),(double) (factor*delta.y/
3349             scale.y+center.y),q,exception);
3350         }
3351       p+=GetPixelChannels(image);
3352       q+=GetPixelChannels(implode_image);
3353     }
3354     if (SyncCacheViewAuthenticPixels(implode_view,exception) == MagickFalse)
3355       status=MagickFalse;
3356     if (image->progress_monitor != (MagickProgressMonitor) NULL)
3357       {
3358         MagickBooleanType
3359           proceed;
3360
3361 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3362         #pragma omp critical (MagickCore_ImplodeImage)
3363 #endif
3364         proceed=SetImageProgress(image,ImplodeImageTag,progress++,image->rows);
3365         if (proceed == MagickFalse)
3366           status=MagickFalse;
3367       }
3368   }
3369   implode_view=DestroyCacheView(implode_view);
3370   image_view=DestroyCacheView(image_view);
3371   if (status == MagickFalse)
3372     implode_image=DestroyImage(implode_image);
3373   return(implode_image);
3374 }
3375 \f
3376 /*
3377 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3378 %                                                                             %
3379 %                                                                             %
3380 %                                                                             %
3381 %     M o r p h I m a g e s                                                   %
3382 %                                                                             %
3383 %                                                                             %
3384 %                                                                             %
3385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3386 %
3387 %  The MorphImages() method requires a minimum of two images.  The first
3388 %  image is transformed into the second by a number of intervening images
3389 %  as specified by frames.
3390 %
3391 %  The format of the MorphImage method is:
3392 %
3393 %      Image *MorphImages(const Image *image,const size_t number_frames,
3394 %        ExceptionInfo *exception)
3395 %
3396 %  A description of each parameter follows:
3397 %
3398 %    o image: the image.
3399 %
3400 %    o number_frames:  Define the number of in-between image to generate.
3401 %      The more in-between frames, the smoother the morph.
3402 %
3403 %    o exception: return any errors or warnings in this structure.
3404 %
3405 */
3406 MagickExport Image *MorphImages(const Image *image,
3407   const size_t number_frames,ExceptionInfo *exception)
3408 {
3409 #define MorphImageTag  "Morph/Image"
3410
3411   Image
3412     *morph_image,
3413     *morph_images;
3414
3415   MagickBooleanType
3416     status;
3417
3418   MagickOffsetType
3419     scene;
3420
3421   double
3422     alpha,
3423     beta;
3424
3425   register const Image
3426     *next;
3427
3428   register ssize_t
3429     i;
3430
3431   ssize_t
3432     y;
3433
3434   /*
3435     Clone first frame in sequence.
3436   */
3437   assert(image != (Image *) NULL);
3438   assert(image->signature == MagickSignature);
3439   if (image->debug != MagickFalse)
3440     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3441   assert(exception != (ExceptionInfo *) NULL);
3442   assert(exception->signature == MagickSignature);
3443   morph_images=CloneImage(image,0,0,MagickTrue,exception);
3444   if (morph_images == (Image *) NULL)
3445     return((Image *) NULL);
3446   if (GetNextImageInList(image) == (Image *) NULL)
3447     {
3448       /*
3449         Morph single image.
3450       */
3451       for (i=1; i < (ssize_t) number_frames; i++)
3452       {
3453         morph_image=CloneImage(image,0,0,MagickTrue,exception);
3454         if (morph_image == (Image *) NULL)
3455           {
3456             morph_images=DestroyImageList(morph_images);
3457             return((Image *) NULL);
3458           }
3459         AppendImageToList(&morph_images,morph_image);
3460         if (image->progress_monitor != (MagickProgressMonitor) NULL)
3461           {
3462             MagickBooleanType
3463               proceed;
3464
3465             proceed=SetImageProgress(image,MorphImageTag,(MagickOffsetType) i,
3466               number_frames);
3467             if (proceed == MagickFalse)
3468               status=MagickFalse;
3469           }
3470       }
3471       return(GetFirstImageInList(morph_images));
3472     }
3473   /*
3474     Morph image sequence.
3475   */
3476   status=MagickTrue;
3477   scene=0;
3478   next=image;
3479   for ( ; GetNextImageInList(next) != (Image *) NULL; next=GetNextImageInList(next))
3480   {
3481     for (i=0; i < (ssize_t) number_frames; i++)
3482     {
3483       CacheView
3484         *image_view,
3485         *morph_view;
3486
3487       beta=(double) (i+1.0)/(double) (number_frames+1.0);
3488       alpha=1.0-beta;
3489       morph_image=ResizeImage(next,(size_t) (alpha*next->columns+beta*
3490         GetNextImageInList(next)->columns+0.5),(size_t) (alpha*next->rows+beta*
3491         GetNextImageInList(next)->rows+0.5),next->filter,exception);
3492       if (morph_image == (Image *) NULL)
3493         {
3494           morph_images=DestroyImageList(morph_images);
3495           return((Image *) NULL);
3496         }
3497       status=SetImageStorageClass(morph_image,DirectClass,exception);
3498       if (status == MagickFalse)
3499         {
3500           morph_image=DestroyImage(morph_image);
3501           return((Image *) NULL);
3502         }
3503       AppendImageToList(&morph_images,morph_image);
3504       morph_images=GetLastImageInList(morph_images);
3505       morph_image=ResizeImage(GetNextImageInList(next),morph_images->columns,
3506         morph_images->rows,GetNextImageInList(next)->filter,exception);
3507       if (morph_image == (Image *) NULL)
3508         {
3509           morph_images=DestroyImageList(morph_images);
3510           return((Image *) NULL);
3511         }
3512       image_view=AcquireVirtualCacheView(morph_image,exception);
3513       morph_view=AcquireAuthenticCacheView(morph_images,exception);
3514 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3515       #pragma omp parallel for schedule(static,4) shared(status) \
3516         dynamic_number_threads(image,image->columns,image->rows,1)
3517 #endif
3518       for (y=0; y < (ssize_t) morph_images->rows; y++)
3519       {
3520         MagickBooleanType
3521           sync;
3522
3523         register const Quantum
3524           *restrict p;
3525
3526         register ssize_t
3527           x;
3528
3529         register Quantum
3530           *restrict q;
3531
3532         if (status == MagickFalse)
3533           continue;
3534         p=GetCacheViewVirtualPixels(image_view,0,y,morph_image->columns,1,
3535           exception);
3536         q=GetCacheViewAuthenticPixels(morph_view,0,y,morph_images->columns,1,
3537           exception);
3538         if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3539           {
3540             status=MagickFalse;
3541             continue;
3542           }
3543         for (x=0; x < (ssize_t) morph_images->columns; x++)
3544         {
3545           register ssize_t
3546             i;
3547
3548           for (i=0; i < (ssize_t) GetPixelChannels(morph_image); i++)
3549           {
3550             PixelChannel
3551               channel;
3552
3553             PixelTrait
3554               morph_traits,
3555               traits;
3556
3557             channel=GetPixelChannelChannel(image,i);
3558             traits=GetPixelChannelTraits(image,channel);
3559             morph_traits=GetPixelChannelTraits(morph_image,channel);
3560             if ((traits == UndefinedPixelTrait) ||
3561                 (morph_traits == UndefinedPixelTrait))
3562               continue;
3563             if (((morph_traits & CopyPixelTrait) != 0) ||
3564                 (GetPixelMask(image,p) != 0))
3565               {
3566                 SetPixelChannel(morph_image,channel,p[i],q);
3567                 continue;
3568               }
3569             SetPixelChannel(morph_image,channel,ClampToQuantum(alpha*
3570               GetPixelChannel(morph_images,channel,q)+beta*p[i]),q);
3571           }
3572           p+=GetPixelChannels(morph_image);
3573           q+=GetPixelChannels(morph_images);
3574         }
3575         sync=SyncCacheViewAuthenticPixels(morph_view,exception);
3576         if (sync == MagickFalse)
3577           status=MagickFalse;
3578       }
3579       morph_view=DestroyCacheView(morph_view);
3580       image_view=DestroyCacheView(image_view);
3581       morph_image=DestroyImage(morph_image);
3582     }
3583     if (i < (ssize_t) number_frames)
3584       break;
3585     /*
3586       Clone last frame in sequence.
3587     */
3588     morph_image=CloneImage(GetNextImageInList(next),0,0,MagickTrue,exception);
3589     if (morph_image == (Image *) NULL)
3590       {
3591         morph_images=DestroyImageList(morph_images);
3592         return((Image *) NULL);
3593       }
3594     AppendImageToList(&morph_images,morph_image);
3595     morph_images=GetLastImageInList(morph_images);
3596     if (image->progress_monitor != (MagickProgressMonitor) NULL)
3597       {
3598         MagickBooleanType
3599           proceed;
3600
3601 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3602         #pragma omp critical (MagickCore_MorphImages)
3603 #endif
3604         proceed=SetImageProgress(image,MorphImageTag,scene,
3605           GetImageListLength(image));
3606         if (proceed == MagickFalse)
3607           status=MagickFalse;
3608       }
3609     scene++;
3610   }
3611   if (GetNextImageInList(next) != (Image *) NULL)
3612     {
3613       morph_images=DestroyImageList(morph_images);
3614       return((Image *) NULL);
3615     }
3616   return(GetFirstImageInList(morph_images));
3617 }
3618 \f
3619 /*
3620 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3621 %                                                                             %
3622 %                                                                             %
3623 %                                                                             %
3624 %     P l a s m a I m a g e                                                   %
3625 %                                                                             %
3626 %                                                                             %
3627 %                                                                             %
3628 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3629 %
3630 %  PlasmaImage() initializes an image with plasma fractal values.  The image
3631 %  must be initialized with a base color and the random number generator
3632 %  seeded before this method is called.
3633 %
3634 %  The format of the PlasmaImage method is:
3635 %
3636 %      MagickBooleanType PlasmaImage(Image *image,const SegmentInfo *segment,
3637 %        size_t attenuate,size_t depth,ExceptionInfo *exception)
3638 %
3639 %  A description of each parameter follows:
3640 %
3641 %    o image: the image.
3642 %
3643 %    o segment:   Define the region to apply plasma fractals values.
3644 %
3645 %    o attenuate: Define the plasma attenuation factor.
3646 %
3647 %    o depth: Limit the plasma recursion depth.
3648 %
3649 %    o exception: return any errors or warnings in this structure.
3650 %
3651 */
3652
3653 static inline Quantum PlasmaPixel(RandomInfo *random_info,
3654   const double pixel,const double noise)
3655 {
3656   Quantum
3657     plasma;
3658
3659   plasma=ClampToQuantum(pixel+noise*GetPseudoRandomValue(random_info)-
3660     noise/2.0);
3661   return(plasma);
3662 }
3663
3664 static MagickBooleanType PlasmaImageProxy(Image *image,CacheView *image_view,
3665   CacheView *u_view,CacheView *v_view,RandomInfo *random_info,
3666   const SegmentInfo *segment,size_t attenuate,size_t depth,
3667   ExceptionInfo *exception)
3668 {
3669   double
3670     plasma;
3671
3672   PixelChannel
3673     channel;
3674
3675   PixelTrait
3676     traits;
3677
3678   register const Quantum
3679     *restrict u,
3680     *restrict v;
3681
3682   register Quantum
3683     *restrict q;
3684
3685   register ssize_t
3686     i;
3687
3688   ssize_t
3689     x,
3690     x_mid,
3691     y,
3692     y_mid;
3693
3694   if (((segment->x2-segment->x1) == 0.0) && ((segment->y2-segment->y1) == 0.0))
3695     return(MagickTrue);
3696   if (depth != 0)
3697     {
3698       SegmentInfo
3699         local_info;
3700
3701       /*
3702         Divide the area into quadrants and recurse.
3703       */
3704       depth--;
3705       attenuate++;
3706       x_mid=(ssize_t) ceil((segment->x1+segment->x2)/2-0.5);
3707       y_mid=(ssize_t) ceil((segment->y1+segment->y2)/2-0.5);
3708       local_info=(*segment);
3709       local_info.x2=(double) x_mid;
3710       local_info.y2=(double) y_mid;
3711       (void) PlasmaImageProxy(image,image_view,u_view,v_view,random_info,
3712         &local_info,attenuate,depth,exception);
3713       local_info=(*segment);
3714       local_info.y1=(double) y_mid;
3715       local_info.x2=(double) x_mid;
3716       (void) PlasmaImageProxy(image,image_view,u_view,v_view,random_info,
3717         &local_info,attenuate,depth,exception);
3718       local_info=(*segment);
3719       local_info.x1=(double) x_mid;
3720       local_info.y2=(double) y_mid;
3721       (void) PlasmaImageProxy(image,image_view,u_view,v_view,random_info,
3722         &local_info,attenuate,depth,exception);
3723       local_info=(*segment);
3724       local_info.x1=(double) x_mid;
3725       local_info.y1=(double) y_mid;
3726       return(PlasmaImageProxy(image,image_view,u_view,v_view,random_info,
3727         &local_info,attenuate,depth,exception));
3728     }
3729   x_mid=(ssize_t) ceil((segment->x1+segment->x2)/2-0.5);
3730   y_mid=(ssize_t) ceil((segment->y1+segment->y2)/2-0.5);
3731   if ((segment->x1 == (double) x_mid) && (segment->x2 == (double) x_mid) &&
3732       (segment->y1 == (double) y_mid) && (segment->y2 == (double) y_mid))
3733     return(MagickFalse);
3734   /*
3735     Average pixels and apply plasma.
3736   */
3737   plasma=(double) QuantumRange/(2.0*attenuate);
3738   if ((segment->x1 != (double) x_mid) || (segment->x2 != (double) x_mid))
3739     {
3740       /*
3741         Left pixel.
3742       */
3743       x=(ssize_t) ceil(segment->x1-0.5);
3744       u=GetCacheViewVirtualPixels(u_view,x,(ssize_t) ceil(segment->y1-0.5),1,1,
3745         exception);
3746       v=GetCacheViewVirtualPixels(v_view,x,(ssize_t) ceil(segment->y2-0.5),1,1,
3747         exception);
3748       q=QueueCacheViewAuthenticPixels(image_view,x,y_mid,1,1,exception);
3749       if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
3750           (q == (Quantum *) NULL))
3751         return(MagickTrue);
3752       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3753       {
3754         channel=GetPixelChannelChannel(image,i);
3755         traits=GetPixelChannelTraits(image,channel);
3756         if (traits == UndefinedPixelTrait)
3757           continue;
3758         q[i]=PlasmaPixel(random_info,(u[channel]+v[channel])/2.0,plasma);
3759       }
3760       (void) SyncCacheViewAuthenticPixels(image_view,exception);
3761       if (segment->x1 != segment->x2)
3762         {
3763           /*
3764             Right pixel.
3765           */
3766           x=(ssize_t) ceil(segment->x2-0.5);
3767           u=GetCacheViewVirtualPixels(u_view,x,(ssize_t) ceil(segment->y1-0.5),
3768             1,1,exception);
3769           v=GetCacheViewVirtualPixels(v_view,x,(ssize_t) ceil(segment->y2-0.5),
3770             1,1,exception);
3771           q=QueueCacheViewAuthenticPixels(image_view,x,y_mid,1,1,exception);
3772           if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
3773               (q == (Quantum *) NULL))
3774             return(MagickTrue);
3775           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3776           {
3777             channel=GetPixelChannelChannel(image,i);
3778             traits=GetPixelChannelTraits(image,channel);
3779             if (traits == UndefinedPixelTrait)
3780               continue;
3781             q[i]=PlasmaPixel(random_info,(u[channel]+v[channel])/2.0,plasma);
3782           }
3783           (void) SyncCacheViewAuthenticPixels(image_view,exception);
3784         }
3785     }
3786   if ((segment->y1 != (double) y_mid) || (segment->y2 != (double) y_mid))
3787     {
3788       if ((segment->x1 != (double) x_mid) || (segment->y2 != (double) y_mid))
3789         {
3790           /*
3791             Bottom pixel.
3792           */
3793           y=(ssize_t) ceil(segment->y2-0.5);
3794           u=GetCacheViewVirtualPixels(u_view,(ssize_t) ceil(segment->x1-0.5),y,
3795             1,1,exception);
3796           v=GetCacheViewVirtualPixels(v_view,(ssize_t) ceil(segment->x2-0.5),y,
3797             1,1,exception);
3798           q=QueueCacheViewAuthenticPixels(image_view,x_mid,y,1,1,exception);
3799           if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
3800               (q == (Quantum *) NULL))
3801             return(MagickTrue);
3802           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3803           {
3804             channel=GetPixelChannelChannel(image,i);
3805             traits=GetPixelChannelTraits(image,channel);
3806             if (traits == UndefinedPixelTrait)
3807               continue;
3808             q[i]=PlasmaPixel(random_info,(u[channel]+v[channel])/2.0,plasma);
3809           }
3810           (void) SyncCacheViewAuthenticPixels(image_view,exception);
3811         }
3812       if (segment->y1 != segment->y2)
3813         {
3814           /*
3815             Top pixel.
3816           */
3817           y=(ssize_t) ceil(segment->y1-0.5);
3818           u=GetCacheViewVirtualPixels(u_view,(ssize_t) ceil(segment->x1-0.5),y,
3819             1,1,exception);
3820           v=GetCacheViewVirtualPixels(v_view,(ssize_t) ceil(segment->x2-0.5),y,
3821             1,1,exception);
3822           q=QueueCacheViewAuthenticPixels(image_view,x_mid,y,1,1,exception);
3823           if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
3824               (q == (Quantum *) NULL))
3825             return(MagickTrue);
3826           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3827           {
3828             channel=GetPixelChannelChannel(image,i);
3829             traits=GetPixelChannelTraits(image,channel);
3830             if (traits == UndefinedPixelTrait)
3831               continue;
3832             q[i]=PlasmaPixel(random_info,(u[channel]+v[channel])/2.0,plasma);
3833           }
3834           (void) SyncCacheViewAuthenticPixels(image_view,exception);
3835         }
3836     }
3837   if ((segment->x1 != segment->x2) || (segment->y1 != segment->y2))
3838     {
3839       /*
3840         Middle pixel.
3841       */
3842       x=(ssize_t) ceil(segment->x1-0.5);
3843       y=(ssize_t) ceil(segment->y1-0.5);
3844       u=GetCacheViewVirtualPixels(u_view,x,y,1,1,exception);
3845       x=(ssize_t) ceil(segment->x2-0.5);
3846       y=(ssize_t) ceil(segment->y2-0.5);
3847       v=GetCacheViewVirtualPixels(v_view,x,y,1,1,exception);
3848       q=QueueCacheViewAuthenticPixels(image_view,x_mid,y_mid,1,1,exception);
3849       if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
3850           (q == (Quantum *) NULL))
3851         return(MagickTrue);
3852       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3853       {
3854         channel=GetPixelChannelChannel(image,i);
3855         traits=GetPixelChannelTraits(image,channel);
3856         if (traits == UndefinedPixelTrait)
3857           continue;
3858         q[i]=PlasmaPixel(random_info,(u[channel]+v[channel])/2.0,plasma);
3859       }
3860       (void) SyncCacheViewAuthenticPixels(image_view,exception);
3861     }
3862   if (((segment->x2-segment->x1) < 3.0) && ((segment->y2-segment->y1) < 3.0))
3863     return(MagickTrue);
3864   return(MagickFalse);
3865 }
3866
3867 MagickExport MagickBooleanType PlasmaImage(Image *image,
3868   const SegmentInfo *segment,size_t attenuate,size_t depth,
3869   ExceptionInfo *exception)
3870 {
3871   CacheView
3872     *image_view,
3873     *u_view,
3874     *v_view;
3875
3876   MagickBooleanType
3877     status;
3878
3879   RandomInfo
3880     *random_info;
3881
3882   if (image->debug != MagickFalse)
3883     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3884   assert(image != (Image *) NULL);
3885   assert(image->signature == MagickSignature);
3886   if (image->debug != MagickFalse)
3887     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3888   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
3889     return(MagickFalse);
3890   image_view=AcquireAuthenticCacheView(image,exception);
3891   u_view=AcquireVirtualCacheView(image,exception);
3892   v_view=AcquireVirtualCacheView(image,exception);
3893   random_info=AcquireRandomInfo();
3894   status=PlasmaImageProxy(image,image_view,u_view,v_view,random_info,segment,
3895     attenuate,depth,exception);
3896   random_info=DestroyRandomInfo(random_info);
3897   v_view=DestroyCacheView(v_view);
3898   u_view=DestroyCacheView(u_view);
3899   image_view=DestroyCacheView(image_view);
3900   return(status);
3901 }
3902 \f
3903 /*
3904 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3905 %                                                                             %
3906 %                                                                             %
3907 %                                                                             %
3908 %   P o l a r o i d I m a g e                                                 %
3909 %                                                                             %
3910 %                                                                             %
3911 %                                                                             %
3912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3913 %
3914 %  PolaroidImage() simulates a Polaroid picture.
3915 %
3916 %  The format of the AnnotateImage method is:
3917 %
3918 %      Image *PolaroidImage(const Image *image,const DrawInfo *draw_info,
3919 %        const char *caption,const double angle,
3920 %        const PixelInterpolateMethod method,ExceptionInfo exception)
3921 %
3922 %  A description of each parameter follows:
3923 %
3924 %    o image: the image.
3925 %
3926 %    o draw_info: the draw info.
3927 %
3928 %    o caption: the Polaroid caption.
3929 %
3930 %    o angle: Apply the effect along this angle.
3931 %
3932 %    o method: the pixel interpolation method.
3933 %
3934 %    o exception: return any errors or warnings in this structure.
3935 %
3936 */
3937 MagickExport Image *PolaroidImage(const Image *image,const DrawInfo *draw_info,
3938   const char *caption,const double angle,const PixelInterpolateMethod method,
3939   ExceptionInfo *exception)
3940 {
3941   Image
3942     *bend_image,
3943     *caption_image,
3944     *flop_image,
3945     *picture_image,
3946     *polaroid_image,
3947     *rotate_image,
3948     *trim_image;
3949
3950   size_t
3951     height;
3952
3953   ssize_t
3954     quantum;
3955
3956   /*
3957     Simulate a Polaroid picture.
3958   */
3959   assert(image != (Image *) NULL);
3960   assert(image->signature == MagickSignature);
3961   if (image->debug != MagickFalse)
3962     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3963   assert(exception != (ExceptionInfo *) NULL);
3964   assert(exception->signature == MagickSignature);
3965   quantum=(ssize_t) MagickMax(MagickMax((double) image->columns,(double)
3966     image->rows)/25.0,10.0);
3967   height=image->rows+2*quantum;
3968   caption_image=(Image *) NULL;
3969   if (caption != (const char *) NULL)
3970     {
3971       char
3972         geometry[MaxTextExtent],
3973         *text;
3974
3975       DrawInfo
3976         *annotate_info;
3977
3978       MagickBooleanType
3979         status;
3980
3981       ssize_t
3982         count;
3983
3984       TypeMetric
3985         metrics;
3986
3987       /*
3988         Generate caption image.
3989       */
3990       caption_image=CloneImage(image,image->columns,1,MagickTrue,exception);
3991       if (caption_image == (Image *) NULL)
3992         return((Image *) NULL);
3993       annotate_info=CloneDrawInfo((const ImageInfo *) NULL,draw_info);
3994       text=InterpretImageProperties((ImageInfo *) NULL,(Image *) image,caption,
3995         exception);
3996       (void) CloneString(&annotate_info->text,text);
3997       count=FormatMagickCaption(caption_image,annotate_info,MagickTrue,&metrics,
3998         &text,exception);
3999       status=SetImageExtent(caption_image,image->columns,(size_t) ((count+1)*
4000         (metrics.ascent-metrics.descent)+0.5),exception);
4001       if (status == MagickFalse)
4002         caption_image=DestroyImage(caption_image);
4003       else
4004         {
4005           caption_image->background_color=image->border_color;
4006           (void) SetImageBackgroundColor(caption_image,exception);
4007           (void) CloneString(&annotate_info->text,text);
4008           (void) FormatLocaleString(geometry,MaxTextExtent,"+0+%g",
4009             metrics.ascent);
4010           if (annotate_info->gravity == UndefinedGravity)
4011             (void) CloneString(&annotate_info->geometry,AcquireString(
4012               geometry));
4013           (void) AnnotateImage(caption_image,annotate_info,exception);
4014           height+=caption_image->rows;
4015         }
4016       annotate_info=DestroyDrawInfo(annotate_info);
4017       text=DestroyString(text);
4018     }
4019   picture_image=CloneImage(image,image->columns+2*quantum,height,MagickTrue,
4020     exception);
4021   if (picture_image == (Image *) NULL)
4022     {
4023       if (caption_image != (Image *) NULL)
4024         caption_image=DestroyImage(caption_image);
4025       return((Image *) NULL);
4026     }
4027   picture_image->background_color=image->border_color;
4028   (void) SetImageBackgroundColor(picture_image,exception);
4029   (void) CompositeImage(picture_image,image,OverCompositeOp,MagickTrue,quantum,
4030     quantum,exception);
4031   if (caption_image != (Image *) NULL)
4032     {
4033       (void) CompositeImage(picture_image,caption_image,OverCompositeOp,
4034         MagickTrue,quantum,(ssize_t) (image->rows+3*quantum/2),exception);
4035       caption_image=DestroyImage(caption_image);
4036     }
4037   (void) QueryColorCompliance("none",AllCompliance,
4038     &picture_image->background_color,exception);
4039   (void) SetImageAlphaChannel(picture_image,OpaqueAlphaChannel,exception);
4040   rotate_image=RotateImage(picture_image,90.0,exception);
4041   picture_image=DestroyImage(picture_image);
4042   if (rotate_image == (Image *) NULL)
4043     return((Image *) NULL);
4044   picture_image=rotate_image;
4045   bend_image=WaveImage(picture_image,0.01*picture_image->rows,2.0*
4046     picture_image->columns,method,exception);
4047   picture_image=DestroyImage(picture_image);
4048   if (bend_image == (Image *) NULL)
4049     return((Image *) NULL);
4050   picture_image=bend_image;
4051   rotate_image=RotateImage(picture_image,-90.0,exception);
4052   picture_image=DestroyImage(picture_image);
4053   if (rotate_image == (Image *) NULL)
4054     return((Image *) NULL);
4055   picture_image=rotate_image;
4056   picture_image->background_color=image->background_color;
4057   polaroid_image=ShadowImage(picture_image,80.0,2.0,quantum/3,quantum/3,
4058     exception);
4059   if (polaroid_image == (Image *) NULL)
4060     {
4061       picture_image=DestroyImage(picture_image);
4062       return(picture_image);
4063     }
4064   flop_image=FlopImage(polaroid_image,exception);
4065   polaroid_image=DestroyImage(polaroid_image);
4066   if (flop_image == (Image *) NULL)
4067     {
4068       picture_image=DestroyImage(picture_image);
4069       return(picture_image);
4070     }
4071   polaroid_image=flop_image;
4072   (void) CompositeImage(polaroid_image,picture_image,OverCompositeOp,
4073     MagickTrue,(ssize_t) (-0.01*picture_image->columns/2.0),0L,exception);
4074   picture_image=DestroyImage(picture_image);
4075   (void) QueryColorCompliance("none",AllCompliance,
4076     &polaroid_image->background_color,exception);
4077   rotate_image=RotateImage(polaroid_image,angle,exception);
4078   polaroid_image=DestroyImage(polaroid_image);
4079   if (rotate_image == (Image *) NULL)
4080     return((Image *) NULL);
4081   polaroid_image=rotate_image;
4082   trim_image=TrimImage(polaroid_image,exception);
4083   polaroid_image=DestroyImage(polaroid_image);
4084   if (trim_image == (Image *) NULL)
4085     return((Image *) NULL);
4086   polaroid_image=trim_image;
4087   return(polaroid_image);
4088 }
4089 \f
4090 /*
4091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4092 %                                                                             %
4093 %                                                                             %
4094 %                                                                             %
4095 %     S e p i a T o n e I m a g e                                             %
4096 %                                                                             %
4097 %                                                                             %
4098 %                                                                             %
4099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4100 %
4101 %  MagickSepiaToneImage() applies a special effect to the image, similar to the
4102 %  effect achieved in a photo darkroom by sepia toning.  Threshold ranges from
4103 %  0 to QuantumRange and is a measure of the extent of the sepia toning.  A
4104 %  threshold of 80% is a good starting point for a reasonable tone.
4105 %
4106 %  The format of the SepiaToneImage method is:
4107 %
4108 %      Image *SepiaToneImage(const Image *image,const double threshold,
4109 %        ExceptionInfo *exception)
4110 %
4111 %  A description of each parameter follows:
4112 %
4113 %    o image: the image.
4114 %
4115 %    o threshold: the tone threshold.
4116 %
4117 %    o exception: return any errors or warnings in this structure.
4118 %
4119 */
4120 MagickExport Image *SepiaToneImage(const Image *image,const double threshold,
4121   ExceptionInfo *exception)
4122 {
4123 #define SepiaToneImageTag  "SepiaTone/Image"
4124
4125   CacheView
4126     *image_view,
4127     *sepia_view;
4128
4129   Image
4130     *sepia_image;
4131
4132   MagickBooleanType
4133     status;
4134
4135   MagickOffsetType
4136     progress;
4137
4138   ssize_t
4139     y;
4140
4141   /*
4142     Initialize sepia-toned image attributes.
4143   */
4144   assert(image != (const Image *) NULL);
4145   assert(image->signature == MagickSignature);
4146   if (image->debug != MagickFalse)
4147     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4148   assert(exception != (ExceptionInfo *) NULL);
4149   assert(exception->signature == MagickSignature);
4150   sepia_image=CloneImage(image,0,0,MagickTrue,exception);
4151   if (sepia_image == (Image *) NULL)
4152     return((Image *) NULL);
4153   if (SetImageStorageClass(sepia_image,DirectClass,exception) == MagickFalse)
4154     {
4155       sepia_image=DestroyImage(sepia_image);
4156       return((Image *) NULL);
4157     }
4158   /*
4159     Tone each row of the image.
4160   */
4161   status=MagickTrue;
4162   progress=0;
4163   image_view=AcquireVirtualCacheView(image,exception);
4164   sepia_view=AcquireAuthenticCacheView(sepia_image,exception);
4165 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4166   #pragma omp parallel for schedule(static,4) shared(progress,status) \
4167     dynamic_number_threads(image,image->columns,image->rows,1)
4168 #endif
4169   for (y=0; y < (ssize_t) image->rows; y++)
4170   {
4171     register const Quantum
4172       *restrict p;
4173
4174     register ssize_t
4175       x;
4176
4177     register Quantum
4178       *restrict q;
4179
4180     if (status == MagickFalse)
4181       continue;
4182     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
4183     q=GetCacheViewAuthenticPixels(sepia_view,0,y,sepia_image->columns,1,
4184       exception);
4185     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
4186       {
4187         status=MagickFalse;
4188         continue;
4189       }
4190     for (x=0; x < (ssize_t) image->columns; x++)
4191     {
4192       double
4193         intensity,
4194         tone;
4195
4196       intensity=GetPixelIntensity(image,p);
4197       tone=intensity > threshold ? (double) QuantumRange : intensity+
4198         (double) QuantumRange-threshold;
4199       SetPixelRed(sepia_image,ClampToQuantum(tone),q);
4200       tone=intensity > (7.0*threshold/6.0) ? (double) QuantumRange :
4201         intensity+(double) QuantumRange-7.0*threshold/6.0;
4202       SetPixelGreen(sepia_image,ClampToQuantum(tone),q);
4203       tone=intensity < (threshold/6.0) ? 0 : intensity-threshold/6.0;
4204       SetPixelBlue(sepia_image,ClampToQuantum(tone),q);
4205       tone=threshold/7.0;
4206       if ((double) GetPixelGreen(image,q) < tone)
4207         SetPixelGreen(sepia_image,ClampToQuantum(tone),q);
4208       if ((double) GetPixelBlue(image,q) < tone)
4209         SetPixelBlue(sepia_image,ClampToQuantum(tone),q);
4210       p+=GetPixelChannels(image);
4211       q+=GetPixelChannels(sepia_image);
4212     }
4213     if (SyncCacheViewAuthenticPixels(sepia_view,exception) == MagickFalse)
4214       status=MagickFalse;
4215     if (image->progress_monitor != (MagickProgressMonitor) NULL)
4216       {
4217         MagickBooleanType
4218           proceed;
4219
4220 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4221         #pragma omp critical (MagickCore_SepiaToneImage)
4222 #endif
4223         proceed=SetImageProgress(image,SepiaToneImageTag,progress++,
4224           image->rows);
4225         if (proceed == MagickFalse)
4226           status=MagickFalse;
4227       }
4228   }
4229   sepia_view=DestroyCacheView(sepia_view);
4230   image_view=DestroyCacheView(image_view);
4231   (void) NormalizeImage(sepia_image,exception);
4232   (void) ContrastImage(sepia_image,MagickTrue,exception);
4233   if (status == MagickFalse)
4234     sepia_image=DestroyImage(sepia_image);
4235   return(sepia_image);
4236 }
4237 \f
4238 /*
4239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4240 %                                                                             %
4241 %                                                                             %
4242 %                                                                             %
4243 %     S h a d o w I m a g e                                                   %
4244 %                                                                             %
4245 %                                                                             %
4246 %                                                                             %
4247 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4248 %
4249 %  ShadowImage() simulates a shadow from the specified image and returns it.
4250 %
4251 %  The format of the ShadowImage method is:
4252 %
4253 %      Image *ShadowImage(const Image *image,const double alpha,
4254 %        const double sigma,const ssize_t x_offset,const ssize_t y_offset,
4255 %        ExceptionInfo *exception)
4256 %
4257 %  A description of each parameter follows:
4258 %
4259 %    o image: the image.
4260 %
4261 %    o alpha: percentage transparency.
4262 %
4263 %    o sigma: the standard deviation of the Gaussian, in pixels.
4264 %
4265 %    o x_offset: the shadow x-offset.
4266 %
4267 %    o y_offset: the shadow y-offset.
4268 %
4269 %    o exception: return any errors or warnings in this structure.
4270 %
4271 */
4272 MagickExport Image *ShadowImage(const Image *image,const double alpha,
4273   const double sigma,const ssize_t x_offset,const ssize_t y_offset,
4274   ExceptionInfo *exception)
4275 {
4276 #define ShadowImageTag  "Shadow/Image"
4277
4278   CacheView
4279     *image_view;
4280
4281   ChannelType
4282     channel_mask;
4283
4284   Image
4285     *border_image,
4286     *clone_image,
4287     *shadow_image;
4288
4289   MagickBooleanType
4290     status;
4291
4292   RectangleInfo
4293     border_info;
4294
4295   ssize_t
4296     y;
4297
4298   assert(image != (Image *) NULL);
4299   assert(image->signature == MagickSignature);
4300   if (image->debug != MagickFalse)
4301     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4302   assert(exception != (ExceptionInfo *) NULL);
4303   assert(exception->signature == MagickSignature);
4304   clone_image=CloneImage(image,0,0,MagickTrue,exception);
4305   if (clone_image == (Image *) NULL)
4306     return((Image *) NULL);
4307   if (IsGrayColorspace(image->colorspace) != MagickFalse)
4308     (void) TransformImageColorspace(clone_image,RGBColorspace,exception);
4309   (void) SetImageVirtualPixelMethod(clone_image,TransparentVirtualPixelMethod,
4310     exception);
4311   border_info.width=(size_t) floor(2.0*sigma+0.5);
4312   border_info.height=(size_t) floor(2.0*sigma+0.5);
4313   border_info.x=0;
4314   border_info.y=0;
4315   (void) QueryColorCompliance("none",AllCompliance,&clone_image->border_color,
4316     exception);
4317   clone_image->alpha_trait=BlendPixelTrait;
4318   border_image=BorderImage(clone_image,&border_info,OverCompositeOp,exception);
4319   clone_image=DestroyImage(clone_image);
4320   if (border_image == (Image *) NULL)
4321     return((Image *) NULL);
4322   if (border_image->alpha_trait != BlendPixelTrait)
4323     (void) SetImageAlphaChannel(border_image,OpaqueAlphaChannel,exception);
4324   /*
4325     Shadow image.
4326   */
4327   status=MagickTrue;
4328   image_view=AcquireAuthenticCacheView(border_image,exception);
4329   for (y=0; y < (ssize_t) border_image->rows; y++)
4330   {
4331     PixelInfo
4332       background_color;
4333
4334     register Quantum
4335       *restrict q;
4336
4337     register ssize_t
4338       x;
4339
4340     if (status == MagickFalse)
4341       continue;
4342     q=QueueCacheViewAuthenticPixels(image_view,0,y,border_image->columns,1,
4343       exception);
4344     if (q == (Quantum *) NULL)
4345       {
4346         status=MagickFalse;
4347         continue;
4348       }
4349     background_color=border_image->background_color;
4350     background_color.alpha_trait=BlendPixelTrait;
4351     for (x=0; x < (ssize_t) border_image->columns; x++)
4352     {
4353       if (border_image->alpha_trait == BlendPixelTrait)
4354         background_color.alpha=GetPixelAlpha(border_image,q)*alpha/100.0;
4355       SetPixelInfoPixel(border_image,&background_color,q);
4356       q+=GetPixelChannels(border_image);
4357     }
4358     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4359       status=MagickFalse;
4360   }
4361   image_view=DestroyCacheView(image_view);
4362   if (status == MagickFalse)
4363     {
4364       border_image=DestroyImage(border_image);
4365       return((Image *) NULL);
4366     }
4367   channel_mask=SetImageChannelMask(border_image,AlphaChannel);
4368   shadow_image=BlurImage(border_image,0.0,sigma,exception);
4369   border_image=DestroyImage(border_image);
4370   if (shadow_image == (Image *) NULL)
4371     return((Image *) NULL);
4372   (void) SetPixelChannelMask(shadow_image,channel_mask);
4373   if (shadow_image->page.width == 0)
4374     shadow_image->page.width=shadow_image->columns;
4375   if (shadow_image->page.height == 0)
4376     shadow_image->page.height=shadow_image->rows;
4377   shadow_image->page.width+=x_offset-(ssize_t) border_info.width;
4378   shadow_image->page.height+=y_offset-(ssize_t) border_info.height;
4379   shadow_image->page.x+=x_offset-(ssize_t) border_info.width;
4380   shadow_image->page.y+=y_offset-(ssize_t) border_info.height;
4381   return(shadow_image);
4382 }
4383 \f
4384 /*
4385 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4386 %                                                                             %
4387 %                                                                             %
4388 %                                                                             %
4389 %     S k e t c h I m a g e                                                   %
4390 %                                                                             %
4391 %                                                                             %
4392 %                                                                             %
4393 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4394 %
4395 %  SketchImage() simulates a pencil sketch.  We convolve the image with a
4396 %  Gaussian operator of the given radius and standard deviation (sigma).  For
4397 %  reasonable results, radius should be larger than sigma.  Use a radius of 0
4398 %  and SketchImage() selects a suitable radius for you.  Angle gives the angle
4399 %  of the sketch.
4400 %
4401 %  The format of the SketchImage method is:
4402 %
4403 %    Image *SketchImage(const Image *image,const double radius,
4404 %      const double sigma,const double angle,ExceptionInfo *exception)
4405 %
4406 %  A description of each parameter follows:
4407 %
4408 %    o image: the image.
4409 %
4410 %    o radius: the radius of the Gaussian, in pixels, not counting the
4411 %      center pixel.
4412 %
4413 %    o sigma: the standard deviation of the Gaussian, in pixels.
4414 %
4415 %    o angle: apply the effect along this angle.
4416 %
4417 %    o exception: return any errors or warnings in this structure.
4418 %
4419 */
4420 MagickExport Image *SketchImage(const Image *image,const double radius,
4421   const double sigma,const double angle,ExceptionInfo *exception)
4422 {
4423   CacheView
4424     *random_view;
4425
4426   Image
4427     *blend_image,
4428     *blur_image,
4429     *dodge_image,
4430     *random_image,
4431     *sketch_image;
4432
4433   MagickBooleanType
4434     status;
4435
4436   RandomInfo
4437     **restrict random_info;
4438
4439   ssize_t
4440     y;
4441
4442 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4443   unsigned long
4444     key;
4445 #endif
4446
4447   /*
4448     Sketch image.
4449   */
4450   random_image=CloneImage(image,image->columns << 1,image->rows << 1,
4451     MagickTrue,exception);
4452   if (random_image == (Image *) NULL)
4453     return((Image *) NULL);
4454   status=MagickTrue;
4455   random_info=AcquireRandomInfoThreadSet();
4456 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4457   key=GetRandomSecretKey(random_info[0]);
4458 #endif
4459   random_view=AcquireAuthenticCacheView(random_image,exception);
4460 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4461   #pragma omp parallel for schedule(static,4) shared(status) \
4462     dynamic_number_threads(image,image->columns,image->rows,key == ~0UL)
4463 #endif
4464   for (y=0; y < (ssize_t) random_image->rows; y++)
4465   {
4466     const int
4467       id = GetOpenMPThreadId();
4468
4469     register ssize_t
4470       x;
4471
4472     register Quantum
4473       *restrict q;
4474
4475     if (status == MagickFalse)
4476       continue;
4477     q=QueueCacheViewAuthenticPixels(random_view,0,y,random_image->columns,1,
4478       exception);
4479     if (q == (Quantum *) NULL)
4480       {
4481         status=MagickFalse;
4482         continue;
4483       }
4484     for (x=0; x < (ssize_t) random_image->columns; x++)
4485     {
4486       double
4487         value;
4488
4489       register ssize_t
4490         i;
4491
4492       if (GetPixelMask(random_image,q) != 0)
4493         {
4494           q+=GetPixelChannels(random_image);
4495           continue;
4496         }
4497       value=GetPseudoRandomValue(random_info[id]);
4498       for (i=0; i < (ssize_t) GetPixelChannels(random_image); i++)
4499       {
4500         PixelChannel
4501           channel;
4502
4503         PixelTrait
4504           traits;
4505
4506         channel=GetPixelChannelChannel(image,i);
4507         traits=GetPixelChannelTraits(image,channel);
4508         if (traits == UndefinedPixelTrait)
4509           continue;
4510         q[i]=ClampToQuantum(QuantumRange*value);
4511       }
4512       q+=GetPixelChannels(random_image);
4513     }
4514     if (SyncCacheViewAuthenticPixels(random_view,exception) == MagickFalse)
4515       status=MagickFalse;
4516   }
4517   random_view=DestroyCacheView(random_view);
4518   random_info=DestroyRandomInfoThreadSet(random_info);
4519   if (status == MagickFalse)
4520     {
4521       random_image=DestroyImage(random_image);
4522       return(random_image);
4523     }
4524   blur_image=MotionBlurImage(random_image,radius,sigma,angle,exception);
4525   random_image=DestroyImage(random_image);
4526   if (blur_image == (Image *) NULL)
4527     return((Image *) NULL);
4528   dodge_image=EdgeImage(blur_image,radius,1.0,exception);
4529   blur_image=DestroyImage(blur_image);
4530   if (dodge_image == (Image *) NULL)
4531     return((Image *) NULL);
4532   (void) NormalizeImage(dodge_image,exception);
4533   (void) NegateImage(dodge_image,MagickFalse,exception);
4534   (void) TransformImage(&dodge_image,(char *) NULL,"50%",exception);
4535   sketch_image=CloneImage(image,0,0,MagickTrue,exception);
4536   if (sketch_image == (Image *) NULL)
4537     {
4538       dodge_image=DestroyImage(dodge_image);
4539       return((Image *) NULL);
4540     }
4541   (void) CompositeImage(sketch_image,dodge_image,ColorDodgeCompositeOp,
4542     MagickTrue,0,0,exception);
4543   dodge_image=DestroyImage(dodge_image);
4544   blend_image=CloneImage(image,0,0,MagickTrue,exception);
4545   if (blend_image == (Image *) NULL)
4546     {
4547       sketch_image=DestroyImage(sketch_image);
4548       return((Image *) NULL);
4549     }
4550   (void) SetImageArtifact(blend_image,"compose:args","20x80");
4551   (void) CompositeImage(sketch_image,blend_image,BlendCompositeOp,MagickTrue,
4552     0,0,exception);
4553   blend_image=DestroyImage(blend_image);
4554   return(sketch_image);
4555 }
4556 \f
4557 /*
4558 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4559 %                                                                             %
4560 %                                                                             %
4561 %                                                                             %
4562 %     S o l a r i z e I m a g e                                               %
4563 %                                                                             %
4564 %                                                                             %
4565 %                                                                             %
4566 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4567 %
4568 %  SolarizeImage() applies a special effect to the image, similar to the effect
4569 %  achieved in a photo darkroom by selectively exposing areas of photo
4570 %  sensitive paper to light.  Threshold ranges from 0 to QuantumRange and is a
4571 %  measure of the extent of the solarization.
4572 %
4573 %  The format of the SolarizeImage method is:
4574 %
4575 %      MagickBooleanType SolarizeImage(Image *image,const double threshold,
4576 %        ExceptionInfo *exception)
4577 %
4578 %  A description of each parameter follows:
4579 %
4580 %    o image: the image.
4581 %
4582 %    o threshold:  Define the extent of the solarization.
4583 %
4584 %    o exception: return any errors or warnings in this structure.
4585 %
4586 */
4587 MagickExport MagickBooleanType SolarizeImage(Image *image,
4588   const double threshold,ExceptionInfo *exception)
4589 {
4590 #define SolarizeImageTag  "Solarize/Image"
4591
4592   CacheView
4593     *image_view;
4594
4595   MagickBooleanType
4596     status;
4597
4598   MagickOffsetType
4599     progress;
4600
4601   ssize_t
4602     y;
4603
4604   assert(image != (Image *) NULL);
4605   assert(image->signature == MagickSignature);
4606   if (image->debug != MagickFalse)
4607     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4608   if (image->storage_class == PseudoClass)
4609     {
4610       register ssize_t
4611         i;
4612
4613       /*
4614         Solarize colormap.
4615       */
4616       for (i=0; i < (ssize_t) image->colors; i++)
4617       {
4618         if ((double) image->colormap[i].red > threshold)
4619           image->colormap[i].red=QuantumRange-image->colormap[i].red;
4620         if ((double) image->colormap[i].green > threshold)
4621           image->colormap[i].green=QuantumRange-
4622             image->colormap[i].green;
4623         if ((double) image->colormap[i].blue > threshold)
4624           image->colormap[i].blue=QuantumRange-
4625             image->colormap[i].blue;
4626       }
4627     }
4628   /*
4629     Solarize image.
4630   */
4631   status=MagickTrue;
4632   progress=0;
4633   image_view=AcquireAuthenticCacheView(image,exception);
4634 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4635   #pragma omp parallel for schedule(static,4) shared(progress,status) \
4636     dynamic_number_threads(image,image->columns,image->rows,1)
4637 #endif
4638   for (y=0; y < (ssize_t) image->rows; y++)
4639   {
4640     register ssize_t
4641       x;
4642
4643     register Quantum
4644       *restrict q;
4645
4646     if (status == MagickFalse)
4647       continue;
4648     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4649     if (q == (Quantum *) NULL)
4650       {
4651         status=MagickFalse;
4652         continue;
4653       }
4654     for (x=0; x < (ssize_t) image->columns; x++)
4655     {
4656       register ssize_t
4657         i;
4658
4659       if (GetPixelMask(image,q) != 0)
4660         {
4661           q+=GetPixelChannels(image);
4662           continue;
4663         }
4664       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4665       {
4666         PixelChannel
4667           channel;
4668
4669         PixelTrait
4670           traits;
4671
4672         channel=GetPixelChannelChannel(image,i);
4673         traits=GetPixelChannelTraits(image,channel);
4674         if ((traits == UndefinedPixelTrait) ||
4675             ((traits & CopyPixelTrait) != 0))
4676           continue;
4677         if ((double) q[i] > threshold)
4678           q[i]=QuantumRange-q[i];
4679       }
4680       q+=GetPixelChannels(image);
4681     }
4682     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4683       status=MagickFalse;
4684     if (image->progress_monitor != (MagickProgressMonitor) NULL)
4685       {
4686         MagickBooleanType
4687           proceed;
4688
4689 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4690         #pragma omp critical (MagickCore_SolarizeImage)
4691 #endif
4692         proceed=SetImageProgress(image,SolarizeImageTag,progress++,image->rows);
4693         if (proceed == MagickFalse)
4694           status=MagickFalse;
4695       }
4696   }
4697   image_view=DestroyCacheView(image_view);
4698   return(status);
4699 }
4700 \f
4701 /*
4702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4703 %                                                                             %
4704 %                                                                             %
4705 %                                                                             %
4706 %   S t e g a n o I m a g e                                                   %
4707 %                                                                             %
4708 %                                                                             %
4709 %                                                                             %
4710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4711 %
4712 %  SteganoImage() hides a digital watermark within the image.  Recover
4713 %  the hidden watermark later to prove that the authenticity of an image.
4714 %  Offset defines the start position within the image to hide the watermark.
4715 %
4716 %  The format of the SteganoImage method is:
4717 %
4718 %      Image *SteganoImage(const Image *image,Image *watermark,
4719 %        ExceptionInfo *exception)
4720 %
4721 %  A description of each parameter follows:
4722 %
4723 %    o image: the image.
4724 %
4725 %    o watermark: the watermark image.
4726 %
4727 %    o exception: return any errors or warnings in this structure.
4728 %
4729 */
4730 MagickExport Image *SteganoImage(const Image *image,const Image *watermark,
4731   ExceptionInfo *exception)
4732 {
4733 #define GetBit(alpha,i) ((((size_t) (alpha) >> (size_t) (i)) & 0x01) != 0)
4734 #define SetBit(alpha,i,set) (Quantum) ((set) != 0 ? (size_t) (alpha) \
4735   | (one << (size_t) (i)) : (size_t) (alpha) & ~(one << (size_t) (i)))
4736 #define SteganoImageTag  "Stegano/Image"
4737
4738   CacheView
4739     *stegano_view,
4740     *watermark_view;
4741
4742   Image
4743     *stegano_image;
4744
4745   int
4746     c;
4747
4748   MagickBooleanType
4749     status;
4750
4751   PixelInfo
4752     pixel;
4753
4754   register Quantum
4755     *q;
4756
4757   register ssize_t
4758     x;
4759
4760   size_t
4761     depth,
4762     one;
4763
4764   ssize_t
4765     i,
4766     j,
4767     k,
4768     y;
4769
4770   /*
4771     Initialize steganographic image attributes.
4772   */
4773   assert(image != (const Image *) NULL);
4774   assert(image->signature == MagickSignature);
4775   if (image->debug != MagickFalse)
4776     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4777   assert(watermark != (const Image *) NULL);
4778   assert(watermark->signature == MagickSignature);
4779   assert(exception != (ExceptionInfo *) NULL);
4780   assert(exception->signature == MagickSignature);
4781   one=1UL;
4782   stegano_image=CloneImage(image,0,0,MagickTrue,exception);
4783   if (stegano_image == (Image *) NULL)
4784     return((Image *) NULL);
4785   stegano_image->depth=MAGICKCORE_QUANTUM_DEPTH;
4786   if (SetImageStorageClass(stegano_image,DirectClass,exception) == MagickFalse)
4787     {
4788       stegano_image=DestroyImage(stegano_image);
4789       return((Image *) NULL);
4790     }
4791   /*
4792     Hide watermark in low-order bits of image.
4793   */
4794   c=0;
4795   i=0;
4796   j=0;
4797   depth=stegano_image->depth;
4798   k=stegano_image->offset;
4799   status=MagickTrue;
4800   watermark_view=AcquireVirtualCacheView(watermark,exception);
4801   stegano_view=AcquireAuthenticCacheView(stegano_image,exception);
4802   for (i=(ssize_t) depth-1; (i >= 0) && (j < (ssize_t) depth); i--)
4803   {
4804     for (y=0; (y < (ssize_t) watermark->rows) && (j < (ssize_t) depth); y++)
4805     {
4806       for (x=0; (x < (ssize_t) watermark->columns) && (j < (ssize_t) depth); x++)
4807       {
4808         ssize_t
4809           offset;
4810
4811         (void) GetOneCacheViewVirtualPixelInfo(watermark_view,x,y,&pixel,
4812           exception);
4813         offset=k/(ssize_t) stegano_image->columns;
4814         if (offset >= (ssize_t) stegano_image->rows)
4815           break;
4816         q=GetCacheViewAuthenticPixels(stegano_view,k % (ssize_t)
4817           stegano_image->columns,k/(ssize_t) stegano_image->columns,1,1,
4818           exception);
4819         if (q == (Quantum *) NULL)
4820           break;
4821         switch (c)
4822         {
4823           case 0:
4824           {
4825             SetPixelRed(stegano_image,SetBit(GetPixelRed(stegano_image,q),j,
4826               GetBit(GetPixelInfoIntensity(&pixel),i)),q);
4827             break;
4828           }
4829           case 1:
4830           {
4831             SetPixelGreen(stegano_image,SetBit(GetPixelGreen(stegano_image,q),j,
4832               GetBit(GetPixelInfoIntensity(&pixel),i)),q);
4833             break;
4834           }
4835           case 2:
4836           {
4837             SetPixelBlue(stegano_image,SetBit(GetPixelBlue(stegano_image,q),j,
4838               GetBit(GetPixelInfoIntensity(&pixel),i)),q);
4839             break;
4840           }
4841         }
4842         if (SyncCacheViewAuthenticPixels(stegano_view,exception) == MagickFalse)
4843           break;
4844         c++;
4845         if (c == 3)
4846           c=0;
4847         k++;
4848         if (k == (ssize_t) (stegano_image->columns*stegano_image->columns))
4849           k=0;
4850         if (k == stegano_image->offset)
4851           j++;
4852       }
4853     }
4854     if (image->progress_monitor != (MagickProgressMonitor) NULL)
4855       {
4856         MagickBooleanType
4857           proceed;
4858
4859         proceed=SetImageProgress(image,SteganoImageTag,(MagickOffsetType)
4860           (depth-i),depth);
4861         if (proceed == MagickFalse)
4862           status=MagickFalse;
4863       }
4864   }
4865   stegano_view=DestroyCacheView(stegano_view);
4866   watermark_view=DestroyCacheView(watermark_view);
4867   if (status == MagickFalse)
4868     {
4869       stegano_image=DestroyImage(stegano_image);
4870       return((Image *) NULL);
4871     }
4872   return(stegano_image);
4873 }
4874 \f
4875 /*
4876 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4877 %                                                                             %
4878 %                                                                             %
4879 %                                                                             %
4880 %   S t e r e o A n a g l y p h I m a g e                                     %
4881 %                                                                             %
4882 %                                                                             %
4883 %                                                                             %
4884 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4885 %
4886 %  StereoAnaglyphImage() combines two images and produces a single image that
4887 %  is the composite of a left and right image of a stereo pair.  Special
4888 %  red-green stereo glasses are required to view this effect.
4889 %
4890 %  The format of the StereoAnaglyphImage method is:
4891 %
4892 %      Image *StereoImage(const Image *left_image,const Image *right_image,
4893 %        ExceptionInfo *exception)
4894 %      Image *StereoAnaglyphImage(const Image *left_image,
4895 %        const Image *right_image,const ssize_t x_offset,const ssize_t y_offset,
4896 %        ExceptionInfo *exception)
4897 %
4898 %  A description of each parameter follows:
4899 %
4900 %    o left_image: the left image.
4901 %
4902 %    o right_image: the right image.
4903 %
4904 %    o exception: return any errors or warnings in this structure.
4905 %
4906 %    o x_offset: amount, in pixels, by which the left image is offset to the
4907 %      right of the right image.
4908 %
4909 %    o y_offset: amount, in pixels, by which the left image is offset to the
4910 %      bottom of the right image.
4911 %
4912 %
4913 */
4914 MagickExport Image *StereoImage(const Image *left_image,
4915   const Image *right_image,ExceptionInfo *exception)
4916 {
4917   return(StereoAnaglyphImage(left_image,right_image,0,0,exception));
4918 }
4919
4920 MagickExport Image *StereoAnaglyphImage(const Image *left_image,
4921   const Image *right_image,const ssize_t x_offset,const ssize_t y_offset,
4922   ExceptionInfo *exception)
4923 {
4924 #define StereoImageTag  "Stereo/Image"
4925
4926   const Image
4927     *image;
4928
4929   Image
4930     *stereo_image;
4931
4932   MagickBooleanType
4933     status;
4934
4935   ssize_t
4936     y;
4937
4938   assert(left_image != (const Image *) NULL);
4939   assert(left_image->signature == MagickSignature);
4940   if (left_image->debug != MagickFalse)
4941     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4942       left_image->filename);
4943   assert(right_image != (const Image *) NULL);
4944   assert(right_image->signature == MagickSignature);
4945   assert(exception != (ExceptionInfo *) NULL);
4946   assert(exception->signature == MagickSignature);
4947   assert(right_image != (const Image *) NULL);
4948   image=left_image;
4949   if ((left_image->columns != right_image->columns) ||
4950       (left_image->rows != right_image->rows))
4951     ThrowImageException(ImageError,"LeftAndRightImageSizesDiffer");
4952   /*
4953     Initialize stereo image attributes.
4954   */
4955   stereo_image=CloneImage(left_image,left_image->columns,left_image->rows,
4956     MagickTrue,exception);
4957   if (stereo_image == (Image *) NULL)
4958     return((Image *) NULL);
4959   if (SetImageStorageClass(stereo_image,DirectClass,exception) == MagickFalse)
4960     {
4961       stereo_image=DestroyImage(stereo_image);
4962       return((Image *) NULL);
4963     }
4964   (void) SetImageColorspace(stereo_image,sRGBColorspace,exception);
4965   /*
4966     Copy left image to red channel and right image to blue channel.
4967   */
4968   status=MagickTrue;
4969   for (y=0; y < (ssize_t) stereo_image->rows; y++)
4970   {
4971     register const Quantum
4972       *restrict p,
4973       *restrict q;
4974
4975     register ssize_t
4976       x;
4977
4978     register Quantum
4979       *restrict r;
4980
4981     p=GetVirtualPixels(left_image,-x_offset,y-y_offset,image->columns,1,
4982       exception);
4983     q=GetVirtualPixels(right_image,0,y,right_image->columns,1,exception);
4984     r=QueueAuthenticPixels(stereo_image,0,y,stereo_image->columns,1,exception);
4985     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL) ||
4986         (r == (Quantum *) NULL))
4987       break;
4988     for (x=0; x < (ssize_t) stereo_image->columns; x++)
4989     {
4990       SetPixelRed(image,GetPixelRed(left_image,p),r);
4991       SetPixelGreen(image,GetPixelGreen(right_image,q),r);
4992       SetPixelBlue(image,GetPixelBlue(right_image,q),r);
4993       if ((GetPixelAlphaTraits(stereo_image) & CopyPixelTrait) != 0)
4994         SetPixelAlpha(image,(GetPixelAlpha(left_image,p)+
4995           GetPixelAlpha(right_image,q))/2,r);
4996       p+=GetPixelChannels(left_image);
4997       q+=GetPixelChannels(right_image);
4998       r+=GetPixelChannels(stereo_image);
4999     }
5000     if (SyncAuthenticPixels(stereo_image,exception) == MagickFalse)
5001       break;
5002     if (image->progress_monitor != (MagickProgressMonitor) NULL)
5003       {
5004         MagickBooleanType
5005           proceed;
5006
5007         proceed=SetImageProgress(image,StereoImageTag,(MagickOffsetType) y,
5008           stereo_image->rows);
5009         if (proceed == MagickFalse)
5010           status=MagickFalse;
5011       }
5012   }
5013   if (status == MagickFalse)
5014     {
5015       stereo_image=DestroyImage(stereo_image);
5016       return((Image *) NULL);
5017     }
5018   return(stereo_image);
5019 }
5020 \f
5021 /*
5022 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5023 %                                                                             %
5024 %                                                                             %
5025 %                                                                             %
5026 %     S w i r l I m a g e                                                     %
5027 %                                                                             %
5028 %                                                                             %
5029 %                                                                             %
5030 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5031 %
5032 %  SwirlImage() swirls the pixels about the center of the image, where
5033 %  degrees indicates the sweep of the arc through which each pixel is moved.
5034 %  You get a more dramatic effect as the degrees move from 1 to 360.
5035 %
5036 %  The format of the SwirlImage method is:
5037 %
5038 %      Image *SwirlImage(const Image *image,double degrees,
5039 %        const PixelInterpolateMethod method,ExceptionInfo *exception)
5040 %
5041 %  A description of each parameter follows:
5042 %
5043 %    o image: the image.
5044 %
5045 %    o degrees: Define the tightness of the swirling effect.
5046 %
5047 %    o method: the pixel interpolation method.
5048 %
5049 %    o exception: return any errors or warnings in this structure.
5050 %
5051 */
5052 MagickExport Image *SwirlImage(const Image *image,double degrees,
5053   const PixelInterpolateMethod method,ExceptionInfo *exception)
5054 {
5055 #define SwirlImageTag  "Swirl/Image"
5056
5057   CacheView
5058     *image_view,
5059     *swirl_view;
5060
5061   Image
5062     *swirl_image;
5063
5064   MagickBooleanType
5065     status;
5066
5067   MagickOffsetType
5068     progress;
5069
5070   double
5071     radius;
5072
5073   PointInfo
5074     center,
5075     scale;
5076
5077   ssize_t
5078     y;
5079
5080   /*
5081     Initialize swirl image attributes.
5082   */
5083   assert(image != (const Image *) NULL);
5084   assert(image->signature == MagickSignature);
5085   if (image->debug != MagickFalse)
5086     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5087   assert(exception != (ExceptionInfo *) NULL);
5088   assert(exception->signature == MagickSignature);
5089   swirl_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
5090   if (swirl_image == (Image *) NULL)
5091     return((Image *) NULL);
5092   if (SetImageStorageClass(swirl_image,DirectClass,exception) == MagickFalse)
5093     {
5094       swirl_image=DestroyImage(swirl_image);
5095       return((Image *) NULL);
5096     }
5097   if (swirl_image->background_color.alpha != OpaqueAlpha)
5098     swirl_image->alpha_trait=BlendPixelTrait;
5099   /*
5100     Compute scaling factor.
5101   */
5102   center.x=(double) image->columns/2.0;
5103   center.y=(double) image->rows/2.0;
5104   radius=MagickMax(center.x,center.y);
5105   scale.x=1.0;
5106   scale.y=1.0;
5107   if (image->columns > image->rows)
5108     scale.y=(double) image->columns/(double) image->rows;
5109   else
5110     if (image->columns < image->rows)
5111       scale.x=(double) image->rows/(double) image->columns;
5112   degrees=(double) DegreesToRadians(degrees);
5113   /*
5114     Swirl image.
5115   */
5116   status=MagickTrue;
5117   progress=0;
5118   image_view=AcquireVirtualCacheView(image,exception);
5119   swirl_view=AcquireAuthenticCacheView(swirl_image,exception);
5120 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5121   #pragma omp parallel for schedule(static,4) shared(progress,status) \
5122     dynamic_number_threads(image,image->columns,image->rows,1)
5123 #endif
5124   for (y=0; y < (ssize_t) image->rows; y++)
5125   {
5126     double
5127       distance;
5128
5129     PointInfo
5130       delta;
5131
5132     register const Quantum
5133       *restrict p;
5134
5135     register ssize_t
5136       x;
5137
5138     register Quantum
5139       *restrict q;
5140
5141     if (status == MagickFalse)
5142       continue;
5143     p=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
5144     q=QueueCacheViewAuthenticPixels(swirl_view,0,y,swirl_image->columns,1,
5145       exception);
5146     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
5147       {
5148         status=MagickFalse;
5149         continue;
5150       }
5151     delta.y=scale.y*(double) (y-center.y);
5152     for (x=0; x < (ssize_t) image->columns; x++)
5153     {
5154       /*
5155         Determine if the pixel is within an ellipse.
5156       */
5157       if (GetPixelMask(image,p) != 0)
5158         {
5159           p+=GetPixelChannels(image);
5160           q+=GetPixelChannels(swirl_image);
5161           continue;
5162         }
5163       delta.x=scale.x*(double) (x-center.x);
5164       distance=delta.x*delta.x+delta.y*delta.y;
5165       if (distance >= (radius*radius))
5166         {
5167           register ssize_t
5168             i;
5169
5170           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
5171           {
5172             PixelChannel
5173               channel;
5174
5175             PixelTrait
5176               swirl_traits,
5177               traits;
5178
5179             channel=GetPixelChannelChannel(image,i);
5180             traits=GetPixelChannelTraits(image,channel);
5181             swirl_traits=GetPixelChannelTraits(swirl_image,channel);
5182             if ((traits == UndefinedPixelTrait) ||
5183                 (swirl_traits == UndefinedPixelTrait))
5184               continue;
5185             SetPixelChannel(swirl_image,channel,p[i],q);
5186           }
5187         }
5188       else
5189         {
5190           double
5191             cosine,
5192             factor,
5193             sine;
5194
5195           /*
5196             Swirl the pixel.
5197           */
5198           factor=1.0-sqrt((double) distance)/radius;
5199           sine=sin((double) (degrees*factor*factor));
5200           cosine=cos((double) (degrees*factor*factor));
5201           status=InterpolatePixelChannels(image,image_view,swirl_image,method,
5202             ((cosine*delta.x-sine*delta.y)/scale.x+center.x),(double)
5203             ((sine*delta.x+cosine*delta.y)/scale.y+center.y),q,exception);
5204         }
5205       p+=GetPixelChannels(image);
5206       q+=GetPixelChannels(swirl_image);
5207     }
5208     if (SyncCacheViewAuthenticPixels(swirl_view,exception) == MagickFalse)
5209       status=MagickFalse;
5210     if (image->progress_monitor != (MagickProgressMonitor) NULL)
5211       {
5212         MagickBooleanType
5213           proceed;
5214
5215 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5216         #pragma omp critical (MagickCore_SwirlImage)
5217 #endif
5218         proceed=SetImageProgress(image,SwirlImageTag,progress++,image->rows);
5219         if (proceed == MagickFalse)
5220           status=MagickFalse;
5221       }
5222   }
5223   swirl_view=DestroyCacheView(swirl_view);
5224   image_view=DestroyCacheView(image_view);
5225   if (status == MagickFalse)
5226     swirl_image=DestroyImage(swirl_image);
5227   return(swirl_image);
5228 }
5229 \f
5230 /*
5231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5232 %                                                                             %
5233 %                                                                             %
5234 %                                                                             %
5235 %     T i n t I m a g e                                                       %
5236 %                                                                             %
5237 %                                                                             %
5238 %                                                                             %
5239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5240 %
5241 %  TintImage() applies a color vector to each pixel in the image.  The length
5242 %  of the vector is 0 for black and white and at its maximum for the midtones.
5243 %  The vector weighting function is f(x)=(1-(4.0*((x-0.5)*(x-0.5))))
5244 %
5245 %  The format of the TintImage method is:
5246 %
5247 %      Image *TintImage(const Image *image,const char *blend,
5248 %        const PixelInfo *tint,ExceptionInfo *exception)
5249 %
5250 %  A description of each parameter follows:
5251 %
5252 %    o image: the image.
5253 %
5254 %    o blend: A color value used for tinting.
5255 %
5256 %    o tint: A color value used for tinting.
5257 %
5258 %    o exception: return any errors or warnings in this structure.
5259 %
5260 */
5261 MagickExport Image *TintImage(const Image *image,const char *blend,
5262   const PixelInfo *tint,ExceptionInfo *exception)
5263 {
5264 #define TintImageTag  "Tint/Image"
5265
5266   CacheView
5267     *image_view,
5268     *tint_view;
5269
5270   GeometryInfo
5271     geometry_info;
5272
5273   Image
5274     *tint_image;
5275
5276   MagickBooleanType
5277     status;
5278
5279   MagickOffsetType
5280     progress;
5281
5282   double
5283     intensity;
5284
5285   PixelInfo
5286     color_vector;
5287
5288   MagickStatusType
5289     flags;
5290
5291   ssize_t
5292     y;
5293
5294   /*
5295     Allocate tint image.
5296   */
5297   assert(image != (const Image *) NULL);
5298   assert(image->signature == MagickSignature);
5299   if (image->debug != MagickFalse)
5300     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5301   assert(exception != (ExceptionInfo *) NULL);
5302   assert(exception->signature == MagickSignature);
5303   tint_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
5304   if (tint_image == (Image *) NULL)
5305     return((Image *) NULL);
5306   if (SetImageStorageClass(tint_image,DirectClass,exception) == MagickFalse)
5307     {
5308       tint_image=DestroyImage(tint_image);
5309       return((Image *) NULL);
5310     }
5311   if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
5312       (IsPixelInfoGray(tint) == MagickFalse))
5313     (void) SetImageColorspace(tint_image,RGBColorspace,exception);
5314   if (blend == (const char *) NULL)
5315     return(tint_image);
5316   /*
5317     Determine RGB values of the color.
5318   */
5319   GetPixelInfo(image,&color_vector);
5320   flags=ParseGeometry(blend,&geometry_info);
5321   color_vector.red=geometry_info.rho;
5322   color_vector.green=geometry_info.rho;
5323   color_vector.blue=geometry_info.rho;
5324   color_vector.alpha=OpaqueAlpha;
5325   if ((flags & SigmaValue) != 0)
5326     color_vector.green=geometry_info.sigma;
5327   if ((flags & XiValue) != 0)
5328     color_vector.blue=geometry_info.xi;
5329   if ((flags & PsiValue) != 0)
5330     color_vector.alpha=geometry_info.psi;
5331   if (image->colorspace == CMYKColorspace)
5332     {
5333       color_vector.black=geometry_info.rho;
5334       if ((flags & PsiValue) != 0)
5335         color_vector.black=geometry_info.psi;
5336       if ((flags & ChiValue) != 0)
5337         color_vector.alpha=geometry_info.chi;
5338     }
5339   intensity=(double) GetPixelInfoIntensity(tint);
5340   color_vector.red=(double) (color_vector.red*tint->red/100.0-
5341     intensity);
5342   color_vector.green=(double) (color_vector.green*tint->green/100.0-
5343     intensity);
5344   color_vector.blue=(double) (color_vector.blue*tint->blue/100.0-
5345     intensity);
5346   color_vector.black=(double) (color_vector.black*tint->black/100.0-
5347     intensity);
5348   color_vector.alpha=(double) (color_vector.alpha*tint->alpha/100.0-
5349     intensity);
5350   /*
5351     Tint image.
5352   */
5353   status=MagickTrue;
5354   progress=0;
5355   image_view=AcquireVirtualCacheView(image,exception);
5356   tint_view=AcquireAuthenticCacheView(tint_image,exception);
5357 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5358   #pragma omp parallel for schedule(static,4) shared(progress,status) \
5359     dynamic_number_threads(image,image->columns,image->rows,1)
5360 #endif
5361   for (y=0; y < (ssize_t) image->rows; y++)
5362   {
5363     register const Quantum
5364       *restrict p;
5365
5366     register Quantum
5367       *restrict q;
5368
5369     register ssize_t
5370       x;
5371
5372     if (status == MagickFalse)
5373       continue;
5374     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
5375     q=QueueCacheViewAuthenticPixels(tint_view,0,y,tint_image->columns,1,
5376       exception);
5377     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
5378       {
5379         status=MagickFalse;
5380         continue;
5381       }
5382     for (x=0; x < (ssize_t) image->columns; x++)
5383     {
5384       PixelInfo
5385         pixel;
5386
5387       double
5388         weight;
5389
5390       register ssize_t
5391         i;
5392
5393       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
5394       {
5395         PixelChannel
5396           channel;
5397
5398         PixelTrait
5399           tint_traits,
5400           traits;
5401
5402         channel=GetPixelChannelChannel(image,i);
5403         traits=GetPixelChannelTraits(image,channel);
5404         tint_traits=GetPixelChannelTraits(tint_image,channel);
5405         if ((traits == UndefinedPixelTrait) ||
5406             (tint_traits == UndefinedPixelTrait))
5407           continue;
5408         if (((tint_traits & CopyPixelTrait) != 0) ||
5409             (GetPixelMask(image,p) != 0))
5410           {
5411             SetPixelChannel(tint_image,channel,p[i],q);
5412             continue;
5413           }
5414       }
5415       GetPixelInfo(image,&pixel);
5416       weight=QuantumScale*GetPixelRed(image,p)-0.5;
5417       pixel.red=(double) GetPixelRed(image,p)+color_vector.red*(1.0-(4.0*
5418         (weight*weight)));
5419       weight=QuantumScale*GetPixelGreen(image,p)-0.5;
5420       pixel.green=(double) GetPixelGreen(image,p)+color_vector.green*(1.0-(4.0*
5421         (weight*weight)));
5422       weight=QuantumScale*GetPixelBlue(image,p)-0.5;
5423       pixel.blue=(double) GetPixelBlue(image,p)+color_vector.blue*(1.0-(4.0*
5424         (weight*weight)));
5425       weight=QuantumScale*GetPixelBlack(image,p)-0.5;
5426       pixel.black=(double) GetPixelBlack(image,p)+color_vector.black*(1.0-(4.0*
5427         (weight*weight)));
5428       SetPixelInfoPixel(tint_image,&pixel,q);
5429       p+=GetPixelChannels(image);
5430       q+=GetPixelChannels(tint_image);
5431     }
5432     if (SyncCacheViewAuthenticPixels(tint_view,exception) == MagickFalse)
5433       status=MagickFalse;
5434     if (image->progress_monitor != (MagickProgressMonitor) NULL)
5435       {
5436         MagickBooleanType
5437           proceed;
5438
5439 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5440         #pragma omp critical (MagickCore_TintImage)
5441 #endif
5442         proceed=SetImageProgress(image,TintImageTag,progress++,image->rows);
5443         if (proceed == MagickFalse)
5444           status=MagickFalse;
5445       }
5446   }
5447   tint_view=DestroyCacheView(tint_view);
5448   image_view=DestroyCacheView(image_view);
5449   if (status == MagickFalse)
5450     tint_image=DestroyImage(tint_image);
5451   return(tint_image);
5452 }
5453 \f
5454 /*
5455 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5456 %                                                                             %
5457 %                                                                             %
5458 %                                                                             %
5459 %     V i g n e t t e I m a g e                                               %
5460 %                                                                             %
5461 %                                                                             %
5462 %                                                                             %
5463 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5464 %
5465 %  VignetteImage() softens the edges of the image in vignette style.
5466 %
5467 %  The format of the VignetteImage method is:
5468 %
5469 %      Image *VignetteImage(const Image *image,const double radius,
5470 %        const double sigma,const ssize_t x,const ssize_t y,
5471 %        ExceptionInfo *exception)
5472 %
5473 %  A description of each parameter follows:
5474 %
5475 %    o image: the image.
5476 %
5477 %    o radius: the radius of the pixel neighborhood.
5478 %
5479 %    o sigma: the standard deviation of the Gaussian, in pixels.
5480 %
5481 %    o x, y:  Define the x and y ellipse offset.
5482 %
5483 %    o exception: return any errors or warnings in this structure.
5484 %
5485 */
5486 MagickExport Image *VignetteImage(const Image *image,const double radius,
5487   const double sigma,const ssize_t x,const ssize_t y,ExceptionInfo *exception)
5488 {
5489   char
5490     ellipse[MaxTextExtent];
5491
5492   DrawInfo
5493     *draw_info;
5494
5495   Image
5496     *canvas_image,
5497     *blur_image,
5498     *oval_image,
5499     *vignette_image;
5500
5501   assert(image != (Image *) NULL);
5502   assert(image->signature == MagickSignature);
5503   if (image->debug != MagickFalse)
5504     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5505   assert(exception != (ExceptionInfo *) NULL);
5506   assert(exception->signature == MagickSignature);
5507   canvas_image=CloneImage(image,0,0,MagickTrue,exception);
5508   if (canvas_image == (Image *) NULL)
5509     return((Image *) NULL);
5510   if (SetImageStorageClass(canvas_image,DirectClass,exception) == MagickFalse)
5511     {
5512       canvas_image=DestroyImage(canvas_image);
5513       return((Image *) NULL);
5514     }
5515   canvas_image->alpha_trait=BlendPixelTrait;
5516   oval_image=CloneImage(canvas_image,canvas_image->columns,canvas_image->rows,
5517     MagickTrue,exception);
5518   if (oval_image == (Image *) NULL)
5519     {
5520       canvas_image=DestroyImage(canvas_image);
5521       return((Image *) NULL);
5522     }
5523   (void) QueryColorCompliance("#000000",AllCompliance,
5524     &oval_image->background_color,exception);
5525   (void) SetImageBackgroundColor(oval_image,exception);
5526   draw_info=CloneDrawInfo((const ImageInfo *) NULL,(const DrawInfo *) NULL);
5527   (void) QueryColorCompliance("#ffffff",AllCompliance,&draw_info->fill,
5528     exception);
5529   (void) QueryColorCompliance("#ffffff",AllCompliance,&draw_info->stroke,
5530     exception);
5531   (void) FormatLocaleString(ellipse,MaxTextExtent,"ellipse %g,%g,%g,%g,"
5532     "0.0,360.0",image->columns/2.0,image->rows/2.0,image->columns/2.0-x,
5533     image->rows/2.0-y);
5534   draw_info->primitive=AcquireString(ellipse);
5535   (void) DrawImage(oval_image,draw_info,exception);
5536   draw_info=DestroyDrawInfo(draw_info);
5537   blur_image=BlurImage(oval_image,radius,sigma,exception);
5538   oval_image=DestroyImage(oval_image);
5539   if (blur_image == (Image *) NULL)
5540     {
5541       canvas_image=DestroyImage(canvas_image);
5542       return((Image *) NULL);
5543     }
5544   blur_image->alpha_trait=UndefinedPixelTrait;
5545   (void) CompositeImage(canvas_image,blur_image,IntensityCompositeOp,MagickTrue,
5546     0,0,exception);
5547   blur_image=DestroyImage(blur_image);
5548   vignette_image=MergeImageLayers(canvas_image,FlattenLayer,exception);
5549   canvas_image=DestroyImage(canvas_image);
5550   if (vignette_image != (Image *) NULL)
5551     (void) TransformImageColorspace(vignette_image,image->colorspace,exception);
5552   return(vignette_image);
5553 }
5554 \f
5555 /*
5556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5557 %                                                                             %
5558 %                                                                             %
5559 %                                                                             %
5560 %     W a v e I m a g e                                                       %
5561 %                                                                             %
5562 %                                                                             %
5563 %                                                                             %
5564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5565 %
5566 %  WaveImage() creates a "ripple" effect in the image by shifting the pixels
5567 %  vertically along a sine wave whose amplitude and wavelength is specified
5568 %  by the given parameters.
5569 %
5570 %  The format of the WaveImage method is:
5571 %
5572 %      Image *WaveImage(const Image *image,const double amplitude,
5573 %        const double wave_length,const PixelInterpolateMethod method,
5574 %        ExceptionInfo *exception)
5575 %
5576 %  A description of each parameter follows:
5577 %
5578 %    o image: the image.
5579 %
5580 %    o amplitude, wave_length:  Define the amplitude and wave length of the
5581 %      sine wave.
5582 %
5583 %    o interpolate: the pixel interpolation method.
5584 %
5585 %    o exception: return any errors or warnings in this structure.
5586 %
5587 */
5588 MagickExport Image *WaveImage(const Image *image,const double amplitude,
5589   const double wave_length,const PixelInterpolateMethod method,
5590   ExceptionInfo *exception)
5591 {
5592 #define WaveImageTag  "Wave/Image"
5593
5594   CacheView
5595     *image_view,
5596     *wave_view;
5597
5598   Image
5599     *wave_image;
5600
5601   MagickBooleanType
5602     status;
5603
5604   MagickOffsetType
5605     progress;
5606
5607   double
5608     *sine_map;
5609
5610   register ssize_t
5611     i;
5612
5613   ssize_t
5614     y;
5615
5616   /*
5617     Initialize wave image attributes.
5618   */
5619   assert(image != (Image *) NULL);
5620   assert(image->signature == MagickSignature);
5621   if (image->debug != MagickFalse)
5622     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5623   assert(exception != (ExceptionInfo *) NULL);
5624   assert(exception->signature == MagickSignature);
5625   wave_image=CloneImage(image,image->columns,(size_t) (image->rows+2.0*
5626     fabs(amplitude)),MagickTrue,exception);
5627   if (wave_image == (Image *) NULL)
5628     return((Image *) NULL);
5629   if (SetImageStorageClass(wave_image,DirectClass,exception) == MagickFalse)
5630     {
5631       wave_image=DestroyImage(wave_image);
5632       return((Image *) NULL);
5633     }
5634   if (wave_image->background_color.alpha != OpaqueAlpha)
5635     wave_image->alpha_trait=BlendPixelTrait;
5636   /*
5637     Allocate sine map.
5638   */
5639   sine_map=(double *) AcquireQuantumMemory((size_t) wave_image->columns,
5640     sizeof(*sine_map));
5641   if (sine_map == (double *) NULL)
5642     {
5643       wave_image=DestroyImage(wave_image);
5644       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
5645     }
5646   for (i=0; i < (ssize_t) wave_image->columns; i++)
5647     sine_map[i]=fabs(amplitude)+amplitude*sin((double) ((2.0*MagickPI*i)/
5648       wave_length));
5649   /*
5650     Wave image.
5651   */
5652   status=MagickTrue;
5653   progress=0;
5654   image_view=AcquireVirtualCacheView(image,exception);
5655   wave_view=AcquireAuthenticCacheView(wave_image,exception);
5656   (void) SetCacheViewVirtualPixelMethod(image_view,
5657     BackgroundVirtualPixelMethod);
5658 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5659   #pragma omp parallel for schedule(static,4) shared(progress,status) \
5660     dynamic_number_threads(image,image->columns,image->rows,1)
5661 #endif
5662   for (y=0; y < (ssize_t) wave_image->rows; y++)
5663   {
5664     register Quantum
5665       *restrict q;
5666
5667     register ssize_t
5668       x;
5669
5670     if (status == MagickFalse)
5671       continue;
5672     q=QueueCacheViewAuthenticPixels(wave_view,0,y,wave_image->columns,1,
5673       exception);
5674     if (q == (Quantum *) NULL)
5675       {
5676         status=MagickFalse;
5677         continue;
5678       }
5679     for (x=0; x < (ssize_t) wave_image->columns; x++)
5680     {
5681       status=InterpolatePixelChannels(image,image_view,wave_image,method,
5682         (double) x,(double) (y-sine_map[x]),q,exception);
5683       q+=GetPixelChannels(wave_image);
5684     }
5685     if (SyncCacheViewAuthenticPixels(wave_view,exception) == MagickFalse)
5686       status=MagickFalse;
5687     if (image->progress_monitor != (MagickProgressMonitor) NULL)
5688       {
5689         MagickBooleanType
5690           proceed;
5691
5692 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5693         #pragma omp critical (MagickCore_WaveImage)
5694 #endif
5695         proceed=SetImageProgress(image,WaveImageTag,progress++,image->rows);
5696         if (proceed == MagickFalse)
5697           status=MagickFalse;
5698       }
5699   }
5700   wave_view=DestroyCacheView(wave_view);
5701   image_view=DestroyCacheView(image_view);
5702   sine_map=(double *) RelinquishMagickMemory(sine_map);
5703   if (status == MagickFalse)
5704     wave_image=DestroyImage(wave_image);
5705   return(wave_image);
5706 }