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