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