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