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