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