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