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