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