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