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