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