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