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