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