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