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