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