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