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