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