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://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  if (LocaleCompare(symbol,"printsize.x") == 0)
1770  return(PerceptibleReciprocal(image->resolution.x)*image->columns);
1771  if (LocaleCompare(symbol,"printsize.y") == 0)
1772  return(PerceptibleReciprocal(image->resolution.y)*image->rows);
1773  break;
1774  }
1775  case 'Q':
1776  case 'q':
1777  {
1778  if (LocaleCompare(symbol,"quality") == 0)
1779  return((double) image->quality);
1780  break;
1781  }
1782  case 'R':
1783  case 'r':
1784  {
1785  if (LocaleCompare(symbol,"resolution.x") == 0)
1786  return(image->resolution.x);
1787  if (LocaleCompare(symbol,"resolution.y") == 0)
1788  return(image->resolution.y);
1789  if (LocaleCompare(symbol,"r") == 0)
1790  return(QuantumScale*pixel.red);
1791  break;
1792  }
1793  case 'S':
1794  case 's':
1795  {
1796  if (LocaleCompare(symbol,"saturation") == 0)
1797  {
1798  double
1799  hue,
1800  lightness,
1801  saturation;
1802 
1803  ConvertRGBToHSL(pixel.red,pixel.green,pixel.blue,&hue,&saturation,
1804  &lightness);
1805  return(saturation);
1806  }
1807  if (LocaleNCompare(symbol,"skewness",8) == 0)
1808  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1809  if (LocaleNCompare(symbol,"standard_deviation",18) == 0)
1810  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1811  break;
1812  }
1813  case 'T':
1814  case 't':
1815  {
1816  if (LocaleCompare(symbol,"t") == 0)
1817  return((double) GetImageIndexInList(fx_info->images));
1818  break;
1819  }
1820  case 'W':
1821  case 'w':
1822  {
1823  if (LocaleCompare(symbol,"w") == 0)
1824  return((double) image->columns);
1825  break;
1826  }
1827  case 'Y':
1828  case 'y':
1829  {
1830  if (LocaleCompare(symbol,"y") == 0)
1831  return(QuantumScale*pixel.blue);
1832  break;
1833  }
1834  case 'Z':
1835  case 'z':
1836  {
1837  if (LocaleCompare(symbol,"z") == 0)
1838  return((double) GetImageDepth(image,fx_info->exception));
1839  break;
1840  }
1841  default:
1842  break;
1843  }
1844  value=(const char *) GetValueFromSplayTree(fx_info->symbols,symbol);
1845  if (value != (const char *) NULL)
1846  return(StringToDouble(value,(char **) NULL));
1848  "UnableToParseExpression","`%s'",symbol);
1849  return(0.0);
1850 }
1851 
1852 static const char *FxOperatorPrecedence(const char *expression,
1853  ExceptionInfo *exception)
1854 {
1855  typedef enum
1856  {
1857  UndefinedPrecedence,
1858  NullPrecedence,
1859  BitwiseComplementPrecedence,
1860  ExponentPrecedence,
1861  ExponentialNotationPrecedence,
1862  MultiplyPrecedence,
1863  AdditionPrecedence,
1864  ShiftPrecedence,
1865  RelationalPrecedence,
1866  EquivalencyPrecedence,
1867  BitwiseAndPrecedence,
1868  BitwiseOrPrecedence,
1869  LogicalAndPrecedence,
1870  LogicalOrPrecedence,
1871  TernaryPrecedence,
1872  AssignmentPrecedence,
1873  CommaPrecedence,
1874  SeparatorPrecedence
1875  } FxPrecedence;
1876 
1877  FxPrecedence
1878  precedence,
1879  target;
1880 
1881  register const char
1882  *subexpression;
1883 
1884  register int
1885  c;
1886 
1887  size_t
1888  level;
1889 
1890  c=(-1);
1891  level=0;
1892  subexpression=(const char *) NULL;
1893  target=NullPrecedence;
1894  while ((c != '\0') && (*expression != '\0'))
1895  {
1896  precedence=UndefinedPrecedence;
1897  if ((isspace((int) ((unsigned char) *expression)) != 0) || (c == (int) '@'))
1898  {
1899  expression++;
1900  continue;
1901  }
1902  switch (*expression)
1903  {
1904  case 'A':
1905  case 'a':
1906  {
1907 #if defined(MAGICKCORE_HAVE_ACOSH)
1908  if (LocaleNCompare(expression,"acosh",5) == 0)
1909  {
1910  expression+=5;
1911  break;
1912  }
1913 #endif
1914 #if defined(MAGICKCORE_HAVE_ASINH)
1915  if (LocaleNCompare(expression,"asinh",5) == 0)
1916  {
1917  expression+=5;
1918  break;
1919  }
1920 #endif
1921 #if defined(MAGICKCORE_HAVE_ATANH)
1922  if (LocaleNCompare(expression,"atanh",5) == 0)
1923  {
1924  expression+=5;
1925  break;
1926  }
1927 #endif
1928  if (LocaleNCompare(expression,"atan2",5) == 0)
1929  {
1930  expression+=5;
1931  break;
1932  }
1933  break;
1934  }
1935  case 'E':
1936  case 'e':
1937  {
1938  if ((isdigit(c) != 0) &&
1939  ((LocaleNCompare(expression,"E+",2) == 0) ||
1940  (LocaleNCompare(expression,"E-",2) == 0)))
1941  {
1942  expression+=2; /* scientific notation */
1943  break;
1944  }
1945  }
1946  case 'J':
1947  case 'j':
1948  {
1949  if ((LocaleNCompare(expression,"j0",2) == 0) ||
1950  (LocaleNCompare(expression,"j1",2) == 0))
1951  {
1952  expression+=2;
1953  break;
1954  }
1955  break;
1956  }
1957  case '#':
1958  {
1959  while (isxdigit((int) ((unsigned char) *(expression+1))) != 0)
1960  expression++;
1961  break;
1962  }
1963  default:
1964  break;
1965  }
1966  if ((c == (int) '{') || (c == (int) '['))
1967  level++;
1968  else
1969  if ((c == (int) '}') || (c == (int) ']'))
1970  level--;
1971  if (level == 0)
1972  switch ((unsigned char) *expression)
1973  {
1974  case '~':
1975  case '!':
1976  {
1977  precedence=BitwiseComplementPrecedence;
1978  break;
1979  }
1980  case '^':
1981  case '@':
1982  {
1983  precedence=ExponentPrecedence;
1984  break;
1985  }
1986  default:
1987  {
1988  if (((c != 0) && ((isdigit(c) != 0) ||
1989  (strchr(")",c) != (char *) NULL))) &&
1990  (((islower((int) ((unsigned char) *expression)) != 0) ||
1991  (strchr("(",(int) ((unsigned char) *expression)) != (char *) NULL)) ||
1992  ((isdigit(c) == 0) &&
1993  (isdigit((int) ((unsigned char) *expression)) != 0))) &&
1994  (strchr("xy",(int) ((unsigned char) *expression)) == (char *) NULL))
1995  precedence=MultiplyPrecedence;
1996  break;
1997  }
1998  case '*':
1999  case '/':
2000  case '%':
2001  {
2002  precedence=MultiplyPrecedence;
2003  break;
2004  }
2005  case '+':
2006  case '-':
2007  {
2008  if ((strchr("(+-/*%:&^|<>~,",c) == (char *) NULL) ||
2009  (isalpha(c) != 0))
2010  precedence=AdditionPrecedence;
2011  break;
2012  }
2013  case LeftShiftOperator:
2014  case RightShiftOperator:
2015  {
2016  precedence=ShiftPrecedence;
2017  break;
2018  }
2019  case '<':
2020  case LessThanEqualOperator:
2022  case '>':
2023  {
2024  precedence=RelationalPrecedence;
2025  break;
2026  }
2027  case EqualOperator:
2028  case NotEqualOperator:
2029  {
2030  precedence=EquivalencyPrecedence;
2031  break;
2032  }
2033  case '&':
2034  {
2035  precedence=BitwiseAndPrecedence;
2036  break;
2037  }
2038  case '|':
2039  {
2040  precedence=BitwiseOrPrecedence;
2041  break;
2042  }
2043  case LogicalAndOperator:
2044  {
2045  precedence=LogicalAndPrecedence;
2046  break;
2047  }
2048  case LogicalOrOperator:
2049  {
2050  precedence=LogicalOrPrecedence;
2051  break;
2052  }
2053  case ExponentialNotation:
2054  {
2055  precedence=ExponentialNotationPrecedence;
2056  break;
2057  }
2058  case ':':
2059  case '?':
2060  {
2061  precedence=TernaryPrecedence;
2062  break;
2063  }
2064  case '=':
2065  {
2066  precedence=AssignmentPrecedence;
2067  break;
2068  }
2069  case ',':
2070  {
2071  precedence=CommaPrecedence;
2072  break;
2073  }
2074  case ';':
2075  {
2076  precedence=SeparatorPrecedence;
2077  break;
2078  }
2079  }
2080  if ((precedence == BitwiseComplementPrecedence) ||
2081  (precedence == TernaryPrecedence) ||
2082  (precedence == AssignmentPrecedence))
2083  {
2084  if (precedence > target)
2085  {
2086  /*
2087  Right-to-left associativity.
2088  */
2089  target=precedence;
2090  subexpression=expression;
2091  }
2092  }
2093  else
2094  if (precedence >= target)
2095  {
2096  /*
2097  Left-to-right associativity.
2098  */
2099  target=precedence;
2100  subexpression=expression;
2101  }
2102  if (strchr("(",(int) *expression) != (char *) NULL)
2103  expression=FxSubexpression(expression,exception);
2104  c=(int) (*expression++);
2105  }
2106  return(subexpression);
2107 }
2108 
2109 static double FxEvaluateSubexpression(FxInfo *fx_info,
2110  const PixelChannel channel,const ssize_t x,const ssize_t y,
2111  const char *expression,const size_t depth,double *beta,
2112  ExceptionInfo *exception)
2113 {
2114 #define FxMaxParenthesisDepth 58
2115 #define FxMaxSubexpressionDepth 200
2116 #define FxReturn(value) \
2117 { \
2118  subexpression=DestroyString(subexpression); \
2119  return(value); \
2120 }
2121 
2122  char
2123  *q,
2124  *subexpression;
2125 
2126  double
2127  alpha,
2128  gamma;
2129 
2130  register const char
2131  *p;
2132 
2133  *beta=0.0;
2134  subexpression=AcquireString(expression);
2135  *subexpression='\0';
2136  if (depth > FxMaxSubexpressionDepth)
2137  {
2139  "UnableToParseExpression","`%s'",expression);
2140  FxReturn(0.0);
2141  }
2142  if (exception->severity >= ErrorException)
2143  FxReturn(0.0);
2144  while (isspace((int) ((unsigned char) *expression)) != 0)
2145  expression++;
2146  if (*expression == '\0')
2147  FxReturn(0.0);
2148  p=FxOperatorPrecedence(expression,exception);
2149  if (p != (const char *) NULL)
2150  {
2151  (void) CopyMagickString(subexpression,expression,(size_t)
2152  (p-expression+1));
2153  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,depth+1,
2154  beta,exception);
2155  switch ((unsigned char) *p)
2156  {
2157  case '~':
2158  {
2159  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2160  exception);
2161  *beta=(double) (~(size_t) *beta);
2162  FxReturn(*beta);
2163  }
2164  case '!':
2165  {
2166  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2167  exception);
2168  FxReturn(*beta == 0.0 ? 1.0 : 0.0);
2169  }
2170  case '^':
2171  {
2172  *beta=pow(alpha,FxEvaluateSubexpression(fx_info,channel,x,y,++p,
2173  depth+1,beta,exception));
2174  FxReturn(*beta);
2175  }
2176  case '*':
2177  case ExponentialNotation:
2178  {
2179  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2180  exception);
2181  FxReturn(alpha*(*beta));
2182  }
2183  case '/':
2184  {
2185  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2186  exception);
2187  if (*beta == 0.0)
2188  {
2189  (void) ThrowMagickException(exception,GetMagickModule(),
2190  OptionError,"DivideByZero","`%s'",expression);
2191  FxReturn(0.0);
2192  }
2193  FxReturn(alpha/(*beta));
2194  }
2195  case '%':
2196  {
2197  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2198  exception);
2199  *beta=fabs(floor((*beta)+0.5));
2200  if (*beta == 0.0)
2201  {
2202  (void) ThrowMagickException(exception,GetMagickModule(),
2203  OptionError,"DivideByZero","`%s'",expression);
2204  FxReturn(0.0);
2205  }
2206  FxReturn(fmod(alpha,*beta));
2207  }
2208  case '+':
2209  {
2210  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2211  exception);
2212  FxReturn(alpha+(*beta));
2213  }
2214  case '-':
2215  {
2216  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2217  exception);
2218  FxReturn(alpha-(*beta));
2219  }
2220  case LeftShiftOperator:
2221  {
2222  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2223  exception);
2224  if ((size_t) (gamma+0.5) >= (8*sizeof(size_t)))
2225  {
2226  (void) ThrowMagickException(exception,GetMagickModule(),
2227  OptionError,"ShiftCountOverflow","`%s'",subexpression);
2228  FxReturn(0.0);
2229  }
2230  *beta=(double) ((size_t) (alpha+0.5) << (size_t) (gamma+0.5));
2231  FxReturn(*beta);
2232  }
2233  case RightShiftOperator:
2234  {
2235  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2236  exception);
2237  if ((size_t) (gamma+0.5) >= (8*sizeof(size_t)))
2238  {
2239  (void) ThrowMagickException(exception,GetMagickModule(),
2240  OptionError,"ShiftCountOverflow","`%s'",subexpression);
2241  FxReturn(0.0);
2242  }
2243  *beta=(double) ((size_t) (alpha+0.5) >> (size_t) (gamma+0.5));
2244  FxReturn(*beta);
2245  }
2246  case '<':
2247  {
2248  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2249  exception);
2250  FxReturn(alpha < *beta ? 1.0 : 0.0);
2251  }
2252  case LessThanEqualOperator:
2253  {
2254  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2255  exception);
2256  FxReturn(alpha <= *beta ? 1.0 : 0.0);
2257  }
2258  case '>':
2259  {
2260  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2261  exception);
2262  FxReturn(alpha > *beta ? 1.0 : 0.0);
2263  }
2265  {
2266  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2267  exception);
2268  FxReturn(alpha >= *beta ? 1.0 : 0.0);
2269  }
2270  case EqualOperator:
2271  {
2272  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2273  exception);
2274  FxReturn(fabs(alpha-(*beta)) < MagickEpsilon ? 1.0 : 0.0);
2275  }
2276  case NotEqualOperator:
2277  {
2278  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2279  exception);
2280  FxReturn(fabs(alpha-(*beta)) >= MagickEpsilon ? 1.0 : 0.0);
2281  }
2282  case '&':
2283  {
2284  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2285  exception);
2286  *beta=(double) ((size_t) (alpha+0.5) & (size_t) (gamma+0.5));
2287  FxReturn(*beta);
2288  }
2289  case '|':
2290  {
2291  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2292  exception);
2293  *beta=(double) ((size_t) (alpha+0.5) | (size_t) (gamma+0.5));
2294  FxReturn(*beta);
2295  }
2296  case LogicalAndOperator:
2297  {
2298  p++;
2299  if (alpha <= 0.0)
2300  {
2301  *beta=0.0;
2302  FxReturn(*beta);
2303  }
2304  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
2305  exception);
2306  *beta=(gamma > 0.0) ? 1.0 : 0.0;
2307  FxReturn(*beta);
2308  }
2309  case LogicalOrOperator:
2310  {
2311  p++;
2312  if (alpha > 0.0)
2313  {
2314  *beta=1.0;
2315  FxReturn(*beta);
2316  }
2317  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
2318  exception);
2319  *beta=(gamma > 0.0) ? 1.0 : 0.0;
2320  FxReturn(*beta);
2321  }
2322  case '?':
2323  {
2324  (void) CopyMagickString(subexpression,++p,MagickPathExtent);
2325  q=subexpression;
2326  p=StringToken(":",&q);
2327  if (q == (char *) NULL)
2328  {
2329  (void) ThrowMagickException(exception,GetMagickModule(),
2330  OptionError,"UnableToParseExpression","`%s'",subexpression);
2331  FxReturn(0.0);
2332  }
2333  if (fabs(alpha) >= MagickEpsilon)
2334  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
2335  exception);
2336  else
2337  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,q,depth+1,beta,
2338  exception);
2339  FxReturn(gamma);
2340  }
2341  case '=':
2342  {
2343  char
2344  numeric[MagickPathExtent];
2345 
2346  q=subexpression;
2347  while (isalpha((int) ((unsigned char) *q)) != 0)
2348  q++;
2349  if (*q != '\0')
2350  {
2351  (void) ThrowMagickException(exception,GetMagickModule(),
2352  OptionError,"UnableToParseExpression","`%s'",subexpression);
2353  FxReturn(0.0);
2354  }
2355  ClearMagickException(exception);
2356  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2357  exception);
2358  (void) FormatLocaleString(numeric,MagickPathExtent,"%.20g",*beta);
2359  (void) DeleteNodeFromSplayTree(fx_info->symbols,subexpression);
2360  (void) AddValueToSplayTree(fx_info->symbols,ConstantString(
2361  subexpression),ConstantString(numeric));
2362  FxReturn(*beta);
2363  }
2364  case ',':
2365  {
2366  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2367  exception);
2368  FxReturn(alpha);
2369  }
2370  case ';':
2371  {
2372  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
2373  exception);
2374  FxReturn(*beta);
2375  }
2376  default:
2377  {
2378  gamma=alpha*FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,
2379  beta,exception);
2380  FxReturn(gamma);
2381  }
2382  }
2383  }
2384  if (strchr("(",(int) *expression) != (char *) NULL)
2385  {
2386  if (depth >= FxMaxParenthesisDepth)
2388  "ParenthesisNestedTooDeeply","`%s'",expression);
2389  (void) CopyMagickString(subexpression,expression+1,MagickPathExtent);
2390  if (strlen(subexpression) != 0)
2391  subexpression[strlen(subexpression)-1]='\0';
2392  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,depth+1,
2393  beta,exception);
2394  FxReturn(gamma);
2395  }
2396  switch (*expression)
2397  {
2398  case '+':
2399  {
2400  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
2401  beta,exception);
2402  FxReturn(1.0*gamma);
2403  }
2404  case '-':
2405  {
2406  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
2407  beta,exception);
2408  FxReturn(-1.0*gamma);
2409  }
2410  case '~':
2411  {
2412  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
2413  beta,exception);
2414  FxReturn((double) (~(size_t) (gamma+0.5)));
2415  }
2416  case 'A':
2417  case 'a':
2418  {
2419  if (LocaleNCompare(expression,"abs",3) == 0)
2420  {
2421  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2422  depth+1,beta,exception);
2423  FxReturn(fabs(alpha));
2424  }
2425 #if defined(MAGICKCORE_HAVE_ACOSH)
2426  if (LocaleNCompare(expression,"acosh",5) == 0)
2427  {
2428  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2429  depth+1,beta,exception);
2430  FxReturn(acosh(alpha));
2431  }
2432 #endif
2433  if (LocaleNCompare(expression,"acos",4) == 0)
2434  {
2435  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2436  depth+1,beta,exception);
2437  FxReturn(acos(alpha));
2438  }
2439 #if defined(MAGICKCORE_HAVE_J1)
2440  if (LocaleNCompare(expression,"airy",4) == 0)
2441  {
2442  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2443  depth+1,beta,exception);
2444  if (alpha == 0.0)
2445  FxReturn(1.0);
2446  gamma=2.0*j1((MagickPI*alpha))/(MagickPI*alpha);
2447  FxReturn(gamma*gamma);
2448  }
2449 #endif
2450 #if defined(MAGICKCORE_HAVE_ASINH)
2451  if (LocaleNCompare(expression,"asinh",5) == 0)
2452  {
2453  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2454  depth+1,beta,exception);
2455  FxReturn(asinh(alpha));
2456  }
2457 #endif
2458  if (LocaleNCompare(expression,"asin",4) == 0)
2459  {
2460  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2461  depth+1,beta,exception);
2462  FxReturn(asin(alpha));
2463  }
2464  if (LocaleNCompare(expression,"alt",3) == 0)
2465  {
2466  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2467  depth+1,beta,exception);
2468  FxReturn(((ssize_t) alpha) & 0x01 ? -1.0 : 1.0);
2469  }
2470  if (LocaleNCompare(expression,"atan2",5) == 0)
2471  {
2472  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2473  depth+1,beta,exception);
2474  FxReturn(atan2(alpha,*beta));
2475  }
2476 #if defined(MAGICKCORE_HAVE_ATANH)
2477  if (LocaleNCompare(expression,"atanh",5) == 0)
2478  {
2479  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2480  depth+1,beta,exception);
2481  FxReturn(atanh(alpha));
2482  }
2483 #endif
2484  if (LocaleNCompare(expression,"atan",4) == 0)
2485  {
2486  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2487  depth+1,beta,exception);
2488  FxReturn(atan(alpha));
2489  }
2490  if (LocaleCompare(expression,"a") == 0)
2491  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2492  break;
2493  }
2494  case 'B':
2495  case 'b':
2496  {
2497  if (LocaleCompare(expression,"b") == 0)
2498  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2499  break;
2500  }
2501  case 'C':
2502  case 'c':
2503  {
2504  if (LocaleNCompare(expression,"ceil",4) == 0)
2505  {
2506  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2507  depth+1,beta,exception);
2508  FxReturn(ceil(alpha));
2509  }
2510  if (LocaleNCompare(expression,"clamp",5) == 0)
2511  {
2512  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2513  depth+1,beta,exception);
2514  if (alpha < 0.0)
2515  FxReturn(0.0);
2516  if (alpha > 1.0)
2517  FxReturn(1.0);
2518  FxReturn(alpha);
2519  }
2520  if (LocaleNCompare(expression,"cosh",4) == 0)
2521  {
2522  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2523  depth+1,beta,exception);
2524  FxReturn(cosh(alpha));
2525  }
2526  if (LocaleNCompare(expression,"cos",3) == 0)
2527  {
2528  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2529  depth+1,beta,exception);
2530  FxReturn(cos(alpha));
2531  }
2532  if (LocaleCompare(expression,"c") == 0)
2533  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2534  break;
2535  }
2536  case 'D':
2537  case 'd':
2538  {
2539  if (LocaleNCompare(expression,"debug",5) == 0)
2540  {
2541  const char
2542  *type;
2543 
2544  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2545  depth+1,beta,exception);
2546  if (fx_info->images->colorspace == CMYKColorspace)
2547  switch (channel)
2548  {
2549  case CyanPixelChannel: type="cyan"; break;
2550  case MagentaPixelChannel: type="magenta"; break;
2551  case YellowPixelChannel: type="yellow"; break;
2552  case AlphaPixelChannel: type="opacity"; break;
2553  case BlackPixelChannel: type="black"; break;
2554  default: type="unknown"; break;
2555  }
2556  else
2557  switch (channel)
2558  {
2559  case RedPixelChannel: type="red"; break;
2560  case GreenPixelChannel: type="green"; break;
2561  case BluePixelChannel: type="blue"; break;
2562  case AlphaPixelChannel: type="opacity"; break;
2563  default: type="unknown"; break;
2564  }
2565  *subexpression='\0';
2566  if (strlen(expression) > 6)
2567  (void) CopyMagickString(subexpression,expression+6,
2569  if (strlen(subexpression) > 1)
2570  subexpression[strlen(subexpression)-1]='\0';
2571  if (fx_info->file != (FILE *) NULL)
2572  (void) FormatLocaleFile(fx_info->file,"%s[%.20g,%.20g].%s: "
2573  "%s=%.*g\n",fx_info->images->filename,(double) x,(double) y,type,
2574  subexpression,GetMagickPrecision(),alpha);
2575  FxReturn(0.0);
2576  }
2577  if (LocaleNCompare(expression,"drc",3) == 0)
2578  {
2579  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2580  depth+1,beta,exception);
2581  FxReturn((alpha/(*beta*(alpha-1.0)+1.0)));
2582  }
2583  break;
2584  }
2585  case 'E':
2586  case 'e':
2587  {
2588  if (LocaleCompare(expression,"epsilon") == 0)
2590 #if defined(MAGICKCORE_HAVE_ERF)
2591  if (LocaleNCompare(expression,"erf",3) == 0)
2592  {
2593  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2594  depth+1,beta,exception);
2595  FxReturn(erf(alpha));
2596  }
2597 #endif
2598  if (LocaleNCompare(expression,"exp",3) == 0)
2599  {
2600  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2601  depth+1,beta,exception);
2602  FxReturn(exp(alpha));
2603  }
2604  if (LocaleCompare(expression,"e") == 0)
2605  FxReturn(2.7182818284590452354);
2606  break;
2607  }
2608  case 'F':
2609  case 'f':
2610  {
2611  if (LocaleNCompare(expression,"floor",5) == 0)
2612  {
2613  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2614  depth+1,beta,exception);
2615  FxReturn(floor(alpha));
2616  }
2617  break;
2618  }
2619  case 'G':
2620  case 'g':
2621  {
2622  if (LocaleNCompare(expression,"gauss",5) == 0)
2623  {
2624  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2625  depth+1,beta,exception);
2626  gamma=exp((-alpha*alpha/2.0))/sqrt(2.0*MagickPI);
2627  FxReturn(gamma);
2628  }
2629  if (LocaleNCompare(expression,"gcd",3) == 0)
2630  {
2632  gcd;
2633 
2634  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2635  depth+1,beta,exception);
2636  gcd=FxGCD((MagickOffsetType) (alpha+0.5),(MagickOffsetType) (*beta+
2637  0.5));
2638  FxReturn((double) gcd);
2639  }
2640  if (LocaleCompare(expression,"g") == 0)
2641  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2642  break;
2643  }
2644  case 'H':
2645  case 'h':
2646  {
2647  if (LocaleCompare(expression,"h") == 0)
2648  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2649  if (LocaleCompare(expression,"hue") == 0)
2650  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2651  if (LocaleNCompare(expression,"hypot",5) == 0)
2652  {
2653  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2654  depth+1,beta,exception);
2655  FxReturn(hypot(alpha,*beta));
2656  }
2657  break;
2658  }
2659  case 'K':
2660  case 'k':
2661  {
2662  if (LocaleCompare(expression,"k") == 0)
2663  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2664  break;
2665  }
2666  case 'I':
2667  case 'i':
2668  {
2669  if (LocaleCompare(expression,"intensity") == 0)
2670  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2671  if (LocaleNCompare(expression,"int",3) == 0)
2672  {
2673  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2674  depth+1,beta,exception);
2675  FxReturn(floor(alpha));
2676  }
2677  if (LocaleNCompare(expression,"isnan",5) == 0)
2678  {
2679  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2680  depth+1,beta,exception);
2681  FxReturn((double) !!IsNaN(alpha));
2682  }
2683  if (LocaleCompare(expression,"i") == 0)
2684  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2685  break;
2686  }
2687  case 'J':
2688  case 'j':
2689  {
2690  if (LocaleCompare(expression,"j") == 0)
2691  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2692 #if defined(MAGICKCORE_HAVE_J0)
2693  if (LocaleNCompare(expression,"j0",2) == 0)
2694  {
2695  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2696  depth+1,beta,exception);
2697  FxReturn(j0(alpha));
2698  }
2699 #endif
2700 #if defined(MAGICKCORE_HAVE_J1)
2701  if (LocaleNCompare(expression,"j1",2) == 0)
2702  {
2703  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2704  depth+1,beta,exception);
2705  FxReturn(j1(alpha));
2706  }
2707 #endif
2708 #if defined(MAGICKCORE_HAVE_J1)
2709  if (LocaleNCompare(expression,"jinc",4) == 0)
2710  {
2711  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2712  depth+1,beta,exception);
2713  if (alpha == 0.0)
2714  FxReturn(1.0);
2715  gamma=(2.0*j1((MagickPI*alpha))/(MagickPI*alpha));
2716  FxReturn(gamma);
2717  }
2718 #endif
2719  break;
2720  }
2721  case 'L':
2722  case 'l':
2723  {
2724  if (LocaleNCompare(expression,"ln",2) == 0)
2725  {
2726  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2727  depth+1,beta,exception);
2728  FxReturn(log(alpha));
2729  }
2730  if (LocaleNCompare(expression,"logtwo",6) == 0)
2731  {
2732  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,
2733  depth+1,beta,exception);
2734  FxReturn(log10(alpha)/log10(2.0));
2735  }
2736  if (LocaleNCompare(expression,"log",3) == 0)
2737  {
2738  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2739  depth+1,beta,exception);
2740  FxReturn(log10(alpha));
2741  }
2742  if (LocaleCompare(expression,"lightness") == 0)
2743  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2744  break;
2745  }
2746  case 'M':
2747  case 'm':
2748  {
2749  if (LocaleCompare(expression,"MaxRGB") == 0)
2751  if (LocaleNCompare(expression,"maxima",6) == 0)
2752  break;
2753  if (LocaleNCompare(expression,"max",3) == 0)
2754  {
2755  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2756  depth+1,beta,exception);
2757  FxReturn(alpha > *beta ? alpha : *beta);
2758  }
2759  if (LocaleNCompare(expression,"minima",6) == 0)
2760  break;
2761  if (LocaleNCompare(expression,"min",3) == 0)
2762  {
2763  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2764  depth+1,beta,exception);
2765  FxReturn(alpha < *beta ? alpha : *beta);
2766  }
2767  if (LocaleNCompare(expression,"mod",3) == 0)
2768  {
2769  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2770  depth+1,beta,exception);
2771  gamma=alpha-floor((alpha*PerceptibleReciprocal(*beta)))*(*beta);
2772  FxReturn(gamma);
2773  }
2774  if (LocaleCompare(expression,"m") == 0)
2775  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2776  break;
2777  }
2778  case 'N':
2779  case 'n':
2780  {
2781  if (LocaleNCompare(expression,"not",3) == 0)
2782  {
2783  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2784  depth+1,beta,exception);
2785  FxReturn((double) (alpha < MagickEpsilon));
2786  }
2787  if (LocaleCompare(expression,"n") == 0)
2788  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2789  break;
2790  }
2791  case 'O':
2792  case 'o':
2793  {
2794  if (LocaleCompare(expression,"Opaque") == 0)
2795  FxReturn(1.0);
2796  if (LocaleCompare(expression,"o") == 0)
2797  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2798  break;
2799  }
2800  case 'P':
2801  case 'p':
2802  {
2803  if (LocaleCompare(expression,"phi") == 0)
2805  if (LocaleCompare(expression,"pi") == 0)
2806  FxReturn(MagickPI);
2807  if (LocaleNCompare(expression,"pow",3) == 0)
2808  {
2809  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2810  depth+1,beta,exception);
2811  FxReturn(pow(alpha,*beta));
2812  }
2813  if (LocaleCompare(expression,"p") == 0)
2814  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2815  break;
2816  }
2817  case 'Q':
2818  case 'q':
2819  {
2820  if (LocaleCompare(expression,"QuantumRange") == 0)
2822  if (LocaleCompare(expression,"QuantumScale") == 0)
2824  break;
2825  }
2826  case 'R':
2827  case 'r':
2828  {
2829  if (LocaleNCompare(expression,"rand",4) == 0)
2830  {
2831 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2832  #pragma omp critical (MagickCore_FxEvaluateSubexpression)
2833 #endif
2834  alpha=GetPseudoRandomValue(fx_info->random_info);
2835  FxReturn(alpha);
2836  }
2837  if (LocaleNCompare(expression,"round",5) == 0)
2838  {
2839  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2840  depth+1,beta,exception);
2841  FxReturn(floor(alpha+0.5));
2842  }
2843  if (LocaleCompare(expression,"r") == 0)
2844  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2845  break;
2846  }
2847  case 'S':
2848  case 's':
2849  {
2850  if (LocaleCompare(expression,"saturation") == 0)
2851  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2852  if (LocaleNCompare(expression,"sign",4) == 0)
2853  {
2854  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2855  depth+1,beta,exception);
2856  FxReturn(alpha < 0.0 ? -1.0 : 1.0);
2857  }
2858  if (LocaleNCompare(expression,"sinc",4) == 0)
2859  {
2860  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2861  depth+1,beta,exception);
2862  if (alpha == 0)
2863  FxReturn(1.0);
2864  gamma=sin((MagickPI*alpha))/(MagickPI*alpha);
2865  FxReturn(gamma);
2866  }
2867  if (LocaleNCompare(expression,"sinh",4) == 0)
2868  {
2869  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2870  depth+1,beta,exception);
2871  FxReturn(sinh(alpha));
2872  }
2873  if (LocaleNCompare(expression,"sin",3) == 0)
2874  {
2875  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2876  depth+1,beta,exception);
2877  FxReturn(sin(alpha));
2878  }
2879  if (LocaleNCompare(expression,"sqrt",4) == 0)
2880  {
2881  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2882  depth+1,beta,exception);
2883  FxReturn(sqrt(alpha));
2884  }
2885  if (LocaleNCompare(expression,"squish",6) == 0)
2886  {
2887  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,
2888  depth+1,beta,exception);
2889  FxReturn((1.0/(1.0+exp(-alpha))));
2890  }
2891  if (LocaleCompare(expression,"s") == 0)
2892  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2893  break;
2894  }
2895  case 'T':
2896  case 't':
2897  {
2898  if (LocaleNCompare(expression,"tanh",4) == 0)
2899  {
2900  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2901  depth+1,beta,exception);
2902  FxReturn(tanh(alpha));
2903  }
2904  if (LocaleNCompare(expression,"tan",3) == 0)
2905  {
2906  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2907  depth+1,beta,exception);
2908  FxReturn(tan(alpha));
2909  }
2910  if (LocaleCompare(expression,"Transparent") == 0)
2911  FxReturn(0.0);
2912  if (LocaleNCompare(expression,"trunc",5) == 0)
2913  {
2914  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2915  depth+1,beta,exception);
2916  if (alpha >= 0.0)
2917  FxReturn(floor(alpha));
2918  FxReturn(ceil(alpha));
2919  }
2920  if (LocaleCompare(expression,"t") == 0)
2921  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2922  break;
2923  }
2924  case 'U':
2925  case 'u':
2926  {
2927  if (LocaleCompare(expression,"u") == 0)
2928  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2929  break;
2930  }
2931  case 'V':
2932  case 'v':
2933  {
2934  if (LocaleCompare(expression,"v") == 0)
2935  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2936  break;
2937  }
2938  case 'W':
2939  case 'w':
2940  {
2941  if (LocaleNCompare(expression,"while",5) == 0)
2942  {
2943  do
2944  {
2945  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2946  depth+1,beta,exception);
2947  } while (fabs(alpha) >= MagickEpsilon);
2948  FxReturn(*beta);
2949  }
2950  if (LocaleCompare(expression,"w") == 0)
2951  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2952  break;
2953  }
2954  case 'Y':
2955  case 'y':
2956  {
2957  if (LocaleCompare(expression,"y") == 0)
2958  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2959  break;
2960  }
2961  case 'Z':
2962  case 'z':
2963  {
2964  if (LocaleCompare(expression,"z") == 0)
2965  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2966  break;
2967  }
2968  default:
2969  break;
2970  }
2971  subexpression=DestroyString(subexpression);
2972  q=(char *) expression;
2973  alpha=InterpretSiPrefixValue(expression,&q);
2974  if (q == expression)
2975  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2976  FxReturn(alpha);
2977 }
2978 
2980  double *alpha,ExceptionInfo *exception)
2981 {
2983  status;
2984 
2985  status=FxEvaluateChannelExpression(fx_info,GrayPixelChannel,0,0,alpha,
2986  exception);
2987  return(status);
2988 }
2989 
2991  double *alpha,ExceptionInfo *exception)
2992 {
2993  FILE
2994  *file;
2995 
2997  status;
2998 
2999  file=fx_info->file;
3000  fx_info->file=(FILE *) NULL;
3001  status=FxEvaluateChannelExpression(fx_info,GrayPixelChannel,0,0,alpha,
3002  exception);
3003  fx_info->file=file;
3004  return(status);
3005 }
3006 
3008  const PixelChannel channel,const ssize_t x,const ssize_t y,
3009  double *alpha,ExceptionInfo *exception)
3010 {
3011  double
3012  beta;
3013 
3014  beta=0.0;
3015  *alpha=FxEvaluateSubexpression(fx_info,channel,x,y,fx_info->expression,0,
3016  &beta,exception);
3017  return(exception->severity == OptionError ? MagickFalse : MagickTrue);
3018 }
3019 
3020 /*
3021 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3022 % %
3023 % %
3024 % %
3025 % F x I m a g e %
3026 % %
3027 % %
3028 % %
3029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3030 %
3031 % FxImage() applies a mathematical expression to the specified image.
3032 %
3033 % The format of the FxImage method is:
3034 %
3035 % Image *FxImage(const Image *image,const char *expression,
3036 % ExceptionInfo *exception)
3037 %
3038 % A description of each parameter follows:
3039 %
3040 % o image: the image.
3041 %
3042 % o expression: A mathematical expression.
3043 %
3044 % o exception: return any errors or warnings in this structure.
3045 %
3046 */
3047 
3048 static FxInfo **DestroyFxThreadSet(FxInfo **fx_info)
3049 {
3050  register ssize_t
3051  i;
3052 
3053  assert(fx_info != (FxInfo **) NULL);
3054  for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
3055  if (fx_info[i] != (FxInfo *) NULL)
3056  fx_info[i]=DestroyFxInfo(fx_info[i]);
3057  fx_info=(FxInfo **) RelinquishMagickMemory(fx_info);
3058  return(fx_info);
3059 }
3060 
3061 static FxInfo **AcquireFxThreadSet(const Image *image,const char *expression,
3062  ExceptionInfo *exception)
3063 {
3064  char
3065  *fx_expression;
3066 
3067  FxInfo
3068  **fx_info;
3069 
3070  double
3071  alpha;
3072 
3073  register ssize_t
3074  i;
3075 
3076  size_t
3077  number_threads;
3078 
3079  number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
3080  fx_info=(FxInfo **) AcquireQuantumMemory(number_threads,sizeof(*fx_info));
3081  if (fx_info == (FxInfo **) NULL)
3082  {
3083  (void) ThrowMagickException(exception,GetMagickModule(),
3084  ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
3085  return((FxInfo **) NULL);
3086  }
3087  (void) memset(fx_info,0,number_threads*sizeof(*fx_info));
3088  if (*expression != '@')
3089  fx_expression=ConstantString(expression);
3090  else
3091  fx_expression=FileToString(expression+1,~0UL,exception);
3092  for (i=0; i < (ssize_t) number_threads; i++)
3093  {
3095  status;
3096 
3097  fx_info[i]=AcquireFxInfo(image,fx_expression,exception);
3098  if (fx_info[i] == (FxInfo *) NULL)
3099  break;
3100  status=FxPreprocessExpression(fx_info[i],&alpha,exception);
3101  if (status == MagickFalse)
3102  break;
3103  }
3104  fx_expression=DestroyString(fx_expression);
3105  if (i < (ssize_t) number_threads)
3106  fx_info=DestroyFxThreadSet(fx_info);
3107  return(fx_info);
3108 }
3109 
3110 MagickExport Image *FxImage(const Image *image,const char *expression,
3111  ExceptionInfo *exception)
3112 {
3113 #define FxImageTag "Fx/Image"
3114 
3115  CacheView
3116  *fx_view,
3117  *image_view;
3118 
3119  FxInfo
3120  **magick_restrict fx_info;
3121 
3122  Image
3123  *fx_image;
3124 
3126  status;
3127 
3129  progress;
3130 
3131  ssize_t
3132  y;
3133 
3134  assert(image != (Image *) NULL);
3135  assert(image->signature == MagickCoreSignature);
3136  if (image->debug != MagickFalse)
3137  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3138  if (expression == (const char *) NULL)
3139  return(CloneImage(image,0,0,MagickTrue,exception));
3140  fx_info=AcquireFxThreadSet(image,expression,exception);
3141  if (fx_info == (FxInfo **) NULL)
3142  return((Image *) NULL);
3143  fx_image=CloneImage(image,0,0,MagickTrue,exception);
3144  if (fx_image == (Image *) NULL)
3145  {
3146  fx_info=DestroyFxThreadSet(fx_info);
3147  return((Image *) NULL);
3148  }
3149  if (SetImageStorageClass(fx_image,DirectClass,exception) == MagickFalse)
3150  {
3151  fx_info=DestroyFxThreadSet(fx_info);
3152  fx_image=DestroyImage(fx_image);
3153  return((Image *) NULL);
3154  }
3155  /*
3156  Fx image.
3157  */
3158  status=MagickTrue;
3159  progress=0;
3160  image_view=AcquireVirtualCacheView(image,exception);
3161  fx_view=AcquireAuthenticCacheView(fx_image,exception);
3162 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3163  #pragma omp parallel for schedule(static) shared(progress,status) \
3164  magick_number_threads(image,fx_image,fx_image->rows,1)
3165 #endif
3166  for (y=0; y < (ssize_t) fx_image->rows; y++)
3167  {
3168  const int
3169  id = GetOpenMPThreadId();
3170 
3171  register const Quantum
3172  *magick_restrict p;
3173 
3174  register Quantum
3175  *magick_restrict q;
3176 
3177  register ssize_t
3178  x;
3179 
3180  if (status == MagickFalse)
3181  continue;
3182  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
3183  q=QueueCacheViewAuthenticPixels(fx_view,0,y,fx_image->columns,1,exception);
3184  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3185  {
3186  status=MagickFalse;
3187  continue;
3188  }
3189  for (x=0; x < (ssize_t) fx_image->columns; x++)
3190  {
3191  register ssize_t
3192  i;
3193 
3194  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3195  {
3196  double
3197  alpha;
3198 
3199  PixelChannel channel = GetPixelChannelChannel(image,i);
3200  PixelTrait traits = GetPixelChannelTraits(image,channel);
3201  PixelTrait fx_traits=GetPixelChannelTraits(fx_image,channel);
3202  if ((traits == UndefinedPixelTrait) ||
3203  (fx_traits == UndefinedPixelTrait))
3204  continue;
3205  if ((fx_traits & CopyPixelTrait) != 0)
3206  {
3207  SetPixelChannel(fx_image,channel,p[i],q);
3208  continue;
3209  }
3210  alpha=0.0;
3211  (void) FxEvaluateChannelExpression(fx_info[id],channel,x,y,&alpha,
3212  exception);
3213  q[i]=ClampToQuantum(QuantumRange*alpha);
3214  }
3215  p+=GetPixelChannels(image);
3216  q+=GetPixelChannels(fx_image);
3217  }
3218  if (SyncCacheViewAuthenticPixels(fx_view,exception) == MagickFalse)
3219  status=MagickFalse;
3220  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3221  {
3223  proceed;
3224 
3225 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3226  #pragma omp critical (MagickCore_FxImage)
3227 #endif
3228  proceed=SetImageProgress(image,FxImageTag,progress++,image->rows);
3229  if (proceed == MagickFalse)
3230  status=MagickFalse;
3231  }
3232  }
3233  fx_view=DestroyCacheView(fx_view);
3234  image_view=DestroyCacheView(image_view);
3235  fx_info=DestroyFxThreadSet(fx_info);
3236  if (status == MagickFalse)
3237  fx_image=DestroyImage(fx_image);
3238  return(fx_image);
3239 }
3240 
3241 /*
3242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3243 % %
3244 % %
3245 % %
3246 % I m p l o d e I m a g e %
3247 % %
3248 % %
3249 % %
3250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3251 %
3252 % ImplodeImage() creates a new image that is a copy of an existing
3253 % one with the image pixels "implode" by the specified percentage. It
3254 % allocates the memory necessary for the new Image structure and returns a
3255 % pointer to the new image.
3256 %
3257 % The format of the ImplodeImage method is:
3258 %
3259 % Image *ImplodeImage(const Image *image,const double amount,
3260 % const PixelInterpolateMethod method,ExceptionInfo *exception)
3261 %
3262 % A description of each parameter follows:
3263 %
3264 % o implode_image: Method ImplodeImage returns a pointer to the image
3265 % after it is implode. A null image is returned if there is a memory
3266 % shortage.
3267 %
3268 % o image: the image.
3269 %
3270 % o amount: Define the extent of the implosion.
3271 %
3272 % o method: the pixel interpolation method.
3273 %
3274 % o exception: return any errors or warnings in this structure.
3275 %
3276 */
3277 MagickExport Image *ImplodeImage(const Image *image,const double amount,
3278  const PixelInterpolateMethod method,ExceptionInfo *exception)
3279 {
3280 #define ImplodeImageTag "Implode/Image"
3281 
3282  CacheView
3283  *canvas_view,
3284  *implode_view,
3285  *interpolate_view;
3286 
3287  double
3288  radius;
3289 
3290  Image
3291  *canvas_image,
3292  *implode_image;
3293 
3295  status;
3296 
3298  progress;
3299 
3300  PointInfo
3301  center,
3302  scale;
3303 
3304  ssize_t
3305  y;
3306 
3307  /*
3308  Initialize implode image attributes.
3309  */
3310  assert(image != (Image *) NULL);
3311  assert(image->signature == MagickCoreSignature);
3312  if (image->debug != MagickFalse)
3313  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3314  assert(exception != (ExceptionInfo *) NULL);
3315  assert(exception->signature == MagickCoreSignature);
3316  canvas_image=CloneImage(image,0,0,MagickTrue,exception);
3317  if (canvas_image == (Image *) NULL)
3318  return((Image *) NULL);
3319  if ((canvas_image->alpha_trait == UndefinedPixelTrait) &&
3320  (canvas_image->background_color.alpha != OpaqueAlpha))
3321  (void) SetImageAlphaChannel(canvas_image,OpaqueAlphaChannel,exception);
3322  implode_image=CloneImage(canvas_image,0,0,MagickTrue,exception);
3323  if (implode_image == (Image *) NULL)
3324  {
3325  canvas_image=DestroyImage(canvas_image);
3326  return((Image *) NULL);
3327  }
3328  if (SetImageStorageClass(implode_image,DirectClass,exception) == MagickFalse)
3329  {
3330  canvas_image=DestroyImage(canvas_image);
3331  implode_image=DestroyImage(implode_image);
3332  return((Image *) NULL);
3333  }
3334  /*
3335  Compute scaling factor.
3336  */
3337  scale.x=1.0;
3338  scale.y=1.0;
3339  center.x=0.5*canvas_image->columns;
3340  center.y=0.5*canvas_image->rows;
3341  radius=center.x;
3342  if (canvas_image->columns > canvas_image->rows)
3343  scale.y=(double) canvas_image->columns/(double) canvas_image->rows;
3344  else
3345  if (canvas_image->columns < canvas_image->rows)
3346  {
3347  scale.x=(double) canvas_image->rows/(double) canvas_image->columns;
3348  radius=center.y;
3349  }
3350  /*
3351  Implode image.
3352  */
3353  status=MagickTrue;
3354  progress=0;
3355  canvas_view=AcquireVirtualCacheView(canvas_image,exception);
3356  interpolate_view=AcquireVirtualCacheView(canvas_image,exception);
3357  implode_view=AcquireAuthenticCacheView(implode_image,exception);
3358 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3359  #pragma omp parallel for schedule(static) shared(progress,status) \
3360  magick_number_threads(canvas_image,implode_image,canvas_image->rows,1)
3361 #endif
3362  for (y=0; y < (ssize_t) canvas_image->rows; y++)
3363  {
3364  double
3365  distance;
3366 
3367  PointInfo
3368  delta;
3369 
3370  register const Quantum
3371  *magick_restrict p;
3372 
3373  register ssize_t
3374  x;
3375 
3376  register Quantum
3377  *magick_restrict q;
3378 
3379  if (status == MagickFalse)
3380  continue;
3381  p=GetCacheViewVirtualPixels(canvas_view,0,y,canvas_image->columns,1,
3382  exception);
3383  q=QueueCacheViewAuthenticPixels(implode_view,0,y,implode_image->columns,1,
3384  exception);
3385  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3386  {
3387  status=MagickFalse;
3388  continue;
3389  }
3390  delta.y=scale.y*(double) (y-center.y);
3391  for (x=0; x < (ssize_t) canvas_image->columns; x++)
3392  {
3393  register ssize_t
3394  i;
3395 
3396  /*
3397  Determine if the pixel is within an ellipse.
3398  */
3399  delta.x=scale.x*(double) (x-center.x);
3400  distance=delta.x*delta.x+delta.y*delta.y;
3401  if (distance >= (radius*radius))
3402  for (i=0; i < (ssize_t) GetPixelChannels(canvas_image); i++)
3403  {
3404  PixelChannel channel = GetPixelChannelChannel(canvas_image,i);
3405  PixelTrait traits = GetPixelChannelTraits(canvas_image,channel);
3406  PixelTrait implode_traits = GetPixelChannelTraits(implode_image,
3407  channel);
3408  if ((traits == UndefinedPixelTrait) ||
3409  (implode_traits == UndefinedPixelTrait))
3410  continue;
3411  SetPixelChannel(implode_image,channel,p[i],q);
3412  }
3413  else
3414  {
3415  double
3416  factor;
3417 
3418  /*
3419  Implode the pixel.
3420  */
3421  factor=1.0;
3422  if (distance > 0.0)
3423  factor=pow(sin(MagickPI*sqrt((double) distance)/radius/2),-amount);
3424  status=InterpolatePixelChannels(canvas_image,interpolate_view,
3425  implode_image,method,(double) (factor*delta.x/scale.x+center.x),
3426  (double) (factor*delta.y/scale.y+center.y),q,exception);
3427  if (status == MagickFalse)
3428  break;
3429  }
3430  p+=GetPixelChannels(canvas_image);
3431  q+=GetPixelChannels(implode_image);
3432  }
3433  if (SyncCacheViewAuthenticPixels(implode_view,exception) == MagickFalse)
3434  status=MagickFalse;
3435  if (canvas_image->progress_monitor != (MagickProgressMonitor) NULL)
3436  {
3438  proceed;
3439 
3440 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3441  #pragma omp critical (MagickCore_ImplodeImage)
3442 #endif
3443  proceed=SetImageProgress(canvas_image,ImplodeImageTag,progress++,
3444  canvas_image->rows);
3445  if (proceed == MagickFalse)
3446  status=MagickFalse;
3447  }
3448  }
3449  implode_view=DestroyCacheView(implode_view);
3450  interpolate_view=DestroyCacheView(interpolate_view);
3451  canvas_view=DestroyCacheView(canvas_view);
3452  canvas_image=DestroyImage(canvas_image);
3453  if (status == MagickFalse)
3454  implode_image=DestroyImage(implode_image);
3455  return(implode_image);
3456 }
3457 
3458 /*
3459 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3460 % %
3461 % %
3462 % %
3463 % M o r p h I m a g e s %
3464 % %
3465 % %
3466 % %
3467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3468 %
3469 % The MorphImages() method requires a minimum of two images. The first
3470 % image is transformed into the second by a number of intervening images
3471 % as specified by frames.
3472 %
3473 % The format of the MorphImage method is:
3474 %
3475 % Image *MorphImages(const Image *image,const size_t number_frames,
3476 % ExceptionInfo *exception)
3477 %
3478 % A description of each parameter follows:
3479 %
3480 % o image: the image.
3481 %
3482 % o number_frames: Define the number of in-between image to generate.
3483 % The more in-between frames, the smoother the morph.
3484 %
3485 % o exception: return any errors or warnings in this structure.
3486 %
3487 */
3488 MagickExport Image *MorphImages(const Image *image,const size_t number_frames,
3489  ExceptionInfo *exception)
3490 {
3491 #define MorphImageTag "Morph/Image"
3492 
3493  double
3494  alpha,
3495  beta;
3496 
3497  Image
3498  *morph_image,
3499  *morph_images;
3500 
3502  status;
3503 
3505  scene;
3506 
3507  register const Image
3508  *next;
3509 
3510  register ssize_t
3511  n;
3512 
3513  ssize_t
3514  y;
3515 
3516  /*
3517  Clone first frame in sequence.
3518  */
3519  assert(image != (Image *) NULL);
3520  assert(image->signature == MagickCoreSignature);
3521  if (image->debug != MagickFalse)
3522  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3523  assert(exception != (ExceptionInfo *) NULL);
3524  assert(exception->signature == MagickCoreSignature);
3525  morph_images=CloneImage(image,0,0,MagickTrue,exception);
3526  if (morph_images == (Image *) NULL)
3527  return((Image *) NULL);
3528  if (GetNextImageInList(image) == (Image *) NULL)
3529  {
3530  /*
3531  Morph single image.
3532  */
3533  for (n=1; n < (ssize_t) number_frames; n++)
3534  {
3535  morph_image=CloneImage(image,0,0,MagickTrue,exception);
3536  if (morph_image == (Image *) NULL)
3537  {
3538  morph_images=DestroyImageList(morph_images);
3539  return((Image *) NULL);
3540  }
3541  AppendImageToList(&morph_images,morph_image);
3542  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3543  {
3545  proceed;
3546 
3548  number_frames);
3549  if (proceed == MagickFalse)
3550  status=MagickFalse;
3551  }
3552  }
3553  return(GetFirstImageInList(morph_images));
3554  }
3555  /*
3556  Morph image sequence.
3557  */
3558  status=MagickTrue;
3559  scene=0;
3560  next=image;
3561  for ( ; GetNextImageInList(next) != (Image *) NULL; next=GetNextImageInList(next))
3562  {
3563  for (n=0; n < (ssize_t) number_frames; n++)
3564  {
3565  CacheView
3566  *image_view,
3567  *morph_view;
3568 
3569  beta=(double) (n+1.0)/(double) (number_frames+1.0);
3570  alpha=1.0-beta;
3571  morph_image=ResizeImage(next,(size_t) (alpha*next->columns+beta*
3572  GetNextImageInList(next)->columns+0.5),(size_t) (alpha*next->rows+beta*
3573  GetNextImageInList(next)->rows+0.5),next->filter,exception);
3574  if (morph_image == (Image *) NULL)
3575  {
3576  morph_images=DestroyImageList(morph_images);
3577  return((Image *) NULL);
3578  }
3579  status=SetImageStorageClass(morph_image,DirectClass,exception);
3580  if (status == MagickFalse)
3581  {
3582  morph_image=DestroyImage(morph_image);
3583  return((Image *) NULL);
3584  }
3585  AppendImageToList(&morph_images,morph_image);
3586  morph_images=GetLastImageInList(morph_images);
3587  morph_image=ResizeImage(GetNextImageInList(next),morph_images->columns,
3588  morph_images->rows,GetNextImageInList(next)->filter,exception);
3589  if (morph_image == (Image *) NULL)
3590  {
3591  morph_images=DestroyImageList(morph_images);
3592  return((Image *) NULL);
3593  }
3594  image_view=AcquireVirtualCacheView(morph_image,exception);
3595  morph_view=AcquireAuthenticCacheView(morph_images,exception);
3596 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3597  #pragma omp parallel for schedule(static) shared(status) \
3598  magick_number_threads(morph_image,morph_image,morph_image->rows,1)
3599 #endif
3600  for (y=0; y < (ssize_t) morph_images->rows; y++)
3601  {
3603  sync;
3604 
3605  register const Quantum
3606  *magick_restrict p;
3607 
3608  register ssize_t
3609  x;
3610 
3611  register Quantum
3612  *magick_restrict q;
3613 
3614  if (status == MagickFalse)
3615  continue;
3616  p=GetCacheViewVirtualPixels(image_view,0,y,morph_image->columns,1,
3617  exception);
3618  q=GetCacheViewAuthenticPixels(morph_view,0,y,morph_images->columns,1,
3619  exception);
3620  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
3621  {
3622  status=MagickFalse;
3623  continue;
3624  }
3625  for (x=0; x < (ssize_t) morph_images->columns; x++)
3626  {
3627  register ssize_t
3628  i;
3629 
3630  for (i=0; i < (ssize_t) GetPixelChannels(morph_image); i++)
3631  {
3632  PixelChannel channel = GetPixelChannelChannel(morph_image,i);
3633  PixelTrait traits = GetPixelChannelTraits(morph_image,channel);
3634  PixelTrait morph_traits=GetPixelChannelTraits(morph_images,channel);
3635  if ((traits == UndefinedPixelTrait) ||
3636  (morph_traits == UndefinedPixelTrait))
3637  continue;
3638  if ((morph_traits & CopyPixelTrait) != 0)
3639  {
3640  SetPixelChannel(morph_image,channel,p[i],q);
3641  continue;
3642  }
3643  SetPixelChannel(morph_image,channel,ClampToQuantum(alpha*
3644  GetPixelChannel(morph_images,channel,q)+beta*p[i]),q);
3645  }
3646  p+=GetPixelChannels(morph_image);
3647  q+=GetPixelChannels(morph_images);
3648  }
3649  sync=SyncCacheViewAuthenticPixels(morph_view,exception);
3650  if (sync == MagickFalse)
3651  status=MagickFalse;
3652  }
3653  morph_view=DestroyCacheView(morph_view);
3654  image_view=DestroyCacheView(image_view);
3655  morph_image=DestroyImage(morph_image);
3656  }
3657  if (n < (ssize_t) number_frames)
3658  break;
3659  /*
3660  Clone last frame in sequence.
3661  */
3662  morph_image=CloneImage(GetNextImageInList(next),0,0,MagickTrue,exception);
3663  if (morph_image == (Image *) NULL)
3664  {
3665  morph_images=DestroyImageList(morph_images);
3666  return((Image *) NULL);
3667  }
3668  AppendImageToList(&morph_images,morph_image);
3669  morph_images=GetLastImageInList(morph_images);
3670  if (image->progress_monitor != (MagickProgressMonitor) NULL)
3671  {
3673  proceed;
3674 
3675 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3676  #pragma omp critical (MagickCore_MorphImages)
3677 #endif
3678  proceed=SetImageProgress(image,MorphImageTag,scene,
3679  GetImageListLength(image));
3680  if (proceed == MagickFalse)
3681  status=MagickFalse;
3682  }
3683  scene++;
3684  }
3685  if (GetNextImageInList(next) != (Image *) NULL)
3686  {
3687  morph_images=DestroyImageList(morph_images);
3688  return((Image *) NULL);
3689  }
3690  return(GetFirstImageInList(morph_images));
3691 }
3692 
3693 /*
3694 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3695 % %
3696 % %
3697 % %
3698 % P l a s m a I m a g e %
3699 % %
3700 % %
3701 % %
3702 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3703 %
3704 % PlasmaImage() initializes an image with plasma fractal values. The image
3705 % must be initialized with a base color and the random number generator
3706 % seeded before this method is called.
3707 %
3708 % The format of the PlasmaImage method is:
3709 %
3710 % MagickBooleanType PlasmaImage(Image *image,const SegmentInfo *segment,
3711 % size_t attenuate,size_t depth,ExceptionInfo *exception)
3712 %
3713 % A description of each parameter follows:
3714 %
3715 % o image: the image.
3716 %
3717 % o segment: Define the region to apply plasma fractals values.
3718 %
3719 % o attenuate: Define the plasma attenuation factor.
3720 %
3721 % o depth: Limit the plasma recursion depth.
3722 %
3723 % o exception: return any errors or warnings in this structure.
3724 %
3725 */
3726 
3728  const double pixel,const double noise)
3729 {
3730  Quantum
3731  plasma;
3732 
3733  plasma=ClampToQuantum(pixel+noise*GetPseudoRandomValue(random_info)-
3734  noise/2.0);
3735  if (plasma <= 0)
3736  return((Quantum) 0);
3737  if (plasma >= QuantumRange)
3738  return(QuantumRange);
3739  return(plasma);
3740 }
3741 
3743  CacheView *u_view,CacheView *v_view,RandomInfo *random_info,
3744  const SegmentInfo *segment,size_t attenuate,size_t depth,
3745  ExceptionInfo *exception)
3746 {
3747  double
3748  plasma;
3749 
3750  register const Quantum
3751  *magick_restrict u,
3752  *magick_restrict v;
3753 
3754  register Quantum
3755  *magick_restrict q;
3756 
3757  register ssize_t
3758  i;
3759 
3760  ssize_t
3761  x,
3762  x_mid,
3763  y,
3764  y_mid;
3765 
3766  if ((fabs(segment->x2-segment->x1) <= MagickEpsilon) &&
3767  (fabs(segment->y2-segment->y1) <= MagickEpsilon))
3768  return(MagickTrue);
3769  if (depth != 0)
3770  {
3772  status;
3773 
3774  SegmentInfo
3775  local_info;
3776 
3777  /*
3778  Divide the area into quadrants and recurse.
3779  */
3780  depth--;
3781  attenuate++;
3782  x_mid=(ssize_t) ceil((segment->x1+segment->x2)/2-0.5);
3783  y_mid=(ssize_t) ceil((segment->y1+segment->y2)/2-0.5);
3784  local_info=(*segment);
3785  local_info.x2=(double) x_mid;
3786  local_info.y2=(double) y_mid;
3787  (void) PlasmaImageProxy(image,image_view,u_view,v_view,random_info,
3788  &local_info,attenuate,depth,exception);
3789  local_info=(*segment);
3790  local_info.y1=(double) y_mid;
3791  local_info.x2=(double) x_mid;
3792  (void) PlasmaImageProxy(image,image_view,u_view,v_view,random_info,
3793  &local_info,attenuate,depth,exception);
3794  local_info=(*segment);
3795  local_info.x1=(double) x_mid;
3796  local_info.y2=(double) y_mid;
3797  (void) PlasmaImageProxy(image,image_view,u_view,v_view,random_info,
3798  &local_info,attenuate,depth,exception);
3799  local_info=(*segment);
3800  local_info.x1=(double) x_mid;
3801  local_info.y1=(double) y_mid;
3802  status=PlasmaImageProxy(image,image_view,u_view,v_view,random_info,
3803  &local_info,attenuate,depth,exception);
3804  return(status);
3805  }
3806  x_mid=(ssize_t) ceil((segment->x1+segment->x2)/2-0.5);
3807  y_mid=(ssize_t) ceil((segment->y1+segment->y2)/2-0.5);
3808  if ((fabs(segment->x1-x_mid) < MagickEpsilon) &&
3809  (fabs(segment->x2-x_mid) < MagickEpsilon) &&
3810  (fabs(segment->y1-y_mid) < MagickEpsilon) &&
3811  (fabs(segment->y2-y_mid) < MagickEpsilon))
3812  return(MagickFalse);
3813  /*
3814  Average pixels and apply plasma.
3815  */
3816  plasma=(double) QuantumRange/(2.0*attenuate);
3817  if ((fabs(segment->x1-x_mid) > MagickEpsilon) ||
3818  (fabs(segment->x2-x_mid) > MagickEpsilon))
3819  {
3820  /*
3821  Left pixel.
3822  */
3823  x=(ssize_t) ceil(segment->x1-0.5);
3824  u=GetCacheViewVirtualPixels(u_view,x,(ssize_t) ceil(segment->y1-0.5),1,1,
3825  exception);
3826  v=GetCacheViewVirtualPixels(v_view,x,(ssize_t) ceil(segment->y2-0.5),1,1,
3827  exception);
3828  q=QueueCacheViewAuthenticPixels(image_view,x,y_mid,1,1,exception);
3829  if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
3830  (q == (Quantum *) NULL))
3831  return(MagickTrue);
3832  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3833  {
3834  PixelChannel channel = GetPixelChannelChannel(image,i);
3835  PixelTrait traits = GetPixelChannelTraits(image,channel);
3836  if (traits == UndefinedPixelTrait)
3837  continue;
3838  q[i]=PlasmaPixel(random_info,(u[i]+v[i])/2.0,plasma);
3839  }
3840  (void) SyncCacheViewAuthenticPixels(image_view,exception);
3841  if (fabs(segment->x1-segment->x2) > MagickEpsilon)
3842  {
3843  /*
3844  Right pixel.
3845  */
3846  x=(ssize_t) ceil(segment->x2-0.5);
3847  u=GetCacheViewVirtualPixels(u_view,x,(ssize_t) ceil(segment->y1-0.5),
3848  1,1,exception);
3849  v=GetCacheViewVirtualPixels(v_view,x,(ssize_t) ceil(segment->y2-0.5),
3850  1,1,exception);
3851  q=QueueCacheViewAuthenticPixels(image_view,x,y_mid,1,1,exception);
3852  if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
3853  (q == (Quantum *) NULL))
3854  return(MagickTrue);
3855  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3856  {
3857  PixelChannel channel = GetPixelChannelChannel(image,i);
3858  PixelTrait traits = GetPixelChannelTraits(image,channel);
3859  if (traits == UndefinedPixelTrait)
3860  continue;
3861  q[i]=PlasmaPixel(random_info,(u[i]+v[i])/2.0,plasma);
3862  }
3863  (void) SyncCacheViewAuthenticPixels(image_view,exception);
3864  }
3865  }
3866  if ((fabs(segment->y1-y_mid) > MagickEpsilon) ||
3867  (fabs(segment->y2-y_mid) > MagickEpsilon))
3868  {
3869  if ((fabs(segment->x1-x_mid) > MagickEpsilon) ||
3870  (fabs(segment->y2-y_mid) > MagickEpsilon))
3871  {
3872  /*
3873  Bottom pixel.
3874  */
3875  y=(ssize_t) ceil(segment->y2-0.5);
3876  u=GetCacheViewVirtualPixels(u_view,(ssize_t) ceil(segment->x1-0.5),y,
3877  1,1,exception);
3878  v=GetCacheViewVirtualPixels(v_view,(ssize_t) ceil(segment->x2-0.5),y,
3879  1,1,exception);
3880  q=QueueCacheViewAuthenticPixels(image_view,x_mid,y,1,1,exception);
3881  if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
3882  (q == (Quantum *) NULL))
3883  return(MagickTrue);
3884  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3885  {
3886  PixelChannel channel = GetPixelChannelChannel(image,i);
3887  PixelTrait traits = GetPixelChannelTraits(image,channel);
3888  if (traits == UndefinedPixelTrait)
3889  continue;
3890  q[i]=PlasmaPixel(random_info,(u[i]+v[i])/2.0,plasma);
3891  }
3892  (void) SyncCacheViewAuthenticPixels(image_view,exception);
3893  }
3894  if (fabs(segment->y1-segment->y2) > MagickEpsilon)
3895  {
3896  /*
3897  Top pixel.
3898  */
3899  y=(ssize_t) ceil(segment->y1-0.5);
3900  u=GetCacheViewVirtualPixels(u_view,(ssize_t) ceil(segment->x1-0.5),y,
3901  1,1,exception);
3902  v=GetCacheViewVirtualPixels(v_view,(ssize_t) ceil(segment->x2-0.5),y,
3903  1,1,exception);
3904  q=QueueCacheViewAuthenticPixels(image_view,x_mid,y,1,1,exception);
3905  if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
3906  (q == (Quantum *) NULL))
3907  return(MagickTrue);
3908  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3909  {
3910  PixelChannel channel = GetPixelChannelChannel(image,i);
3911  PixelTrait traits = GetPixelChannelTraits(image,channel);
3912  if (traits == UndefinedPixelTrait)
3913  continue;
3914  q[i]=PlasmaPixel(random_info,(u[i]+v[i])/2.0,plasma);
3915  }
3916  (void) SyncCacheViewAuthenticPixels(image_view,exception);
3917  }
3918  }
3919  if ((fabs(segment->x1-segment->x2) > MagickEpsilon) ||
3920  (fabs(segment->y1-segment->y2) > MagickEpsilon))
3921  {
3922  /*
3923  Middle pixel.
3924  */
3925  x=(ssize_t) ceil(segment->x1-0.5);
3926  y=(ssize_t) ceil(segment->y1-0.5);
3927  u=GetCacheViewVirtualPixels(u_view,x,y,1,1,exception);
3928  x=(ssize_t) ceil(segment->x2-0.5);
3929  y=(ssize_t) ceil(segment->y2-0.5);
3930  v=GetCacheViewVirtualPixels(v_view,x,y,1,1,exception);
3931  q=QueueCacheViewAuthenticPixels(image_view,x_mid,y_mid,1,1,exception);
3932  if ((u == (const Quantum *) NULL) || (v == (const Quantum *) NULL) ||
3933  (q == (Quantum *) NULL))
3934  return(MagickTrue);
3935  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
3936  {
3937  PixelChannel channel = GetPixelChannelChannel(image,i);
3938  PixelTrait traits = GetPixelChannelTraits(image,channel);
3939  if (traits == UndefinedPixelTrait)
3940  continue;
3941  q[i]=PlasmaPixel(random_info,(u[i]+v[i])/2.0,plasma);
3942  }
3943  (void) SyncCacheViewAuthenticPixels(image_view,exception);
3944  }
3945  if ((fabs(segment->x2-segment->x1) < 3.0) &&
3946  (fabs(segment->y2-segment->y1) < 3.0))
3947  return(MagickTrue);
3948  return(MagickFalse);
3949 }
3950 
3952  const SegmentInfo *segment,size_t attenuate,size_t depth,
3953  ExceptionInfo *exception)
3954 {
3955  CacheView
3956  *image_view,
3957  *u_view,
3958  *v_view;
3959 
3961  status;
3962 
3963  RandomInfo
3964  *random_info;
3965 
3966  assert(image != (Image *) NULL);
3967  if (image->debug != MagickFalse)
3968  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3969  assert(image->signature == MagickCoreSignature);
3970  if (image->debug != MagickFalse)
3971  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
3972  if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
3973  return(MagickFalse);
3974  image_view=AcquireAuthenticCacheView(image,exception);
3975  u_view=AcquireVirtualCacheView(image,exception);
3976  v_view=AcquireVirtualCacheView(image,exception);
3978  status=PlasmaImageProxy(image,image_view,u_view,v_view,random_info,segment,
3979  attenuate,depth,exception);
3981  v_view=DestroyCacheView(v_view);
3982  u_view=DestroyCacheView(u_view);
3983  image_view=DestroyCacheView(image_view);
3984  return(status);
3985 }
3986 
3987 /*
3988 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3989 % %
3990 % %
3991 % %
3992 % P o l a r o i d I m a g e %
3993 % %
3994 % %
3995 % %
3996 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3997 %
3998 % PolaroidImage() simulates a Polaroid picture.
3999 %
4000 % The format of the PolaroidImage method is:
4001 %
4002 % Image *PolaroidImage(const Image *image,const DrawInfo *draw_info,
4003 % const char *caption,const double angle,
4004 % const PixelInterpolateMethod method,ExceptionInfo exception)
4005 %
4006 % A description of each parameter follows:
4007 %
4008 % o image: the image.
4009 %
4010 % o draw_info: the draw info.
4011 %
4012 % o caption: the Polaroid caption.
4013 %
4014 % o angle: Apply the effect along this angle.
4015 %
4016 % o method: the pixel interpolation method.
4017 %
4018 % o exception: return any errors or warnings in this structure.
4019 %
4020 */
4021 MagickExport Image *PolaroidImage(const Image *image,const DrawInfo *draw_info,
4022  const char *caption,const double angle,const PixelInterpolateMethod method,
4023  ExceptionInfo *exception)
4024 {
4025  Image
4026  *bend_image,
4027  *caption_image,
4028  *flop_image,
4029  *picture_image,
4030  *polaroid_image,
4031  *rotate_image,
4032  *trim_image;
4033 
4034  size_t
4035  height;
4036 
4037  ssize_t
4038  quantum;
4039 
4040  /*
4041  Simulate a Polaroid picture.
4042  */
4043  assert(image != (Image *) NULL);
4044  assert(image->signature == MagickCoreSignature);
4045  if (image->debug != MagickFalse)
4046  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4047  assert(exception != (ExceptionInfo *) NULL);
4048  assert(exception->signature == MagickCoreSignature);
4049  quantum=(ssize_t) MagickMax(MagickMax((double) image->columns,(double)
4050  image->rows)/25.0,10.0);
4051  height=image->rows+2*quantum;
4052  caption_image=(Image *) NULL;
4053  if (caption != (const char *) NULL)
4054  {
4055  char
4056  *text;
4057 
4058  /*
4059  Generate caption image.
4060  */
4061  caption_image=CloneImage(image,image->columns,1,MagickTrue,exception);
4062  if (caption_image == (Image *) NULL)
4063  return((Image *) NULL);
4064  text=InterpretImageProperties((ImageInfo *) NULL,(Image *) image,caption,
4065  exception);
4066  if (text != (char *) NULL)
4067  {
4068  char
4069  geometry[MagickPathExtent];
4070 
4071  DrawInfo
4072  *annotate_info;
4073 
4075  status;
4076 
4077  ssize_t
4078  count;
4079 
4080  TypeMetric
4081  metrics;
4082 
4083  annotate_info=CloneDrawInfo((const ImageInfo *) NULL,draw_info);
4084  (void) CloneString(&annotate_info->text,text);
4085  count=FormatMagickCaption(caption_image,annotate_info,MagickTrue,
4086  &metrics,&text,exception);
4087  status=SetImageExtent(caption_image,image->columns,(size_t)
4088  ((count+1)*(metrics.ascent-metrics.descent)+0.5),exception);
4089  if (status == MagickFalse)
4090  caption_image=DestroyImage(caption_image);
4091  else
4092  {
4093  caption_image->background_color=image->border_color;
4094  (void) SetImageBackgroundColor(caption_image,exception);
4095  (void) CloneString(&annotate_info->text,text);
4096  (void) FormatLocaleString(geometry,MagickPathExtent,"+0+%.20g",
4097  metrics.ascent);
4098  if (annotate_info->gravity == UndefinedGravity)
4099  (void) CloneString(&annotate_info->geometry,AcquireString(
4100  geometry));
4101  (void) AnnotateImage(caption_image,annotate_info,exception);
4102  height+=caption_image->rows;
4103  }
4104  annotate_info=DestroyDrawInfo(annotate_info);
4105  text=DestroyString(text);
4106  }
4107  }
4108  picture_image=CloneImage(image,image->columns+2*quantum,height,MagickTrue,
4109  exception);
4110  if (picture_image == (Image *) NULL)
4111  {
4112  if (caption_image != (Image *) NULL)
4113  caption_image=DestroyImage(caption_image);
4114  return((Image *) NULL);
4115  }
4116  picture_image->background_color=image->border_color;
4117  (void) SetImageBackgroundColor(picture_image,exception);
4118  (void) CompositeImage(picture_image,image,OverCompositeOp,MagickTrue,quantum,
4119  quantum,exception);
4120  if (caption_image != (Image *) NULL)
4121  {
4122  (void) CompositeImage(picture_image,caption_image,OverCompositeOp,
4123  MagickTrue,quantum,(ssize_t) (image->rows+3*quantum/2),exception);
4124  caption_image=DestroyImage(caption_image);
4125  }
4126  (void) QueryColorCompliance("none",AllCompliance,
4127  &picture_image->background_color,exception);
4128  (void) SetImageAlphaChannel(picture_image,OpaqueAlphaChannel,exception);
4129  rotate_image=RotateImage(picture_image,90.0,exception);
4130  picture_image=DestroyImage(picture_image);
4131  if (rotate_image == (Image *) NULL)
4132  return((Image *) NULL);
4133  picture_image=rotate_image;
4134  bend_image=WaveImage(picture_image,0.01*picture_image->rows,2.0*
4135  picture_image->columns,method,exception);
4136  picture_image=DestroyImage(picture_image);
4137  if (bend_image == (Image *) NULL)
4138  return((Image *) NULL);
4139  picture_image=bend_image;
4140  rotate_image=RotateImage(picture_image,-90.0,exception);
4141  picture_image=DestroyImage(picture_image);
4142  if (rotate_image == (Image *) NULL)
4143  return((Image *) NULL);
4144  picture_image=rotate_image;
4145  picture_image->background_color=image->background_color;
4146  polaroid_image=ShadowImage(picture_image,80.0,2.0,quantum/3,quantum/3,
4147  exception);
4148  if (polaroid_image == (Image *) NULL)
4149  {
4150  picture_image=DestroyImage(picture_image);
4151  return(picture_image);
4152  }
4153  flop_image=FlopImage(polaroid_image,exception);
4154  polaroid_image=DestroyImage(polaroid_image);
4155  if (flop_image == (Image *) NULL)
4156  {
4157  picture_image=DestroyImage(picture_image);
4158  return(picture_image);
4159  }
4160  polaroid_image=flop_image;
4161  (void) CompositeImage(polaroid_image,picture_image,OverCompositeOp,
4162  MagickTrue,(ssize_t) (-0.01*picture_image->columns/2.0),0L,exception);
4163  picture_image=DestroyImage(picture_image);
4164  (void) QueryColorCompliance("none",AllCompliance,
4165  &polaroid_image->background_color,exception);
4166  rotate_image=RotateImage(polaroid_image,angle,exception);
4167  polaroid_image=DestroyImage(polaroid_image);
4168  if (rotate_image == (Image *) NULL)
4169  return((Image *) NULL);
4170  polaroid_image=rotate_image;
4171  trim_image=TrimImage(polaroid_image,exception);
4172  polaroid_image=DestroyImage(polaroid_image);
4173  if (trim_image == (Image *) NULL)
4174  return((Image *) NULL);
4175  polaroid_image=trim_image;
4176  return(polaroid_image);
4177 }
4178 
4179 /*
4180 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4181 % %
4182 % %
4183 % %
4184 % S e p i a T o n e I m a g e %
4185 % %
4186 % %
4187 % %
4188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4189 %
4190 % MagickSepiaToneImage() applies a special effect to the image, similar to the
4191 % effect achieved in a photo darkroom by sepia toning. Threshold ranges from
4192 % 0 to QuantumRange and is a measure of the extent of the sepia toning. A
4193 % threshold of 80% is a good starting point for a reasonable tone.
4194 %
4195 % The format of the SepiaToneImage method is:
4196 %
4197 % Image *SepiaToneImage(const Image *image,const double threshold,
4198 % ExceptionInfo *exception)
4199 %
4200 % A description of each parameter follows:
4201 %
4202 % o image: the image.
4203 %
4204 % o threshold: the tone threshold.
4205 %
4206 % o exception: return any errors or warnings in this structure.
4207 %
4208 */
4209 MagickExport Image *SepiaToneImage(const Image *image,const double threshold,
4210  ExceptionInfo *exception)
4211 {
4212 #define SepiaToneImageTag "SepiaTone/Image"
4213 
4214  CacheView
4215  *image_view,
4216  *sepia_view;
4217 
4218  Image
4219  *sepia_image;
4220 
4222  status;
4223 
4225  progress;
4226 
4227  ssize_t
4228  y;
4229 
4230  /*
4231  Initialize sepia-toned image attributes.
4232  */
4233  assert(image != (const Image *) NULL);
4234  assert(image->signature == MagickCoreSignature);
4235  if (image->debug != MagickFalse)
4236  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4237  assert(exception != (ExceptionInfo *) NULL);
4238  assert(exception->signature == MagickCoreSignature);
4239  sepia_image=CloneImage(image,0,0,MagickTrue,exception);
4240  if (sepia_image == (Image *) NULL)
4241  return((Image *) NULL);
4242  if (SetImageStorageClass(sepia_image,DirectClass,exception) == MagickFalse)
4243  {
4244  sepia_image=DestroyImage(sepia_image);
4245  return((Image *) NULL);
4246  }
4247  /*
4248  Tone each row of the image.
4249  */
4250  status=MagickTrue;
4251  progress=0;
4252  image_view=AcquireVirtualCacheView(image,exception);
4253  sepia_view=AcquireAuthenticCacheView(sepia_image,exception);
4254 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4255  #pragma omp parallel for schedule(static) shared(progress,status) \
4256  magick_number_threads(image,sepia_image,image->rows,1)
4257 #endif
4258  for (y=0; y < (ssize_t) image->rows; y++)
4259  {
4260  register const Quantum
4261  *magick_restrict p;
4262 
4263  register ssize_t
4264  x;
4265 
4266  register Quantum
4267  *magick_restrict q;
4268 
4269  if (status == MagickFalse)
4270  continue;
4271  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
4272  q=GetCacheViewAuthenticPixels(sepia_view,0,y,sepia_image->columns,1,
4273  exception);
4274  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
4275  {
4276  status=MagickFalse;
4277  continue;
4278  }
4279  for (x=0; x < (ssize_t) image->columns; x++)
4280  {
4281  double
4282  intensity,
4283  tone;
4284 
4285  intensity=GetPixelIntensity(image,p);
4286  tone=intensity > threshold ? (double) QuantumRange : intensity+
4287  (double) QuantumRange-threshold;
4288  SetPixelRed(sepia_image,ClampToQuantum(tone),q);
4289  tone=intensity > (7.0*threshold/6.0) ? (double) QuantumRange :
4290  intensity+(double) QuantumRange-7.0*threshold/6.0;
4291  SetPixelGreen(sepia_image,ClampToQuantum(tone),q);
4292  tone=intensity < (threshold/6.0) ? 0 : intensity-threshold/6.0;
4293  SetPixelBlue(sepia_image,ClampToQuantum(tone),q);
4294  tone=threshold/7.0;
4295  if ((double) GetPixelGreen(image,q) < tone)
4296  SetPixelGreen(sepia_image,ClampToQuantum(tone),q);
4297  if ((double) GetPixelBlue(image,q) < tone)
4298  SetPixelBlue(sepia_image,ClampToQuantum(tone),q);
4299  SetPixelAlpha(sepia_image,GetPixelAlpha(image,p),q);
4300  p+=GetPixelChannels(image);
4301  q+=GetPixelChannels(sepia_image);
4302  }
4303  if (SyncCacheViewAuthenticPixels(sepia_view,exception) == MagickFalse)
4304  status=MagickFalse;
4305  if (image->progress_monitor != (MagickProgressMonitor) NULL)
4306  {
4308  proceed;
4309 
4310 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4311  #pragma omp critical (MagickCore_SepiaToneImage)
4312 #endif
4313  proceed=SetImageProgress(image,SepiaToneImageTag,progress++,
4314  image->rows);
4315  if (proceed == MagickFalse)
4316  status=MagickFalse;
4317  }
4318  }
4319  sepia_view=DestroyCacheView(sepia_view);
4320  image_view=DestroyCacheView(image_view);
4321  (void) NormalizeImage(sepia_image,exception);
4322  (void) ContrastImage(sepia_image,MagickTrue,exception);
4323  if (status == MagickFalse)
4324  sepia_image=DestroyImage(sepia_image);
4325  return(sepia_image);
4326 }
4327 
4328 /*
4329 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4330 % %
4331 % %
4332 % %
4333 % S h a d o w I m a g e %
4334 % %
4335 % %
4336 % %
4337 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4338 %
4339 % ShadowImage() simulates a shadow from the specified image and returns it.
4340 %
4341 % The format of the ShadowImage method is:
4342 %
4343 % Image *ShadowImage(const Image *image,const double alpha,
4344 % const double sigma,const ssize_t x_offset,const ssize_t y_offset,
4345 % ExceptionInfo *exception)
4346 %
4347 % A description of each parameter follows:
4348 %
4349 % o image: the image.
4350 %
4351 % o alpha: percentage transparency.
4352 %
4353 % o sigma: the standard deviation of the Gaussian, in pixels.
4354 %
4355 % o x_offset: the shadow x-offset.
4356 %
4357 % o y_offset: the shadow y-offset.
4358 %
4359 % o exception: return any errors or warnings in this structure.
4360 %
4361 */
4362 MagickExport Image *ShadowImage(const Image *image,const double alpha,
4363  const double sigma,const ssize_t x_offset,const ssize_t y_offset,
4364  ExceptionInfo *exception)
4365 {
4366 #define ShadowImageTag "Shadow/Image"
4367 
4368  CacheView
4369  *image_view;
4370 
4371  ChannelType
4372  channel_mask;
4373 
4374  Image
4375  *border_image,
4376  *clone_image,
4377  *shadow_image;
4378 
4380  status;
4381 
4382  PixelInfo
4383  background_color;
4384 
4386  border_info;
4387 
4388  ssize_t
4389  y;
4390 
4391  assert(image != (Image *) NULL);
4392  assert(image->signature == MagickCoreSignature);
4393  if (image->debug != MagickFalse)
4394  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4395  assert(exception != (ExceptionInfo *) NULL);
4396  assert(exception->signature == MagickCoreSignature);
4397  clone_image=CloneImage(image,0,0,MagickTrue,exception);
4398  if (clone_image == (Image *) NULL)
4399  return((Image *) NULL);
4400  if (IsGrayColorspace(image->colorspace) != MagickFalse)
4401  (void) SetImageColorspace(clone_image,sRGBColorspace,exception);
4403  exception);
4404  border_info.width=(size_t) floor(2.0*sigma+0.5);
4405  border_info.height=(size_t) floor(2.0*sigma+0.5);
4406  border_info.x=0;
4407  border_info.y=0;
4408  (void) QueryColorCompliance("none",AllCompliance,&clone_image->border_color,
4409  exception);
4410  clone_image->alpha_trait=BlendPixelTrait;
4411  border_image=BorderImage(clone_image,&border_info,OverCompositeOp,exception);
4412  clone_image=DestroyImage(clone_image);
4413  if (border_image == (Image *) NULL)
4414  return((Image *) NULL);
4415  if (border_image->alpha_trait == UndefinedPixelTrait)
4416  (void) SetImageAlphaChannel(border_image,OpaqueAlphaChannel,exception);
4417  /*
4418  Shadow image.
4419  */
4420  status=MagickTrue;
4421  background_color=border_image->background_color;
4422  background_color.alpha_trait=BlendPixelTrait;
4423  image_view=AcquireAuthenticCacheView(border_image,exception);
4424  for (y=0; y < (ssize_t) border_image->rows; y++)
4425  {
4426  register Quantum
4427  *magick_restrict q;
4428 
4429  register ssize_t
4430  x;
4431 
4432  if (status == MagickFalse)
4433  continue;
4434  q=QueueCacheViewAuthenticPixels(image_view,0,y,border_image->columns,1,
4435  exception);
4436  if (q == (Quantum *) NULL)
4437  {
4438  status=MagickFalse;
4439  continue;
4440  }
4441  for (x=0; x < (ssize_t) border_image->columns; x++)
4442  {
4443  if (border_image->alpha_trait != UndefinedPixelTrait)
4444  background_color.alpha=GetPixelAlpha(border_image,q)*alpha/100.0;
4445  SetPixelViaPixelInfo(border_image,&background_color,q);
4446  q+=GetPixelChannels(border_image);
4447  }
4448  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4449  status=MagickFalse;
4450  }
4451  image_view=DestroyCacheView(image_view);
4452  if (status == MagickFalse)
4453  {
4454  border_image=DestroyImage(border_image);
4455  return((Image *) NULL);
4456  }
4457  channel_mask=SetImageChannelMask(border_image,AlphaChannel);
4458  shadow_image=BlurImage(border_image,0.0,sigma,exception);
4459  border_image=DestroyImage(border_image);
4460  if (shadow_image == (Image *) NULL)
4461  return((Image *) NULL);
4462  (void) SetPixelChannelMask(shadow_image,channel_mask);
4463  if (shadow_image->page.width == 0)
4464  shadow_image->page.width=shadow_image->columns;
4465  if (shadow_image->page.height == 0)
4466  shadow_image->page.height=shadow_image->rows;
4467  shadow_image->page.width+=x_offset-(ssize_t) border_info.width;
4468  shadow_image->page.height+=y_offset-(ssize_t) border_info.height;
4469  shadow_image->page.x+=x_offset-(ssize_t) border_info.width;
4470  shadow_image->page.y+=y_offset-(ssize_t) border_info.height;
4471  return(shadow_image);
4472 }
4473 
4474 /*
4475 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4476 % %
4477 % %
4478 % %
4479 % S k e t c h I m a g e %
4480 % %
4481 % %
4482 % %
4483 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4484 %
4485 % SketchImage() simulates a pencil sketch. We convolve the image with a
4486 % Gaussian operator of the given radius and standard deviation (sigma). For
4487 % reasonable results, radius should be larger than sigma. Use a radius of 0
4488 % and SketchImage() selects a suitable radius for you. Angle gives the angle
4489 % of the sketch.
4490 %
4491 % The format of the SketchImage method is:
4492 %
4493 % Image *SketchImage(const Image *image,const double radius,
4494 % const double sigma,const double angle,ExceptionInfo *exception)
4495 %
4496 % A description of each parameter follows:
4497 %
4498 % o image: the image.
4499 %
4500 % o radius: the radius of the Gaussian, in pixels, not counting the
4501 % center pixel.
4502 %
4503 % o sigma: the standard deviation of the Gaussian, in pixels.
4504 %
4505 % o angle: apply the effect along this angle.
4506 %
4507 % o exception: return any errors or warnings in this structure.
4508 %
4509 */
4510 MagickExport Image *SketchImage(const Image *image,const double radius,
4511  const double sigma,const double angle,ExceptionInfo *exception)
4512 {
4513  CacheView
4514  *random_view;
4515 
4516  Image
4517  *blend_image,
4518  *blur_image,
4519  *dodge_image,
4520  *random_image,
4521  *sketch_image;
4522 
4524  status;
4525 
4526  RandomInfo
4528 
4529  ssize_t
4530  y;
4531 
4532 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4533  unsigned long
4534  key;
4535 #endif
4536 
4537  /*
4538  Sketch image.
4539  */
4540  random_image=CloneImage(image,image->columns << 1,image->rows << 1,
4541  MagickTrue,exception);
4542  if (random_image == (Image *) NULL)
4543  return((Image *) NULL);
4544  status=MagickTrue;
4546  random_view=AcquireAuthenticCacheView(random_image,exception);
4547 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4549  #pragma omp parallel for schedule(static) shared(status) \
4550  magick_number_threads(random_image,random_image,random_image->rows,key == ~0UL)
4551 #endif
4552  for (y=0; y < (ssize_t) random_image->rows; y++)
4553  {
4554  const int
4555  id = GetOpenMPThreadId();
4556 
4557  register Quantum
4558  *magick_restrict q;
4559 
4560  register ssize_t
4561  x;
4562 
4563  if (status == MagickFalse)
4564  continue;
4565  q=QueueCacheViewAuthenticPixels(random_view,0,y,random_image->columns,1,
4566  exception);
4567  if (q == (Quantum *) NULL)
4568  {
4569  status=MagickFalse;
4570  continue;
4571  }
4572  for (x=0; x < (ssize_t) random_image->columns; x++)
4573  {
4574  double
4575  value;
4576 
4577  register ssize_t
4578  i;
4579 
4580  value=GetPseudoRandomValue(random_info[id]);
4581  for (i=0; i < (ssize_t) GetPixelChannels(random_image); i++)
4582  {
4583  PixelChannel channel = GetPixelChannelChannel(image,i);
4584  PixelTrait traits = GetPixelChannelTraits(image,channel);
4585  if (traits == UndefinedPixelTrait)
4586  continue;
4587  q[i]=ClampToQuantum(QuantumRange*value);
4588  }
4589  q+=GetPixelChannels(random_image);
4590  }
4591  if (SyncCacheViewAuthenticPixels(random_view,exception) == MagickFalse)
4592  status=MagickFalse;
4593  }
4594  random_view=DestroyCacheView(random_view);
4596  if (status == MagickFalse)
4597  {
4598  random_image=DestroyImage(random_image);
4599  return(random_image);
4600  }
4601  blur_image=MotionBlurImage(random_image,radius,sigma,angle,exception);
4602  random_image=DestroyImage(random_image);
4603  if (blur_image == (Image *) NULL)
4604  return((Image *) NULL);
4605  dodge_image=EdgeImage(blur_image,radius,exception);
4606  blur_image=DestroyImage(blur_image);
4607  if (dodge_image == (Image *) NULL)
4608  return((Image *) NULL);
4609  (void) NormalizeImage(dodge_image,exception);
4610  (void) NegateImage(dodge_image,MagickFalse,exception);
4611  (void) TransformImage(&dodge_image,(char *) NULL,"50%",exception);
4612  sketch_image=CloneImage(image,0,0,MagickTrue,exception);
4613  if (sketch_image == (Image *) NULL)
4614  {
4615  dodge_image=DestroyImage(dodge_image);
4616  return((Image *) NULL);
4617  }
4618  (void) CompositeImage(sketch_image,dodge_image,ColorDodgeCompositeOp,
4619  MagickTrue,0,0,exception);
4620  dodge_image=DestroyImage(dodge_image);
4621  blend_image=CloneImage(image,0,0,MagickTrue,exception);
4622  if (blend_image == (Image *) NULL)
4623  {
4624  sketch_image=DestroyImage(sketch_image);
4625  return((Image *) NULL);
4626  }
4627  if (blend_image->alpha_trait != BlendPixelTrait)
4628  (void) SetImageAlpha(blend_image,TransparentAlpha,exception);
4629  (void) SetImageArtifact(blend_image,"compose:args","20x80");
4630  (void) CompositeImage(sketch_image,blend_image,BlendCompositeOp,MagickTrue,
4631  0,0,exception);
4632  blend_image=DestroyImage(blend_image);
4633  return(sketch_image);
4634 }
4635 
4636 /*
4637 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4638 % %
4639 % %
4640 % %
4641 % S o l a r i z e I m a g e %
4642 % %
4643 % %
4644 % %
4645 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4646 %
4647 % SolarizeImage() applies a special effect to the image, similar to the effect
4648 % achieved in a photo darkroom by selectively exposing areas of photo
4649 % sensitive paper to light. Threshold ranges from 0 to QuantumRange and is a
4650 % measure of the extent of the solarization.
4651 %
4652 % The format of the SolarizeImage method is:
4653 %
4654 % MagickBooleanType SolarizeImage(Image *image,const double threshold,
4655 % ExceptionInfo *exception)
4656 %
4657 % A description of each parameter follows:
4658 %
4659 % o image: the image.
4660 %
4661 % o threshold: Define the extent of the solarization.
4662 %
4663 % o exception: return any errors or warnings in this structure.
4664 %
4665 */
4667  const double threshold,ExceptionInfo *exception)
4668 {
4669 #define SolarizeImageTag "Solarize/Image"
4670 
4671  CacheView
4672  *image_view;
4673 
4675  status;
4676 
4678  progress;
4679 
4680  ssize_t
4681  y;
4682 
4683  assert(image != (Image *) NULL);
4684  assert(image->signature == MagickCoreSignature);
4685  if (image->debug != MagickFalse)
4686  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4687  if (IsGrayColorspace(image->colorspace) != MagickFalse)
4688  (void) SetImageColorspace(image,sRGBColorspace,exception);
4689  if (image->storage_class == PseudoClass)
4690  {
4691  register ssize_t
4692  i;
4693 
4694  /*
4695  Solarize colormap.
4696  */
4697  for (i=0; i < (ssize_t) image->colors; i++)
4698  {
4699  if ((double) image->colormap[i].red > threshold)
4700  image->colormap[i].red=QuantumRange-image->colormap[i].red;
4701  if ((double) image->colormap[i].green > threshold)
4702  image->colormap[i].green=QuantumRange-image->colormap[i].green;
4703  if ((double) image->colormap[i].blue > threshold)
4704  image->colormap[i].blue=QuantumRange-image->colormap[i].blue;
4705  }
4706  }
4707  /*
4708  Solarize image.
4709  */
4710  status=MagickTrue;
4711  progress=0;
4712  image_view=AcquireAuthenticCacheView(image,exception);
4713 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4714  #pragma omp parallel for schedule(static) shared(progress,status) \
4715  magick_number_threads(image,image,image->rows,1)
4716 #endif
4717  for (y=0; y < (ssize_t) image->rows; y++)
4718  {
4719  register ssize_t
4720  x;
4721 
4722  register Quantum
4723  *magick_restrict q;
4724 
4725  if (status == MagickFalse)
4726  continue;
4727  q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,exception);
4728  if (q == (Quantum *) NULL)
4729  {
4730  status=MagickFalse;
4731  continue;
4732  }
4733  for (x=0; x < (ssize_t) image->columns; x++)
4734  {
4735  register ssize_t
4736  i;
4737 
4738  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4739  {
4740  PixelChannel channel = GetPixelChannelChannel(image,i);
4741  PixelTrait traits = GetPixelChannelTraits(image,channel);
4742  if ((traits & UpdatePixelTrait) == 0)
4743  continue;
4744  if ((double) q[i] > threshold)
4745  q[i]=QuantumRange-q[i];
4746  }
4747  q+=GetPixelChannels(image);
4748  }
4749  if (SyncCacheViewAuthenticPixels(image_view,exception) == MagickFalse)
4750  status=MagickFalse;
4751  if (image->progress_monitor != (MagickProgressMonitor) NULL)
4752  {
4754  proceed;
4755 
4756 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4757  #pragma omp critical (MagickCore_SolarizeImage)
4758 #endif
4759  proceed=SetImageProgress(image,SolarizeImageTag,progress++,image->rows);
4760  if (proceed == MagickFalse)
4761  status=MagickFalse;
4762  }
4763  }
4764  image_view=DestroyCacheView(image_view);
4765  return(status);
4766 }
4767 
4768 /*
4769 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4770 % %
4771 % %
4772 % %
4773 % S t e g a n o I m a g e %
4774 % %
4775 % %
4776 % %
4777 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4778 %
4779 % SteganoImage() hides a digital watermark within the image. Recover
4780 % the hidden watermark later to prove that the authenticity of an image.
4781 % Offset defines the start position within the image to hide the watermark.
4782 %
4783 % The format of the SteganoImage method is:
4784 %
4785 % Image *SteganoImage(const Image *image,Image *watermark,
4786 % ExceptionInfo *exception)
4787 %
4788 % A description of each parameter follows:
4789 %
4790 % o image: the image.
4791 %
4792 % o watermark: the watermark image.
4793 %
4794 % o exception: return any errors or warnings in this structure.
4795 %
4796 */
4797 MagickExport Image *SteganoImage(const Image *image,const Image *watermark,
4798  ExceptionInfo *exception)
4799 {
4800 #define GetBit(alpha,i) ((((size_t) (alpha) >> (size_t) (i)) & 0x01) != 0)
4801 #define SetBit(alpha,i,set) (Quantum) ((set) != 0 ? (size_t) (alpha) \
4802  | (one << (size_t) (i)) : (size_t) (alpha) & ~(one << (size_t) (i)))
4803 #define SteganoImageTag "Stegano/Image"
4804 
4805  CacheView
4806  *stegano_view,
4807  *watermark_view;
4808 
4809  Image
4810  *stegano_image;
4811 
4812  int
4813  c;
4814 
4816  status;
4817 
4818  PixelInfo
4819  pixel;
4820 
4821  register Quantum
4822  *q;
4823 
4824  register ssize_t
4825  x;
4826 
4827  size_t
4828  depth,
4829  one;
4830 
4831  ssize_t
4832  i,
4833  j,
4834  k,
4835  y;
4836 
4837  /*
4838  Initialize steganographic image attributes.
4839  */
4840  assert(image != (const Image *) NULL);
4841  assert(image->signature == MagickCoreSignature);
4842  if (image->debug != MagickFalse)
4843  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4844  assert(watermark != (const Image *) NULL);
4845  assert(watermark->signature == MagickCoreSignature);
4846  assert(exception != (ExceptionInfo *) NULL);
4847  assert(exception->signature == MagickCoreSignature);
4848  one=1UL;
4849  stegano_image=CloneImage(image,0,0,MagickTrue,exception);
4850  if (stegano_image == (Image *) NULL)
4851  return((Image *) NULL);
4852  stegano_image->depth=MAGICKCORE_QUANTUM_DEPTH;
4853  if (SetImageStorageClass(stegano_image,DirectClass,exception) == MagickFalse)
4854  {
4855  stegano_image=DestroyImage(stegano_image);
4856  return((Image *) NULL);
4857  }
4858  /*
4859  Hide watermark in low-order bits of image.
4860  */
4861  c=0;
4862  i=0;
4863  j=0;
4864  depth=stegano_image->depth;
4865  k=stegano_image->offset;
4866  status=MagickTrue;
4867  watermark_view=AcquireVirtualCacheView(watermark,exception);
4868  stegano_view=AcquireAuthenticCacheView(stegano_image,exception);
4869  for (i=(ssize_t) depth-1; (i >= 0) && (j < (ssize_t) depth); i--)
4870  {
4871  for (y=0; (y < (ssize_t) watermark->rows) && (j < (ssize_t) depth); y++)
4872  {
4873  for (x=0; (x < (ssize_t) watermark->columns) && (j < (ssize_t) depth); x++)
4874  {
4875  ssize_t
4876  offset;
4877 
4878  (void) GetOneCacheViewVirtualPixelInfo(watermark_view,x,y,&pixel,
4879  exception);
4880  offset=k/(ssize_t) stegano_image->columns;
4881  if (offset >= (ssize_t) stegano_image->rows)
4882  break;
4883  q=GetCacheViewAuthenticPixels(stegano_view,k % (ssize_t)
4884  stegano_image->columns,k/(ssize_t) stegano_image->columns,1,1,
4885  exception);
4886  if (q == (Quantum *) NULL)
4887  break;
4888  switch (c)
4889  {
4890  case 0:
4891  {
4892  SetPixelRed(stegano_image,SetBit(GetPixelRed(stegano_image,q),j,
4893  GetBit(GetPixelInfoIntensity(stegano_image,&pixel),i)),q);
4894  break;
4895  }
4896  case 1:
4897  {
4898  SetPixelGreen(stegano_image,SetBit(GetPixelGreen(stegano_image,q),j,
4899  GetBit(GetPixelInfoIntensity(stegano_image,&pixel),i)),q);
4900  break;
4901  }
4902  case 2:
4903  {
4904  SetPixelBlue(stegano_image,SetBit(GetPixelBlue(stegano_image,q),j,
4905  GetBit(GetPixelInfoIntensity(stegano_image,&pixel),i)),q);
4906  break;
4907  }
4908  }
4909  if (SyncCacheViewAuthenticPixels(stegano_view,exception) == MagickFalse)
4910  break;
4911  c++;
4912  if (c == 3)
4913  c=0;
4914  k++;
4915  if (k == (ssize_t) (stegano_image->columns*stegano_image->columns))
4916  k=0;
4917  if (k == stegano_image->offset)
4918  j++;
4919  }
4920  }
4921  if (image->progress_monitor != (MagickProgressMonitor) NULL)
4922  {
4924  proceed;
4925 
4927  (depth-i),depth);
4928  if (proceed == MagickFalse)
4929  status=MagickFalse;
4930  }
4931  }
4932  stegano_view=DestroyCacheView(stegano_view);
4933  watermark_view=DestroyCacheView(watermark_view);
4934  if (status == MagickFalse)
4935  stegano_image=DestroyImage(stegano_image);
4936  return(stegano_image);
4937 }
4938 
4939 /*
4940 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4941 % %
4942 % %
4943 % %
4944 % S t e r e o A n a g l y p h I m a g e %
4945 % %
4946 % %
4947 % %
4948 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4949 %
4950 % StereoAnaglyphImage() combines two images and produces a single image that
4951 % is the composite of a left and right image of a stereo pair. Special
4952 % red-green stereo glasses are required to view this effect.
4953 %
4954 % The format of the StereoAnaglyphImage method is:
4955 %
4956 % Image *StereoImage(const Image *left_image,const Image *right_image,
4957 % ExceptionInfo *exception)
4958 % Image *StereoAnaglyphImage(const Image *left_image,
4959 % const Image *right_image,const ssize_t x_offset,const ssize_t y_offset,
4960 % ExceptionInfo *exception)
4961 %
4962 % A description of each parameter follows:
4963 %
4964 % o left_image: the left image.
4965 %
4966 % o right_image: the right image.
4967 %
4968 % o exception: return any errors or warnings in this structure.
4969 %
4970 % o x_offset: amount, in pixels, by which the left image is offset to the
4971 % right of the right image.
4972 %
4973 % o y_offset: amount, in pixels, by which the left image is offset to the
4974 % bottom of the right image.
4975 %
4976 %
4977 */
4979  const Image *right_image,ExceptionInfo *exception)
4980 {
4981  return(StereoAnaglyphImage(left_image,right_image,0,0,exception));
4982 }
4983 
4985  const Image *right_image,const ssize_t x_offset,const ssize_t y_offset,
4986  ExceptionInfo *exception)
4987 {
4988 #define StereoImageTag "Stereo/Image"
4989 
4990  const Image
4991  *image;
4992 
4993  Image
4994  *stereo_image;
4995 
4997  status;
4998 
4999  ssize_t
5000  y;
5001 
5002  assert(left_image != (const Image *) NULL);
5003  assert(left_image->signature == MagickCoreSignature);
5004  if (left_image->debug != MagickFalse)
5006  left_image->filename);
5007  assert(right_image != (const Image *) NULL);
5008  assert(right_image->signature == MagickCoreSignature);
5009  assert(exception != (ExceptionInfo *) NULL);
5010  assert(exception->signature == MagickCoreSignature);
5011  image=left_image;
5012  if ((left_image->columns != right_image->columns) ||
5013  (left_image->rows != right_image->rows))
5014  ThrowImageException(ImageError,"LeftAndRightImageSizesDiffer");
5015  /*
5016  Initialize stereo image attributes.
5017  */
5018  stereo_image=CloneImage(left_image,left_image->columns,left_image->rows,
5019  MagickTrue,exception);
5020  if (stereo_image == (Image *) NULL)
5021  return((Image *) NULL);
5022  if (SetImageStorageClass(stereo_image,DirectClass,exception) == MagickFalse)
5023  {
5024  stereo_image=DestroyImage(stereo_image);
5025  return((Image *) NULL);
5026  }
5027  (void) SetImageColorspace(stereo_image,sRGBColorspace,exception);
5028  /*
5029  Copy left image to red channel and right image to blue channel.
5030  */
5031  status=MagickTrue;
5032  for (y=0; y < (ssize_t) stereo_image->rows; y++)
5033  {
5034  register const Quantum
5035  *magick_restrict p,
5036  *magick_restrict q;
5037 
5038  register ssize_t
5039  x;
5040 
5041  register Quantum
5042  *magick_restrict r;
5043 
5044  p=GetVirtualPixels(left_image,-x_offset,y-y_offset,image->columns,1,
5045  exception);
5046  q=GetVirtualPixels(right_image,0,y,right_image->columns,1,exception);
5047  r=QueueAuthenticPixels(stereo_image,0,y,stereo_image->columns,1,exception);
5048  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL) ||
5049  (r == (Quantum *) NULL))
5050  break;
5051  for (x=0; x < (ssize_t) stereo_image->columns; x++)
5052  {
5053  SetPixelRed(stereo_image,GetPixelRed(left_image,p),r);
5054  SetPixelGreen(stereo_image,GetPixelGreen(right_image,q),r);
5055  SetPixelBlue(stereo_image,GetPixelBlue(right_image,q),r);
5056  if ((GetPixelAlphaTraits(stereo_image) & CopyPixelTrait) != 0)
5057  SetPixelAlpha(stereo_image,(GetPixelAlpha(left_image,p)+
5058  GetPixelAlpha(right_image,q))/2,r);
5059  p+=GetPixelChannels(left_image);
5060  q+=GetPixelChannels(right_image);
5061  r+=GetPixelChannels(stereo_image);
5062  }
5063  if (SyncAuthenticPixels(stereo_image,exception) == MagickFalse)
5064  break;
5065  if (image->progress_monitor != (MagickProgressMonitor) NULL)
5066  {
5068  proceed;
5069 
5071  stereo_image->rows);
5072  if (proceed == MagickFalse)
5073  status=MagickFalse;
5074  }
5075  }
5076  if (status == MagickFalse)
5077  stereo_image=DestroyImage(stereo_image);
5078  return(stereo_image);
5079 }
5080 
5081 /*
5082 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5083 % %
5084 % %
5085 % %
5086 % S w i r l I m a g e %
5087 % %
5088 % %
5089 % %
5090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5091 %
5092 % SwirlImage() swirls the pixels about the center of the image, where
5093 % degrees indicates the sweep of the arc through which each pixel is moved.
5094 % You get a more dramatic effect as the degrees move from 1 to 360.
5095 %
5096 % The format of the SwirlImage method is:
5097 %
5098 % Image *SwirlImage(const Image *image,double degrees,
5099 % const PixelInterpolateMethod method,ExceptionInfo *exception)
5100 %
5101 % A description of each parameter follows:
5102 %
5103 % o image: the image.
5104 %
5105 % o degrees: Define the tightness of the swirling effect.
5106 %
5107 % o method: the pixel interpolation method.
5108 %
5109 % o exception: return any errors or warnings in this structure.
5110 %
5111 */
5112 MagickExport Image *SwirlImage(const Image *image,double degrees,
5113  const PixelInterpolateMethod method,ExceptionInfo *exception)
5114 {
5115 #define SwirlImageTag "Swirl/Image"
5116 
5117  CacheView
5118  *canvas_view,
5119  *interpolate_view,
5120  *swirl_view;
5121 
5122  double
5123  radius;
5124 
5125  Image
5126  *canvas_image,
5127  *swirl_image;
5128 
5130  status;
5131 
5133  progress;
5134 
5135  PointInfo
5136  center,
5137  scale;
5138 
5139  ssize_t
5140  y;
5141 
5142  /*
5143  Initialize swirl image attributes.
5144  */
5145  assert(image != (const Image *) NULL);
5146  assert(image->signature == MagickCoreSignature);
5147  if (image->debug != MagickFalse)
5148  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5149  assert(exception != (ExceptionInfo *) NULL);
5150  assert(exception->signature == MagickCoreSignature);
5151  canvas_image=CloneImage(image,0,0,MagickTrue,exception);
5152  if (canvas_image == (Image *) NULL)
5153  return((Image *) NULL);
5154  if ((canvas_image->alpha_trait == UndefinedPixelTrait) &&
5155  (canvas_image->background_color.alpha != OpaqueAlpha))
5156  (void) SetImageAlphaChannel(canvas_image,OpaqueAlphaChannel,exception);
5157  swirl_image=CloneImage(canvas_image,0,0,MagickTrue,exception);
5158  if (swirl_image == (Image *) NULL)
5159  {
5160  canvas_image=DestroyImage(canvas_image);
5161  return((Image *) NULL);
5162  }
5163  if (SetImageStorageClass(swirl_image,DirectClass,exception) == MagickFalse)
5164  {
5165  canvas_image=DestroyImage(canvas_image);
5166  swirl_image=DestroyImage(swirl_image);
5167  return((Image *) NULL);
5168  }
5169  /*
5170  Compute scaling factor.
5171  */
5172  center.x=(double) canvas_image->columns/2.0;
5173  center.y=(double) canvas_image->rows/2.0;
5174  radius=MagickMax(center.x,center.y);
5175  scale.x=1.0;
5176  scale.y=1.0;
5177  if (canvas_image->columns > canvas_image->rows)
5178  scale.y=(double) canvas_image->columns/(double) canvas_image->rows;
5179  else
5180  if (canvas_image->columns < canvas_image->rows)
5181  scale.x=(double) canvas_image->rows/(double) canvas_image->columns;
5182  degrees=(double) DegreesToRadians(degrees);
5183  /*
5184  Swirl image.
5185  */
5186  status=MagickTrue;
5187  progress=0;
5188  canvas_view=AcquireVirtualCacheView(canvas_image,exception);
5189  interpolate_view=AcquireVirtualCacheView(image,exception);
5190  swirl_view=AcquireAuthenticCacheView(swirl_image,exception);
5191 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5192  #pragma omp parallel for schedule(static) shared(progress,status) \
5193  magick_number_threads(canvas_image,swirl_image,canvas_image->rows,1)
5194 #endif
5195  for (y=0; y < (ssize_t) canvas_image->rows; y++)
5196  {
5197  double
5198  distance;
5199 
5200  PointInfo
5201  delta;
5202 
5203  register const Quantum
5204  *magick_restrict p;
5205 
5206  register ssize_t
5207  x;
5208 
5209  register Quantum
5210  *magick_restrict q;
5211 
5212  if (status == MagickFalse)
5213  continue;
5214  p=GetCacheViewVirtualPixels(canvas_view,0,y,canvas_image->columns,1,
5215  exception);
5216  q=QueueCacheViewAuthenticPixels(swirl_view,0,y,swirl_image->columns,1,
5217  exception);
5218  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
5219  {
5220  status=MagickFalse;
5221  continue;
5222  }
5223  delta.y=scale.y*(double) (y-center.y);
5224  for (x=0; x < (ssize_t) canvas_image->columns; x++)
5225  {
5226  /*
5227  Determine if the pixel is within an ellipse.
5228  */
5229  delta.x=scale.x*(double) (x-center.x);
5230  distance=delta.x*delta.x+delta.y*delta.y;
5231  if (distance >= (radius*radius))
5232  {
5233  register ssize_t
5234  i;
5235 
5236  for (i=0; i < (ssize_t) GetPixelChannels(canvas_image); i++)
5237  {
5238  PixelChannel channel = GetPixelChannelChannel(canvas_image,i);
5239  PixelTrait traits = GetPixelChannelTraits(canvas_image,channel);
5240  PixelTrait swirl_traits = GetPixelChannelTraits(swirl_image,
5241  channel);
5242  if ((traits == UndefinedPixelTrait) ||
5243  (swirl_traits == UndefinedPixelTrait))
5244  continue;
5245  SetPixelChannel(swirl_image,channel,p[i],q);
5246  }
5247  }
5248  else
5249  {
5250  double
5251  cosine,
5252  factor,
5253  sine;
5254 
5255  /*
5256  Swirl the pixel.
5257  */
5258  factor=1.0-sqrt((double) distance)/radius;
5259  sine=sin((double) (degrees*factor*factor));
5260  cosine=cos((double) (degrees*factor*factor));
5261  status=InterpolatePixelChannels(canvas_image,interpolate_view,
5262  swirl_image,method,((cosine*delta.x-sine*delta.y)/scale.x+center.x),
5263  (double) ((sine*delta.x+cosine*delta.y)/scale.y+center.y),q,
5264  exception);
5265  if (status == MagickFalse)
5266  break;
5267  }
5268  p+=GetPixelChannels(canvas_image);
5269  q+=GetPixelChannels(swirl_image);
5270  }
5271  if (SyncCacheViewAuthenticPixels(swirl_view,exception) == MagickFalse)
5272  status=MagickFalse;
5273  if (canvas_image->progress_monitor != (MagickProgressMonitor) NULL)
5274  {
5276  proceed;
5277 
5278 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5279  #pragma omp critical (MagickCore_SwirlImage)
5280 #endif
5281  proceed=SetImageProgress(canvas_image,SwirlImageTag,progress++,
5282  canvas_image->rows);
5283  if (proceed == MagickFalse)
5284  status=MagickFalse;
5285  }
5286  }
5287  swirl_view=DestroyCacheView(swirl_view);
5288  interpolate_view=DestroyCacheView(interpolate_view);
5289  canvas_view=DestroyCacheView(canvas_view);
5290  canvas_image=DestroyImage(canvas_image);
5291  if (status == MagickFalse)
5292  swirl_image=DestroyImage(swirl_image);
5293  return(swirl_image);
5294 }
5295 
5296 /*
5297 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5298 % %
5299 % %
5300 % %
5301 % T i n t I m a g e %
5302 % %
5303 % %
5304 % %
5305 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5306 %
5307 % TintImage() applies a color vector to each pixel in the image. The length
5308 % of the vector is 0 for black and white and at its maximum for the midtones.
5309 % The vector weighting function is f(x)=(1-(4.0*((x-0.5)*(x-0.5))))
5310 %
5311 % The format of the TintImage method is:
5312 %
5313 % Image *TintImage(const Image *image,const char *blend,
5314 % const PixelInfo *tint,ExceptionInfo *exception)
5315 %
5316 % A description of each parameter follows:
5317 %
5318 % o image: the image.
5319 %
5320 % o blend: A color value used for tinting.
5321 %
5322 % o tint: A color value used for tinting.
5323 %
5324 % o exception: return any errors or warnings in this structure.
5325 %
5326 */
5327 MagickExport Image *TintImage(const Image *image,const char *blend,
5328  const PixelInfo *tint,ExceptionInfo *exception)
5329 {
5330 #define TintImageTag "Tint/Image"
5331 
5332  CacheView
5333  *image_view,
5334  *tint_view;
5335 
5336  double
5337  intensity;
5338 
5339  GeometryInfo
5340  geometry_info;
5341 
5342  Image
5343  *tint_image;
5344 
5346  status;
5347 
5349  progress;
5350 
5351  PixelInfo
5352  color_vector;
5353 
5355  flags;
5356 
5357  ssize_t
5358  y;
5359 
5360  /*
5361  Allocate tint image.
5362  */
5363  assert(image != (const Image *) NULL);
5364  assert(image->signature == MagickCoreSignature);
5365  if (image->debug != MagickFalse)
5366  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5367  assert(exception != (ExceptionInfo *) NULL);
5368  assert(exception->signature == MagickCoreSignature);
5369  tint_image=CloneImage(image,0,0,MagickTrue,exception);
5370  if (tint_image == (Image *) NULL)
5371  return((Image *) NULL);
5372  if (SetImageStorageClass(tint_image,DirectClass,exception) == MagickFalse)
5373  {
5374  tint_image=DestroyImage(tint_image);
5375  return((Image *) NULL);
5376  }
5377  if ((IsGrayColorspace(image->colorspace) != MagickFalse) &&
5378  (IsPixelInfoGray(tint) == MagickFalse))
5379  (void) SetImageColorspace(tint_image,sRGBColorspace,exception);
5380  if (blend == (const char *) NULL)
5381  return(tint_image);
5382  /*
5383  Determine RGB values of the color.
5384  */
5385  GetPixelInfo(image,&color_vector);
5386  flags=ParseGeometry(blend,&geometry_info);
5387  color_vector.red=geometry_info.rho;
5388  color_vector.green=geometry_info.rho;
5389  color_vector.blue=geometry_info.rho;
5390  color_vector.alpha=(MagickRealType) OpaqueAlpha;
5391  if ((flags & SigmaValue) != 0)
5392  color_vector.green=geometry_info.sigma;
5393  if ((flags & XiValue) != 0)
5394  color_vector.blue=geometry_info.xi;
5395  if ((flags & PsiValue) != 0)
5396  color_vector.alpha=geometry_info.psi;
5397  if (image->colorspace == CMYKColorspace)
5398  {
5399  color_vector.black=geometry_info.rho;
5400  if ((flags & PsiValue) != 0)
5401  color_vector.black=geometry_info.psi;
5402  if ((flags & ChiValue) != 0)
5403  color_vector.alpha=geometry_info.chi;
5404  }
5405  intensity=(double) GetPixelInfoIntensity((const Image *) NULL,tint);
5406  color_vector.red=(double) (color_vector.red*tint->red/100.0-intensity);
5407  color_vector.green=(double) (color_vector.green*tint->green/100.0-intensity);
5408  color_vector.blue=(double) (color_vector.blue*tint->blue/100.0-intensity);
5409  color_vector.black=(double) (color_vector.black*tint->black/100.0-intensity);
5410  color_vector.alpha=(double) (color_vector.alpha*tint->alpha/100.0-intensity);
5411  /*
5412  Tint image.
5413  */
5414  status=MagickTrue;
5415  progress=0;
5416  image_view=AcquireVirtualCacheView(image,exception);
5417  tint_view=AcquireAuthenticCacheView(tint_image,exception);
5418 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5419  #pragma omp parallel for schedule(static) shared(progress,status) \
5420  magick_number_threads(image,tint_image,image->rows,1)
5421 #endif
5422  for (y=0; y < (ssize_t) image->rows; y++)
5423  {
5424  register const Quantum
5425  *magick_restrict p;
5426 
5427  register Quantum
5428  *magick_restrict q;
5429 
5430  register ssize_t
5431  x;
5432 
5433  if (status == MagickFalse)
5434  continue;
5435  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
5436  q=QueueCacheViewAuthenticPixels(tint_view,0,y,tint_image->columns,1,
5437  exception);
5438  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
5439  {
5440  status=MagickFalse;
5441  continue;
5442  }
5443  for (x=0; x < (ssize_t) image->columns; x++)
5444  {
5445  PixelInfo
5446  pixel;
5447 
5448  double
5449  weight;
5450 
5451  GetPixelInfo(image,&pixel);
5452  weight=QuantumScale*GetPixelRed(image,p)-0.5;
5453  pixel.red=(MagickRealType) GetPixelRed(image,p)+color_vector.red*
5454  (1.0-(4.0*(weight*weight)));
5455  weight=QuantumScale*GetPixelGreen(image,p)-0.5;
5456  pixel.green=(MagickRealType) GetPixelGreen(image,p)+color_vector.green*
5457  (1.0-(4.0*(weight*weight)));
5458  weight=QuantumScale*GetPixelBlue(image,p)-0.5;
5459  pixel.blue=(MagickRealType) GetPixelBlue(image,p)+color_vector.blue*
5460  (1.0-(4.0*(weight*weight)));
5461  weight=QuantumScale*GetPixelBlack(image,p)-0.5;
5462  pixel.black=(MagickRealType) GetPixelBlack(image,p)+color_vector.black*
5463  (1.0-(4.0*(weight*weight)));
5464  pixel.alpha=(MagickRealType) GetPixelAlpha(image,p);
5465  SetPixelViaPixelInfo(tint_image,&pixel,q);
5466  p+=GetPixelChannels(image);
5467  q+=GetPixelChannels(tint_image);
5468  }
5469  if (SyncCacheViewAuthenticPixels(tint_view,exception) == MagickFalse)
5470  status=MagickFalse;
5471  if (image->progress_monitor != (MagickProgressMonitor) NULL)
5472  {
5474  proceed;
5475 
5476 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5477  #pragma omp critical (MagickCore_TintImage)
5478 #endif
5479  proceed=SetImageProgress(image,TintImageTag,progress++,image->rows);
5480  if (proceed == MagickFalse)
5481  status=MagickFalse;
5482  }
5483  }
5484  tint_view=DestroyCacheView(tint_view);
5485  image_view=DestroyCacheView(image_view);
5486  if (status == MagickFalse)
5487  tint_image=DestroyImage(tint_image);
5488  return(tint_image);
5489 }
5490 
5491 /*
5492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5493 % %
5494 % %
5495 % %
5496 % V i g n e t t e I m a g e %
5497 % %
5498 % %
5499 % %
5500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5501 %
5502 % VignetteImage() softens the edges of the image in vignette style.
5503 %
5504 % The format of the VignetteImage method is:
5505 %
5506 % Image *VignetteImage(const Image *image,const double radius,
5507 % const double sigma,const ssize_t x,const ssize_t y,
5508 % ExceptionInfo *exception)
5509 %
5510 % A description of each parameter follows:
5511 %
5512 % o image: the image.
5513 %
5514 % o radius: the radius of the pixel neighborhood.
5515 %
5516 % o sigma: the standard deviation of the Gaussian, in pixels.
5517 %
5518 % o x, y: Define the x and y ellipse offset.
5519 %
5520 % o exception: return any errors or warnings in this structure.
5521 %
5522 */
5523 MagickExport Image *VignetteImage(const Image *image,const double radius,
5524  const double sigma,const ssize_t x,const ssize_t y,ExceptionInfo *exception)
5525 {
5526  char
5527  ellipse[MagickPathExtent];
5528 
5529  DrawInfo
5530  *draw_info;
5531 
5532  Image
5533  *canvas,
5534  *blur_image,
5535  *oval_image,
5536  *vignette_image;
5537 
5538  assert(image != (Image *) NULL);
5539  assert(image->signature == MagickCoreSignature);
5540  if (image->debug != MagickFalse)
5541  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5542  assert(exception != (ExceptionInfo *) NULL);
5543  assert(exception->signature == MagickCoreSignature);
5544  canvas=CloneImage(image,0,0,MagickTrue,exception);
5545  if (canvas == (Image *) NULL)
5546  return((Image *) NULL);
5547  if (SetImageStorageClass(canvas,DirectClass,exception) == MagickFalse)
5548  {
5549  canvas=DestroyImage(canvas);
5550  return((Image *) NULL);
5551  }
5552  canvas->alpha_trait=BlendPixelTrait;
5553  oval_image=CloneImage(canvas,canvas->columns,canvas->rows,MagickTrue,
5554  exception);
5555  if (oval_image == (Image *) NULL)
5556  {
5557  canvas=DestroyImage(canvas);
5558  return((Image *) NULL);
5559  }
5560  (void) QueryColorCompliance("#000000",AllCompliance,
5561  &oval_image->background_color,exception);
5562  (void) SetImageBackgroundColor(oval_image,exception);
5563  draw_info=CloneDrawInfo((const ImageInfo *) NULL,(const DrawInfo *) NULL);
5564  (void) QueryColorCompliance("#ffffff",AllCompliance,&draw_info->fill,
5565  exception);
5566  (void) QueryColorCompliance("#ffffff",AllCompliance,&draw_info->stroke,
5567  exception);
5568  (void) FormatLocaleString(ellipse,MagickPathExtent,"ellipse %g,%g,%g,%g,"
5569  "0.0,360.0",image->columns/2.0,image->rows/2.0,image->columns/2.0-x,
5570  image->rows/2.0-y);
5571  draw_info->primitive=AcquireString(ellipse);
5572  (void) DrawImage(oval_image,draw_info,exception);
5573  draw_info=DestroyDrawInfo(draw_info);
5574  blur_image=BlurImage(oval_image,radius,sigma,exception);
5575  oval_image=DestroyImage(oval_image);
5576  if (blur_image == (Image *) NULL)
5577  {
5578  canvas=DestroyImage(canvas);
5579  return((Image *) NULL);
5580  }
5581  blur_image->alpha_trait=UndefinedPixelTrait;
5582  (void) CompositeImage(canvas,blur_image,IntensityCompositeOp,MagickTrue,
5583  0,0,exception);
5584  blur_image=DestroyImage(blur_image);
5585  vignette_image=MergeImageLayers(canvas,FlattenLayer,exception);
5586  canvas=DestroyImage(canvas);
5587  if (vignette_image != (Image *) NULL)
5588  (void) TransformImageColorspace(vignette_image,image->colorspace,exception);
5589  return(vignette_image);
5590 }
5591 
5592 /*
5593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5594 % %
5595 % %
5596 % %
5597 % W a v e I m a g e %
5598 % %
5599 % %
5600 % %
5601 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5602 %
5603 % WaveImage() creates a "ripple" effect in the image by shifting the pixels
5604 % vertically along a sine wave whose amplitude and wavelength is specified
5605 % by the given parameters.
5606 %
5607 % The format of the WaveImage method is:
5608 %
5609 % Image *WaveImage(const Image *image,const double amplitude,
5610 % const double wave_length,const PixelInterpolateMethod method,
5611 % ExceptionInfo *exception)
5612 %
5613 % A description of each parameter follows:
5614 %
5615 % o image: the image.
5616 %
5617 % o amplitude, wave_length: Define the amplitude and wave length of the
5618 % sine wave.
5619 %
5620 % o interpolate: the pixel interpolation method.
5621 %
5622 % o exception: return any errors or warnings in this structure.
5623 %
5624 */
5625 MagickExport Image *WaveImage(const Image *image,const double amplitude,
5626  const double wave_length,const PixelInterpolateMethod method,
5627  ExceptionInfo *exception)
5628 {
5629 #define WaveImageTag "Wave/Image"
5630 
5631  CacheView
5632  *canvas_image_view,
5633  *wave_view;
5634 
5635  Image
5636  *canvas_image,
5637  *wave_image;
5638 
5640  status;
5641 
5643  progress;
5644 
5645  double
5646  *sine_map;
5647 
5648  register ssize_t
5649  i;
5650 
5651  ssize_t
5652  y;
5653 
5654  /*
5655  Initialize wave image attributes.
5656  */
5657  assert(image != (Image *) NULL);
5658  assert(image->signature == MagickCoreSignature);
5659  if (image->debug != MagickFalse)
5660  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5661  assert(exception != (ExceptionInfo *) NULL);
5662  assert(exception->signature == MagickCoreSignature);
5663  canvas_image=CloneImage(image,0,0,MagickTrue,exception);
5664  if (canvas_image == (Image *) NULL)
5665  return((Image *) NULL);
5666  if ((canvas_image->alpha_trait == UndefinedPixelTrait) &&
5667  (canvas_image->background_color.alpha != OpaqueAlpha))
5668  (void) SetImageAlpha(canvas_image,OpaqueAlpha,exception);
5669  wave_image=CloneImage(canvas_image,canvas_image->columns,(size_t)
5670  (canvas_image->rows+2.0*fabs(amplitude)),MagickTrue,exception);
5671  if (wave_image == (Image *) NULL)
5672  {
5673  canvas_image=DestroyImage(canvas_image);
5674  return((Image *) NULL);
5675  }
5676  if (SetImageStorageClass(wave_image,DirectClass,exception) == MagickFalse)
5677  {
5678  canvas_image=DestroyImage(canvas_image);
5679  wave_image=DestroyImage(wave_image);
5680  return((Image *) NULL);
5681  }
5682  /*
5683  Allocate sine map.
5684  */
5685  sine_map=(double *) AcquireQuantumMemory((size_t) wave_image->columns,
5686  sizeof(*sine_map));
5687  if (sine_map == (double *) NULL)
5688  {
5689  canvas_image=DestroyImage(canvas_image);
5690  wave_image=DestroyImage(wave_image);
5691  ThrowImageException(ResourceLimitError,"MemoryAllocationFailed");
5692  }
5693  for (i=0; i < (ssize_t) wave_image->columns; i++)
5694  sine_map[i]=fabs(amplitude)+amplitude*sin((double) ((2.0*MagickPI*i)/
5695  wave_length));
5696  /*
5697  Wave image.
5698  */
5699  status=MagickTrue;
5700  progress=0;
5701  canvas_image_view=AcquireVirtualCacheView(canvas_image,exception);
5702  wave_view=AcquireAuthenticCacheView(wave_image,exception);
5703  (void) SetCacheViewVirtualPixelMethod(canvas_image_view,
5705 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5706  #pragma omp parallel for schedule(static) shared(progress,status) \
5707  magick_number_threads(canvas_image,wave_image,wave_image->rows,1)
5708 #endif
5709  for (y=0; y < (ssize_t) wave_image->rows; y++)
5710  {
5711  register const Quantum
5712  *magick_restrict p;
5713 
5714  register Quantum
5715  *magick_restrict q;
5716 
5717  register ssize_t
5718  x;
5719 
5720  if (status == MagickFalse)
5721  continue;
5722  p=GetCacheViewVirtualPixels(canvas_image_view,0,y,canvas_image->columns,1,
5723  exception);
5724  q=QueueCacheViewAuthenticPixels(wave_view,0,y,wave_image->columns,1,
5725  exception);
5726  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
5727  {
5728  status=MagickFalse;
5729  continue;
5730  }
5731  for (x=0; x < (ssize_t) wave_image->columns; x++)
5732  {
5733  status=InterpolatePixelChannels(canvas_image,canvas_image_view,
5734  wave_image,method,(double) x,(double) (y-sine_map[x]),q,exception);
5735  if (status == MagickFalse)
5736  break;
5737  p+=GetPixelChannels(canvas_image);
5738  q+=GetPixelChannels(wave_image);
5739  }
5740  if (SyncCacheViewAuthenticPixels(wave_view,exception) == MagickFalse)
5741  status=MagickFalse;
5742  if (image->progress_monitor != (MagickProgressMonitor) NULL)
5743  {
5745  proceed;
5746 
5747 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5748  #pragma omp critical (MagickCore_WaveImage)
5749 #endif
5750  proceed=SetImageProgress(canvas_image,WaveImageTag,progress++,canvas_image->rows);
5751  if (proceed == MagickFalse)
5752  status=MagickFalse;
5753  }
5754  }
5755  wave_view=DestroyCacheView(wave_view);
5756  canvas_image_view=DestroyCacheView(canvas_image_view);
5757  canvas_image=DestroyImage(canvas_image);
5758  sine_map=(double *) RelinquishMagickMemory(sine_map);
5759  if (status == MagickFalse)
5760  wave_image=DestroyImage(wave_image);
5761  return(wave_image);
5762 }
5763 
5764 /*
5765 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5766 % %
5767 % %
5768 % %
5769 % W a v e l e t D e n o i s e I m a g e %
5770 % %
5771 % %
5772 % %
5773 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5774 %
5775 % WaveletDenoiseImage() removes noise from the image using a wavelet
5776 % transform. The wavelet transform is a fast hierarchical scheme for
5777 % processing an image using a set of consecutive lowpass and high_pass filters,
5778 % followed by a decimation. This results in a decomposition into different
5779 % scales which can be regarded as different “frequency bands”, determined by
5780 % the mother wavelet. Adapted from dcraw.c by David Coffin.
5781 %
5782 % The format of the WaveletDenoiseImage method is:
5783 %
5784 % Image *WaveletDenoiseImage(const Image *image,const double threshold,
5785 % const double softness,ExceptionInfo *exception)
5786 %
5787 % A description of each parameter follows:
5788 %
5789 % o image: the image.
5790 %
5791 % o threshold: set the threshold for smoothing.
5792 %
5793 % o softness: attenuate the smoothing threshold.
5794 %
5795 % o exception: return any errors or warnings in this structure.
5796 %
5797 */
5798 
5799 static inline void HatTransform(const float *magick_restrict pixels,
5800  const size_t stride,const size_t extent,const size_t scale,float *kernel)
5801 {
5802  const float
5803  *magick_restrict p,
5804  *magick_restrict q,
5805  *magick_restrict r;
5806 
5807  register ssize_t
5808  i;
5809 
5810  p=pixels;
5811  q=pixels+scale*stride;
5812  r=pixels+scale*stride;
5813  for (i=0; i < (ssize_t) scale; i++)
5814  {
5815  kernel[i]=0.25f*(*p+(*p)+(*q)+(*r));
5816  p+=stride;
5817  q-=stride;
5818  r+=stride;
5819  }
5820  for ( ; i < (ssize_t) (extent-scale); i++)
5821  {
5822  kernel[i]=0.25f*(2.0f*(*p)+*(p-scale*stride)+*(p+scale*stride));
5823  p+=stride;
5824  }
5825  q=p-scale*stride;
5826  r=pixels+stride*(extent-2);
5827  for ( ; i < (ssize_t) extent; i++)
5828  {
5829  kernel[i]=0.25f*(*p+(*p)+(*q)+(*r));
5830  p+=stride;
5831  q+=stride;
5832  r-=stride;
5833  }
5834 }
5835 
5837  const double threshold,const double softness,ExceptionInfo *exception)
5838 {
5839  CacheView
5840  *image_view,
5841  *noise_view;
5842 
5843  float
5844  *kernel,
5845  *pixels;
5846 
5847  Image
5848  *noise_image;
5849 
5851  status;
5852 
5854  number_pixels;
5855 
5856  MemoryInfo
5857  *pixels_info;
5858 
5859  ssize_t
5860  channel;
5861 
5862  static const float
5863  noise_levels[] = { 0.8002f, 0.2735f, 0.1202f, 0.0585f, 0.0291f, 0.0152f,
5864  0.0080f, 0.0044f };
5865 
5866  /*
5867  Initialize noise image attributes.
5868  */
5869  assert(image != (const Image *) NULL);
5870  assert(image->signature ==