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