]> 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->resolution.x);
1760       if (LocaleCompare(symbol,"image.resolution.y") == 0)
1761         return(image->resolution.y);
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->resolution.x);
1844       if (LocaleCompare(symbol,"resolution.y") == 0)
1845         return(image->resolution.y);
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   picture_image=bend_image;
4005   rotate_image=RotateImage(picture_image,-90.0,exception);
4006   picture_image=DestroyImage(picture_image);
4007   if (rotate_image == (Image *) NULL)
4008     return((Image *) NULL);
4009   picture_image=rotate_image;
4010   picture_image->background_color=image->background_color;
4011   polaroid_image=ShadowImage(picture_image,80.0,2.0,quantum/3,quantum/3,
4012     exception);
4013   if (polaroid_image == (Image *) NULL)
4014     {
4015       picture_image=DestroyImage(picture_image);
4016       return(picture_image);
4017     }
4018   flop_image=FlopImage(polaroid_image,exception);
4019   polaroid_image=DestroyImage(polaroid_image);
4020   if (flop_image == (Image *) NULL)
4021     {
4022       picture_image=DestroyImage(picture_image);
4023       return(picture_image);
4024     }
4025   polaroid_image=flop_image;
4026   (void) CompositeImage(polaroid_image,OverCompositeOp,picture_image,
4027     (ssize_t) (-0.01*picture_image->columns/2.0),0L,exception);
4028   picture_image=DestroyImage(picture_image);
4029   (void) QueryColorCompliance("none",AllCompliance,
4030     &polaroid_image->background_color,exception);
4031   rotate_image=RotateImage(polaroid_image,angle,exception);
4032   polaroid_image=DestroyImage(polaroid_image);
4033   if (rotate_image == (Image *) NULL)
4034     return((Image *) NULL);
4035   polaroid_image=rotate_image;
4036   trim_image=TrimImage(polaroid_image,exception);
4037   polaroid_image=DestroyImage(polaroid_image);
4038   if (trim_image == (Image *) NULL)
4039     return((Image *) NULL);
4040   polaroid_image=trim_image;
4041   return(polaroid_image);
4042 }
4043 \f
4044 /*
4045 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4046 %                                                                             %
4047 %                                                                             %
4048 %                                                                             %
4049 %     S e p i a T o n e I m a g e                                             %
4050 %                                                                             %
4051 %                                                                             %
4052 %                                                                             %
4053 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4054 %
4055 %  MagickSepiaToneImage() applies a special effect to the image, similar to the
4056 %  effect achieved in a photo darkroom by sepia toning.  Threshold ranges from
4057 %  0 to QuantumRange and is a measure of the extent of the sepia toning.  A
4058 %  threshold of 80% is a good starting point for a reasonable tone.
4059 %
4060 %  The format of the SepiaToneImage method is:
4061 %
4062 %      Image *SepiaToneImage(const Image *image,const double threshold,
4063 %        ExceptionInfo *exception)
4064 %
4065 %  A description of each parameter follows:
4066 %
4067 %    o image: the image.
4068 %
4069 %    o threshold: the tone threshold.
4070 %
4071 %    o exception: return any errors or warnings in this structure.
4072 %
4073 */
4074 MagickExport Image *SepiaToneImage(const Image *image,const double threshold,
4075   ExceptionInfo *exception)
4076 {
4077 #define SepiaToneImageTag  "SepiaTone/Image"
4078
4079   CacheView
4080     *image_view,
4081     *sepia_view;
4082
4083   Image
4084     *sepia_image;
4085
4086   MagickBooleanType
4087     status;
4088
4089   MagickOffsetType
4090     progress;
4091
4092   ssize_t
4093     y;
4094
4095   /*
4096     Initialize sepia-toned image attributes.
4097   */
4098   assert(image != (const Image *) NULL);
4099   assert(image->signature == MagickSignature);
4100   if (image->debug != MagickFalse)
4101     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4102   assert(exception != (ExceptionInfo *) NULL);
4103   assert(exception->signature == MagickSignature);
4104   sepia_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
4105   if (sepia_image == (Image *) NULL)
4106     return((Image *) NULL);
4107   if (SetImageStorageClass(sepia_image,DirectClass,exception) == MagickFalse)
4108     {
4109       sepia_image=DestroyImage(sepia_image);
4110       return((Image *) NULL);
4111     }
4112   /*
4113     Tone each row of the image.
4114   */
4115   status=MagickTrue;
4116   progress=0;
4117   image_view=AcquireCacheView(image);
4118   sepia_view=AcquireCacheView(sepia_image);
4119 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4120   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
4121 #endif
4122   for (y=0; y < (ssize_t) image->rows; y++)
4123   {
4124     register const Quantum
4125       *restrict p;
4126
4127     register ssize_t
4128       x;
4129
4130     register Quantum
4131       *restrict q;
4132
4133     if (status == MagickFalse)
4134       continue;
4135     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
4136     q=QueueCacheViewAuthenticPixels(sepia_view,0,y,sepia_image->columns,1,
4137       exception);
4138     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
4139       {
4140         status=MagickFalse;
4141         continue;
4142       }
4143     for (x=0; x < (ssize_t) image->columns; x++)
4144     {
4145       MagickRealType
4146         intensity,
4147         tone;
4148
4149       intensity=(MagickRealType) GetPixelIntensity(image,p);
4150       tone=intensity > threshold ? (MagickRealType) QuantumRange : intensity+
4151         (MagickRealType) QuantumRange-threshold;
4152       SetPixelRed(sepia_image,ClampToQuantum(tone),q);
4153       tone=intensity > (7.0*threshold/6.0) ? (MagickRealType) QuantumRange :
4154         intensity+(MagickRealType) QuantumRange-7.0*threshold/6.0;
4155       SetPixelGreen(sepia_image,ClampToQuantum(tone),q);
4156       tone=intensity < (threshold/6.0) ? 0 : intensity-threshold/6.0;
4157       SetPixelBlue(sepia_image,ClampToQuantum(tone),q);
4158       tone=threshold/7.0;
4159       if ((MagickRealType) GetPixelGreen(image,q) < tone)
4160         SetPixelGreen(sepia_image,ClampToQuantum(tone),q);
4161       if ((MagickRealType) GetPixelBlue(image,q) < tone)
4162         SetPixelBlue(sepia_image,ClampToQuantum(tone),q);
4163       p+=GetPixelChannels(image);
4164       q+=GetPixelChannels(sepia_image);
4165     }
4166     if (SyncCacheViewAuthenticPixels(sepia_view,exception) == MagickFalse)
4167       status=MagickFalse;
4168     if (image->progress_monitor != (MagickProgressMonitor) NULL)
4169       {
4170         MagickBooleanType
4171           proceed;
4172
4173 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4174   #pragma omp critical (MagickCore_SepiaToneImage)
4175 #endif
4176         proceed=SetImageProgress(image,SepiaToneImageTag,progress++,
4177           image->rows);
4178         if (proceed == MagickFalse)
4179           status=MagickFalse;
4180       }
4181   }
4182   sepia_view=DestroyCacheView(sepia_view);
4183   image_view=DestroyCacheView(image_view);
4184   (void) NormalizeImage(sepia_image,exception);
4185   (void) ContrastImage(sepia_image,MagickTrue,exception);
4186   if (status == MagickFalse)
4187     sepia_image=DestroyImage(sepia_image);
4188   return(sepia_image);
4189 }
4190 \f
4191 /*
4192 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4193 %                                                                             %
4194 %                                                                             %
4195 %                                                                             %
4196 %     S h a d o w I m a g e                                                   %
4197 %                                                                             %
4198 %                                                                             %
4199 %                                                                             %
4200 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4201 %
4202 %  ShadowImage() simulates a shadow from the specified image and returns it.
4203 %
4204 %  The format of the ShadowImage method is:
4205 %
4206 %      Image *ShadowImage(const Image *image,const double opacity,
4207 %        const double sigma,const ssize_t x_offset,const ssize_t y_offset,
4208 %        ExceptionInfo *exception)
4209 %
4210 %  A description of each parameter follows:
4211 %
4212 %    o image: the image.
4213 %
4214 %    o opacity: percentage transparency.
4215 %
4216 %    o sigma: the standard deviation of the Gaussian, in pixels.
4217 %
4218 %    o x_offset: the shadow x-offset.
4219 %
4220 %    o y_offset: the shadow y-offset.
4221 %
4222 %    o exception: return any errors or warnings in this structure.
4223 %
4224 */
4225 MagickExport Image *ShadowImage(const Image *image,const double opacity,
4226   const double sigma,const ssize_t x_offset,const ssize_t y_offset,
4227   ExceptionInfo *exception)
4228 {
4229 #define ShadowImageTag  "Shadow/Image"
4230
4231   ChannelType
4232     channel_mask;
4233
4234   Image
4235     *border_image,
4236     *clone_image,
4237     *shadow_image;
4238
4239   RectangleInfo
4240     border_info;
4241
4242   assert(image != (Image *) NULL);
4243   assert(image->signature == MagickSignature);
4244   if (image->debug != MagickFalse)
4245     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4246   assert(exception != (ExceptionInfo *) NULL);
4247   assert(exception->signature == MagickSignature);
4248   clone_image=CloneImage(image,0,0,MagickTrue,exception);
4249   if (clone_image == (Image *) NULL)
4250     return((Image *) NULL);
4251   (void) SetImageVirtualPixelMethod(clone_image,EdgeVirtualPixelMethod);
4252   clone_image->compose=OverCompositeOp;
4253   border_info.width=(size_t) floor(2.0*sigma+0.5);
4254   border_info.height=(size_t) floor(2.0*sigma+0.5);
4255   border_info.x=0;
4256   border_info.y=0;
4257   (void) QueryColorCompliance("none",AllCompliance,&clone_image->border_color,
4258     exception);
4259   border_image=BorderImage(clone_image,&border_info,image->compose,exception);
4260   clone_image=DestroyImage(clone_image);
4261   if (border_image == (Image *) NULL)
4262     return((Image *) NULL);
4263   if (border_image->matte == MagickFalse)
4264     (void) SetImageAlphaChannel(border_image,OpaqueAlphaChannel,exception);
4265   /*
4266     Shadow image.
4267   */
4268   (void) SetImageBackgroundColor(border_image,exception);
4269   channel_mask=SetPixelChannelMask(border_image,AlphaChannel);
4270   shadow_image=BlurImage(border_image,0.0,sigma,image->bias,exception);
4271   (void) SetPixelChannelMap(border_image,channel_mask);
4272   border_image=DestroyImage(border_image);
4273   if (shadow_image == (Image *) NULL)
4274     return((Image *) NULL);
4275   if (shadow_image->page.width == 0)
4276     shadow_image->page.width=shadow_image->columns;
4277   if (shadow_image->page.height == 0)
4278     shadow_image->page.height=shadow_image->rows;
4279   shadow_image->page.width+=x_offset-(ssize_t) border_info.width;
4280   shadow_image->page.height+=y_offset-(ssize_t) border_info.height;
4281   shadow_image->page.x+=x_offset-(ssize_t) border_info.width;
4282   shadow_image->page.y+=y_offset-(ssize_t) border_info.height;
4283   return(shadow_image);
4284 }
4285 \f
4286 /*
4287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4288 %                                                                             %
4289 %                                                                             %
4290 %                                                                             %
4291 %     S k e t c h I m a g e                                                   %
4292 %                                                                             %
4293 %                                                                             %
4294 %                                                                             %
4295 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4296 %
4297 %  SketchImage() simulates a pencil sketch.  We convolve the image with a
4298 %  Gaussian operator of the given radius and standard deviation (sigma).  For
4299 %  reasonable results, radius should be larger than sigma.  Use a radius of 0
4300 %  and SketchImage() selects a suitable radius for you.  Angle gives the angle
4301 %  of the sketch.
4302 %
4303 %  The format of the SketchImage method is:
4304 %
4305 %    Image *SketchImage(const Image *image,const double radius,
4306 %      const double sigma,const double angle,const double bias,
4307 %      ExceptionInfo *exception)
4308 %
4309 %  A description of each parameter follows:
4310 %
4311 %    o image: the image.
4312 %
4313 %    o radius: the radius of the Gaussian, in pixels, not counting the
4314 %      center pixel.
4315 %
4316 %    o sigma: the standard deviation of the Gaussian, in pixels.
4317 %
4318 %    o angle: apply the effect along this angle.
4319 %
4320 %    o bias: the bias.
4321 %
4322 %    o exception: return any errors or warnings in this structure.
4323 %
4324 */
4325 MagickExport Image *SketchImage(const Image *image,const double radius,
4326   const double sigma,const double angle,const double bias,
4327   ExceptionInfo *exception)
4328 {
4329   CacheView
4330     *random_view;
4331
4332   Image
4333     *blend_image,
4334     *blur_image,
4335     *dodge_image,
4336     *random_image,
4337     *sketch_image;
4338
4339   MagickBooleanType
4340     status;
4341
4342   RandomInfo
4343     **restrict random_info;
4344
4345   ssize_t
4346     y;
4347
4348   /*
4349     Sketch image.
4350   */
4351   random_image=CloneImage(image,image->columns << 1,image->rows << 1,
4352     MagickTrue,exception);
4353   if (random_image == (Image *) NULL)
4354     return((Image *) NULL);
4355   status=MagickTrue;
4356   random_info=AcquireRandomInfoThreadSet();
4357   random_view=AcquireCacheView(random_image);
4358 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4359   #pragma omp parallel for schedule(dynamic,4) shared(status)
4360 #endif
4361   for (y=0; y < (ssize_t) random_image->rows; y++)
4362   {
4363     const int
4364       id = GetOpenMPThreadId();
4365
4366     register ssize_t
4367       x;
4368
4369     register Quantum
4370       *restrict q;
4371
4372     if (status == MagickFalse)
4373       continue;
4374     q=QueueCacheViewAuthenticPixels(random_view,0,y,random_image->columns,1,
4375       exception);
4376     if (q == (Quantum *) NULL)
4377       {
4378         status=MagickFalse;
4379         continue;
4380       }
4381     for (x=0; x < (ssize_t) random_image->columns; x++)
4382     {
4383       MagickRealType
4384         value;
4385
4386       register ssize_t
4387         i;
4388
4389       value=GetPseudoRandomValue(random_info[id]);
4390       for (i=0; i < (ssize_t) GetPixelChannels(random_image); i++)
4391       {
4392         PixelTrait
4393           traits;
4394
4395         traits=GetPixelChannelMapTraits(random_image,(PixelChannel) i);
4396         if (traits == UndefinedPixelTrait)
4397           continue;
4398         q[i]=ClampToQuantum(QuantumRange*value);
4399       }
4400       q+=GetPixelChannels(random_image);
4401     }
4402     if (SyncCacheViewAuthenticPixels(random_view,exception) == MagickFalse)
4403       status=MagickFalse;
4404   }
4405   random_view=DestroyCacheView(random_view);
4406   random_info=DestroyRandomInfoThreadSet(random_info);
4407   if (status == MagickFalse)
4408     {
4409       random_image=DestroyImage(random_image);
4410       return(random_image);
4411     }
4412   blur_image=MotionBlurImage(random_image,radius,sigma,angle,bias,exception);
4413   random_image=DestroyImage(random_image);
4414   if (blur_image == (Image *) NULL)
4415     return((Image *) NULL);
4416   dodge_image=EdgeImage(blur_image,radius,sigma,exception);
4417   blur_image=DestroyImage(blur_image);
4418   if (dodge_image == (Image *) NULL)
4419     return((Image *) NULL);
4420   (void) NormalizeImage(dodge_image,exception);
4421   (void) NegateImage(dodge_image,MagickFalse,exception);
4422   (void) TransformImage(&dodge_image,(char *) NULL,"50%",exception);
4423   sketch_image=CloneImage(image,0,0,MagickTrue,exception);
4424   if (sketch_image == (Image *) NULL)
4425     {
4426       dodge_image=DestroyImage(dodge_image);
4427       return((Image *) NULL);
4428     }
4429   (void) CompositeImage(sketch_image,ColorDodgeCompositeOp,dodge_image,0,0,
4430     exception);
4431   dodge_image=DestroyImage(dodge_image);
4432   blend_image=CloneImage(image,0,0,MagickTrue,exception);
4433   if (blend_image == (Image *) NULL)
4434     {
4435       sketch_image=DestroyImage(sketch_image);
4436       return((Image *) NULL);
4437     }
4438   (void) SetImageArtifact(blend_image,"compose:args","20x80");
4439   (void) CompositeImage(sketch_image,BlendCompositeOp,blend_image,0,0,
4440     exception);
4441   blend_image=DestroyImage(blend_image);
4442   return(sketch_image);
4443 }
4444 \f
4445 /*
4446 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4447 %                                                                             %
4448 %                                                                             %
4449 %                                                                             %
4450 %     S o l a r i z e I m a g e                                               %
4451 %                                                                             %
4452 %                                                                             %
4453 %                                                                             %
4454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4455 %
4456 %  SolarizeImage() applies a special effect to the image, similar to the effect
4457 %  achieved in a photo darkroom by selectively exposing areas of photo
4458 %  sensitive paper to light.  Threshold ranges from 0 to QuantumRange and is a
4459 %  measure of the extent of the solarization.
4460 %
4461 %  The format of the SolarizeImage method is:
4462 %
4463 %      MagickBooleanType SolarizeImage(Image *image,const double threshold,
4464 %        ExceptionInfo *exception)
4465 %
4466 %  A description of each parameter follows:
4467 %
4468 %    o image: the image.
4469 %
4470 %    o threshold:  Define the extent of the solarization.
4471 %
4472 %    o exception: return any errors or warnings in this structure.
4473 %
4474 */
4475 MagickExport MagickBooleanType SolarizeImage(Image *image,
4476   const double threshold,ExceptionInfo *exception)
4477 {
4478 #define SolarizeImageTag  "Solarize/Image"
4479
4480   CacheView
4481     *image_view;
4482
4483   MagickBooleanType
4484     status;
4485
4486   MagickOffsetType
4487     progress;
4488
4489   ssize_t
4490     y;
4491
4492   assert(image != (Image *) NULL);
4493   assert(image->signature == MagickSignature);
4494   if (image->debug != MagickFalse)
4495     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4496   if (image->storage_class == PseudoClass)
4497     {
4498       register ssize_t
4499         i;
4500
4501       /*
4502         Solarize colormap.
4503       */
4504       for (i=0; i < (ssize_t) image->colors; i++)
4505       {
4506         if ((MagickRealType) image->colormap[i].red > threshold)
4507           image->colormap[i].red=(Quantum) QuantumRange-image->colormap[i].red;
4508         if ((MagickRealType) image->colormap[i].green > threshold)
4509           image->colormap[i].green=(Quantum) QuantumRange-
4510             image->colormap[i].green;
4511         if ((MagickRealType) image->colormap[i].blue > threshold)
4512           image->colormap[i].blue=(Quantum) QuantumRange-
4513             image->colormap[i].blue;
4514       }
4515     }
4516   /*
4517     Solarize image.
4518   */
4519   status=MagickTrue;
4520   progress=0;
4521   image_view=AcquireCacheView(image);
4522 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4523   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
4524 #endif
4525   for (y=0; y < (ssize_t) image->rows; y++)
4526   {
4527     register ssize_t
4528       x;
4529
4530     register Quantum
4531       *restrict q;
4532
4533     if (status == MagickFalse)
4534       continue;
4535     q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4536     if (q == (Quantum *) NULL)
4537       {
4538         status=MagickFalse;
4539         continue;
4540       }
4541     for (x=0; x < (ssize_t) image->columns; x++)
4542     {
4543       register ssize_t
4544         i;
4545
4546       for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4547       {
4548         PixelTrait
4549           traits;
4550
4551         traits=GetPixelChannelMapTraits(image,(PixelChannel) i);
4552         if ((traits == UndefinedPixelTrait) ||
4553             ((traits & CopyPixelTrait) != 0))
4554           continue;
4555         if ((MagickRealType) q[i] > threshold)
4556           q[i]=QuantumRange-q[i];
4557       }
4558       q+=GetPixelChannels(image);
4559     }
4560     if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4561       status=MagickFalse;
4562     if (image->progress_monitor != (MagickProgressMonitor) NULL)
4563       {
4564         MagickBooleanType
4565           proceed;
4566
4567 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4568   #pragma omp critical (MagickCore_SolarizeImage)
4569 #endif
4570         proceed=SetImageProgress(image,SolarizeImageTag,progress++,image->rows);
4571         if (proceed == MagickFalse)
4572           status=MagickFalse;
4573       }
4574   }
4575   image_view=DestroyCacheView(image_view);
4576   return(status);
4577 }
4578 \f
4579 /*
4580 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4581 %                                                                             %
4582 %                                                                             %
4583 %                                                                             %
4584 %   S t e g a n o I m a g e                                                   %
4585 %                                                                             %
4586 %                                                                             %
4587 %                                                                             %
4588 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4589 %
4590 %  SteganoImage() hides a digital watermark within the image.  Recover
4591 %  the hidden watermark later to prove that the authenticity of an image.
4592 %  Offset defines the start position within the image to hide the watermark.
4593 %
4594 %  The format of the SteganoImage method is:
4595 %
4596 %      Image *SteganoImage(const Image *image,Image *watermark,
4597 %        ExceptionInfo *exception)
4598 %
4599 %  A description of each parameter follows:
4600 %
4601 %    o image: the image.
4602 %
4603 %    o watermark: the watermark image.
4604 %
4605 %    o exception: return any errors or warnings in this structure.
4606 %
4607 */
4608 MagickExport Image *SteganoImage(const Image *image,const Image *watermark,
4609   ExceptionInfo *exception)
4610 {
4611 #define GetBit(alpha,i) ((((size_t) (alpha) >> (size_t) (i)) & 0x01) != 0)
4612 #define SetBit(alpha,i,set) (Quantum) ((set) != 0 ? (size_t) (alpha) \
4613   | (one << (size_t) (i)) : (size_t) (alpha) & ~(one << (size_t) (i)))
4614 #define SteganoImageTag  "Stegano/Image"
4615
4616   CacheView
4617     *stegano_view,
4618     *watermark_view;
4619
4620   Image
4621     *stegano_image;
4622
4623   int
4624     c;
4625
4626   MagickBooleanType
4627     status;
4628
4629   PixelInfo
4630     pixel;
4631
4632   register Quantum
4633     *q;
4634
4635   register ssize_t
4636     x;
4637
4638   size_t
4639     depth,
4640     one;
4641
4642   ssize_t
4643     i,
4644     j,
4645     k,
4646     y;
4647
4648   /*
4649     Initialize steganographic image attributes.
4650   */
4651   assert(image != (const Image *) NULL);
4652   assert(image->signature == MagickSignature);
4653   if (image->debug != MagickFalse)
4654     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4655   assert(watermark != (const Image *) NULL);
4656   assert(watermark->signature == MagickSignature);
4657   assert(exception != (ExceptionInfo *) NULL);
4658   assert(exception->signature == MagickSignature);
4659   one=1UL;
4660   stegano_image=CloneImage(image,0,0,MagickTrue,exception);
4661   if (stegano_image == (Image *) NULL)
4662     return((Image *) NULL);
4663   if (SetImageStorageClass(stegano_image,DirectClass,exception) == MagickFalse)
4664     {
4665       stegano_image=DestroyImage(stegano_image);
4666       return((Image *) NULL);
4667     }
4668   stegano_image->depth=MAGICKCORE_QUANTUM_DEPTH;
4669   /*
4670     Hide watermark in low-order bits of image.
4671   */
4672   c=0;
4673   i=0;
4674   j=0;
4675   depth=stegano_image->depth;
4676   k=image->offset;
4677   status=MagickTrue;
4678   watermark_view=AcquireCacheView(watermark);
4679   stegano_view=AcquireCacheView(stegano_image);
4680   for (i=(ssize_t) depth-1; (i >= 0) && (j < (ssize_t) depth); i--)
4681   {
4682     for (y=0; (y < (ssize_t) watermark->rows) && (j < (ssize_t) depth); y++)
4683     {
4684       for (x=0; (x < (ssize_t) watermark->columns) && (j < (ssize_t) depth); x++)
4685       {
4686         Quantum
4687           virtual_pixel[CompositePixelChannel];
4688
4689         (void) GetOneCacheViewVirtualPixel(watermark_view,x,y,virtual_pixel,
4690           exception);
4691         pixel.red=(double) virtual_pixel[RedPixelChannel];
4692         pixel.green=(double) virtual_pixel[GreenPixelChannel];
4693         pixel.blue=(double) virtual_pixel[BluePixelChannel];
4694         pixel.alpha=(double) virtual_pixel[AlphaPixelChannel];
4695         if ((k/(ssize_t) stegano_image->columns) >= (ssize_t) stegano_image->rows)
4696           break;
4697         q=GetCacheViewAuthenticPixels(stegano_view,k % (ssize_t)
4698           stegano_image->columns,k/(ssize_t) stegano_image->columns,1,1,
4699           exception);
4700         if (q == (Quantum *) NULL)
4701           break;
4702         switch (c)
4703         {
4704           case 0:
4705           {
4706             SetPixelRed(image,SetBit(GetPixelRed(image,q),j,GetBit(
4707               GetPixelInfoIntensity(&pixel),i)),q);
4708             break;
4709           }
4710           case 1:
4711           {
4712             SetPixelGreen(image,SetBit(GetPixelGreen(image,q),j,GetBit(
4713               GetPixelInfoIntensity(&pixel),i)),q);
4714             break;
4715           }
4716           case 2:
4717           {
4718             SetPixelBlue(image,SetBit(GetPixelBlue(image,q),j,GetBit(
4719               GetPixelInfoIntensity(&pixel),i)),q);
4720             break;
4721           }
4722         }
4723         if (SyncCacheViewAuthenticPixels(stegano_view,exception) == MagickFalse)
4724           break;
4725         c++;
4726         if (c == 3)
4727           c=0;
4728         k++;
4729         if (k == (ssize_t) (stegano_image->columns*stegano_image->columns))
4730           k=0;
4731         if (k == image->offset)
4732           j++;
4733       }
4734     }
4735     if (image->progress_monitor != (MagickProgressMonitor) NULL)
4736       {
4737         MagickBooleanType
4738           proceed;
4739
4740         proceed=SetImageProgress(image,SteganoImageTag,(MagickOffsetType)
4741           (depth-i),depth);
4742         if (proceed == MagickFalse)
4743           status=MagickFalse;
4744       }
4745   }
4746   stegano_view=DestroyCacheView(stegano_view);
4747   watermark_view=DestroyCacheView(watermark_view);
4748   if (stegano_image->storage_class == PseudoClass)
4749     (void) SyncImage(stegano_image,exception);
4750   if (status == MagickFalse)
4751     {
4752       stegano_image=DestroyImage(stegano_image);
4753       return((Image *) NULL);
4754     }
4755   return(stegano_image);
4756 }
4757 \f
4758 /*
4759 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4760 %                                                                             %
4761 %                                                                             %
4762 %                                                                             %
4763 %   S t e r e o A n a g l y p h I m a g e                                     %
4764 %                                                                             %
4765 %                                                                             %
4766 %                                                                             %
4767 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4768 %
4769 %  StereoAnaglyphImage() combines two images and produces a single image that
4770 %  is the composite of a left and right image of a stereo pair.  Special
4771 %  red-green stereo glasses are required to view this effect.
4772 %
4773 %  The format of the StereoAnaglyphImage method is:
4774 %
4775 %      Image *StereoImage(const Image *left_image,const Image *right_image,
4776 %        ExceptionInfo *exception)
4777 %      Image *StereoAnaglyphImage(const Image *left_image,
4778 %        const Image *right_image,const ssize_t x_offset,const ssize_t y_offset,
4779 %        ExceptionInfo *exception)
4780 %
4781 %  A description of each parameter follows:
4782 %
4783 %    o left_image: the left image.
4784 %
4785 %    o right_image: the right image.
4786 %
4787 %    o exception: return any errors or warnings in this structure.
4788 %
4789 %    o x_offset: amount, in pixels, by which the left image is offset to the
4790 %      right of the right image.
4791 %
4792 %    o y_offset: amount, in pixels, by which the left image is offset to the
4793 %      bottom of the right image.
4794 %
4795 %
4796 */
4797 MagickExport Image *StereoImage(const Image *left_image,
4798   const Image *right_image,ExceptionInfo *exception)
4799 {
4800   return(StereoAnaglyphImage(left_image,right_image,0,0,exception));
4801 }
4802
4803 MagickExport Image *StereoAnaglyphImage(const Image *left_image,
4804   const Image *right_image,const ssize_t x_offset,const ssize_t y_offset,
4805   ExceptionInfo *exception)
4806 {
4807 #define StereoImageTag  "Stereo/Image"
4808
4809   const Image
4810     *image;
4811
4812   Image
4813     *stereo_image;
4814
4815   MagickBooleanType
4816     status;
4817
4818   ssize_t
4819     y;
4820
4821   assert(left_image != (const Image *) NULL);
4822   assert(left_image->signature == MagickSignature);
4823   if (left_image->debug != MagickFalse)
4824     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
4825       left_image->filename);
4826   assert(right_image != (const Image *) NULL);
4827   assert(right_image->signature == MagickSignature);
4828   assert(exception != (ExceptionInfo *) NULL);
4829   assert(exception->signature == MagickSignature);
4830   assert(right_image != (const Image *) NULL);
4831   image=left_image;
4832   if ((left_image->columns != right_image->columns) ||
4833       (left_image->rows != right_image->rows))
4834     ThrowImageException(ImageError,"LeftAndRightImageSizesDiffer");
4835   /*
4836     Initialize stereo image attributes.
4837   */
4838   stereo_image=CloneImage(left_image,left_image->columns,left_image->rows,
4839     MagickTrue,exception);
4840   if (stereo_image == (Image *) NULL)
4841     return((Image *) NULL);
4842   if (SetImageStorageClass(stereo_image,DirectClass,exception) == MagickFalse)
4843     {
4844       stereo_image=DestroyImage(stereo_image);
4845       return((Image *) NULL);
4846     }
4847   /*
4848     Copy left image to red channel and right image to blue channel.
4849   */
4850   status=MagickTrue;
4851   for (y=0; y < (ssize_t) stereo_image->rows; y++)
4852   {
4853     register const Quantum
4854       *restrict p,
4855       *restrict q;
4856
4857     register ssize_t
4858       x;
4859
4860     register Quantum
4861       *restrict r;
4862
4863     p=GetVirtualPixels(left_image,-x_offset,y-y_offset,image->columns,1,
4864       exception);
4865     q=GetVirtualPixels(right_image,0,y,right_image->columns,1,exception);
4866     r=QueueAuthenticPixels(stereo_image,0,y,stereo_image->columns,1,exception);
4867     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL) ||
4868         (r == (Quantum *) NULL))
4869       break;
4870     for (x=0; x < (ssize_t) stereo_image->columns; x++)
4871     {
4872       SetPixelRed(image,GetPixelRed(left_image,p),r);
4873       SetPixelGreen(image,GetPixelGreen(right_image,q),r);
4874       SetPixelBlue(image,GetPixelBlue(right_image,q),r);
4875       if ((GetPixelAlphaTraits(stereo_image) & CopyPixelTrait) != 0)
4876         SetPixelAlpha(image,(GetPixelAlpha(left_image,p)+
4877           GetPixelAlpha(right_image,q))/2,r);
4878       p+=GetPixelChannels(left_image);
4879       q+=GetPixelChannels(right_image);
4880       r+=GetPixelChannels(stereo_image);
4881     }
4882     if (SyncAuthenticPixels(stereo_image,exception) == MagickFalse)
4883       break;
4884     if (image->progress_monitor != (MagickProgressMonitor) NULL)
4885       {
4886         MagickBooleanType
4887           proceed;
4888
4889         proceed=SetImageProgress(image,StereoImageTag,(MagickOffsetType) y,
4890           stereo_image->rows);
4891         if (proceed == MagickFalse)
4892           status=MagickFalse;
4893       }
4894   }
4895   if (status == MagickFalse)
4896     {
4897       stereo_image=DestroyImage(stereo_image);
4898       return((Image *) NULL);
4899     }
4900   return(stereo_image);
4901 }
4902 \f
4903 /*
4904 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4905 %                                                                             %
4906 %                                                                             %
4907 %                                                                             %
4908 %     S w i r l I m a g e                                                     %
4909 %                                                                             %
4910 %                                                                             %
4911 %                                                                             %
4912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4913 %
4914 %  SwirlImage() swirls the pixels about the center of the image, where
4915 %  degrees indicates the sweep of the arc through which each pixel is moved.
4916 %  You get a more dramatic effect as the degrees move from 1 to 360.
4917 %
4918 %  The format of the SwirlImage method is:
4919 %
4920 %      Image *SwirlImage(const Image *image,double degrees,
4921 %        const PixelInterpolateMethod method,ExceptionInfo *exception)
4922 %
4923 %  A description of each parameter follows:
4924 %
4925 %    o image: the image.
4926 %
4927 %    o degrees: Define the tightness of the swirling effect.
4928 %
4929 %    o method: the pixel interpolation method.
4930 %
4931 %    o exception: return any errors or warnings in this structure.
4932 %
4933 */
4934 MagickExport Image *SwirlImage(const Image *image,double degrees,
4935   const PixelInterpolateMethod method,ExceptionInfo *exception)
4936 {
4937 #define SwirlImageTag  "Swirl/Image"
4938
4939   CacheView
4940     *image_view,
4941     *swirl_view;
4942
4943   Image
4944     *swirl_image;
4945
4946   MagickBooleanType
4947     status;
4948
4949   MagickOffsetType
4950     progress;
4951
4952   MagickRealType
4953     radius;
4954
4955   PointInfo
4956     center,
4957     scale;
4958
4959   ssize_t
4960     y;
4961
4962   /*
4963     Initialize swirl image attributes.
4964   */
4965   assert(image != (const Image *) NULL);
4966   assert(image->signature == MagickSignature);
4967   if (image->debug != MagickFalse)
4968     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4969   assert(exception != (ExceptionInfo *) NULL);
4970   assert(exception->signature == MagickSignature);
4971   swirl_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
4972   if (swirl_image == (Image *) NULL)
4973     return((Image *) NULL);
4974   if (SetImageStorageClass(swirl_image,DirectClass,exception) == MagickFalse)
4975     {
4976       swirl_image=DestroyImage(swirl_image);
4977       return((Image *) NULL);
4978     }
4979   if (swirl_image->background_color.alpha != OpaqueAlpha)
4980     swirl_image->matte=MagickTrue;
4981   /*
4982     Compute scaling factor.
4983   */
4984   center.x=(double) image->columns/2.0;
4985   center.y=(double) image->rows/2.0;
4986   radius=MagickMax(center.x,center.y);
4987   scale.x=1.0;
4988   scale.y=1.0;
4989   if (image->columns > image->rows)
4990     scale.y=(double) image->columns/(double) image->rows;
4991   else
4992     if (image->columns < image->rows)
4993       scale.x=(double) image->rows/(double) image->columns;
4994   degrees=(double) DegreesToRadians(degrees);
4995   /*
4996     Swirl image.
4997   */
4998   status=MagickTrue;
4999   progress=0;
5000   image_view=AcquireCacheView(image);
5001   swirl_view=AcquireCacheView(swirl_image);
5002 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5003   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
5004 #endif
5005   for (y=0; y < (ssize_t) image->rows; y++)
5006   {
5007     MagickRealType
5008       distance;
5009
5010     PointInfo
5011       delta;
5012
5013     register const Quantum
5014       *restrict p;
5015
5016     register ssize_t
5017       x;
5018
5019     register Quantum
5020       *restrict q;
5021
5022     if (status == MagickFalse)
5023       continue;
5024     p=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
5025     q=GetCacheViewAuthenticPixels(swirl_view,0,y,swirl_image->columns,1,
5026       exception);
5027     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
5028       {
5029         status=MagickFalse;
5030         continue;
5031       }
5032     delta.y=scale.y*(double) (y-center.y);
5033     for (x=0; x < (ssize_t) image->columns; x++)
5034     {
5035       register ssize_t
5036         i;
5037
5038       /*
5039         Determine if the pixel is within an ellipse.
5040       */
5041       delta.x=scale.x*(double) (x-center.x);
5042       distance=delta.x*delta.x+delta.y*delta.y;
5043       if (distance >= (radius*radius))
5044         {
5045           for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
5046             q[i]=p[i];
5047         }
5048       else
5049         {
5050           MagickRealType
5051             cosine,
5052             factor,
5053             sine;
5054
5055           /*
5056             Swirl the pixel.
5057           */
5058           factor=1.0-sqrt((double) distance)/radius;
5059           sine=sin((double) (degrees*factor*factor));
5060           cosine=cos((double) (degrees*factor*factor));
5061           status=InterpolatePixelChannels(image,image_view,swirl_image,method,
5062             ((cosine*delta.x-sine*delta.y)/scale.x+center.x),(double)
5063             ((sine*delta.x+cosine*delta.y)/scale.y+center.y),q,exception);
5064         }
5065       p+=GetPixelChannels(image);
5066       q+=GetPixelChannels(swirl_image);
5067     }
5068     if (SyncCacheViewAuthenticPixels(swirl_view,exception) == MagickFalse)
5069       status=MagickFalse;
5070     if (image->progress_monitor != (MagickProgressMonitor) NULL)
5071       {
5072         MagickBooleanType
5073           proceed;
5074
5075 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5076   #pragma omp critical (MagickCore_SwirlImage)
5077 #endif
5078         proceed=SetImageProgress(image,SwirlImageTag,progress++,image->rows);
5079         if (proceed == MagickFalse)
5080           status=MagickFalse;
5081       }
5082   }
5083   swirl_view=DestroyCacheView(swirl_view);
5084   image_view=DestroyCacheView(image_view);
5085   if (status == MagickFalse)
5086     swirl_image=DestroyImage(swirl_image);
5087   return(swirl_image);
5088 }
5089 \f
5090 /*
5091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5092 %                                                                             %
5093 %                                                                             %
5094 %                                                                             %
5095 %     T i n t I m a g e                                                       %
5096 %                                                                             %
5097 %                                                                             %
5098 %                                                                             %
5099 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5100 %
5101 %  TintImage() applies a color vector to each pixel in the image.  The length
5102 %  of the vector is 0 for black and white and at its maximum for the midtones.
5103 %  The vector weighting function is f(x)=(1-(4.0*((x-0.5)*(x-0.5))))
5104 %
5105 %  The format of the TintImage method is:
5106 %
5107 %      Image *TintImage(const Image *image,const char *blend,
5108 %        const PixelInfo *tint,ExceptionInfo *exception)
5109 %
5110 %  A description of each parameter follows:
5111 %
5112 %    o image: the image.
5113 %
5114 %    o blend: A color value used for tinting.
5115 %
5116 %    o tint: A color value used for tinting.
5117 %
5118 %    o exception: return any errors or warnings in this structure.
5119 %
5120 */
5121 MagickExport Image *TintImage(const Image *image,const char *blend,
5122   const PixelInfo *tint,ExceptionInfo *exception)
5123 {
5124 #define TintImageTag  "Tint/Image"
5125
5126   CacheView
5127     *image_view,
5128     *tint_view;
5129
5130   GeometryInfo
5131     geometry_info;
5132
5133   Image
5134     *tint_image;
5135
5136   MagickBooleanType
5137     status;
5138
5139   MagickOffsetType
5140     progress;
5141
5142   MagickRealType
5143     intensity;
5144
5145   PixelInfo
5146     color_vector,
5147     pixel;
5148
5149   MagickStatusType
5150     flags;
5151
5152   ssize_t
5153     y;
5154
5155   /*
5156     Allocate tint image.
5157   */
5158   assert(image != (const Image *) NULL);
5159   assert(image->signature == MagickSignature);
5160   if (image->debug != MagickFalse)
5161     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5162   assert(exception != (ExceptionInfo *) NULL);
5163   assert(exception->signature == MagickSignature);
5164   tint_image=CloneImage(image,image->columns,image->rows,MagickTrue,exception);
5165   if (tint_image == (Image *) NULL)
5166     return((Image *) NULL);
5167   if (SetImageStorageClass(tint_image,DirectClass,exception) == MagickFalse)
5168     {
5169       tint_image=DestroyImage(tint_image);
5170       return((Image *) NULL);
5171     }
5172   if (blend == (const char *) NULL)
5173     return(tint_image);
5174   /*
5175     Determine RGB values of the color.
5176   */
5177   GetPixelInfo(image,&pixel);
5178   flags=ParseGeometry(blend,&geometry_info);
5179   pixel.red=geometry_info.rho;
5180   pixel.green=geometry_info.rho;
5181   pixel.blue=geometry_info.rho;
5182   pixel.alpha=OpaqueAlpha;
5183   if ((flags & SigmaValue) != 0)
5184     pixel.green=geometry_info.sigma;
5185   if ((flags & XiValue) != 0)
5186     pixel.blue=geometry_info.xi;
5187   if ((flags & PsiValue) != 0)
5188     pixel.alpha=geometry_info.psi;
5189   if (image->colorspace == CMYKColorspace)
5190     {
5191       pixel.black=geometry_info.rho;
5192       if ((flags & PsiValue) != 0)
5193         pixel.black=geometry_info.psi;
5194       if ((flags & ChiValue) != 0)
5195         pixel.alpha=geometry_info.chi;
5196     }
5197   intensity=(MagickRealType) GetPixelInfoIntensity(tint);
5198   color_vector.red=(MagickRealType) (pixel.red*tint->red/100.0-intensity);
5199   color_vector.green=(MagickRealType) (pixel.green*tint->green/100.0-intensity);
5200   color_vector.blue=(MagickRealType) (pixel.blue*tint->blue/100.0-intensity);
5201   color_vector.black=(MagickRealType) (pixel.black*tint->black/100.0-intensity);
5202   color_vector.alpha=(MagickRealType) (pixel.alpha*tint->alpha/100.0-intensity);
5203   /*
5204     Tint image.
5205   */
5206   status=MagickTrue;
5207   progress=0;
5208   image_view=AcquireCacheView(image);
5209   tint_view=AcquireCacheView(tint_image);
5210 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5211   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
5212 #endif
5213   for (y=0; y < (ssize_t) image->rows; y++)
5214   {
5215     register const Quantum
5216       *restrict p;
5217
5218     register Quantum
5219       *restrict q;
5220
5221     register ssize_t
5222       x;
5223
5224     if (status == MagickFalse)
5225       continue;
5226     p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
5227     q=QueueCacheViewAuthenticPixels(tint_view,0,y,tint_image->columns,1,
5228       exception);
5229     if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
5230       {
5231         status=MagickFalse;
5232         continue;
5233       }
5234     for (x=0; x < (ssize_t) image->columns; x++)
5235     {
5236       PixelInfo
5237         pixel;
5238
5239       MagickRealType
5240         weight;
5241
5242       if ((GetPixelRedTraits(tint_image) & UpdatePixelTrait) != 0)
5243         {
5244           weight=QuantumScale*GetPixelRed(image,p)-0.5;
5245           pixel.red=(MagickRealType) GetPixelRed(image,p)+
5246             color_vector.red*(1.0-(4.0*(weight*weight)));
5247           SetPixelRed(tint_image,ClampToQuantum(pixel.red),q);
5248         }
5249       if ((GetPixelGreenTraits(tint_image) & UpdatePixelTrait) != 0)
5250         {
5251           weight=QuantumScale*GetPixelGreen(image,p)-0.5;
5252           pixel.green=(MagickRealType) GetPixelGreen(image,p)+
5253             color_vector.green*(1.0-(4.0*(weight*weight)));
5254           SetPixelGreen(tint_image,ClampToQuantum(pixel.green),q);
5255         }
5256       if ((GetPixelBlueTraits(tint_image) & UpdatePixelTrait) != 0)
5257         {
5258           weight=QuantumScale*GetPixelBlue(image,p)-0.5;
5259           pixel.blue=(MagickRealType) GetPixelBlue(image,p)+
5260             color_vector.blue*(1.0-(4.0*(weight*weight)));
5261           SetPixelBlue(tint_image,ClampToQuantum(pixel.blue),q);
5262         }
5263       if ((GetPixelBlackTraits(tint_image) & UpdatePixelTrait) != 0)
5264         {
5265           weight=QuantumScale*GetPixelBlack(image,p)-0.5;
5266           pixel.black=(MagickRealType) GetPixelBlack(image,p)+
5267             color_vector.black*(1.0-(4.0*(weight*weight)));
5268           SetPixelBlack(tint_image,ClampToQuantum(pixel.black),q);
5269         }
5270       if ((GetPixelAlphaTraits(tint_image) & CopyPixelTrait) != 0)
5271         SetPixelAlpha(tint_image,GetPixelAlpha(image,p),q);
5272       p+=GetPixelChannels(image);
5273       q+=GetPixelChannels(tint_image);
5274     }
5275     if (SyncCacheViewAuthenticPixels(tint_view,exception) == MagickFalse)
5276       status=MagickFalse;
5277     if (image->progress_monitor != (MagickProgressMonitor) NULL)
5278       {
5279         MagickBooleanType
5280           proceed;
5281
5282 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5283   #pragma omp critical (MagickCore_TintImage)
5284 #endif
5285         proceed=SetImageProgress(image,TintImageTag,progress++,image->rows);
5286         if (proceed == MagickFalse)
5287           status=MagickFalse;
5288       }
5289   }
5290   tint_view=DestroyCacheView(tint_view);
5291   image_view=DestroyCacheView(image_view);
5292   if (status == MagickFalse)
5293     tint_image=DestroyImage(tint_image);
5294   return(tint_image);
5295 }
5296 \f
5297 /*
5298 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5299 %                                                                             %
5300 %                                                                             %
5301 %                                                                             %
5302 %     V i g n e t t e I m a g e                                               %
5303 %                                                                             %
5304 %                                                                             %
5305 %                                                                             %
5306 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5307 %
5308 %  VignetteImage() softens the edges of the image in vignette style.
5309 %
5310 %  The format of the VignetteImage method is:
5311 %
5312 %      Image *VignetteImage(const Image *image,const double radius,
5313 %        const double sigma,const ssize_t x,const ssize_t y,
5314 %        ExceptionInfo *exception)
5315 %
5316 %  A description of each parameter follows:
5317 %
5318 %    o image: the image.
5319 %
5320 %    o radius: the radius of the pixel neighborhood.
5321 %
5322 %    o sigma: the standard deviation of the Gaussian, in pixels.
5323 %
5324 %    o x, y:  Define the x and y ellipse offset.
5325 %
5326 %    o exception: return any errors or warnings in this structure.
5327 %
5328 */
5329 MagickExport Image *VignetteImage(const Image *image,const double radius,
5330   const double sigma,const ssize_t x,const ssize_t y,ExceptionInfo *exception)
5331 {
5332   char
5333     ellipse[MaxTextExtent];
5334
5335   DrawInfo
5336     *draw_info;
5337
5338   Image
5339     *canvas_image,
5340     *blur_image,
5341     *oval_image,
5342     *vignette_image;
5343
5344   assert(image != (Image *) NULL);
5345   assert(image->signature == MagickSignature);
5346   if (image->debug != MagickFalse)
5347     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5348   assert(exception != (ExceptionInfo *) NULL);
5349   assert(exception->signature == MagickSignature);
5350   canvas_image=CloneImage(image,0,0,MagickTrue,exception);
5351   if (canvas_image == (Image *) NULL)
5352     return((Image *) NULL);
5353   if (SetImageStorageClass(canvas_image,DirectClass,exception) == MagickFalse)
5354     {
5355       canvas_image=DestroyImage(canvas_image);
5356       return((Image *) NULL);
5357     }
5358   canvas_image->matte=MagickTrue;
5359   oval_image=CloneImage(canvas_image,canvas_image->columns,
5360     canvas_image->rows,MagickTrue,exception);
5361   if (oval_image == (Image *) NULL)
5362     {
5363       canvas_image=DestroyImage(canvas_image);
5364       return((Image *) NULL);
5365     }
5366   (void) QueryColorCompliance("#000000",AllCompliance,
5367     &oval_image->background_color,exception);
5368   (void) SetImageBackgroundColor(oval_image,exception);
5369   draw_info=CloneDrawInfo((const ImageInfo *) NULL,(const DrawInfo *) NULL);
5370   (void) QueryColorCompliance("#ffffff",AllCompliance,&draw_info->fill,
5371     exception);
5372   (void) QueryColorCompliance("#ffffff",AllCompliance,&draw_info->stroke,
5373     exception);
5374   (void) FormatLocaleString(ellipse,MaxTextExtent,
5375     "ellipse %g,%g,%g,%g,0.0,360.0",image->columns/2.0,
5376     image->rows/2.0,image->columns/2.0-x,image->rows/2.0-y);
5377   draw_info->primitive=AcquireString(ellipse);
5378   (void) DrawImage(oval_image,draw_info,exception);
5379   draw_info=DestroyDrawInfo(draw_info);
5380   blur_image=BlurImage(oval_image,radius,sigma,image->bias,exception);
5381   oval_image=DestroyImage(oval_image);
5382   if (blur_image == (Image *) NULL)
5383     {
5384       canvas_image=DestroyImage(canvas_image);
5385       return((Image *) NULL);
5386     }
5387   blur_image->matte=MagickFalse;
5388   (void) CompositeImage(canvas_image,CopyOpacityCompositeOp,blur_image,0,0,
5389     exception);
5390   blur_image=DestroyImage(blur_image);
5391   vignette_image=MergeImageLayers(canvas_image,FlattenLayer,exception);
5392   canvas_image=DestroyImage(canvas_image);
5393   return(vignette_image);
5394 }
5395 \f
5396 /*
5397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5398 %                                                                             %
5399 %                                                                             %
5400 %                                                                             %
5401 %     W a v e I m a g e                                                       %
5402 %                                                                             %
5403 %                                                                             %
5404 %                                                                             %
5405 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5406 %
5407 %  WaveImage() creates a "ripple" effect in the image by shifting the pixels
5408 %  vertically along a sine wave whose amplitude and wavelength is specified
5409 %  by the given parameters.
5410 %
5411 %  The format of the WaveImage method is:
5412 %
5413 %      Image *WaveImage(const Image *image,const double amplitude,
5414 %        const double wave_length,const PixelInterpolateMethod method,
5415 %        ExceptionInfo *exception)
5416 %
5417 %  A description of each parameter follows:
5418 %
5419 %    o image: the image.
5420 %
5421 %    o amplitude, wave_length:  Define the amplitude and wave length of the
5422 %      sine wave.
5423 %
5424 %    o interpolate: the pixel interpolation method.
5425 %
5426 %    o exception: return any errors or warnings in this structure.
5427 %
5428 */
5429 MagickExport Image *WaveImage(const Image *image,const double amplitude,
5430   const double wave_length,const PixelInterpolateMethod method,
5431   ExceptionInfo *exception)
5432 {
5433 #define WaveImageTag  "Wave/Image"
5434
5435   CacheView
5436     *image_view,
5437     *wave_view;
5438
5439   Image
5440     *wave_image;
5441
5442   MagickBooleanType
5443     status;
5444
5445   MagickOffsetType
5446     progress;
5447
5448   MagickRealType
5449     *sine_map;
5450
5451   register ssize_t
5452     i;
5453
5454   ssize_t
5455     y;
5456
5457   /*
5458     Initialize wave image attributes.
5459   */
5460   assert(image != (Image *) NULL);
5461   assert(image->signature == MagickSignature);
5462   if (image->debug != MagickFalse)
5463     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5464   assert(exception != (ExceptionInfo *) NULL);
5465   assert(exception->signature == MagickSignature);
5466   wave_image=CloneImage(image,image->columns,(size_t) (image->rows+2.0*
5467     fabs(amplitude)),MagickTrue,exception);
5468   if (wave_image == (Image *) NULL)
5469     return((Image *) NULL);
5470   if (SetImageStorageClass(wave_image,DirectClass,exception) == MagickFalse)
5471     {
5472       wave_image=DestroyImage(wave_image);
5473       return((Image *) NULL);
5474     }
5475   if (wave_image->background_color.alpha != OpaqueAlpha)
5476     wave_image->matte=MagickTrue;
5477   /*
5478     Allocate sine map.
5479   */
5480   sine_map=(MagickRealType *) AcquireQuantumMemory((size_t) wave_image->columns,
5481     sizeof(*sine_map));
5482   if (sine_map == (MagickRealType *) NULL)
5483     {
5484       wave_image=DestroyImage(wave_image);
5485       ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
5486     }
5487   for (i=0; i < (ssize_t) wave_image->columns; i++)
5488     sine_map[i]=fabs(amplitude)+amplitude*sin((double) ((2.0*MagickPI*i)/
5489       wave_length));
5490   /*
5491     Wave image.
5492   */
5493   status=MagickTrue;
5494   progress=0;
5495   image_view=AcquireCacheView(image);
5496   wave_view=AcquireCacheView(wave_image);
5497   (void) SetCacheViewVirtualPixelMethod(image_view,
5498     BackgroundVirtualPixelMethod);
5499 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5500   #pragma omp parallel for schedule(dynamic,4) shared(progress,status)
5501 #endif
5502   for (y=0; y < (ssize_t) wave_image->rows; y++)
5503   {
5504     register Quantum
5505       *restrict q;
5506
5507     register ssize_t
5508       x;
5509
5510     if (status == MagickFalse)
5511       continue;
5512     q=QueueCacheViewAuthenticPixels(wave_view,0,y,wave_image->columns,1,
5513       exception);
5514     if (q == (Quantum *) NULL)
5515       {
5516         status=MagickFalse;
5517         continue;
5518       }
5519     for (x=0; x < (ssize_t) wave_image->columns; x++)
5520     {
5521       status=InterpolatePixelChannels(image,image_view,wave_image,method,
5522         (double) x,(double) (y-sine_map[x]),q,exception);
5523       q+=GetPixelChannels(wave_image);
5524     }
5525     if (SyncCacheViewAuthenticPixels(wave_view,exception) == MagickFalse)
5526       status=MagickFalse;
5527     if (image->progress_monitor != (MagickProgressMonitor) NULL)
5528       {
5529         MagickBooleanType
5530           proceed;
5531
5532 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5533   #pragma omp critical (MagickCore_WaveImage)
5534 #endif
5535         proceed=SetImageProgress(image,WaveImageTag,progress++,image->rows);
5536         if (proceed == MagickFalse)
5537           status=MagickFalse;
5538       }
5539   }
5540   wave_view=DestroyCacheView(wave_view);
5541   image_view=DestroyCacheView(image_view);
5542   sine_map=(MagickRealType *) RelinquishMagickMemory(sine_map);
5543   if (status == MagickFalse)
5544     wave_image=DestroyImage(wave_image);
5545   return(wave_image);
5546 }