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