]> granicus.if.org Git - imagemagick/blob - MagickCore/fx.c
Kill some defined-but-not-used warnings in effect.c and fx.c
[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     return((FxInfo **) NULL);
2998   (void) ResetMagickMemory(fx_info,0,number_threads*sizeof(*fx_info));
2999   if (*expression != '@')
3000     fx_expression=ConstantString(expression);
3001   else
3002     fx_expression=FileToString(expression+1,~0,exception);
3003   for (i=0; i < (ssize_t) number_threads; i++)
3004   {
3005     fx_info[i]=AcquireFxInfo(image,fx_expression,exception);
3006     if (fx_info[i] == (FxInfo *) NULL)
3007       return(DestroyFxThreadSet(fx_info));
3008     (void) FxPreprocessExpression(fx_info[i],&alpha,fx_info[i]->exception);
3009   }
3010   fx_expression=DestroyString(fx_expression);
3011   return(fx_info);
3012 }
3013
3014 MagickExport Image *FxImage(const Image *image,const char *expression,
3015   ExceptionInfo *exception)
3016 {
3017 #define FxImageTag  "Fx/Image"
3018
3019   CacheView
3020     *fx_view,
3021     *image_view;
3022
3023   FxInfo
3024     **restrict fx_info;
3025
3026   Image
3027     *fx_image;
3028
3029   MagickBooleanType
3030     status;
3031
3032   MagickOffsetType
3033     progress;
3034
3035   double
3036     alpha;
3037
3038   ssize_t
3039     y;
3040
3041   assert(image != (Image *) NULL);
3042   assert(image->signature == MagickSignature);
3043   if (image->debug != MagickFalse)
3044     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3045   fx_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
3046   if (fx_image == (Image *) NULL)
3047     return((Image *) NULL);
3048   if (SetImageStorageClass(fx_image,DirectClass,exception) == MagickFalse)
3049     {
3050       fx_image=DestroyImage(fx_image);
3051       return((Image *) NULL);
3052     }
3053   fx_info=AcquireFxThreadSet(image,expression,exception);
3054   if (fx_info == (FxInfo **) NULL)
3055     {
3056       fx_image=DestroyImage(fx_image);
3057       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
3058     }
3059   status=FxPreprocessExpression(fx_info[0],&alpha,exception);
3060   if (status == MagickFalse)
3061     {
3062       fx_image=DestroyImage(fx_image);
3063       fx_info=DestroyFxThreadSet(fx_info);
3064       return((Image *) NULL);
3065     }
3066   /*
3067     Fx image.
3068   */
3069   status=MagickTrue;
3070   progress=0;
3071   image_view=AcquireVirtualCacheView(image,exception);
3072   fx_view=AcquireAuthenticCacheView(fx_image,exception);
3073 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3074   #pragma omp parallel for schedule(static,4) shared(progress,status) \
3075     dynamic_number_threads(image,image->columns,image->rows,1)
3076 #endif
3077   for (y=0; y < (ssize_t) fx_image->rows; y++)
3078   {
3079     const int
3080       id = GetOpenMPThreadId();
3081
3082     register const Quantum
3083       *restrict p;
3084
3085     register Quantum
3086       *restrict q;
3087
3088     register ssize_t
3089       x;
3090
3091     if (status == MagickFalse)
3092       continue;
3093     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
3094     q=QueueCacheViewAuthenticPixels(fx_view,0,y,fx_image->columns,1,exception);
3095     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3096       {
3097         status=MagickFalse;
3098         continue;
3099       }
3100     for (x=0; x < (ssize_t) fx_image->columns; x++)
3101     {
3102       register ssize_t
3103         i;
3104
3105       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3106       {
3107         double
3108           alpha;
3109
3110         PixelChannel
3111           channel;
3112
3113         PixelTrait
3114           fx_traits,
3115           traits;
3116
3117         channel=GetPixelChannelChannel(image,i);
3118         traits=GetPixelChannelTraits(image,channel);
3119         fx_traits=GetPixelChannelTraits(fx_image,channel);
3120         if ((traits == UndefinedPixelTrait) ||
3121             (fx_traits == UndefinedPixelTrait))
3122           continue;
3123         if (((fx_traits & CopyPixelTrait) != 0) ||
3124             (GetPixelMask(image,p) != 0))
3125           {
3126             SetPixelChannel(fx_image,channel,p[i],q);
3127             continue;
3128           }
3129         alpha=0.0;
3130         (void) FxEvaluateChannelExpression(fx_info[id],channel,x,y,&alpha,
3131           exception);
3132         q[i]=ClampToQuantum(QuantumRange*alpha);
3133       }
3134       p+=GetPixelChannels(image);
3135       q+=GetPixelChannels(fx_image);
3136     }
3137     if (SyncCacheViewAuthenticPixels(fx_view,exception) == MagickFalse)
3138       status=MagickFalse;
3139     if (image->progress_monitor != (MagickProgressMonitor) NULL)
3140       {
3141         MagickBooleanType
3142           proceed;
3143
3144 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3145         #pragma omp critical (MagickCore_FxImage)
3146 #endif
3147         proceed=SetImageProgress(image,FxImageTag,progress++,image->rows);
3148         if (proceed == MagickFalse)
3149           status=MagickFalse;
3150       }
3151   }
3152   fx_view=DestroyCacheView(fx_view);
3153   image_view=DestroyCacheView(image_view);
3154   fx_info=DestroyFxThreadSet(fx_info);
3155   if (status == MagickFalse)
3156     fx_image=DestroyImage(fx_image);
3157   return(fx_image);
3158 }
3159 \f
3160 /*
3161 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3162 %                                                                             %
3163 %                                                                             %
3164 %                                                                             %
3165 %     I m p l o d e I m a g e                                                 %
3166 %                                                                             %
3167 %                                                                             %
3168 %                                                                             %
3169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3170 %
3171 %  ImplodeImage() creates a new image that is a copy of an existing
3172 %  one with the image pixels "implode" by the specified percentage.  It
3173 %  allocates the memory necessary for the new Image structure and returns a
3174 %  pointer to the new image.
3175 %
3176 %  The format of the ImplodeImage method is:
3177 %
3178 %      Image *ImplodeImage(const Image *image,const double amount,
3179 %        const PixelInterpolateMethod method,ExceptionInfo *exception)
3180 %
3181 %  A description of each parameter follows:
3182 %
3183 %    o implode_image: Method ImplodeImage returns a pointer to the image
3184 %      after it is implode.  A null image is returned if there is a memory
3185 %      shortage.
3186 %
3187 %    o image: the image.
3188 %
3189 %    o amount:  Define the extent of the implosion.
3190 %
3191 %    o method: the pixel interpolation method.
3192 %
3193 %    o exception: return any errors or warnings in this structure.
3194 %
3195 */
3196 MagickExport Image *ImplodeImage(const Image *image,const double amount,
3197   const PixelInterpolateMethod method,ExceptionInfo *exception)
3198 {
3199 #define ImplodeImageTag  "Implode/Image"
3200
3201   CacheView
3202     *image_view,
3203     *implode_view;
3204
3205   Image
3206     *implode_image;
3207
3208   MagickBooleanType
3209     status;
3210
3211   MagickOffsetType
3212     progress;
3213
3214   double
3215     radius;
3216
3217   PointInfo
3218     center,
3219     scale;
3220
3221   ssize_t
3222     y;
3223
3224   /*
3225     Initialize implode image attributes.
3226   */
3227   assert(image != (Image *) NULL);
3228   assert(image->signature == MagickSignature);
3229   if (image->debug != MagickFalse)
3230     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3231   assert(exception != (ExceptionInfo *) NULL);
3232   assert(exception->signature == MagickSignature);
3233   implode_image=CloneImage(image,image->columns,image->rows,MagickTrue,
3234     exception);
3235   if (implode_image == (Image *) NULL)
3236     return((Image *) NULL);
3237   if (SetImageStorageClass(implode_image,DirectClass,exception) == MagickFalse)
3238     {
3239       implode_image=DestroyImage(implode_image);
3240       return((Image *) NULL);
3241     }
3242   if (implode_image->background_color.alpha != OpaqueAlpha)
3243     implode_image->alpha_trait=BlendPixelTrait;
3244   /*
3245     Compute scaling factor.
3246   */
3247   scale.x=1.0;
3248   scale.y=1.0;
3249   center.x=0.5*image->columns;
3250   center.y=0.5*image->rows;
3251   radius=center.x;
3252   if (image->columns > image->rows)
3253     scale.y=(double) image->columns/(double) image->rows;
3254   else
3255     if (image->columns < image->rows)
3256       {
3257         scale.x=(double) image->rows/(double) image->columns;
3258         radius=center.y;
3259       }
3260   /*
3261     Implode image.
3262   */
3263   status=MagickTrue;
3264   progress=0;
3265   image_view=AcquireVirtualCacheView(image,exception);
3266   implode_view=AcquireAuthenticCacheView(implode_image,exception);
3267 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3268   #pragma omp parallel for schedule(static,4) shared(progress,status) \
3269     dynamic_number_threads(image,image->columns,image->rows,1)
3270 #endif
3271   for (y=0; y < (ssize_t) image->rows; y++)
3272   {
3273     double
3274       distance;
3275
3276     PointInfo
3277       delta;
3278
3279     register const Quantum
3280       *restrict p;
3281
3282     register ssize_t
3283       x;
3284
3285     register Quantum
3286       *restrict q;
3287
3288     if (status == MagickFalse)
3289       continue;
3290     p=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
3291     q=QueueCacheViewAuthenticPixels(implode_view,0,y,implode_image->columns,1,
3292       exception);
3293     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3294       {
3295         status=MagickFalse;
3296         continue;
3297       }
3298     delta.y=scale.y*(double) (y-center.y);
3299     for (x=0; x < (ssize_t) image->columns; x++)
3300     {
3301       register ssize_t
3302         i;
3303
3304       /*
3305         Determine if the pixel is within an ellipse.
3306       */
3307       if (GetPixelMask(image,p) != 0)
3308         {
3309           p+=GetPixelChannels(image);
3310           q+=GetPixelChannels(implode_image);
3311           continue;
3312         }
3313       delta.x=scale.x*(double) (x-center.x);
3314       distance=delta.x*delta.x+delta.y*delta.y;
3315       if (distance >= (radius*radius))
3316         for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3317         {
3318           PixelChannel
3319             channel;
3320
3321           PixelTrait
3322             implode_traits,
3323             traits;
3324
3325           channel=GetPixelChannelChannel(image,i);
3326           traits=GetPixelChannelTraits(image,channel);
3327           implode_traits=GetPixelChannelTraits(implode_image,channel);
3328           if ((traits == UndefinedPixelTrait) ||
3329               (implode_traits == UndefinedPixelTrait))
3330             continue;
3331           SetPixelChannel(implode_image,channel,p[i],q);
3332         }
3333       else
3334         {
3335           double
3336             factor;
3337
3338           /*
3339             Implode the pixel.
3340           */
3341           factor=1.0;
3342           if (distance > 0.0)
3343             factor=pow(sin((double) (MagickPI*sqrt((double) distance)/radius/
3344               2)),-amount);
3345           status=InterpolatePixelChannels(image,image_view,implode_image,method,
3346             (double) (factor*delta.x/scale.x+center.x),(double) (factor*delta.y/
3347             scale.y+center.y),q,exception);
3348         }
3349       p+=GetPixelChannels(image);
3350       q+=GetPixelChannels(implode_image);
3351     }
3352     if (SyncCacheViewAuthenticPixels(implode_view,exception) == MagickFalse)
3353       status=MagickFalse;
3354     if (image->progress_monitor != (MagickProgressMonitor) NULL)
3355       {
3356         MagickBooleanType
3357           proceed;
3358
3359 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3360         #pragma omp critical (MagickCore_ImplodeImage)
3361 #endif
3362         proceed=SetImageProgress(image,ImplodeImageTag,progress++,image->rows);
3363         if (proceed == MagickFalse)
3364           status=MagickFalse;
3365       }
3366   }
3367   implode_view=DestroyCacheView(implode_view);
3368   image_view=DestroyCacheView(image_view);
3369   if (status == MagickFalse)
3370     implode_image=DestroyImage(implode_image);
3371   return(implode_image);
3372 }
3373 \f
3374 /*
3375 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3376 %                                                                             %
3377 %                                                                             %
3378 %                                                                             %
3379 %     M o r p h I m a g e s                                                   %
3380 %                                                                             %
3381 %                                                                             %
3382 %                                                                             %
3383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3384 %
3385 %  The MorphImages() method requires a minimum of two images.  The first
3386 %  image is transformed into the second by a number of intervening images
3387 %  as specified by frames.
3388 %
3389 %  The format of the MorphImage method is:
3390 %
3391 %      Image *MorphImages(const Image *image,const size_t number_frames,
3392 %        ExceptionInfo *exception)
3393 %
3394 %  A description of each parameter follows:
3395 %
3396 %    o image: the image.
3397 %
3398 %    o number_frames:  Define the number of in-between image to generate.
3399 %      The more in-between frames, the smoother the morph.
3400 %
3401 %    o exception: return any errors or warnings in this structure.
3402 %
3403 */
3404 MagickExport Image *MorphImages(const Image *image,
3405   const size_t number_frames,ExceptionInfo *exception)
3406 {
3407 #define MorphImageTag  "Morph/Image"
3408
3409   Image
3410     *morph_image,
3411     *morph_images;
3412
3413   MagickBooleanType
3414     status;
3415
3416   MagickOffsetType
3417     scene;
3418
3419   double
3420     alpha,
3421     beta;
3422
3423   register const Image
3424     *next;
3425
3426   register ssize_t
3427     i;
3428
3429   ssize_t
3430     y;
3431
3432   /*
3433     Clone first frame in sequence.
3434   */
3435   assert(image != (Image *) NULL);
3436   assert(image->signature == MagickSignature);
3437   if (image->debug != MagickFalse)
3438     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3439   assert(exception != (ExceptionInfo *) NULL);
3440   assert(exception->signature == MagickSignature);
3441   morph_images=CloneImage(image,0,0,MagickTrue,exception);
3442   if (morph_images == (Image *) NULL)
3443     return((Image *) NULL);
3444   if (GetNextImageInList(image) == (Image *) NULL)
3445     {
3446       /*
3447         Morph single image.
3448       */
3449       for (i=1; i < (ssize_t) number_frames; i++)
3450       {
3451         morph_image=CloneImage(image,0,0,MagickTrue,exception);
3452         if (morph_image == (Image *) NULL)
3453           {
3454             morph_images=DestroyImageList(morph_images);
3455             return((Image *) NULL);
3456           }
3457         AppendImageToList(&morph_images,morph_image);
3458         if (image->progress_monitor != (MagickProgressMonitor) NULL)
3459           {
3460             MagickBooleanType
3461               proceed;
3462
3463             proceed=SetImageProgress(image,MorphImageTag,(MagickOffsetType) i,
3464               number_frames);
3465             if (proceed == MagickFalse)
3466               status=MagickFalse;
3467           }
3468       }
3469       return(GetFirstImageInList(morph_images));
3470     }
3471   /*
3472     Morph image sequence.
3473   */
3474   status=MagickTrue;
3475   scene=0;
3476   next=image;
3477   for ( ; GetNextImageInList(next) != (Image *) NULL; next=GetNextImageInList(next))
3478   {
3479     for (i=0; i < (ssize_t) number_frames; i++)
3480     {
3481       CacheView
3482         *image_view,
3483         *morph_view;
3484
3485       beta=(double) (i+1.0)/(double) (number_frames+1.0);
3486       alpha=1.0-beta;
3487       morph_image=ResizeImage(next,(size_t) (alpha*next->columns+beta*
3488         GetNextImageInList(next)->columns+0.5),(size_t) (alpha*next->rows+beta*
3489         GetNextImageInList(next)->rows+0.5),next->filter,exception);
3490       if (morph_image == (Image *) NULL)
3491         {
3492           morph_images=DestroyImageList(morph_images);
3493           return((Image *) NULL);
3494         }
3495       status=SetImageStorageClass(morph_image,DirectClass,exception);
3496       if (status == MagickFalse)
3497         {
3498           morph_image=DestroyImage(morph_image);
3499           return((Image *) NULL);
3500         }
3501       AppendImageToList(&morph_images,morph_image);
3502       morph_images=GetLastImageInList(morph_images);
3503       morph_image=ResizeImage(GetNextImageInList(next),morph_images->columns,
3504         morph_images->rows,GetNextImageInList(next)->filter,exception);
3505       if (morph_image == (Image *) NULL)
3506         {
3507           morph_images=DestroyImageList(morph_images);
3508           return((Image *) NULL);
3509         }
3510       image_view=AcquireVirtualCacheView(morph_image,exception);
3511       morph_view=AcquireAuthenticCacheView(morph_images,exception);
3512 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3513       #pragma omp parallel for schedule(static,4) shared(status) \
3514         dynamic_number_threads(image,image->columns,image->rows,1)
3515 #endif
3516       for (y=0; y < (ssize_t) morph_images->rows; y++)
3517       {
3518         MagickBooleanType
3519           sync;
3520
3521         register const Quantum
3522           *restrict p;
3523
3524         register ssize_t
3525           x;
3526
3527         register Quantum
3528           *restrict q;
3529
3530         if (status == MagickFalse)
3531           continue;
3532         p=GetCacheViewVirtualPixels(image_view,0,y,morph_image->columns,1,
3533           exception);
3534         q=GetCacheViewAuthenticPixels(morph_view,0,y,morph_images->columns,1,
3535           exception);
3536         if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3537           {
3538             status=MagickFalse;
3539             continue;
3540           }
3541         for (x=0; x < (ssize_t) morph_images->columns; x++)
3542         {
3543           register ssize_t
3544             i;
3545
3546           for (i=0; i < (ssize_t) GetPixelChannels(morph_image); i++)
3547           {
3548             PixelChannel
3549               channel;
3550
3551             PixelTrait
3552               morph_traits,
3553               traits;
3554
3555             channel=GetPixelChannelChannel(image,i);
3556             traits=GetPixelChannelTraits(image,channel);
3557             morph_traits=GetPixelChannelTraits(morph_image,channel);
3558             if ((traits == UndefinedPixelTrait) ||
3559                 (morph_traits == UndefinedPixelTrait))
3560               continue;
3561             if (((morph_traits & CopyPixelTrait) != 0) ||
3562                 (GetPixelMask(image,p) != 0))
3563               {
3564                 SetPixelChannel(morph_image,channel,p[i],q);
3565                 continue;
3566               }
3567             SetPixelChannel(morph_image,channel,ClampToQuantum(alpha*
3568               GetPixelChannel(morph_images,channel,q)+beta*p[i]),q);
3569           }
3570           p+=GetPixelChannels(morph_image);
3571           q+=GetPixelChannels(morph_images);
3572         }
3573         sync=SyncCacheViewAuthenticPixels(morph_view,exception);
3574         if (sync == MagickFalse)
3575           status=MagickFalse;
3576       }
3577       morph_view=DestroyCacheView(morph_view);
3578       image_view=DestroyCacheView(image_view);
3579       morph_image=DestroyImage(morph_image);
3580     }
3581     if (i < (ssize_t) number_frames)
3582       break;
3583     /*
3584       Clone last frame in sequence.
3585     */
3586     morph_image=CloneImage(GetNextImageInList(next),0,0,MagickTrue,exception);
3587     if (morph_image == (Image *) NULL)
3588       {
3589         morph_images=DestroyImageList(morph_images);
3590         return((Image *) NULL);
3591       }
3592     AppendImageToList(&morph_images,morph_image);
3593     morph_images=GetLastImageInList(morph_images);
3594     if (image->progress_monitor != (MagickProgressMonitor) NULL)
3595       {
3596         MagickBooleanType
3597           proceed;
3598
3599 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3600         #pragma omp critical (MagickCore_MorphImages)
3601 #endif
3602         proceed=SetImageProgress(image,MorphImageTag,scene,
3603           GetImageListLength(image));
3604         if (proceed == MagickFalse)
3605           status=MagickFalse;
3606       }
3607     scene++;
3608   }
3609   if (GetNextImageInList(next) != (Image *) NULL)
3610     {
3611       morph_images=DestroyImageList(morph_images);
3612       return((Image *) NULL);
3613     }
3614   return(GetFirstImageInList(morph_images));
3615 }
3616 \f
3617 /*
3618 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3619 %                                                                             %
3620 %                                                                             %
3621 %                                                                             %
3622 %     P l a s m a I m a g e                                                   %
3623 %                                                                             %
3624 %                                                                             %
3625 %                                                                             %
3626 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3627 %
3628 %  PlasmaImage() initializes an image with plasma fractal values.  The image
3629 %  must be initialized with a base color and the random number generator
3630 %  seeded before this method is called.
3631 %
3632 %  The format of the PlasmaImage method is:
3633 %
3634 %      MagickBooleanType PlasmaImage(Image *image,const SegmentInfo *segment,
3635 %        size_t attenuate,size_t depth,ExceptionInfo *exception)
3636 %
3637 %  A description of each parameter follows:
3638 %
3639 %    o image: the image.
3640 %
3641 %    o segment:   Define the region to apply plasma fractals values.
3642 %
3643 %    o attenuate: Define the plasma attenuation factor.
3644 %
3645 %    o depth: Limit the plasma recursion depth.
3646 %
3647 %    o exception: return any errors or warnings in this structure.
3648 %
3649 */
3650
3651 static inline Quantum PlasmaPixel(RandomInfo *random_info,
3652   const double pixel,const double noise)
3653 {
3654   Quantum
3655     plasma;
3656
3657   plasma=ClampToQuantum(pixel+noise*GetPseudoRandomValue(random_info)-
3658     noise/2.0);
3659   return(plasma);
3660 }
3661
3662 static MagickBooleanType PlasmaImageProxy(Image *image,CacheView *image_view,
3663   CacheView *u_view,CacheView *v_view,RandomInfo *random_info,
3664   const SegmentInfo *segment,size_t attenuate,size_t depth,
3665   ExceptionInfo *exception)
3666 {
3667   double
3668     plasma;
3669
3670   PixelChannel
3671     channel;
3672
3673   PixelTrait
3674     traits;
3675
3676   register const Quantum
3677     *restrict u,
3678     *restrict v;
3679
3680   register Quantum
3681     *restrict q;
3682
3683   register ssize_t
3684     i;
3685
3686   ssize_t
3687     x,
3688     x_mid,
3689     y,
3690     y_mid;
3691
3692   if (((segment->x2-segment->x1) == 0.0) && ((segment->y2-segment->y1) == 0.0))
3693     return(MagickTrue);
3694   if (depth != 0)
3695     {
3696       SegmentInfo
3697         local_info;
3698
3699       /*
3700         Divide the area into quadrants and recurse.
3701       */
3702       depth--;
3703       attenuate++;
3704       x_mid=(ssize_t) ceil((segment->x1+segment->x2)/2-0.5);
3705       y_mid=(ssize_t) ceil((segment->y1+segment->y2)/2-0.5);
3706       local_info=(*segment);
3707       local_info.x2=(double) x_mid;
3708       local_info.y2=(double) y_mid;
3709       (void) PlasmaImageProxy(image,image_view,u_view,v_view,random_info,
3710         &local_info,attenuate,depth,exception);
3711       local_info=(*segment);
3712       local_info.y1=(double) y_mid;
3713       local_info.x2=(double) x_mid;
3714       (void) PlasmaImageProxy(image,image_view,u_view,v_view,random_info,
3715         &local_info,attenuate,depth,exception);
3716       local_info=(*segment);
3717       local_info.x1=(double) x_mid;
3718       local_info.y2=(double) y_mid;
3719       (void) PlasmaImageProxy(image,image_view,u_view,v_view,random_info,
3720         &local_info,attenuate,depth,exception);
3721       local_info=(*segment);
3722       local_info.x1=(double) x_mid;
3723       local_info.y1=(double) y_mid;
3724       return(PlasmaImageProxy(image,image_view,u_view,v_view,random_info,
3725         &local_info,attenuate,depth,exception));
3726     }
3727   x_mid=(ssize_t) ceil((segment->x1+segment->x2)/2-0.5);
3728   y_mid=(ssize_t) ceil((segment->y1+segment->y2)/2-0.5);
3729   if ((segment->x1 == (double) x_mid) && (segment->x2 == (double) x_mid) &&
3730       (segment->y1 == (double) y_mid) && (segment->y2 == (double) y_mid))
3731     return(MagickFalse);
3732   /*
3733     Average pixels and apply plasma.
3734   */
3735   plasma=(double) QuantumRange/(2.0*attenuate);
3736   if ((segment->x1 != (double) x_mid) || (segment->x2 != (double) x_mid))
3737     {
3738       /*
3739         Left pixel.
3740       */
3741       x=(ssize_t) ceil(segment->x1-0.5);
3742       u=GetCacheViewVirtualPixels(u_view,x,(ssize_t) ceil(segment->y1-0.5),1,1,
3743         exception);
3744       v=GetCacheViewVirtualPixels(v_view,x,(ssize_t) ceil(segment->y2-0.5),1,1,
3745         exception);
3746       q=QueueCacheViewAuthenticPixels(image_view,x,y_mid,1,1,exception);
3747       if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
3748           (q == (Quantum *) NULL))
3749         return(MagickTrue);
3750       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3751       {
3752         channel=GetPixelChannelChannel(image,i);
3753         traits=GetPixelChannelTraits(image,channel);
3754         if (traits == UndefinedPixelTrait)
3755           continue;
3756         q[i]=PlasmaPixel(random_info,(u[channel]+v[channel])/2.0,plasma);
3757       }
3758       (void) SyncCacheViewAuthenticPixels(image_view,exception);
3759       if (segment->x1 != segment->x2)
3760         {
3761           /*
3762             Right pixel.
3763           */
3764           x=(ssize_t) ceil(segment->x2-0.5);
3765           u=GetCacheViewVirtualPixels(u_view,x,(ssize_t) ceil(segment->y1-0.5),
3766             1,1,exception);
3767           v=GetCacheViewVirtualPixels(v_view,x,(ssize_t) ceil(segment->y2-0.5),
3768             1,1,exception);
3769           q=QueueCacheViewAuthenticPixels(image_view,x,y_mid,1,1,exception);
3770           if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
3771               (q == (Quantum *) NULL))
3772             return(MagickTrue);
3773           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3774           {
3775             channel=GetPixelChannelChannel(image,i);
3776             traits=GetPixelChannelTraits(image,channel);
3777             if (traits == UndefinedPixelTrait)
3778               continue;
3779             q[i]=PlasmaPixel(random_info,(u[channel]+v[channel])/2.0,plasma);
3780           }
3781           (void) SyncCacheViewAuthenticPixels(image_view,exception);
3782         }
3783     }
3784   if ((segment->y1 != (double) y_mid) || (segment->y2 != (double) y_mid))
3785     {
3786       if ((segment->x1 != (double) x_mid) || (segment->y2 != (double) y_mid))
3787         {
3788           /*
3789             Bottom pixel.
3790           */
3791           y=(ssize_t) ceil(segment->y2-0.5);
3792           u=GetCacheViewVirtualPixels(u_view,(ssize_t) ceil(segment->x1-0.5),y,
3793             1,1,exception);
3794           v=GetCacheViewVirtualPixels(v_view,(ssize_t) ceil(segment->x2-0.5),y,
3795             1,1,exception);
3796           q=QueueCacheViewAuthenticPixels(image_view,x_mid,y,1,1,exception);
3797           if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
3798               (q == (Quantum *) NULL))
3799             return(MagickTrue);
3800           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3801           {
3802             channel=GetPixelChannelChannel(image,i);
3803             traits=GetPixelChannelTraits(image,channel);
3804             if (traits == UndefinedPixelTrait)
3805               continue;
3806             q[i]=PlasmaPixel(random_info,(u[channel]+v[channel])/2.0,plasma);
3807           }
3808           (void) SyncCacheViewAuthenticPixels(image_view,exception);
3809         }
3810       if (segment->y1 != segment->y2)
3811         {
3812           /*
3813             Top pixel.
3814           */
3815           y=(ssize_t) ceil(segment->y1-0.5);
3816           u=GetCacheViewVirtualPixels(u_view,(ssize_t) ceil(segment->x1-0.5),y,
3817             1,1,exception);
3818           v=GetCacheViewVirtualPixels(v_view,(ssize_t) ceil(segment->x2-0.5),y,
3819             1,1,exception);
3820           q=QueueCacheViewAuthenticPixels(image_view,x_mid,y,1,1,exception);
3821           if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
3822               (q == (Quantum *) NULL))
3823             return(MagickTrue);
3824           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3825           {
3826             channel=GetPixelChannelChannel(image,i);
3827             traits=GetPixelChannelTraits(image,channel);
3828             if (traits == UndefinedPixelTrait)
3829               continue;
3830             q[i]=PlasmaPixel(random_info,(u[channel]+v[channel])/2.0,plasma);
3831           }
3832           (void) SyncCacheViewAuthenticPixels(image_view,exception);
3833         }
3834     }
3835   if ((segment->x1 != segment->x2) || (segment->y1 != segment->y2))
3836     {
3837       /*
3838         Middle pixel.
3839       */
3840       x=(ssize_t) ceil(segment->x1-0.5);
3841       y=(ssize_t) ceil(segment->y1-0.5);
3842       u=GetCacheViewVirtualPixels(u_view,x,y,1,1,exception);
3843       x=(ssize_t) ceil(segment->x2-0.5);
3844       y=(ssize_t) ceil(segment->y2-0.5);
3845       v=GetCacheViewVirtualPixels(v_view,x,y,1,1,exception);
3846       q=QueueCacheViewAuthenticPixels(image_view,x_mid,y_mid,1,1,exception);
3847       if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
3848           (q == (Quantum *) NULL))
3849         return(MagickTrue);
3850       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3851       {
3852         channel=GetPixelChannelChannel(image,i);
3853         traits=GetPixelChannelTraits(image,channel);
3854         if (traits == UndefinedPixelTrait)
3855           continue;
3856         q[i]=PlasmaPixel(random_info,(u[channel]+v[channel])/2.0,plasma);
3857       }
3858       (void) SyncCacheViewAuthenticPixels(image_view,exception);
3859     }
3860   if (((segment->x2-segment->x1) < 3.0) && ((segment->y2-segment->y1) < 3.0))
3861     return(MagickTrue);
3862   return(MagickFalse);
3863 }
3864
3865 MagickExport MagickBooleanType PlasmaImage(Image *image,
3866   const SegmentInfo *segment,size_t attenuate,size_t depth,
3867   ExceptionInfo *exception)
3868 {
3869   CacheView
3870     *image_view,
3871     *u_view,
3872     *v_view;
3873
3874   MagickBooleanType
3875     status;
3876
3877   RandomInfo
3878     *random_info;
3879
3880   if (image->debug != MagickFalse)
3881     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3882   assert(image != (Image *) NULL);
3883   assert(image->signature == MagickSignature);
3884   if (image->debug != MagickFalse)
3885     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3886   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
3887     return(MagickFalse);
3888   image_view=AcquireAuthenticCacheView(image,exception);
3889   u_view=AcquireVirtualCacheView(image,exception);
3890   v_view=AcquireVirtualCacheView(image,exception);
3891   random_info=AcquireRandomInfo();
3892   status=PlasmaImageProxy(image,image_view,u_view,v_view,random_info,segment,
3893     attenuate,depth,exception);
3894   random_info=DestroyRandomInfo(random_info);
3895   v_view=DestroyCacheView(v_view);
3896   u_view=DestroyCacheView(u_view);
3897   image_view=DestroyCacheView(image_view);
3898   return(status);
3899 }
3900 \f
3901 /*
3902 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3903 %                                                                             %
3904 %                                                                             %
3905 %                                                                             %
3906 %   P o l a r o i d I m a g e                                                 %
3907 %                                                                             %
3908 %                                                                             %
3909 %                                                                             %
3910 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3911 %
3912 %  PolaroidImage() simulates a Polaroid picture.
3913 %
3914 %  The format of the AnnotateImage method is:
3915 %
3916 %      Image *PolaroidImage(const Image *image,const DrawInfo *draw_info,
3917 %        const char *caption,const double angle,
3918 %        const PixelInterpolateMethod method,ExceptionInfo exception)
3919 %
3920 %  A description of each parameter follows:
3921 %
3922 %    o image: the image.
3923 %
3924 %    o draw_info: the draw info.
3925 %
3926 %    o caption: the Polaroid caption.
3927 %
3928 %    o angle: Apply the effect along this angle.
3929 %
3930 %    o method: the pixel interpolation method.
3931 %
3932 %    o exception: return any errors or warnings in this structure.
3933 %
3934 */
3935 MagickExport Image *PolaroidImage(const Image *image,const DrawInfo *draw_info,
3936   const char *caption,const double angle,const PixelInterpolateMethod method,
3937   ExceptionInfo *exception)
3938 {
3939   Image
3940     *bend_image,
3941     *caption_image,
3942     *flop_image,
3943     *picture_image,
3944     *polaroid_image,
3945     *rotate_image,
3946     *trim_image;
3947
3948   size_t
3949     height;
3950
3951   ssize_t
3952     quantum;
3953
3954   /*
3955     Simulate a Polaroid picture.
3956   */
3957   assert(image != (Image *) NULL);
3958   assert(image->signature == MagickSignature);
3959   if (image->debug != MagickFalse)
3960     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3961   assert(exception != (ExceptionInfo *) NULL);
3962   assert(exception->signature == MagickSignature);
3963   quantum=(ssize_t) MagickMax(MagickMax((double) image->columns,(double)
3964     image->rows)/25.0,10.0);
3965   height=image->rows+2*quantum;
3966   caption_image=(Image *) NULL;
3967   if (caption != (const char *) NULL)
3968     {
3969       char
3970         geometry[MaxTextExtent],
3971         *text;
3972
3973       DrawInfo
3974         *annotate_info;
3975
3976       MagickBooleanType
3977         status;
3978
3979       ssize_t
3980         count;
3981
3982       TypeMetric
3983         metrics;
3984
3985       /*
3986         Generate caption image.
3987       */
3988       caption_image=CloneImage(image,image->columns,1,MagickTrue,exception);
3989       if (caption_image == (Image *) NULL)
3990         return((Image *) NULL);
3991       annotate_info=CloneDrawInfo((const ImageInfo *) NULL,draw_info);
3992       text=InterpretImageProperties((ImageInfo *) NULL,(Image *) image,caption,
3993         exception);
3994       (void) CloneString(&annotate_info->text,text);
3995       count=FormatMagickCaption(caption_image,annotate_info,MagickTrue,&metrics,
3996         &text,exception);
3997       status=SetImageExtent(caption_image,image->columns,(size_t) ((count+1)*
3998         (metrics.ascent-metrics.descent)+0.5),exception);
3999       if (status == MagickFalse)
4000         caption_image=DestroyImage(caption_image);
4001       else
4002         {
4003           caption_image->background_color=image->border_color;
4004           (void) SetImageBackgroundColor(caption_image,exception);
4005           (void) CloneString(&annotate_info->text,text);
4006           (void) FormatLocaleString(geometry,MaxTextExtent,"+0+%g",
4007             metrics.ascent);
4008           if (annotate_info->gravity == UndefinedGravity)
4009             (void) CloneString(&annotate_info->geometry,AcquireString(
4010               geometry));
4011           (void) AnnotateImage(caption_image,annotate_info,exception);
4012           height+=caption_image->rows;
4013         }
4014       annotate_info=DestroyDrawInfo(annotate_info);
4015       text=DestroyString(text);
4016     }
4017   picture_image=CloneImage(image,image->columns+2*quantum,height,MagickTrue,
4018     exception);
4019   if (picture_image == (Image *) NULL)
4020     {
4021       if (caption_image != (Image *) NULL)
4022         caption_image=DestroyImage(caption_image);
4023       return((Image *) NULL);
4024     }
4025   picture_image->background_color=image->border_color;
4026   (void) SetImageBackgroundColor(picture_image,exception);
4027   (void) CompositeImage(picture_image,image,OverCompositeOp,MagickTrue,quantum,
4028     quantum,exception);
4029   if (caption_image != (Image *) NULL)
4030     {
4031       (void) CompositeImage(picture_image,caption_image,OverCompositeOp,
4032         MagickTrue,quantum,(ssize_t) (image->rows+3*quantum/2),exception);
4033       caption_image=DestroyImage(caption_image);
4034     }
4035   (void) QueryColorCompliance("none",AllCompliance,
4036     &picture_image->background_color,exception);
4037   (void) SetImageAlphaChannel(picture_image,OpaqueAlphaChannel,exception);
4038   rotate_image=RotateImage(picture_image,90.0,exception);
4039   picture_image=DestroyImage(picture_image);
4040   if (rotate_image == (Image *) NULL)
4041     return((Image *) NULL);
4042   picture_image=rotate_image;
4043   bend_image=WaveImage(picture_image,0.01*picture_image->rows,2.0*
4044     picture_image->columns,method,exception);
4045   picture_image=DestroyImage(picture_image);
4046   if (bend_image == (Image *) NULL)
4047     return((Image *) NULL);
4048   picture_image=bend_image;
4049   rotate_image=RotateImage(picture_image,-90.0,exception);
4050   picture_image=DestroyImage(picture_image);
4051   if (rotate_image == (Image *) NULL)
4052     return((Image *) NULL);
4053   picture_image=rotate_image;
4054   picture_image->background_color=image->background_color;
4055   polaroid_image=ShadowImage(picture_image,80.0,2.0,quantum/3,quantum/3,
4056     exception);
4057   if (polaroid_image == (Image *) NULL)
4058     {
4059       picture_image=DestroyImage(picture_image);
4060       return(picture_image);
4061     }
4062   flop_image=FlopImage(polaroid_image,exception);
4063   polaroid_image=DestroyImage(polaroid_image);
4064   if (flop_image == (Image *) NULL)
4065     {
4066       picture_image=DestroyImage(picture_image);
4067       return(picture_image);
4068     }
4069   polaroid_image=flop_image;
4070   (void) CompositeImage(polaroid_image,picture_image,OverCompositeOp,
4071     MagickTrue,(ssize_t) (-0.01*picture_image->columns/2.0),0L,exception);
4072   picture_image=DestroyImage(picture_image);
4073   (void) QueryColorCompliance("none",AllCompliance,
4074     &polaroid_image->background_color,exception);
4075   rotate_image=RotateImage(polaroid_image,angle,exception);
4076   polaroid_image=DestroyImage(polaroid_image);
4077   if (rotate_image == (Image *) NULL)
4078     return((Image *) NULL);
4079   polaroid_image=rotate_image;
4080   trim_image=TrimImage(polaroid_image,exception);
4081   polaroid_image=DestroyImage(polaroid_image);
4082   if (trim_image == (Image *) NULL)
4083     return((Image *) NULL);
4084   polaroid_image=trim_image;
4085   return(polaroid_image);
4086 }
4087 \f
4088 /*
4089 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4090 %                                                                             %
4091 %                                                                             %
4092 %                                                                             %
4093 %     S e p i a T o n e I m a g e                                             %
4094 %                                                                             %
4095 %                                                                             %
4096 %                                                                             %
4097 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4098 %
4099 %  MagickSepiaToneImage() applies a special effect to the image, similar to the
4100 %  effect achieved in a photo darkroom by sepia toning.  Threshold ranges from
4101 %  0 to QuantumRange and is a measure of the extent of the sepia toning.  A
4102 %  threshold of 80% is a good starting point for a reasonable tone.
4103 %
4104 %  The format of the SepiaToneImage method is:
4105 %
4106 %      Image *SepiaToneImage(const Image *image,const double threshold,
4107 %        ExceptionInfo *exception)
4108 %
4109 %  A description of each parameter follows:
4110 %
4111 %    o image: the image.
4112 %
4113 %    o threshold: the tone threshold.
4114 %
4115 %    o exception: return any errors or warnings in this structure.
4116 %
4117 */
4118 MagickExport Image *SepiaToneImage(const Image *image,const double threshold,
4119   ExceptionInfo *exception)
4120 {
4121 #define SepiaToneImageTag  "SepiaTone/Image"
4122
4123   CacheView
4124     *image_view,
4125     *sepia_view;
4126
4127   Image
4128     *sepia_image;
4129
4130   MagickBooleanType
4131     status;
4132
4133   MagickOffsetType
4134     progress;
4135
4136   ssize_t
4137     y;
4138
4139   /*
4140     Initialize sepia-toned image attributes.
4141   */
4142   assert(image != (const Image *) NULL);
4143   assert(image->signature == MagickSignature);
4144   if (image->debug != MagickFalse)
4145     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4146   assert(exception != (ExceptionInfo *) NULL);
4147   assert(exception->signature == MagickSignature);
4148   sepia_image=CloneImage(image,0,0,MagickTrue,exception);
4149   if (sepia_image == (Image *) NULL)
4150     return((Image *) NULL);
4151   if (SetImageStorageClass(sepia_image,DirectClass,exception) == MagickFalse)
4152     {
4153       sepia_image=DestroyImage(sepia_image);
4154       return((Image *) NULL);
4155     }
4156   /*
4157     Tone each row of the image.
4158   */
4159   status=MagickTrue;
4160   progress=0;
4161   image_view=AcquireVirtualCacheView(image,exception);
4162   sepia_view=AcquireAuthenticCacheView(sepia_image,exception);
4163 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4164   #pragma omp parallel for schedule(static,4) shared(progress,status) \
4165     dynamic_number_threads(image,image->columns,image->rows,1)
4166 #endif
4167   for (y=0; y < (ssize_t) image->rows; y++)
4168   {
4169     register const Quantum
4170       *restrict p;
4171
4172     register ssize_t
4173       x;
4174
4175     register Quantum
4176       *restrict q;
4177
4178     if (status == MagickFalse)
4179       continue;
4180     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
4181     q=GetCacheViewAuthenticPixels(sepia_view,0,y,sepia_image->columns,1,
4182       exception);
4183     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
4184       {
4185         status=MagickFalse;
4186         continue;
4187       }
4188     for (x=0; x < (ssize_t) image->columns; x++)
4189     {
4190       double
4191         intensity,
4192         tone;
4193
4194       intensity=GetPixelIntensity(image,p);
4195       tone=intensity > threshold ? (double) QuantumRange : intensity+
4196         (double) QuantumRange-threshold;
4197       SetPixelRed(sepia_image,ClampToQuantum(tone),q);
4198       tone=intensity > (7.0*threshold/6.0) ? (double) QuantumRange :
4199         intensity+(double) QuantumRange-7.0*threshold/6.0;
4200       SetPixelGreen(sepia_image,ClampToQuantum(tone),q);
4201       tone=intensity < (threshold/6.0) ? 0 : intensity-threshold/6.0;
4202       SetPixelBlue(sepia_image,ClampToQuantum(tone),q);
4203       tone=threshold/7.0;
4204       if ((double) GetPixelGreen(image,q) < tone)
4205         SetPixelGreen(sepia_image,ClampToQuantum(tone),q);
4206       if ((double) GetPixelBlue(image,q) < tone)
4207         SetPixelBlue(sepia_image,ClampToQuantum(tone),q);
4208       p+=GetPixelChannels(image);
4209       q+=GetPixelChannels(sepia_image);
4210     }
4211     if (SyncCacheViewAuthenticPixels(sepia_view,exception) == MagickFalse)
4212       status=MagickFalse;
4213     if (image->progress_monitor != (MagickProgressMonitor) NULL)
4214       {
4215         MagickBooleanType
4216           proceed;
4217
4218 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4219         #pragma omp critical (MagickCore_SepiaToneImage)
4220 #endif
4221         proceed=SetImageProgress(image,SepiaToneImageTag,progress++,
4222           image->rows);
4223         if (proceed == MagickFalse)
4224           status=MagickFalse;
4225       }
4226   }
4227   sepia_view=DestroyCacheView(sepia_view);
4228   image_view=DestroyCacheView(image_view);
4229   (void) NormalizeImage(sepia_image,exception);
4230   (void) ContrastImage(sepia_image,MagickTrue,exception);
4231   if (status == MagickFalse)
4232     sepia_image=DestroyImage(sepia_image);
4233   return(sepia_image);
4234 }
4235 \f
4236 /*
4237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4238 %                                                                             %
4239 %                                                                             %
4240 %                                                                             %
4241 %     S h a d o w I m a g e                                                   %
4242 %                                                                             %
4243 %                                                                             %
4244 %                                                                             %
4245 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4246 %
4247 %  ShadowImage() simulates a shadow from the specified image and returns it.
4248 %
4249 %  The format of the ShadowImage method is:
4250 %
4251 %      Image *ShadowImage(const Image *image,const double alpha,
4252 %        const double sigma,const ssize_t x_offset,const ssize_t y_offset,
4253 %        ExceptionInfo *exception)
4254 %
4255 %  A description of each parameter follows:
4256 %
4257 %    o image: the image.
4258 %
4259 %    o alpha: percentage transparency.
4260 %
4261 %    o sigma: the standard deviation of the Gaussian, in pixels.
4262 %
4263 %    o x_offset: the shadow x-offset.
4264 %
4265 %    o y_offset: the shadow y-offset.
4266 %
4267 %    o exception: return any errors or warnings in this structure.
4268 %
4269 */
4270 MagickExport Image *ShadowImage(const Image *image,const double alpha,
4271   const double sigma,const ssize_t x_offset,const ssize_t y_offset,
4272   ExceptionInfo *exception)
4273 {
4274 #define ShadowImageTag  "Shadow/Image"
4275
4276   CacheView
4277     *image_view;
4278
4279   ChannelType
4280     channel_mask;
4281
4282   Image
4283     *border_image,
4284     *clone_image,
4285     *shadow_image;
4286
4287   MagickBooleanType
4288     status;
4289
4290   RectangleInfo
4291     border_info;
4292
4293   ssize_t
4294     y;
4295
4296   assert(image != (Image *) NULL);
4297   assert(image->signature == MagickSignature);
4298   if (image->debug != MagickFalse)
4299     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4300   assert(exception != (ExceptionInfo *) NULL);
4301   assert(exception->signature == MagickSignature);
4302   clone_image=CloneImage(image,0,0,MagickTrue,exception);
4303   if (clone_image == (Image *) NULL)
4304     return((Image *) NULL);
4305   if (IsGrayColorspace(image->colorspace) != MagickFalse)
4306     (void) TransformImageColorspace(clone_image,RGBColorspace,exception);
4307   (void) SetImageVirtualPixelMethod(clone_image,TransparentVirtualPixelMethod,
4308     exception);
4309   border_info.width=(size_t) floor(2.0*sigma+0.5);
4310   border_info.height=(size_t) floor(2.0*sigma+0.5);
4311   border_info.x=0;
4312   border_info.y=0;
4313   (void) QueryColorCompliance("none",AllCompliance,&clone_image->border_color,
4314     exception);
4315   clone_image->alpha_trait=BlendPixelTrait;
4316   border_image=BorderImage(clone_image,&border_info,OverCompositeOp,exception);
4317   clone_image=DestroyImage(clone_image);
4318   if (border_image == (Image *) NULL)
4319     return((Image *) NULL);
4320   if (border_image->alpha_trait != BlendPixelTrait)
4321     (void) SetImageAlphaChannel(border_image,OpaqueAlphaChannel,exception);
4322   /*
4323     Shadow image.
4324   */
4325   status=MagickTrue;
4326   image_view=AcquireAuthenticCacheView(border_image,exception);
4327   for (y=0; y < (ssize_t) border_image->rows; y++)
4328   {
4329     PixelInfo
4330       background_color;
4331
4332     register Quantum
4333       *restrict q;
4334
4335     register ssize_t
4336       x;
4337
4338     if (status == MagickFalse)
4339       continue;
4340     q=QueueCacheViewAuthenticPixels(image_view,0,y,border_image->columns,1,
4341       exception);
4342     if (q == (Quantum *) NULL)
4343       {
4344         status=MagickFalse;
4345         continue;
4346       }
4347     background_color=border_image->background_color;
4348     background_color.alpha_trait=BlendPixelTrait;
4349     for (x=0; x < (ssize_t) border_image->columns; x++)
4350     {
4351       if (border_image->alpha_trait == BlendPixelTrait)
4352         background_color.alpha=GetPixelAlpha(border_image,q)*alpha/100.0;
4353       SetPixelInfoPixel(border_image,&background_color,q);
4354       q+=GetPixelChannels(border_image);
4355     }
4356     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4357       status=MagickFalse;
4358   }
4359   image_view=DestroyCacheView(image_view);
4360   if (status == MagickFalse)
4361     {
4362       border_image=DestroyImage(border_image);
4363       return((Image *) NULL);
4364     }
4365   channel_mask=SetImageChannelMask(border_image,AlphaChannel);
4366   shadow_image=BlurImage(border_image,0.0,sigma,exception);
4367   border_image=DestroyImage(border_image);
4368   if (shadow_image == (Image *) NULL)
4369     return((Image *) NULL);
4370   (void) SetPixelChannelMask(shadow_image,channel_mask);
4371   if (shadow_image->page.width == 0)
4372     shadow_image->page.width=shadow_image->columns;
4373   if (shadow_image->page.height == 0)
4374     shadow_image->page.height=shadow_image->rows;
4375   shadow_image->page.width+=x_offset-(ssize_t) border_info.width;
4376   shadow_image->page.height+=y_offset-(ssize_t) border_info.height;
4377   shadow_image->page.x+=x_offset-(ssize_t) border_info.width;
4378   shadow_image->page.y+=y_offset-(ssize_t) border_info.height;
4379   return(shadow_image);
4380 }
4381 \f
4382 /*
4383 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4384 %                                                                             %
4385 %                                                                             %
4386 %                                                                             %
4387 %     S k e t c h I m a g e                                                   %
4388 %                                                                             %
4389 %                                                                             %
4390 %                                                                             %
4391 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4392 %
4393 %  SketchImage() simulates a pencil sketch.  We convolve the image with a
4394 %  Gaussian operator of the given radius and standard deviation (sigma).  For
4395 %  reasonable results, radius should be larger than sigma.  Use a radius of 0
4396 %  and SketchImage() selects a suitable radius for you.  Angle gives the angle
4397 %  of the sketch.
4398 %
4399 %  The format of the SketchImage method is:
4400 %
4401 %    Image *SketchImage(const Image *image,const double radius,
4402 %      const double sigma,const double angle,ExceptionInfo *exception)
4403 %
4404 %  A description of each parameter follows:
4405 %
4406 %    o image: the image.
4407 %
4408 %    o radius: the radius of the Gaussian, in pixels, not counting the
4409 %      center pixel.
4410 %
4411 %    o sigma: the standard deviation of the Gaussian, in pixels.
4412 %
4413 %    o angle: apply the effect along this angle.
4414 %
4415 %    o exception: return any errors or warnings in this structure.
4416 %
4417 */
4418 MagickExport Image *SketchImage(const Image *image,const double radius,
4419   const double sigma,const double angle,ExceptionInfo *exception)
4420 {
4421   CacheView
4422     *random_view;
4423
4424   Image
4425     *blend_image,
4426     *blur_image,
4427     *dodge_image,
4428     *random_image,
4429     *sketch_image;
4430
4431   MagickBooleanType
4432     status;
4433
4434   RandomInfo
4435     **restrict random_info;
4436
4437   ssize_t
4438     y;
4439
4440 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4441   unsigned long
4442     key;
4443 #endif
4444
4445   /*
4446     Sketch image.
4447   */
4448   random_image=CloneImage(image,image->columns << 1,image->rows << 1,
4449     MagickTrue,exception);
4450   if (random_image == (Image *) NULL)
4451     return((Image *) NULL);
4452   status=MagickTrue;
4453   random_info=AcquireRandomInfoThreadSet();
4454 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4455   key=GetRandomSecretKey(random_info[0]);
4456 #endif
4457   random_view=AcquireAuthenticCacheView(random_image,exception);
4458 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4459   #pragma omp parallel for schedule(static,4) shared(status) \
4460     dynamic_number_threads(image,image->columns,image->rows,key == ~0UL)
4461 #endif
4462   for (y=0; y < (ssize_t) random_image->rows; y++)
4463   {
4464     const int
4465       id = GetOpenMPThreadId();
4466
4467     register ssize_t
4468       x;
4469
4470     register Quantum
4471       *restrict q;
4472
4473     if (status == MagickFalse)
4474       continue;
4475     q=QueueCacheViewAuthenticPixels(random_view,0,y,random_image->columns,1,
4476       exception);
4477     if (q == (Quantum *) NULL)
4478       {
4479         status=MagickFalse;
4480         continue;
4481       }
4482     for (x=0; x < (ssize_t) random_image->columns; x++)
4483     {
4484       double
4485         value;
4486
4487       register ssize_t
4488         i;
4489
4490       if (GetPixelMask(random_image,q) != 0)
4491         {
4492           q+=GetPixelChannels(random_image);
4493           continue;
4494         }
4495       value=GetPseudoRandomValue(random_info[id]);
4496       for (i=0; i < (ssize_t) GetPixelChannels(random_image); i++)
4497       {
4498         PixelChannel
4499           channel;
4500
4501         PixelTrait
4502           traits;
4503
4504         channel=GetPixelChannelChannel(image,i);
4505         traits=GetPixelChannelTraits(image,channel);
4506         if (traits == UndefinedPixelTrait)
4507           continue;
4508         q[i]=ClampToQuantum(QuantumRange*value);
4509       }
4510       q+=GetPixelChannels(random_image);
4511     }
4512     if (SyncCacheViewAuthenticPixels(random_view,exception) == MagickFalse)
4513       status=MagickFalse;
4514   }
4515   random_view=DestroyCacheView(random_view);
4516   random_info=DestroyRandomInfoThreadSet(random_info);
4517   if (status == MagickFalse)
4518     {
4519       random_image=DestroyImage(random_image);
4520       return(random_image);
4521     }
4522   blur_image=MotionBlurImage(random_image,radius,sigma,angle,exception);
4523   random_image=DestroyImage(random_image);
4524   if (blur_image == (Image *) NULL)
4525     return((Image *) NULL);
4526   dodge_image=EdgeImage(blur_image,radius,1.0,exception);
4527   blur_image=DestroyImage(blur_image);
4528   if (dodge_image == (Image *) NULL)
4529     return((Image *) NULL);
4530   (void) NormalizeImage(dodge_image,exception);
4531   (void) NegateImage(dodge_image,MagickFalse,exception);
4532   (void) TransformImage(&dodge_image,(char *) NULL,"50%",exception);
4533   sketch_image=CloneImage(image,0,0,MagickTrue,exception);
4534   if (sketch_image == (Image *) NULL)
4535     {
4536       dodge_image=DestroyImage(dodge_image);
4537       return((Image *) NULL);
4538     }
4539   (void) CompositeImage(sketch_image,dodge_image,ColorDodgeCompositeOp,
4540     MagickTrue,0,0,exception);
4541   dodge_image=DestroyImage(dodge_image);
4542   blend_image=CloneImage(image,0,0,MagickTrue,exception);
4543   if (blend_image == (Image *) NULL)
4544     {
4545       sketch_image=DestroyImage(sketch_image);
4546       return((Image *) NULL);
4547     }
4548   (void) SetImageArtifact(blend_image,"compose:args","20x80");
4549   (void) CompositeImage(sketch_image,blend_image,BlendCompositeOp,MagickTrue,
4550     0,0,exception);
4551   blend_image=DestroyImage(blend_image);
4552   return(sketch_image);
4553 }
4554 \f
4555 /*
4556 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4557 %                                                                             %
4558 %                                                                             %
4559 %                                                                             %
4560 %     S o l a r i z e I m a g e                                               %
4561 %                                                                             %
4562 %                                                                             %
4563 %                                                                             %
4564 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4565 %
4566 %  SolarizeImage() applies a special effect to the image, similar to the effect
4567 %  achieved in a photo darkroom by selectively exposing areas of photo
4568 %  sensitive paper to light.  Threshold ranges from 0 to QuantumRange and is a
4569 %  measure of the extent of the solarization.
4570 %
4571 %  The format of the SolarizeImage method is:
4572 %
4573 %      MagickBooleanType SolarizeImage(Image *image,const double threshold,
4574 %        ExceptionInfo *exception)
4575 %
4576 %  A description of each parameter follows:
4577 %
4578 %    o image: the image.
4579 %
4580 %    o threshold:  Define the extent of the solarization.
4581 %
4582 %    o exception: return any errors or warnings in this structure.
4583 %
4584 */
4585 MagickExport MagickBooleanType SolarizeImage(Image *image,
4586   const double threshold,ExceptionInfo *exception)
4587 {
4588 #define SolarizeImageTag  "Solarize/Image"
4589
4590   CacheView
4591     *image_view;
4592
4593   MagickBooleanType
4594     status;
4595
4596   MagickOffsetType
4597     progress;
4598
4599   ssize_t
4600     y;
4601
4602   assert(image != (Image *) NULL);
4603   assert(image->signature == MagickSignature);
4604   if (image->debug != MagickFalse)
4605     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4606   if (image->storage_class == PseudoClass)
4607     {
4608       register ssize_t
4609         i;
4610
4611       /*
4612         Solarize colormap.
4613       */
4614       for (i=0; i < (ssize_t) image->colors; i++)
4615       {
4616         if ((double) image->colormap[i].red > threshold)
4617           image->colormap[i].red=QuantumRange-image->colormap[i].red;
4618         if ((double) image->colormap[i].green > threshold)
4619           image->colormap[i].green=QuantumRange-
4620             image->colormap[i].green;
4621         if ((double) image->colormap[i].blue > threshold)
4622           image->colormap[i].blue=QuantumRange-
4623             image->colormap[i].blue;
4624       }
4625     }
4626   /*
4627     Solarize image.
4628   */
4629   status=MagickTrue;
4630   progress=0;
4631   image_view=AcquireAuthenticCacheView(image,exception);
4632 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4633   #pragma omp parallel for schedule(static,4) shared(progress,status) \
4634     dynamic_number_threads(image,image->columns,image->rows,1)
4635 #endif
4636   for (y=0; y < (ssize_t) image->rows; y++)
4637   {
4638     register ssize_t
4639       x;
4640
4641     register Quantum
4642       *restrict q;
4643
4644     if (status == MagickFalse)
4645       continue;
4646     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4647     if (q == (Quantum *) NULL)
4648       {
4649         status=MagickFalse;
4650         continue;
4651       }
4652     for (x=0; x < (ssize_t) image->columns; x++)
4653     {
4654       register ssize_t
4655         i;
4656
4657       if (GetPixelMask(image,q) != 0)
4658         {
4659           q+=GetPixelChannels(image);
4660           continue;
4661         }
4662       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4663       {
4664         PixelChannel
4665           channel;
4666
4667         PixelTrait
4668           traits;
4669
4670         channel=GetPixelChannelChannel(image,i);
4671         traits=GetPixelChannelTraits(image,channel);
4672         if ((traits == UndefinedPixelTrait) ||
4673             ((traits & CopyPixelTrait) != 0))
4674           continue;
4675         if ((double) q[i] > threshold)
4676           q[i]=QuantumRange-q[i];
4677       }
4678       q+=GetPixelChannels(image);
4679     }
4680     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4681       status=MagickFalse;
4682     if (image->progress_monitor != (MagickProgressMonitor) NULL)
4683       {
4684         MagickBooleanType
4685           proceed;
4686
4687 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4688         #pragma omp critical (MagickCore_SolarizeImage)
4689 #endif
4690         proceed=SetImageProgress(image,SolarizeImageTag,progress++,image->rows);
4691         if (proceed == MagickFalse)
4692           status=MagickFalse;
4693       }
4694   }
4695   image_view=DestroyCacheView(image_view);
4696   return(status);
4697 }
4698 \f
4699 /*
4700 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4701 %                                                                             %
4702 %                                                                             %
4703 %                                                                             %
4704 %   S t e g a n o I m a g e                                                   %
4705 %                                                                             %
4706 %                                                                             %
4707 %                                                                             %
4708 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4709 %
4710 %  SteganoImage() hides a digital watermark within the image.  Recover
4711 %  the hidden watermark later to prove that the authenticity of an image.
4712 %  Offset defines the start position within the image to hide the watermark.
4713 %
4714 %  The format of the SteganoImage method is:
4715 %
4716 %      Image *SteganoImage(const Image *image,Image *watermark,
4717 %        ExceptionInfo *exception)
4718 %
4719 %  A description of each parameter follows:
4720 %
4721 %    o image: the image.
4722 %
4723 %    o watermark: the watermark image.
4724 %
4725 %    o exception: return any errors or warnings in this structure.
4726 %
4727 */
4728 MagickExport Image *SteganoImage(const Image *image,const Image *watermark,
4729   ExceptionInfo *exception)
4730 {
4731 #define GetBit(alpha,i) ((((size_t) (alpha) >> (size_t) (i)) & 0x01) != 0)
4732 #define SetBit(alpha,i,set) (Quantum) ((set) != 0 ? (size_t) (alpha) \
4733   | (one << (size_t) (i)) : (size_t) (alpha) & ~(one << (size_t) (i)))
4734 #define SteganoImageTag  "Stegano/Image"
4735
4736   CacheView
4737     *stegano_view,
4738     *watermark_view;
4739
4740   Image
4741     *stegano_image;
4742
4743   int
4744     c;
4745
4746   MagickBooleanType
4747     status;
4748
4749   PixelInfo
4750     pixel;
4751
4752   register Quantum
4753     *q;
4754
4755   register ssize_t
4756     x;
4757
4758   size_t
4759     depth,
4760     one;
4761
4762   ssize_t
4763     i,
4764     j,
4765     k,
4766     y;
4767
4768   /*
4769     Initialize steganographic image attributes.
4770   */
4771   assert(image != (const Image *) NULL);
4772   assert(image->signature == MagickSignature);
4773   if (image->debug != MagickFalse)
4774     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4775   assert(watermark != (const Image *) NULL);
4776   assert(watermark->signature == MagickSignature);
4777   assert(exception != (ExceptionInfo *) NULL);
4778   assert(exception->signature == MagickSignature);
4779   one=1UL;
4780   stegano_image=CloneImage(image,0,0,MagickTrue,exception);
4781   if (stegano_image == (Image *) NULL)
4782     return((Image *) NULL);
4783   stegano_image->depth=MAGICKCORE_QUANTUM_DEPTH;
4784   if (SetImageStorageClass(stegano_image,DirectClass,exception) == MagickFalse)
4785     {
4786       stegano_image=DestroyImage(stegano_image);
4787       return((Image *) NULL);
4788     }
4789   /*
4790     Hide watermark in low-order bits of image.
4791   */
4792   c=0;
4793   i=0;
4794   j=0;
4795   depth=stegano_image->depth;
4796   k=stegano_image->offset;
4797   status=MagickTrue;
4798   watermark_view=AcquireVirtualCacheView(watermark,exception);
4799   stegano_view=AcquireAuthenticCacheView(stegano_image,exception);
4800   for (i=(ssize_t) depth-1; (i >= 0) && (j < (ssize_t) depth); i--)
4801   {
4802     for (y=0; (y < (ssize_t) watermark->rows) && (j < (ssize_t) depth); y++)
4803     {
4804       for (x=0; (x < (ssize_t) watermark->columns) && (j < (ssize_t) depth); x++)
4805       {
4806         ssize_t
4807           offset;
4808
4809         (void) GetOneCacheViewVirtualPixelInfo(watermark_view,x,y,&pixel,
4810           exception);
4811         offset=k/(ssize_t) stegano_image->columns;
4812         if (offset >= (ssize_t) stegano_image->rows)
4813           break;
4814         q=GetCacheViewAuthenticPixels(stegano_view,k % (ssize_t)
4815           stegano_image->columns,k/(ssize_t) stegano_image->columns,1,1,
4816           exception);
4817         if (q == (Quantum *) NULL)
4818           break;
4819         switch (c)
4820         {
4821           case 0:
4822           {
4823             SetPixelRed(stegano_image,SetBit(GetPixelRed(stegano_image,q),j,
4824               GetBit(GetPixelInfoIntensity(&pixel),i)),q);
4825             break;
4826           }
4827           case 1:
4828           {
4829             SetPixelGreen(stegano_image,SetBit(GetPixelGreen(stegano_image,q),j,
4830               GetBit(GetPixelInfoIntensity(&pixel),i)),q);
4831             break;
4832           }
4833           case 2:
4834           {
4835             SetPixelBlue(stegano_image,SetBit(GetPixelBlue(stegano_image,q),j,
4836               GetBit(GetPixelInfoIntensity(&pixel),i)),q);
4837             break;
4838           }
4839         }
4840         if (SyncCacheViewAuthenticPixels(stegano_view,exception) == MagickFalse)
4841           break;
4842         c++;
4843         if (c == 3)
4844           c=0;
4845         k++;
4846         if (k == (ssize_t) (stegano_image->columns*stegano_image->columns))
4847           k=0;
4848         if (k == stegano_image->offset)
4849           j++;
4850       }
4851     }
4852     if (image->progress_monitor != (MagickProgressMonitor) NULL)
4853       {
4854         MagickBooleanType
4855           proceed;
4856
4857         proceed=SetImageProgress(image,SteganoImageTag,(MagickOffsetType)
4858           (depth-i),depth);
4859         if (proceed == MagickFalse)
4860           status=MagickFalse;
4861       }
4862   }
4863   stegano_view=DestroyCacheView(stegano_view);
4864   watermark_view=DestroyCacheView(watermark_view);
4865   if (status == MagickFalse)
4866     {
4867       stegano_image=DestroyImage(stegano_image);
4868       return((Image *) NULL);
4869     }
4870   return(stegano_image);
4871 }
4872 \f
4873 /*
4874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4875 %                                                                             %
4876 %                                                                             %
4877 %                                                                             %
4878 %   S t e r e o A n a g l y p h I m a g e                                     %
4879 %                                                                             %
4880 %                                                                             %
4881 %                                                                             %
4882 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4883 %
4884 %  StereoAnaglyphImage() combines two images and produces a single image that
4885 %  is the composite of a left and right image of a stereo pair.  Special
4886 %  red-green stereo glasses are required to view this effect.
4887 %
4888 %  The format of the StereoAnaglyphImage method is:
4889 %
4890 %      Image *StereoImage(const Image *left_image,const Image *right_image,
4891 %        ExceptionInfo *exception)
4892 %      Image *StereoAnaglyphImage(const Image *left_image,
4893 %        const Image *right_image,const ssize_t x_offset,const ssize_t y_offset,
4894 %        ExceptionInfo *exception)
4895 %
4896 %  A description of each parameter follows:
4897 %
4898 %    o left_image: the left image.
4899 %
4900 %    o right_image: the right image.
4901 %
4902 %    o exception: return any errors or warnings in this structure.
4903 %
4904 %    o x_offset: amount, in pixels, by which the left image is offset to the
4905 %      right of the right image.
4906 %
4907 %    o y_offset: amount, in pixels, by which the left image is offset to the
4908 %      bottom of the right image.
4909 %
4910 %
4911 */
4912 MagickExport Image *StereoImage(const Image *left_image,
4913   const Image *right_image,ExceptionInfo *exception)
4914 {
4915   return(StereoAnaglyphImage(left_image,right_image,0,0,exception));
4916 }
4917
4918 MagickExport Image *StereoAnaglyphImage(const Image *left_image,
4919   const Image *right_image,const ssize_t x_offset,const ssize_t y_offset,
4920   ExceptionInfo *exception)
4921 {
4922 #define StereoImageTag  "Stereo/Image"
4923
4924   const Image
4925     *image;
4926
4927   Image
4928     *stereo_image;
4929
4930   MagickBooleanType
4931     status;
4932
4933   ssize_t
4934     y;
4935
4936   assert(left_image != (const Image *) NULL);
4937   assert(left_image->signature == MagickSignature);
4938   if (left_image->debug != MagickFalse)
4939     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4940       left_image->filename);
4941   assert(right_image != (const Image *) NULL);
4942   assert(right_image->signature == MagickSignature);
4943   assert(exception != (ExceptionInfo *) NULL);
4944   assert(exception->signature == MagickSignature);
4945   assert(right_image != (const Image *) NULL);
4946   image=left_image;
4947   if ((left_image->columns != right_image->columns) ||
4948       (left_image->rows != right_image->rows))
4949     ThrowImageException(ImageError,"LeftAndRightImageSizesDiffer");
4950   /*
4951     Initialize stereo image attributes.
4952   */
4953   stereo_image=CloneImage(left_image,left_image->columns,left_image->rows,
4954     MagickTrue,exception);
4955   if (stereo_image == (Image *) NULL)
4956     return((Image *) NULL);
4957   if (SetImageStorageClass(stereo_image,DirectClass,exception) == MagickFalse)
4958     {
4959       stereo_image=DestroyImage(stereo_image);
4960       return((Image *) NULL);
4961     }
4962   (void) SetImageColorspace(stereo_image,sRGBColorspace,exception);
4963   /*
4964     Copy left image to red channel and right image to blue channel.
4965   */
4966   status=MagickTrue;
4967   for (y=0; y < (ssize_t) stereo_image->rows; y++)
4968   {
4969     register const Quantum
4970       *restrict p,
4971       *restrict q;
4972
4973     register ssize_t
4974       x;
4975
4976     register Quantum
4977       *restrict r;
4978
4979     p=GetVirtualPixels(left_image,-x_offset,y-y_offset,image->columns,1,
4980       exception);
4981     q=GetVirtualPixels(right_image,0,y,right_image->columns,1,exception);
4982     r=QueueAuthenticPixels(stereo_image,0,y,stereo_image->columns,1,exception);
4983     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL) ||
4984         (r == (Quantum *) NULL))
4985       break;
4986     for (x=0; x < (ssize_t) stereo_image->columns; x++)
4987     {
4988       SetPixelRed(image,GetPixelRed(left_image,p),r);
4989       SetPixelGreen(image,GetPixelGreen(right_image,q),r);
4990       SetPixelBlue(image,GetPixelBlue(right_image,q),r);
4991       if ((GetPixelAlphaTraits(stereo_image) & CopyPixelTrait) != 0)
4992         SetPixelAlpha(image,(GetPixelAlpha(left_image,p)+
4993           GetPixelAlpha(right_image,q))/2,r);
4994       p+=GetPixelChannels(left_image);
4995       q+=GetPixelChannels(right_image);
4996       r+=GetPixelChannels(stereo_image);
4997     }
4998     if (SyncAuthenticPixels(stereo_image,exception) == MagickFalse)
4999       break;
5000     if (image->progress_monitor != (MagickProgressMonitor) NULL)
5001       {
5002         MagickBooleanType
5003           proceed;
5004
5005         proceed=SetImageProgress(image,StereoImageTag,(MagickOffsetType) y,
5006           stereo_image->rows);
5007         if (proceed == MagickFalse)
5008           status=MagickFalse;
5009       }
5010   }
5011   if (status == MagickFalse)
5012     {
5013       stereo_image=DestroyImage(stereo_image);
5014       return((Image *) NULL);
5015     }
5016   return(stereo_image);
5017 }
5018 \f
5019 /*
5020 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5021 %                                                                             %
5022 %                                                                             %
5023 %                                                                             %
5024 %     S w i r l I m a g e                                                     %
5025 %                                                                             %
5026 %                                                                             %
5027 %                                                                             %
5028 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5029 %
5030 %  SwirlImage() swirls the pixels about the center of the image, where
5031 %  degrees indicates the sweep of the arc through which each pixel is moved.
5032 %  You get a more dramatic effect as the degrees move from 1 to 360.
5033 %
5034 %  The format of the SwirlImage method is:
5035 %
5036 %      Image *SwirlImage(const Image *image,double degrees,
5037 %        const PixelInterpolateMethod method,ExceptionInfo *exception)
5038 %
5039 %  A description of each parameter follows:
5040 %
5041 %    o image: the image.
5042 %
5043 %    o degrees: Define the tightness of the swirling effect.
5044 %
5045 %    o method: the pixel interpolation method.
5046 %
5047 %    o exception: return any errors or warnings in this structure.
5048 %
5049 */
5050 MagickExport Image *SwirlImage(const Image *image,double degrees,
5051   const PixelInterpolateMethod method,ExceptionInfo *exception)
5052 {
5053 #define SwirlImageTag  "Swirl/Image"
5054
5055   CacheView
5056     *image_view,
5057     *swirl_view;
5058
5059   Image
5060     *swirl_image;
5061
5062   MagickBooleanType
5063     status;
5064
5065   MagickOffsetType
5066     progress;
5067
5068   double
5069     radius;
5070
5071   PointInfo
5072     center,
5073     scale;
5074
5075   ssize_t
5076     y;
5077
5078   /*
5079     Initialize swirl image attributes.
5080   */
5081   assert(image != (const Image *) NULL);
5082   assert(image->signature == MagickSignature);
5083   if (image->debug != MagickFalse)
5084     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5085   assert(exception != (ExceptionInfo *) NULL);
5086   assert(exception->signature == MagickSignature);
5087   swirl_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
5088   if (swirl_image == (Image *) NULL)
5089     return((Image *) NULL);
5090   if (SetImageStorageClass(swirl_image,DirectClass,exception) == MagickFalse)
5091     {
5092       swirl_image=DestroyImage(swirl_image);
5093       return((Image *) NULL);
5094     }
5095   if (swirl_image->background_color.alpha != OpaqueAlpha)
5096     swirl_image->alpha_trait=BlendPixelTrait;
5097   /*
5098     Compute scaling factor.
5099   */
5100   center.x=(double) image->columns/2.0;
5101   center.y=(double) image->rows/2.0;
5102   radius=MagickMax(center.x,center.y);
5103   scale.x=1.0;
5104   scale.y=1.0;
5105   if (image->columns > image->rows)
5106     scale.y=(double) image->columns/(double) image->rows;
5107   else
5108     if (image->columns < image->rows)
5109       scale.x=(double) image->rows/(double) image->columns;
5110   degrees=(double) DegreesToRadians(degrees);
5111   /*
5112     Swirl image.
5113   */
5114   status=MagickTrue;
5115   progress=0;
5116   image_view=AcquireVirtualCacheView(image,exception);
5117   swirl_view=AcquireAuthenticCacheView(swirl_image,exception);
5118 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5119   #pragma omp parallel for schedule(static,4) shared(progress,status) \
5120     dynamic_number_threads(image,image->columns,image->rows,1)
5121 #endif
5122   for (y=0; y < (ssize_t) image->rows; y++)
5123   {
5124     double
5125       distance;
5126
5127     PointInfo
5128       delta;
5129
5130     register const Quantum
5131       *restrict p;
5132
5133     register ssize_t
5134       x;
5135
5136     register Quantum
5137       *restrict q;
5138
5139     if (status == MagickFalse)
5140       continue;
5141     p=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
5142     q=QueueCacheViewAuthenticPixels(swirl_view,0,y,swirl_image->columns,1,
5143       exception);
5144     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
5145       {
5146         status=MagickFalse;
5147         continue;
5148       }
5149     delta.y=scale.y*(double) (y-center.y);
5150     for (x=0; x < (ssize_t) image->columns; x++)
5151     {
5152       /*
5153         Determine if the pixel is within an ellipse.
5154       */
5155       if (GetPixelMask(image,p) != 0)
5156         {
5157           p+=GetPixelChannels(image);
5158           q+=GetPixelChannels(swirl_image);
5159           continue;
5160         }
5161       delta.x=scale.x*(double) (x-center.x);
5162       distance=delta.x*delta.x+delta.y*delta.y;
5163       if (distance >= (radius*radius))
5164         {
5165           register ssize_t
5166             i;
5167
5168           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
5169           {
5170             PixelChannel
5171               channel;
5172
5173             PixelTrait
5174               swirl_traits,
5175               traits;
5176
5177             channel=GetPixelChannelChannel(image,i);
5178             traits=GetPixelChannelTraits(image,channel);
5179             swirl_traits=GetPixelChannelTraits(swirl_image,channel);
5180             if ((traits == UndefinedPixelTrait) ||
5181                 (swirl_traits == UndefinedPixelTrait))
5182               continue;
5183             SetPixelChannel(swirl_image,channel,p[i],q);
5184           }
5185         }
5186       else
5187         {
5188           double
5189             cosine,
5190             factor,
5191             sine;
5192
5193           /*
5194             Swirl the pixel.
5195           */
5196           factor=1.0-sqrt((double) distance)/radius;
5197           sine=sin((double) (degrees*factor*factor));
5198           cosine=cos((double) (degrees*factor*factor));
5199           status=InterpolatePixelChannels(image,image_view,swirl_image,method,
5200             ((cosine*delta.x-sine*delta.y)/scale.x+center.x),(double)
5201             ((sine*delta.x+cosine*delta.y)/scale.y+center.y),q,exception);
5202         }
5203       p+=GetPixelChannels(image);
5204       q+=GetPixelChannels(swirl_image);
5205     }
5206     if (SyncCacheViewAuthenticPixels(swirl_view,exception) == MagickFalse)
5207       status=MagickFalse;
5208     if (image->progress_monitor != (MagickProgressMonitor) NULL)
5209       {
5210         MagickBooleanType
5211           proceed;
5212
5213 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5214         #pragma omp critical (MagickCore_SwirlImage)
5215 #endif
5216         proceed=SetImageProgress(image,SwirlImageTag,progress++,image->rows);
5217         if (proceed == MagickFalse)
5218           status=MagickFalse;
5219       }
5220   }
5221   swirl_view=DestroyCacheView(swirl_view);
5222   image_view=DestroyCacheView(image_view);
5223   if (status == MagickFalse)
5224     swirl_image=DestroyImage(swirl_image);
5225   return(swirl_image);
5226 }
5227 \f
5228 /*
5229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5230 %                                                                             %
5231 %                                                                             %
5232 %                                                                             %
5233 %     T i n t I m a g e                                                       %
5234 %                                                                             %
5235 %                                                                             %
5236 %                                                                             %
5237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5238 %
5239 %  TintImage() applies a color vector to each pixel in the image.  The length
5240 %  of the vector is 0 for black and white and at its maximum for the midtones.
5241 %  The vector weighting function is f(x)=(1-(4.0*((x-0.5)*(x-0.5))))
5242 %
5243 %  The format of the TintImage method is:
5244 %
5245 %      Image *TintImage(const Image *image,const char *blend,
5246 %        const PixelInfo *tint,ExceptionInfo *exception)
5247 %
5248 %  A description of each parameter follows:
5249 %
5250 %    o image: the image.
5251 %
5252 %    o blend: A color value used for tinting.
5253 %
5254 %    o tint: A color value used for tinting.
5255 %
5256 %    o exception: return any errors or warnings in this structure.
5257 %
5258 */
5259 MagickExport Image *TintImage(const Image *image,const char *blend,
5260   const PixelInfo *tint,ExceptionInfo *exception)
5261 {
5262 #define TintImageTag  "Tint/Image"
5263
5264   CacheView
5265     *image_view,
5266     *tint_view;
5267
5268   GeometryInfo
5269     geometry_info;
5270
5271   Image
5272     *tint_image;
5273
5274   MagickBooleanType
5275     status;
5276
5277   MagickOffsetType
5278     progress;
5279
5280   double
5281     intensity;
5282
5283   PixelInfo
5284     color_vector;
5285
5286   MagickStatusType
5287     flags;
5288
5289   ssize_t
5290     y;
5291
5292   /*
5293     Allocate tint image.
5294   */
5295   assert(image != (const Image *) NULL);
5296   assert(image->signature == MagickSignature);
5297   if (image->debug != MagickFalse)
5298     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5299   assert(exception != (ExceptionInfo *) NULL);
5300   assert(exception->signature == MagickSignature);
5301   tint_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
5302   if (tint_image == (Image *) NULL)
5303     return((Image *) NULL);
5304   if (SetImageStorageClass(tint_image,DirectClass,exception) == MagickFalse)
5305     {
5306       tint_image=DestroyImage(tint_image);
5307       return((Image *) NULL);
5308     }
5309   if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
5310       (IsPixelInfoGray(tint) == MagickFalse))
5311     (void) SetImageColorspace(tint_image,RGBColorspace,exception);
5312   if (blend == (const char *) NULL)
5313     return(tint_image);
5314   /*
5315     Determine RGB values of the color.
5316   */
5317   GetPixelInfo(image,&color_vector);
5318   flags=ParseGeometry(blend,&geometry_info);
5319   color_vector.red=geometry_info.rho;
5320   color_vector.green=geometry_info.rho;
5321   color_vector.blue=geometry_info.rho;
5322   color_vector.alpha=OpaqueAlpha;
5323   if ((flags & SigmaValue) != 0)
5324     color_vector.green=geometry_info.sigma;
5325   if ((flags & XiValue) != 0)
5326     color_vector.blue=geometry_info.xi;
5327   if ((flags & PsiValue) != 0)
5328     color_vector.alpha=geometry_info.psi;
5329   if (image->colorspace == CMYKColorspace)
5330     {
5331       color_vector.black=geometry_info.rho;
5332       if ((flags & PsiValue) != 0)
5333         color_vector.black=geometry_info.psi;
5334       if ((flags & ChiValue) != 0)
5335         color_vector.alpha=geometry_info.chi;
5336     }
5337   intensity=(double) GetPixelInfoIntensity(tint);
5338   color_vector.red=(double) (color_vector.red*tint->red/100.0-
5339     intensity);
5340   color_vector.green=(double) (color_vector.green*tint->green/100.0-
5341     intensity);
5342   color_vector.blue=(double) (color_vector.blue*tint->blue/100.0-
5343     intensity);
5344   color_vector.black=(double) (color_vector.black*tint->black/100.0-
5345     intensity);
5346   color_vector.alpha=(double) (color_vector.alpha*tint->alpha/100.0-
5347     intensity);
5348   /*
5349     Tint image.
5350   */
5351   status=MagickTrue;
5352   progress=0;
5353   image_view=AcquireVirtualCacheView(image,exception);
5354   tint_view=AcquireAuthenticCacheView(tint_image,exception);
5355 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5356   #pragma omp parallel for schedule(static,4) shared(progress,status) \
5357     dynamic_number_threads(image,image->columns,image->rows,1)
5358 #endif
5359   for (y=0; y < (ssize_t) image->rows; y++)
5360   {
5361     register const Quantum
5362       *restrict p;
5363
5364     register Quantum
5365       *restrict q;
5366
5367     register ssize_t
5368       x;
5369
5370     if (status == MagickFalse)
5371       continue;
5372     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
5373     q=QueueCacheViewAuthenticPixels(tint_view,0,y,tint_image->columns,1,
5374       exception);
5375     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
5376       {
5377         status=MagickFalse;
5378         continue;
5379       }
5380     for (x=0; x < (ssize_t) image->columns; x++)
5381     {
5382       PixelInfo
5383         pixel;
5384
5385       double
5386         weight;
5387
5388       register ssize_t
5389         i;
5390
5391       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
5392       {
5393         PixelChannel
5394           channel;
5395
5396         PixelTrait
5397           tint_traits,
5398           traits;
5399
5400         channel=GetPixelChannelChannel(image,i);
5401         traits=GetPixelChannelTraits(image,channel);
5402         tint_traits=GetPixelChannelTraits(tint_image,channel);
5403         if ((traits == UndefinedPixelTrait) ||
5404             (tint_traits == UndefinedPixelTrait))
5405           continue;
5406         if (((tint_traits & CopyPixelTrait) != 0) ||
5407             (GetPixelMask(image,p) != 0))
5408           {
5409             SetPixelChannel(tint_image,channel,p[i],q);
5410             continue;
5411           }
5412       }
5413       GetPixelInfo(image,&pixel);
5414       weight=QuantumScale*GetPixelRed(image,p)-0.5;
5415       pixel.red=(double) GetPixelRed(image,p)+color_vector.red*(1.0-(4.0*
5416         (weight*weight)));
5417       weight=QuantumScale*GetPixelGreen(image,p)-0.5;
5418       pixel.green=(double) GetPixelGreen(image,p)+color_vector.green*(1.0-(4.0*
5419         (weight*weight)));
5420       weight=QuantumScale*GetPixelBlue(image,p)-0.5;
5421       pixel.blue=(double) GetPixelBlue(image,p)+color_vector.blue*(1.0-(4.0*
5422         (weight*weight)));
5423       weight=QuantumScale*GetPixelBlack(image,p)-0.5;
5424       pixel.black=(double) GetPixelBlack(image,p)+color_vector.black*(1.0-(4.0*
5425         (weight*weight)));
5426       SetPixelInfoPixel(tint_image,&pixel,q);
5427       p+=GetPixelChannels(image);
5428       q+=GetPixelChannels(tint_image);
5429     }
5430     if (SyncCacheViewAuthenticPixels(tint_view,exception) == MagickFalse)
5431       status=MagickFalse;
5432     if (image->progress_monitor != (MagickProgressMonitor) NULL)
5433       {
5434         MagickBooleanType
5435           proceed;
5436
5437 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5438         #pragma omp critical (MagickCore_TintImage)
5439 #endif
5440         proceed=SetImageProgress(image,TintImageTag,progress++,image->rows);
5441         if (proceed == MagickFalse)
5442           status=MagickFalse;
5443       }
5444   }
5445   tint_view=DestroyCacheView(tint_view);
5446   image_view=DestroyCacheView(image_view);
5447   if (status == MagickFalse)
5448     tint_image=DestroyImage(tint_image);
5449   return(tint_image);
5450 }
5451 \f
5452 /*
5453 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5454 %                                                                             %
5455 %                                                                             %
5456 %                                                                             %
5457 %     V i g n e t t e I m a g e                                               %
5458 %                                                                             %
5459 %                                                                             %
5460 %                                                                             %
5461 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5462 %
5463 %  VignetteImage() softens the edges of the image in vignette style.
5464 %
5465 %  The format of the VignetteImage method is:
5466 %
5467 %      Image *VignetteImage(const Image *image,const double radius,
5468 %        const double sigma,const ssize_t x,const ssize_t y,
5469 %        ExceptionInfo *exception)
5470 %
5471 %  A description of each parameter follows:
5472 %
5473 %    o image: the image.
5474 %
5475 %    o radius: the radius of the pixel neighborhood.
5476 %
5477 %    o sigma: the standard deviation of the Gaussian, in pixels.
5478 %
5479 %    o x, y:  Define the x and y ellipse offset.
5480 %
5481 %    o exception: return any errors or warnings in this structure.
5482 %
5483 */
5484 MagickExport Image *VignetteImage(const Image *image,const double radius,
5485   const double sigma,const ssize_t x,const ssize_t y,ExceptionInfo *exception)
5486 {
5487   char
5488     ellipse[MaxTextExtent];
5489
5490   DrawInfo
5491     *draw_info;
5492
5493   Image
5494     *canvas_image,
5495     *blur_image,
5496     *oval_image,
5497     *vignette_image;
5498
5499   assert(image != (Image *) NULL);
5500   assert(image->signature == MagickSignature);
5501   if (image->debug != MagickFalse)
5502     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5503   assert(exception != (ExceptionInfo *) NULL);
5504   assert(exception->signature == MagickSignature);
5505   canvas_image=CloneImage(image,0,0,MagickTrue,exception);
5506   if (canvas_image == (Image *) NULL)
5507     return((Image *) NULL);
5508   if (SetImageStorageClass(canvas_image,DirectClass,exception) == MagickFalse)
5509     {
5510       canvas_image=DestroyImage(canvas_image);
5511       return((Image *) NULL);
5512     }
5513   canvas_image->alpha_trait=BlendPixelTrait;
5514   oval_image=CloneImage(canvas_image,canvas_image->columns,canvas_image->rows,
5515     MagickTrue,exception);
5516   if (oval_image == (Image *) NULL)
5517     {
5518       canvas_image=DestroyImage(canvas_image);
5519       return((Image *) NULL);
5520     }
5521   (void) QueryColorCompliance("#000000",AllCompliance,
5522     &oval_image->background_color,exception);
5523   (void) SetImageBackgroundColor(oval_image,exception);
5524   draw_info=CloneDrawInfo((const ImageInfo *) NULL,(const DrawInfo *) NULL);
5525   (void) QueryColorCompliance("#ffffff",AllCompliance,&draw_info->fill,
5526     exception);
5527   (void) QueryColorCompliance("#ffffff",AllCompliance,&draw_info->stroke,
5528     exception);
5529   (void) FormatLocaleString(ellipse,MaxTextExtent,"ellipse %g,%g,%g,%g,"
5530     "0.0,360.0",image->columns/2.0,image->rows/2.0,image->columns/2.0-x,
5531     image->rows/2.0-y);
5532   draw_info->primitive=AcquireString(ellipse);
5533   (void) DrawImage(oval_image,draw_info,exception);
5534   draw_info=DestroyDrawInfo(draw_info);
5535   blur_image=BlurImage(oval_image,radius,sigma,exception);
5536   oval_image=DestroyImage(oval_image);
5537   if (blur_image == (Image *) NULL)
5538     {
5539       canvas_image=DestroyImage(canvas_image);
5540       return((Image *) NULL);
5541     }
5542   blur_image->alpha_trait=UndefinedPixelTrait;
5543   (void) CompositeImage(canvas_image,blur_image,IntensityCompositeOp,MagickTrue,
5544     0,0,exception);
5545   blur_image=DestroyImage(blur_image);
5546   vignette_image=MergeImageLayers(canvas_image,FlattenLayer,exception);
5547   canvas_image=DestroyImage(canvas_image);
5548   if (vignette_image != (Image *) NULL)
5549     (void) TransformImageColorspace(vignette_image,image->colorspace,exception);
5550   return(vignette_image);
5551 }
5552 \f
5553 /*
5554 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5555 %                                                                             %
5556 %                                                                             %
5557 %                                                                             %
5558 %     W a v e I m a g e                                                       %
5559 %                                                                             %
5560 %                                                                             %
5561 %                                                                             %
5562 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5563 %
5564 %  WaveImage() creates a "ripple" effect in the image by shifting the pixels
5565 %  vertically along a sine wave whose amplitude and wavelength is specified
5566 %  by the given parameters.
5567 %
5568 %  The format of the WaveImage method is:
5569 %
5570 %      Image *WaveImage(const Image *image,const double amplitude,
5571 %        const double wave_length,const PixelInterpolateMethod method,
5572 %        ExceptionInfo *exception)
5573 %
5574 %  A description of each parameter follows:
5575 %
5576 %    o image: the image.
5577 %
5578 %    o amplitude, wave_length:  Define the amplitude and wave length of the
5579 %      sine wave.
5580 %
5581 %    o interpolate: the pixel interpolation method.
5582 %
5583 %    o exception: return any errors or warnings in this structure.
5584 %
5585 */
5586 MagickExport Image *WaveImage(const Image *image,const double amplitude,
5587   const double wave_length,const PixelInterpolateMethod method,
5588   ExceptionInfo *exception)
5589 {
5590 #define WaveImageTag  "Wave/Image"
5591
5592   CacheView
5593     *image_view,
5594     *wave_view;
5595
5596   Image
5597     *wave_image;
5598
5599   MagickBooleanType
5600     status;
5601
5602   MagickOffsetType
5603     progress;
5604
5605   double
5606     *sine_map;
5607
5608   register ssize_t
5609     i;
5610
5611   ssize_t
5612     y;
5613
5614   /*
5615     Initialize wave image attributes.
5616   */
5617   assert(image != (Image *) NULL);
5618   assert(image->signature == MagickSignature);
5619   if (image->debug != MagickFalse)
5620     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5621   assert(exception != (ExceptionInfo *) NULL);
5622   assert(exception->signature == MagickSignature);
5623   wave_image=CloneImage(image,image->columns,(size_t) (image->rows+2.0*
5624     fabs(amplitude)),MagickTrue,exception);
5625   if (wave_image == (Image *) NULL)
5626     return((Image *) NULL);
5627   if (SetImageStorageClass(wave_image,DirectClass,exception) == MagickFalse)
5628     {
5629       wave_image=DestroyImage(wave_image);
5630       return((Image *) NULL);
5631     }
5632   if (wave_image->background_color.alpha != OpaqueAlpha)
5633     wave_image->alpha_trait=BlendPixelTrait;
5634   /*
5635     Allocate sine map.
5636   */
5637   sine_map=(double *) AcquireQuantumMemory((size_t) wave_image->columns,
5638     sizeof(*sine_map));
5639   if (sine_map == (double *) NULL)
5640     {
5641       wave_image=DestroyImage(wave_image);
5642       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
5643     }
5644   for (i=0; i < (ssize_t) wave_image->columns; i++)
5645     sine_map[i]=fabs(amplitude)+amplitude*sin((double) ((2.0*MagickPI*i)/
5646       wave_length));
5647   /*
5648     Wave image.
5649   */
5650   status=MagickTrue;
5651   progress=0;
5652   image_view=AcquireVirtualCacheView(image,exception);
5653   wave_view=AcquireAuthenticCacheView(wave_image,exception);
5654   (void) SetCacheViewVirtualPixelMethod(image_view,
5655     BackgroundVirtualPixelMethod);
5656 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5657   #pragma omp parallel for schedule(static,4) shared(progress,status) \
5658     dynamic_number_threads(image,image->columns,image->rows,1)
5659 #endif
5660   for (y=0; y < (ssize_t) wave_image->rows; y++)
5661   {
5662     register Quantum
5663       *restrict q;
5664
5665     register ssize_t
5666       x;
5667
5668     if (status == MagickFalse)
5669       continue;
5670     q=QueueCacheViewAuthenticPixels(wave_view,0,y,wave_image->columns,1,
5671       exception);
5672     if (q == (Quantum *) NULL)
5673       {
5674         status=MagickFalse;
5675         continue;
5676       }
5677     for (x=0; x < (ssize_t) wave_image->columns; x++)
5678     {
5679       status=InterpolatePixelChannels(image,image_view,wave_image,method,
5680         (double) x,(double) (y-sine_map[x]),q,exception);
5681       q+=GetPixelChannels(wave_image);
5682     }
5683     if (SyncCacheViewAuthenticPixels(wave_view,exception) == MagickFalse)
5684       status=MagickFalse;
5685     if (image->progress_monitor != (MagickProgressMonitor) NULL)
5686       {
5687         MagickBooleanType
5688           proceed;
5689
5690 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5691         #pragma omp critical (MagickCore_WaveImage)
5692 #endif
5693         proceed=SetImageProgress(image,WaveImageTag,progress++,image->rows);
5694         if (proceed == MagickFalse)
5695           status=MagickFalse;
5696       }
5697   }
5698   wave_view=DestroyCacheView(wave_view);
5699   image_view=DestroyCacheView(image_view);
5700   sine_map=(double *) RelinquishMagickMemory(sine_map);
5701   if (status == MagickFalse)
5702     wave_image=DestroyImage(wave_image);
5703   return(wave_image);
5704 }