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