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