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