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