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