MagickCore  7.1.0
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-2021 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/token.h"
97 #include "MagickCore/transform.h"
99 #include "MagickCore/utility.h"
100 
101 /*
102  Typedef declarations.
103 */
104 typedef enum
105 {
127 } FxOperator;
128 
129 struct _FxInfo
130 {
131  const Image
133 
134  char
136 
137  FILE
139 
142  *symbols;
143 
144  CacheView
145  **view;
146 
147  RandomInfo
149 
152 };
153 
154 /*
155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
156 % %
157 % %
158 % %
159 + A c q u i r e F x I n f o %
160 % %
161 % %
162 % %
163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164 %
165 % AcquireFxInfo() allocates the FxInfo structure.
166 %
167 % The format of the AcquireFxInfo method is:
168 %
169 % FxInfo *AcquireFxInfo(Image *images,const char *expression,
170 % ExceptionInfo *exception)
171 %
172 % A description of each parameter follows:
173 %
174 % o images: the image sequence.
175 %
176 % o expression: the expression.
177 %
178 % o exception: return any errors or warnings in this structure.
179 %
180 */
181 MagickPrivate FxInfo *AcquireFxInfo(const Image *images,const char *expression,
182  ExceptionInfo *exception)
183 {
184  const Image
185  *next;
186 
187  FxInfo
188  *fx_info;
189 
190  ssize_t
191  i;
192 
193  unsigned char
194  fx_op[2];
195 
196  fx_info=(FxInfo *) AcquireCriticalMemory(sizeof(*fx_info));
197  (void) memset(fx_info,0,sizeof(*fx_info));
198  fx_info->exception=AcquireExceptionInfo();
199  fx_info->images=images;
205  fx_info->images),sizeof(*fx_info->view));
206  if (fx_info->view == (CacheView **) NULL)
207  ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
208  i=0;
209  next=GetFirstImageInList(fx_info->images);
210  for ( ; next != (Image *) NULL; next=next->next)
211  {
212  fx_info->view[i]=AcquireVirtualCacheView(next,exception);
213  i++;
214  }
215  fx_info->random_info=AcquireRandomInfo();
216  fx_info->expression=ConstantString(expression);
217  fx_info->file=stderr;
218  /*
219  Convert compound to simple operators.
220  */
221  fx_op[1]='\0';
222  *fx_op=(unsigned char) BitwiseAndAssignmentOperator;
223  (void) SubstituteString(&fx_info->expression,"&=",(char *) fx_op);
224  *fx_op=(unsigned char) BitwiseOrAssignmentOperator;
225  (void) SubstituteString(&fx_info->expression,"|=",(char *) fx_op);
226  *fx_op=(unsigned char) LeftShiftAssignmentOperator;
227  (void) SubstituteString(&fx_info->expression,"<<=",(char *) fx_op);
228  *fx_op=(unsigned char) RightShiftAssignmentOperator;
229  (void) SubstituteString(&fx_info->expression,">>=",(char *) fx_op);
230  *fx_op=(unsigned char) PowerAssignmentOperator;
231  (void) SubstituteString(&fx_info->expression,"^=",(char *) fx_op);
232  *fx_op=(unsigned char) ModuloAssignmentOperator;
233  (void) SubstituteString(&fx_info->expression,"%=",(char *) fx_op);
234  *fx_op=(unsigned char) PlusAssignmentOperator;
235  (void) SubstituteString(&fx_info->expression,"+=",(char *) fx_op);
236  *fx_op=(unsigned char) SubtractAssignmentOperator;
237  (void) SubstituteString(&fx_info->expression,"-=",(char *) fx_op);
238  *fx_op=(unsigned char) MultiplyAssignmentOperator;
239  (void) SubstituteString(&fx_info->expression,"*=",(char *) fx_op);
240  *fx_op=(unsigned char) DivideAssignmentOperator;
241  (void) SubstituteString(&fx_info->expression,"/=",(char *) fx_op);
242  *fx_op=(unsigned char) IncrementAssignmentOperator;
243  (void) SubstituteString(&fx_info->expression,"++",(char *) fx_op);
244  *fx_op=(unsigned char) DecrementAssignmentOperator;
245  (void) SubstituteString(&fx_info->expression,"--",(char *) fx_op);
246  *fx_op=(unsigned char) LeftShiftOperator;
247  (void) SubstituteString(&fx_info->expression,"<<",(char *) fx_op);
248  *fx_op=(unsigned char) RightShiftOperator;
249  (void) SubstituteString(&fx_info->expression,">>",(char *) fx_op);
250  *fx_op=(unsigned char) LessThanEqualOperator;
251  (void) SubstituteString(&fx_info->expression,"<=",(char *) fx_op);
252  *fx_op=(unsigned char) GreaterThanEqualOperator;
253  (void) SubstituteString(&fx_info->expression,">=",(char *) fx_op);
254  *fx_op=(unsigned char) EqualOperator;
255  (void) SubstituteString(&fx_info->expression,"==",(char *) fx_op);
256  *fx_op=(unsigned char) NotEqualOperator;
257  (void) SubstituteString(&fx_info->expression,"!=",(char *) fx_op);
258  *fx_op=(unsigned char) LogicalAndOperator;
259  (void) SubstituteString(&fx_info->expression,"&&",(char *) fx_op);
260  *fx_op=(unsigned char) LogicalOrOperator;
261  (void) SubstituteString(&fx_info->expression,"||",(char *) fx_op);
262  *fx_op=(unsigned char) ExponentialNotation;
263  (void) SubstituteString(&fx_info->expression,"**",(char *) fx_op);
264  /*
265  Force right-to-left associativity for unary negation.
266  */
267  (void) SubstituteString(&fx_info->expression,"-","-1.0*");
268  (void) SubstituteString(&fx_info->expression,"^-1.0*","^-");
269  (void) SubstituteString(&fx_info->expression,"E-1.0*","E-");
270  (void) SubstituteString(&fx_info->expression,"e-1.0*","e-");
271  (void) SubstituteString(&fx_info->expression," ",""); /* compact string */
272  return(fx_info);
273 }
274 
275 /*
276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
277 % %
278 % %
279 % %
280 + D e s t r o y F x I n f o %
281 % %
282 % %
283 % %
284 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
285 %
286 % DestroyFxInfo() deallocates memory associated with an FxInfo structure.
287 %
288 % The format of the DestroyFxInfo method is:
289 %
290 % ImageInfo *DestroyFxInfo(ImageInfo *fx_info)
291 %
292 % A description of each parameter follows:
293 %
294 % o fx_info: the fx info.
295 %
296 */
298 {
299  ssize_t
300  i;
301 
302  fx_info->exception=DestroyExceptionInfo(fx_info->exception);
303  fx_info->expression=DestroyString(fx_info->expression);
304  fx_info->symbols=DestroySplayTree(fx_info->symbols);
305  fx_info->colors=DestroySplayTree(fx_info->colors);
306  for (i=(ssize_t) GetImageListLength(fx_info->images)-1; i >= 0; i--)
307  fx_info->view[i]=DestroyCacheView(fx_info->view[i]);
308  fx_info->view=(CacheView **) RelinquishMagickMemory(fx_info->view);
309  fx_info->random_info=DestroyRandomInfo(fx_info->random_info);
310  fx_info=(FxInfo *) RelinquishMagickMemory(fx_info);
311  return(fx_info);
312 }
313 
314 /*
315 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
316 % %
317 % %
318 % %
319 + 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 %
320 % %
321 % %
322 % %
323 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
324 %
325 % FxEvaluateChannelExpression() evaluates an expression and returns the
326 % results.
327 %
328 % The format of the FxEvaluateExpression method is:
329 %
330 % double FxEvaluateChannelExpression(FxInfo *fx_info,
331 % const PixelChannel channel,const ssize_t x,const ssize_t y,
332 % double *alpha,Exceptioninfo *exception)
333 % double FxEvaluateExpression(FxInfo *fx_info,
334 % double *alpha,Exceptioninfo *exception)
335 %
336 % A description of each parameter follows:
337 %
338 % o fx_info: the fx info.
339 %
340 % o channel: the channel.
341 %
342 % o x,y: the pixel position.
343 %
344 % o alpha: the result.
345 %
346 % o exception: return any errors or warnings in this structure.
347 %
348 */
349 
350 static inline const double *GetFxSymbolValue(FxInfo *magick_restrict fx_info,
351  const char *symbol)
352 {
353  return((const double *) GetValueFromSplayTree(fx_info->symbols,symbol));
354 }
355 
357  FxInfo *magick_restrict fx_info,const char *magick_restrict symbol,
358  double const value)
359 {
360  double
361  *object;
362 
363  object=(double *) GetValueFromSplayTree(fx_info->symbols,symbol);
364  if (object != (double *) NULL)
365  {
366  *object=value;
367  return(MagickTrue);
368  }
369  object=(double *) AcquireMagickMemory(sizeof(*object));
370  if (object == (double *) NULL)
371  {
372  (void) ThrowMagickException(fx_info->exception,GetMagickModule(),
373  ResourceLimitError,"MemoryAllocationFailed","`%s'",
374  fx_info->images->filename);
375  return(MagickFalse);
376  }
377  *object=value;
378  return(AddValueToSplayTree(fx_info->symbols,ConstantString(symbol),object));
379 }
380 
381 static double FxChannelStatistics(FxInfo *fx_info,Image *image,
382  PixelChannel channel,const char *symbol,ExceptionInfo *exception)
383 {
385  channel_mask;
386 
387  char
388  key[MagickPathExtent];
389 
390  const double
391  *value;
392 
393  double
394  statistic;
395 
396  const char
397  *p;
398 
399  channel_mask=UndefinedChannel;
400  for (p=symbol; (*p != '.') && (*p != '\0'); p++) ;
401  if (*p == '.')
402  {
403  ssize_t
404  option;
405 
407  if (option >= 0)
408  {
409  channel=(PixelChannel) option;
410  channel_mask=SetPixelChannelMask(image,(ChannelType)
411  (1UL << channel));
412  }
413  }
414  (void) FormatLocaleString(key,MagickPathExtent,"%p.%.20g.%s",(void *) image,
415  (double) channel,symbol);
416  value=GetFxSymbolValue(fx_info,key);
417  if (value != (const double *) NULL)
418  {
419  if (channel_mask != UndefinedChannel)
420  (void) SetPixelChannelMask(image,channel_mask);
421  return(QuantumScale*(*value));
422  }
423  statistic=0.0;
424  if (LocaleNCompare(symbol,"depth",5) == 0)
425  {
426  size_t
427  depth;
428 
429  depth=GetImageDepth(image,exception);
430  statistic=(double) depth;
431  }
432  if (LocaleNCompare(symbol,"kurtosis",8) == 0)
433  {
434  double
435  kurtosis,
436  skewness;
437 
438  (void) GetImageKurtosis(image,&kurtosis,&skewness,exception);
439  statistic=kurtosis;
440  }
441  if (LocaleNCompare(symbol,"maxima",6) == 0)
442  {
443  double
444  maxima,
445  minima;
446 
447  (void) GetImageRange(image,&minima,&maxima,exception);
448  statistic=maxima;
449  }
450  if (LocaleNCompare(symbol,"mean",4) == 0)
451  {
452  double
453  mean,
454  standard_deviation;
455 
456  (void) GetImageMean(image,&mean,&standard_deviation,exception);
457  statistic=mean;
458  }
459  if (LocaleNCompare(symbol,"median",6) == 0)
460  {
461  double
462  median;
463 
464  (void) GetImageMedian(image,&median,exception);
465  statistic=median;
466  }
467  if (LocaleNCompare(symbol,"minima",6) == 0)
468  {
469  double
470  maxima,
471  minima;
472 
473  (void) GetImageRange(image,&minima,&maxima,exception);
474  statistic=minima;
475  }
476  if (LocaleNCompare(symbol,"skewness",8) == 0)
477  {
478  double
479  kurtosis,
480  skewness;
481 
482  (void) GetImageKurtosis(image,&kurtosis,&skewness,exception);
483  statistic=skewness;
484  }
485  if (LocaleNCompare(symbol,"standard_deviation",18) == 0)
486  {
487  double
488  mean,
489  standard_deviation;
490 
491  (void) GetImageMean(image,&mean,&standard_deviation,exception);
492  statistic=standard_deviation;
493  }
494  if (channel_mask != UndefinedChannel)
495  (void) SetPixelChannelMask(image,channel_mask);
496  if (SetFxSymbolValue(fx_info,key,statistic) == MagickFalse)
497  return(0.0);
498  return(QuantumScale*statistic);
499 }
500 
501 static double
502  FxEvaluateSubexpression(FxInfo *,const PixelChannel,const ssize_t,
503  const ssize_t,const char *,const size_t,double *,ExceptionInfo *);
504 
505 static inline MagickBooleanType IsFxFunction(const char *expression,
506  const char *name,const size_t length)
507 {
508  int
509  c;
510 
511  size_t
512  i;
513 
514  for (i=0; i <= length; i++)
515  if (expression[i] == '\0')
516  return(MagickFalse);
517  c=expression[length];
518  if ((LocaleNCompare(expression,name,length) == 0) &&
519  ((isspace((int) ((unsigned char) c)) == 0) || (c == '(')))
520  return(MagickTrue);
521  return(MagickFalse);
522 }
523 
524 static inline double FxGCD(const double alpha,const double beta)
525 {
526  if (alpha < beta)
527  return(FxGCD(beta,alpha));
528  if (fabs(beta) < 0.001)
529  return(alpha);
530  return(FxGCD(beta,alpha-beta*floor(alpha/beta)));
531 }
532 
533 static inline const char *FxSubexpression(const char *expression,
534  ExceptionInfo *exception)
535 {
536  const char
537  *subexpression;
538 
539  ssize_t
540  level;
541 
542  level=0;
543  subexpression=expression;
544  while ((*subexpression != '\0') &&
545  ((level != 1) || (strchr(")",(int) *subexpression) == (char *) NULL)))
546  {
547  if (strchr("(",(int) *subexpression) != (char *) NULL)
548  level++;
549  else
550  if (strchr(")",(int) *subexpression) != (char *) NULL)
551  level--;
552  subexpression++;
553  }
554  if (*subexpression == '\0')
556  "UnbalancedParenthesis","`%s'",expression);
557  return(subexpression);
558 }
559 
560 static double FxGetSymbol(FxInfo *fx_info,const PixelChannel channel,
561  const ssize_t x,const ssize_t y,const char *expression,const size_t depth,
562  ExceptionInfo *exception)
563 {
564  char
565  *q,
566  symbol[MagickPathExtent];
567 
568  const char
569  *artifact,
570  *p;
571 
572  const double
573  *value;
574 
575  double
576  alpha,
577  beta;
578 
579  Image
580  *image;
581 
583  status;
584 
585  PixelInfo
586  pixel;
587 
588  PointInfo
589  point;
590 
591  ssize_t
592  i;
593 
594  size_t
595  level;
596 
597  p=expression;
598  i=GetImageIndexInList(fx_info->images);
599  level=0;
600  point.x=(double) x;
601  point.y=(double) y;
602  if (isalpha((int) ((unsigned char) *(p+1))) == 0)
603  {
604  char
605  *subexpression;
606 
607  subexpression=AcquireString(expression);
608  if (strchr("suv",(int) *p) != (char *) NULL)
609  {
610  switch (*p)
611  {
612  case 's':
613  default:
614  {
615  i=GetImageIndexInList(fx_info->images);
616  break;
617  }
618  case 'u': i=0; break;
619  case 'v': i=1; break;
620  }
621  p++;
622  if (*p == '[')
623  {
624  level++;
625  q=subexpression;
626  for (p++; *p != '\0'; )
627  {
628  if (*p == '[')
629  level++;
630  else
631  if (*p == ']')
632  {
633  level--;
634  if (level == 0)
635  break;
636  }
637  *q++=(*p++);
638  }
639  *q='\0';
640  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
641  depth,&beta,exception);
642  i=(ssize_t) alpha;
643  if (*p != '\0')
644  p++;
645  }
646  if (*p == '.')
647  p++;
648  }
649  if ((*p == 'p') && (isalpha((int) ((unsigned char) *(p+1))) == 0))
650  {
651  p++;
652  if (*p == '{')
653  {
654  level++;
655  q=subexpression;
656  for (p++; *p != '\0'; )
657  {
658  if (*p == '{')
659  level++;
660  else
661  if (*p == '}')
662  {
663  level--;
664  if (level == 0)
665  break;
666  }
667  *q++=(*p++);
668  }
669  *q='\0';
670  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
671  depth,&beta,exception);
672  point.x=alpha;
673  point.y=beta;
674  if (*p != '\0')
675  p++;
676  }
677  else
678  if (*p == '[')
679  {
680  level++;
681  q=subexpression;
682  for (p++; *p != '\0'; )
683  {
684  if (*p == '[')
685  level++;
686  else
687  if (*p == ']')
688  {
689  level--;
690  if (level == 0)
691  break;
692  }
693  *q++=(*p++);
694  }
695  *q='\0';
696  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
697  depth,&beta,exception);
698  point.x+=alpha;
699  point.y+=beta;
700  if (*p != '\0')
701  p++;
702  }
703  if (*p == '.')
704  p++;
705  }
706  subexpression=DestroyString(subexpression);
707  }
708  image=GetImageFromList(fx_info->images,i);
709  if (image == (Image *) NULL)
710  {
712  "NoSuchImage","`%s'",expression);
713  return(0.0);
714  }
715  i=GetImageIndexInList(image);
716  GetPixelInfo(image,&pixel);
717  status=InterpolatePixelInfo(image,fx_info->view[i],image->interpolate,
718  point.x,point.y,&pixel,exception);
719  (void) status;
720  if ((*p != '\0') && (*(p+1) != '\0') && (*(p+2) != '\0') &&
721  (LocaleCompare(p,"intensity") != 0) && (LocaleCompare(p,"luma") != 0) &&
722  (LocaleCompare(p,"luminance") != 0) && (LocaleCompare(p,"hue") != 0) &&
723  (LocaleCompare(p,"saturation") != 0) &&
724  (LocaleCompare(p,"lightness") != 0))
725  {
726  char
727  name[MagickPathExtent];
728 
729  size_t
730  length;
731 
732  (void) CopyMagickString(name,p,MagickPathExtent);
733  length=strlen(name);
734  for (q=name+length-1; q > name; q--)
735  {
736  if (*q == ')')
737  break;
738  if (*q == '.')
739  {
740  *q='\0';
741  break;
742  }
743  }
744  q=name;
745  if ((*q != '\0') && (*(q+1) != '\0') && (*(q+2) != '\0') &&
746  (GetFxSymbolValue(fx_info,name) == (const double *) NULL))
747  {
748  PixelInfo
749  *color;
750 
751  color=(PixelInfo *) GetValueFromSplayTree(fx_info->colors,name);
752  if (color != (PixelInfo *) NULL)
753  {
754  pixel=(*color);
755  p+=length;
756  }
757  else
758  {
759  status=QueryColorCompliance(name,AllCompliance,&pixel,
760  fx_info->exception);
761  if (status != MagickFalse)
762  {
763  (void) AddValueToSplayTree(fx_info->colors,
764  ConstantString(name),ClonePixelInfo(&pixel));
765  p+=length;
766  }
767  }
768  }
769  }
770  (void) CopyMagickString(symbol,p,MagickPathExtent);
771  (void) StripMagickString(symbol);
772  if (*symbol == '\0')
773  {
774  switch (channel)
775  {
776  case RedPixelChannel: return(QuantumScale*pixel.red);
777  case GreenPixelChannel: return(QuantumScale*pixel.green);
778  case BluePixelChannel: return(QuantumScale*pixel.blue);
779  case BlackPixelChannel:
780  {
781  if (image->colorspace != CMYKColorspace)
782  {
783  (void) ThrowMagickException(exception,GetMagickModule(),
784  ImageError,"ColorSeparatedImageRequired","`%s'",
785  image->filename);
786  return(0.0);
787  }
788  return(QuantumScale*pixel.black);
789  }
790  case AlphaPixelChannel:
791  {
792  if (pixel.alpha_trait == UndefinedPixelTrait)
793  return(1.0);
794  alpha=(double) (QuantumScale*pixel.alpha);
795  return(alpha);
796  }
798  {
799  Quantum
800  quantum_pixel[MaxPixelChannels];
801 
802  SetPixelViaPixelInfo(image,&pixel,quantum_pixel);
803  return(QuantumScale*GetPixelIntensity(image,quantum_pixel));
804  }
805  case IndexPixelChannel:
806  return(0.0);
807  default:
808  break;
809  }
811  "UnableToParseExpression","`%s'",p);
812  return(0.0);
813  }
814  switch (*symbol)
815  {
816  case 'A':
817  case 'a':
818  {
819  if (LocaleCompare(symbol,"a") == 0)
820  return((QuantumScale*pixel.alpha));
821  break;
822  }
823  case 'B':
824  case 'b':
825  {
826  if (LocaleCompare(symbol,"b") == 0)
827  return(QuantumScale*pixel.blue);
828  break;
829  }
830  case 'C':
831  case 'c':
832  {
833  if (IsFxFunction(symbol,"channel",7) != MagickFalse)
834  {
836  channel_info;
837 
839  flags;
840 
841  flags=ParseGeometry(symbol+7,&channel_info);
842  if (image->colorspace == CMYKColorspace)
843  switch (channel)
844  {
845  case CyanPixelChannel:
846  {
847  if ((flags & RhoValue) == 0)
848  return(0.0);
849  return(channel_info.rho);
850  }
851  case MagentaPixelChannel:
852  {
853  if ((flags & SigmaValue) == 0)
854  return(0.0);
855  return(channel_info.sigma);
856  }
857  case YellowPixelChannel:
858  {
859  if ((flags & XiValue) == 0)
860  return(0.0);
861  return(channel_info.xi);
862  }
863  case BlackPixelChannel:
864  {
865  if ((flags & PsiValue) == 0)
866  return(0.0);
867  return(channel_info.psi);
868  }
869  case AlphaPixelChannel:
870  {
871  if ((flags & ChiValue) == 0)
872  return(0.0);
873  return(channel_info.chi);
874  }
875  default:
876  return(0.0);
877  }
878  switch (channel)
879  {
880  case RedPixelChannel:
881  {
882  if ((flags & RhoValue) == 0)
883  return(0.0);
884  return(channel_info.rho);
885  }
886  case GreenPixelChannel:
887  {
888  if ((flags & SigmaValue) == 0)
889  return(0.0);
890  return(channel_info.sigma);
891  }
892  case BluePixelChannel:
893  {
894  if ((flags & XiValue) == 0)
895  return(0.0);
896  return(channel_info.xi);
897  }
898  case BlackPixelChannel:
899  {
900  if ((flags & ChiValue) == 0)
901  return(0.0);
902  return(channel_info.chi);
903  }
904  case AlphaPixelChannel:
905  {
906  if ((flags & PsiValue) == 0)
907  return(0.0);
908  return(channel_info.psi);
909  }
910  default:
911  return(0.0);
912  }
913  }
914  if (LocaleCompare(symbol,"c") == 0)
915  return(QuantumScale*pixel.red);
916  break;
917  }
918  case 'D':
919  case 'd':
920  {
921  if (LocaleNCompare(symbol,"depth",5) == 0)
922  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
923  break;
924  }
925  case 'E':
926  case 'e':
927  {
928  if (LocaleCompare(symbol,"extent") == 0)
929  {
930  if (image->extent != 0)
931  return((double) image->extent);
932  return((double) GetBlobSize(image));
933  }
934  break;
935  }
936  case 'G':
937  case 'g':
938  {
939  if (LocaleCompare(symbol,"g") == 0)
940  return(QuantumScale*pixel.green);
941  break;
942  }
943  case 'K':
944  case 'k':
945  {
946  if (LocaleNCompare(symbol,"kurtosis",8) == 0)
947  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
948  if (LocaleCompare(symbol,"k") == 0)
949  {
950  if (image->colorspace != CMYKColorspace)
951  {
952  (void) ThrowMagickException(exception,GetMagickModule(),
953  OptionError,"ColorSeparatedImageRequired","`%s'",
954  image->filename);
955  return(0.0);
956  }
957  return(QuantumScale*pixel.black);
958  }
959  break;
960  }
961  case 'H':
962  case 'h':
963  {
964  if (LocaleCompare(symbol,"h") == 0)
965  return((double) image->rows);
966  if (LocaleCompare(symbol,"hue") == 0)
967  {
968  double
969  hue,
970  lightness,
971  saturation;
972 
973  ConvertRGBToHSL(pixel.red,pixel.green,pixel.blue,&hue,&saturation,
974  &lightness);
975  return(hue);
976  }
977  break;
978  }
979  case 'I':
980  case 'i':
981  {
982  if ((LocaleCompare(symbol,"image.depth") == 0) ||
983  (LocaleCompare(symbol,"image.minima") == 0) ||
984  (LocaleCompare(symbol,"image.maxima") == 0) ||
985  (LocaleCompare(symbol,"image.mean") == 0) ||
986  (LocaleCompare(symbol,"image.kurtosis") == 0) ||
987  (LocaleCompare(symbol,"image.skewness") == 0) ||
988  (LocaleCompare(symbol,"image.standard_deviation") == 0))
989  return(FxChannelStatistics(fx_info,image,channel,symbol+6,exception));
990  if (LocaleCompare(symbol,"image.resolution.x") == 0)
991  return(image->resolution.x);
992  if (LocaleCompare(symbol,"image.resolution.y") == 0)
993  return(image->resolution.y);
994  if (LocaleCompare(symbol,"intensity") == 0)
995  {
996  Quantum
997  quantum_pixel[MaxPixelChannels];
998 
999  SetPixelViaPixelInfo(image,&pixel,quantum_pixel);
1000  return(QuantumScale*GetPixelIntensity(image,quantum_pixel));
1001  }
1002  if (LocaleCompare(symbol,"i") == 0)
1003  return((double) x);
1004  break;
1005  }
1006  case 'J':
1007  case 'j':
1008  {
1009  if (LocaleCompare(symbol,"j") == 0)
1010  return((double) y);
1011  break;
1012  }
1013  case 'L':
1014  case 'l':
1015  {
1016  if (LocaleCompare(symbol,"lightness") == 0)
1017  {
1018  double
1019  hue,
1020  lightness,
1021  saturation;
1022 
1023  ConvertRGBToHSL(pixel.red,pixel.green,pixel.blue,&hue,&saturation,
1024  &lightness);
1025  return(lightness);
1026  }
1027  if (LocaleCompare(symbol,"luma") == 0)
1028  {
1029  double
1030  luma;
1031 
1032  luma=0.212656*pixel.red+0.715158*pixel.green+0.072186*pixel.blue;
1033  return(QuantumScale*luma);
1034  }
1035  if (LocaleCompare(symbol,"luminance") == 0)
1036  {
1037  double
1038  luminence;
1039 
1040  luminence=0.212656*pixel.red+0.715158*pixel.green+0.072186*pixel.blue;
1041  return(QuantumScale*luminence);
1042  }
1043  break;
1044  }
1045  case 'M':
1046  case 'm':
1047  {
1048  if (LocaleNCompare(symbol,"maxima",6) == 0)
1049  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1050  if (LocaleNCompare(symbol,"mean",4) == 0)
1051  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1052  if (LocaleNCompare(symbol,"median",6) == 0)
1053  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1054  if (LocaleNCompare(symbol,"minima",6) == 0)
1055  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1056  if (LocaleCompare(symbol,"m") == 0)
1057  return(QuantumScale*pixel.green);
1058  break;
1059  }
1060  case 'N':
1061  case 'n':
1062  {
1063  if (LocaleCompare(symbol,"n") == 0)
1064  return((double) GetImageListLength(fx_info->images));
1065  break;
1066  }
1067  case 'O':
1068  case 'o':
1069  {
1070  if (LocaleCompare(symbol,"o") == 0)
1071  return(QuantumScale*pixel.alpha);
1072  break;
1073  }
1074  case 'P':
1075  case 'p':
1076  {
1077  if (LocaleCompare(symbol,"page.height") == 0)
1078  return((double) image->page.height);
1079  if (LocaleCompare(symbol,"page.width") == 0)
1080  return((double) image->page.width);
1081  if (LocaleCompare(symbol,"page.x") == 0)
1082  return((double) image->page.x);
1083  if (LocaleCompare(symbol,"page.y") == 0)
1084  return((double) image->page.y);
1085  if (LocaleCompare(symbol,"printsize.x") == 0)
1086  return(PerceptibleReciprocal(image->resolution.x)*image->columns);
1087  if (LocaleCompare(symbol,"printsize.y") == 0)
1088  return(PerceptibleReciprocal(image->resolution.y)*image->rows);
1089  break;
1090  }
1091  case 'Q':
1092  case 'q':
1093  {
1094  if (LocaleCompare(symbol,"quality") == 0)
1095  return((double) image->quality);
1096  break;
1097  }
1098  case 'R':
1099  case 'r':
1100  {
1101  if (LocaleCompare(symbol,"resolution.x") == 0)
1102  return(image->resolution.x);
1103  if (LocaleCompare(symbol,"resolution.y") == 0)
1104  return(image->resolution.y);
1105  if (LocaleCompare(symbol,"r") == 0)
1106  return(QuantumScale*pixel.red);
1107  break;
1108  }
1109  case 'S':
1110  case 's':
1111  {
1112  if (LocaleCompare(symbol,"saturation") == 0)
1113  {
1114  double
1115  hue,
1116  lightness,
1117  saturation;
1118 
1119  ConvertRGBToHSL(pixel.red,pixel.green,pixel.blue,&hue,&saturation,
1120  &lightness);
1121  return(saturation);
1122  }
1123  if (LocaleNCompare(symbol,"skewness",8) == 0)
1124  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1125  if (LocaleNCompare(symbol,"standard_deviation",18) == 0)
1126  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1127  break;
1128  }
1129  case 'T':
1130  case 't':
1131  {
1132  if (LocaleCompare(symbol,"t") == 0)
1133  return((double) GetImageIndexInList(fx_info->images));
1134  break;
1135  }
1136  case 'W':
1137  case 'w':
1138  {
1139  if (LocaleCompare(symbol,"w") == 0)
1140  return((double) image->columns);
1141  break;
1142  }
1143  case 'Y':
1144  case 'y':
1145  {
1146  if (LocaleCompare(symbol,"y") == 0)
1147  return(QuantumScale*pixel.blue);
1148  break;
1149  }
1150  case 'Z':
1151  case 'z':
1152  {
1153  if (LocaleCompare(symbol,"z") == 0)
1154  return((double) GetImageDepth(image,fx_info->exception));
1155  break;
1156  }
1157  default:
1158  break;
1159  }
1160  value=GetFxSymbolValue(fx_info,symbol);
1161  if (value != (const double *) NULL)
1162  return(*value);
1163  artifact=GetImageArtifact(image,symbol);
1164  if (artifact != (const char *) NULL)
1165  return(StringToDouble(artifact,(char **) NULL));
1167  "UndefinedVariable","`%s'",symbol);
1168  (void) SetFxSymbolValue(fx_info,symbol,0.0);
1169  return(0.0);
1170 }
1171 
1172 static const char *FxOperatorPrecedence(const char *expression,
1173  ExceptionInfo *exception)
1174 {
1175  typedef enum
1176  {
1177  UndefinedPrecedence,
1178  NullPrecedence,
1179  BitwiseComplementPrecedence,
1180  ExponentPrecedence,
1181  ExponentialNotationPrecedence,
1182  MultiplyPrecedence,
1183  AdditionPrecedence,
1184  ShiftPrecedence,
1185  RelationalPrecedence,
1186  EquivalencyPrecedence,
1187  BitwiseAndPrecedence,
1188  BitwiseOrPrecedence,
1189  LogicalAndPrecedence,
1190  LogicalOrPrecedence,
1191  TernaryPrecedence,
1192  AssignmentPrecedence,
1193  CommaPrecedence,
1194  SeparatorPrecedence
1195  } FxPrecedence;
1196 
1197  FxPrecedence
1198  precedence,
1199  target;
1200 
1201  const char
1202  *subexpression;
1203 
1204  int
1205  c;
1206 
1207  size_t
1208  level;
1209 
1210  c=(-1);
1211  level=0;
1212  subexpression=(const char *) NULL;
1213  target=NullPrecedence;
1214  while ((c != '\0') && (*expression != '\0'))
1215  {
1216  precedence=UndefinedPrecedence;
1217  if ((isspace((int) ((unsigned char) *expression)) != 0) || (c == (int) '@'))
1218  {
1219  expression++;
1220  continue;
1221  }
1222  switch (*expression)
1223  {
1224  case 'A':
1225  case 'a':
1226  {
1227 #if defined(MAGICKCORE_HAVE_ACOSH)
1228  if (IsFxFunction(expression,"acosh",5) != MagickFalse)
1229  {
1230  expression+=5;
1231  break;
1232  }
1233 #endif
1234 #if defined(MAGICKCORE_HAVE_ASINH)
1235  if (IsFxFunction(expression,"asinh",5) != MagickFalse)
1236  {
1237  expression+=5;
1238  break;
1239  }
1240 #endif
1241 #if defined(MAGICKCORE_HAVE_ATANH)
1242  if (IsFxFunction(expression,"atanh",5) != MagickFalse)
1243  {
1244  expression+=5;
1245  break;
1246  }
1247 #endif
1248  if (IsFxFunction(expression,"atan2",5) != MagickFalse)
1249  {
1250  expression+=5;
1251  break;
1252  }
1253  break;
1254  }
1255  case 'E':
1256  case 'e':
1257  {
1258  if ((isdigit((int) ((unsigned char) c)) != 0) &&
1259  ((LocaleNCompare(expression,"E+",2) == 0) ||
1260  (LocaleNCompare(expression,"E-",2) == 0)))
1261  {
1262  expression+=2; /* scientific notation */
1263  break;
1264  }
1265  }
1266  case 'J':
1267  case 'j':
1268  {
1269  if ((IsFxFunction(expression,"j0",2) != MagickFalse) ||
1270  (IsFxFunction(expression,"j1",2) != MagickFalse))
1271  {
1272  expression+=2;
1273  break;
1274  }
1275  break;
1276  }
1277  case '#':
1278  {
1279  while (isxdigit((int) ((unsigned char) *(expression+1))) != 0)
1280  expression++;
1281  break;
1282  }
1283  default:
1284  break;
1285  }
1286  if ((c == (int) '{') || (c == (int) '['))
1287  level++;
1288  else
1289  if ((c == (int) '}') || (c == (int) ']'))
1290  level--;
1291  if (level == 0)
1292  switch ((unsigned char) *expression)
1293  {
1294  case '~':
1295  case '!':
1296  {
1297  precedence=BitwiseComplementPrecedence;
1298  break;
1299  }
1300  case '^':
1301  case '@':
1302  {
1303  precedence=ExponentPrecedence;
1304  break;
1305  }
1306  default:
1307  {
1308  if (((c != 0) && ((isdigit((int) ((unsigned char) c)) != 0) ||
1309  (strchr(")",c) != (char *) NULL))) &&
1310  (((islower((int) ((unsigned char) *expression)) != 0) ||
1311  (strchr("(",(int) ((unsigned char) *expression)) != (char *) NULL)) ||
1312  ((isdigit((int) ((unsigned char) c)) == 0) &&
1313  (isdigit((int) ((unsigned char) *expression)) != 0))) &&
1314  (strchr("xy",(int) ((unsigned char) *expression)) == (char *) NULL))
1315  precedence=MultiplyPrecedence;
1316  break;
1317  }
1318  case '*':
1319  case '/':
1320  case '%':
1321  {
1322  precedence=MultiplyPrecedence;
1323  break;
1324  }
1325  case '+':
1326  case '-':
1327  {
1328  if ((strchr("(+-/*%:&^|<>~,",c) == (char *) NULL) ||
1329  (isalpha((int) ((unsigned char) c)) != 0))
1330  precedence=AdditionPrecedence;
1331  break;
1332  }
1345  {
1346  precedence=AssignmentPrecedence;
1347  break;
1348  }
1349  case LeftShiftOperator:
1350  case RightShiftOperator:
1351  {
1352  precedence=ShiftPrecedence;
1353  break;
1354  }
1355  case '<':
1356  case LessThanEqualOperator:
1358  case '>':
1359  {
1360  precedence=RelationalPrecedence;
1361  break;
1362  }
1363  case EqualOperator:
1364  case NotEqualOperator:
1365  {
1366  precedence=EquivalencyPrecedence;
1367  break;
1368  }
1369  case '&':
1370  {
1371  precedence=BitwiseAndPrecedence;
1372  break;
1373  }
1374  case '|':
1375  {
1376  precedence=BitwiseOrPrecedence;
1377  break;
1378  }
1379  case LogicalAndOperator:
1380  {
1381  precedence=LogicalAndPrecedence;
1382  break;
1383  }
1384  case LogicalOrOperator:
1385  {
1386  precedence=LogicalOrPrecedence;
1387  break;
1388  }
1389  case ExponentialNotation:
1390  {
1391  precedence=ExponentialNotationPrecedence;
1392  break;
1393  }
1394  case ':':
1395  case '?':
1396  {
1397  precedence=TernaryPrecedence;
1398  break;
1399  }
1400  case '=':
1401  {
1402  precedence=AssignmentPrecedence;
1403  break;
1404  }
1405  case ',':
1406  {
1407  precedence=CommaPrecedence;
1408  break;
1409  }
1410  case ';':
1411  {
1412  precedence=SeparatorPrecedence;
1413  break;
1414  }
1415  }
1416  if ((precedence == BitwiseComplementPrecedence) ||
1417  (precedence == TernaryPrecedence) ||
1418  (precedence == AssignmentPrecedence))
1419  {
1420  if (precedence > target)
1421  {
1422  /*
1423  Right-to-left associativity.
1424  */
1425  target=precedence;
1426  subexpression=expression;
1427  }
1428  }
1429  else
1430  if (precedence >= target)
1431  {
1432  /*
1433  Left-to-right associativity.
1434  */
1435  target=precedence;
1436  subexpression=expression;
1437  }
1438  if (strchr("(",(int) *expression) != (char *) NULL)
1439  expression=FxSubexpression(expression,exception);
1440  c=(int) (*expression++);
1441  }
1442  return(subexpression);
1443 }
1444 
1445 static double FxEvaluateSubexpression(FxInfo *fx_info,
1446  const PixelChannel channel,const ssize_t x,const ssize_t y,
1447  const char *expression,const size_t depth,double *beta,
1448  ExceptionInfo *exception)
1449 {
1450 #define FxMaxParenthesisDepth 58
1451 #define FxMaxSubexpressionDepth 200
1452 #define FxReturn(value) \
1453 { \
1454  subexpression=DestroyString(subexpression); \
1455  return(value); \
1456 }
1457 #define FxParseConditional(subexpression,sentinal,p,q) \
1458 { \
1459  p=subexpression; \
1460  for (q=(char *) p; (*q != (sentinal)) && (*q != '\0'); q++) \
1461  if (*q == '(') \
1462  { \
1463  for (q++; (*q != ')') && (*q != '\0'); q++); \
1464  if (*q == '\0') \
1465  break; \
1466  } \
1467  if (*q == '\0') \
1468  { \
1469  (void) ThrowMagickException(exception,GetMagickModule(), \
1470  OptionError,"UnableToParseExpression","`%s'",subexpression); \
1471  FxReturn(0.0); \
1472  } \
1473  if (strlen(q) == 1) \
1474  *(q+1)='\0'; \
1475  *q='\0'; \
1476 }
1477 
1478  char
1479  *q,
1480  *subexpression;
1481 
1482  double
1483  alpha,
1484  gamma,
1485  sans,
1486  value;
1487 
1488  const char
1489  *p;
1490 
1491  *beta=0.0;
1492  sans=0.0;
1493  subexpression=AcquireString(expression);
1494  *subexpression='\0';
1495  if (depth > FxMaxSubexpressionDepth)
1496  {
1498  "UnableToParseExpression","`%s'",expression);
1499  FxReturn(0.0);
1500  }
1501  if (exception->severity >= ErrorException)
1502  FxReturn(0.0);
1503  while (isspace((int) ((unsigned char) *expression)) != 0)
1504  expression++;
1505  if (*expression == '\0')
1506  FxReturn(0.0);
1507  p=FxOperatorPrecedence(expression,exception);
1508  if (p != (const char *) NULL)
1509  {
1510  (void) CopyMagickString(subexpression,expression,(size_t)
1511  (p-expression+1));
1512  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,depth+1,
1513  beta,exception);
1514  switch ((unsigned char) *p)
1515  {
1516  case '~':
1517  {
1518  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1519  exception);
1520  *beta=(double) (~(size_t) *beta);
1521  FxReturn(*beta);
1522  }
1523  case '!':
1524  {
1525  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1526  exception);
1527  FxReturn(*beta == 0.0 ? 1.0 : 0.0);
1528  }
1529  case '^':
1530  {
1531  *beta=pow(alpha,FxEvaluateSubexpression(fx_info,channel,x,y,++p,
1532  depth+1,beta,exception));
1533  FxReturn(*beta);
1534  }
1535  case '*':
1536  case ExponentialNotation:
1537  {
1538  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1539  exception);
1540  FxReturn(alpha*(*beta));
1541  }
1542  case '/':
1543  {
1544  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1545  exception);
1546  FxReturn(PerceptibleReciprocal(*beta)*alpha);
1547  }
1548  case '%':
1549  {
1550  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1551  exception);
1552  FxReturn(fmod(alpha,*beta));
1553  }
1554  case '+':
1555  {
1556  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1557  exception);
1558  FxReturn(alpha+(*beta));
1559  }
1560  case '-':
1561  {
1562  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1563  exception);
1564  FxReturn(alpha-(*beta));
1565  }
1567  {
1568  q=subexpression;
1569  while (isalpha((int) ((unsigned char) *q)) != 0)
1570  q++;
1571  if (*q != '\0')
1572  {
1573  (void) ThrowMagickException(exception,GetMagickModule(),
1574  OptionError,"UnableToParseExpression","`%s'",subexpression);
1575  FxReturn(0.0);
1576  }
1577  ClearMagickException(exception);
1578  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1579  exception);
1580  value=(double) ((size_t) (alpha+0.5) & (size_t) (*beta+0.5));
1581  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1582  return(0.0);
1583  FxReturn(*beta);
1584  }
1586  {
1587  q=subexpression;
1588  while (isalpha((int) ((unsigned char) *q)) != 0)
1589  q++;
1590  if (*q != '\0')
1591  {
1592  (void) ThrowMagickException(exception,GetMagickModule(),
1593  OptionError,"UnableToParseExpression","`%s'",subexpression);
1594  FxReturn(0.0);
1595  }
1596  ClearMagickException(exception);
1597  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1598  exception);
1599  value=(double) ((size_t) (alpha+0.5) | (size_t) (*beta+0.5));
1600  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1601  return(0.0);
1602  FxReturn(*beta);
1603  }
1605  {
1606  q=subexpression;
1607  while (isalpha((int) ((unsigned char) *q)) != 0)
1608  q++;
1609  if (*q != '\0')
1610  {
1611  (void) ThrowMagickException(exception,GetMagickModule(),
1612  OptionError,"UnableToParseExpression","`%s'",subexpression);
1613  FxReturn(0.0);
1614  }
1615  ClearMagickException(exception);
1616  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1617  exception);
1618  if ((size_t) (*beta+0.5) >= (8*sizeof(size_t)))
1619  {
1620  (void) ThrowMagickException(exception,GetMagickModule(),
1621  OptionError,"ShiftCountOverflow","`%s'",subexpression);
1622  FxReturn(0.0);
1623  }
1624  value=(double) ((size_t) (alpha+0.5) << (size_t) (*beta+0.5));
1625  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1626  return(0.0);
1627  FxReturn(*beta);
1628  }
1630  {
1631  q=subexpression;
1632  while (isalpha((int) ((unsigned char) *q)) != 0)
1633  q++;
1634  if (*q != '\0')
1635  {
1636  (void) ThrowMagickException(exception,GetMagickModule(),
1637  OptionError,"UnableToParseExpression","`%s'",subexpression);
1638  FxReturn(0.0);
1639  }
1640  ClearMagickException(exception);
1641  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1642  exception);
1643  if ((size_t) (*beta+0.5) >= (8*sizeof(size_t)))
1644  {
1645  (void) ThrowMagickException(exception,GetMagickModule(),
1646  OptionError,"ShiftCountOverflow","`%s'",subexpression);
1647  FxReturn(0.0);
1648  }
1649  value=(double) ((size_t) (alpha+0.5) >> (size_t) (*beta+0.5));
1650  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1651  return(0.0);
1652  FxReturn(*beta);
1653  }
1655  {
1656  q=subexpression;
1657  while (isalpha((int) ((unsigned char) *q)) != 0)
1658  q++;
1659  if (*q != '\0')
1660  {
1661  (void) ThrowMagickException(exception,GetMagickModule(),
1662  OptionError,"UnableToParseExpression","`%s'",subexpression);
1663  FxReturn(0.0);
1664  }
1665  ClearMagickException(exception);
1666  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1667  exception);
1668  value=pow(alpha,*beta);
1669  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1670  return(0.0);
1671  FxReturn(*beta);
1672  }
1674  {
1675  q=subexpression;
1676  while (isalpha((int) ((unsigned char) *q)) != 0)
1677  q++;
1678  if (*q != '\0')
1679  {
1680  (void) ThrowMagickException(exception,GetMagickModule(),
1681  OptionError,"UnableToParseExpression","`%s'",subexpression);
1682  FxReturn(0.0);
1683  }
1684  ClearMagickException(exception);
1685  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1686  exception);
1687  value=fmod(alpha,*beta);
1688  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1689  return(0.0);
1690  FxReturn(*beta);
1691  }
1693  {
1694  q=subexpression;
1695  while (isalpha((int) ((unsigned char) *q)) != 0)
1696  q++;
1697  if (*q != '\0')
1698  {
1699  (void) ThrowMagickException(exception,GetMagickModule(),
1700  OptionError,"UnableToParseExpression","`%s'",subexpression);
1701  FxReturn(0.0);
1702  }
1703  ClearMagickException(exception);
1704  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1705  exception);
1706  value=alpha+(*beta);
1707  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1708  return(0.0);
1709  FxReturn(*beta);
1710  }
1712  {
1713  q=subexpression;
1714  while (isalpha((int) ((unsigned char) *q)) != 0)
1715  q++;
1716  if (*q != '\0')
1717  {
1718  (void) ThrowMagickException(exception,GetMagickModule(),
1719  OptionError,"UnableToParseExpression","`%s'",subexpression);
1720  FxReturn(0.0);
1721  }
1722  ClearMagickException(exception);
1723  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1724  exception);
1725  value=alpha-(*beta);
1726  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1727  return(0.0);
1728  FxReturn(*beta);
1729  }
1731  {
1732  q=subexpression;
1733  while (isalpha((int) ((unsigned char) *q)) != 0)
1734  q++;
1735  if (*q != '\0')
1736  {
1737  (void) ThrowMagickException(exception,GetMagickModule(),
1738  OptionError,"UnableToParseExpression","`%s'",subexpression);
1739  FxReturn(0.0);
1740  }
1741  ClearMagickException(exception);
1742  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1743  exception);
1744  value=alpha*(*beta);
1745  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1746  return(0.0);
1747  FxReturn(*beta);
1748  }
1750  {
1751  q=subexpression;
1752  while (isalpha((int) ((unsigned char) *q)) != 0)
1753  q++;
1754  if (*q != '\0')
1755  {
1756  (void) ThrowMagickException(exception,GetMagickModule(),
1757  OptionError,"UnableToParseExpression","`%s'",subexpression);
1758  FxReturn(0.0);
1759  }
1760  ClearMagickException(exception);
1761  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1762  exception);
1763  value=alpha*PerceptibleReciprocal(*beta);
1764  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1765  return(0.0);
1766  FxReturn(*beta);
1767  }
1769  {
1770  if (*subexpression == '\0')
1771  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1772  exception);
1773  value=alpha+1.0;
1774  if (*subexpression == '\0')
1775  {
1776  if (SetFxSymbolValue(fx_info,p,value) == MagickFalse)
1777  return(0.0);
1778  }
1779  else
1780  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1781  return(0.0);
1782  FxReturn(*beta);
1783  }
1785  {
1786  if (*subexpression == '\0')
1787  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1788  exception);
1789  value=alpha-1.0;
1790  if (*subexpression == '\0')
1791  {
1792  if (SetFxSymbolValue(fx_info,p,value) == MagickFalse)
1793  return(0.0);
1794  }
1795  else
1796  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1797  return(0.0);
1798  FxReturn(*beta);
1799  }
1800  case LeftShiftOperator:
1801  {
1802  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1803  exception);
1804  if ((size_t) (gamma+0.5) >= (8*sizeof(size_t)))
1805  {
1806  (void) ThrowMagickException(exception,GetMagickModule(),
1807  OptionError,"ShiftCountOverflow","`%s'",subexpression);
1808  FxReturn(0.0);
1809  }
1810  *beta=(double) ((size_t) (alpha+0.5) << (size_t) (gamma+0.5));
1811  FxReturn(*beta);
1812  }
1813  case RightShiftOperator:
1814  {
1815  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1816  exception);
1817  if ((size_t) (gamma+0.5) >= (8*sizeof(size_t)))
1818  {
1819  (void) ThrowMagickException(exception,GetMagickModule(),
1820  OptionError,"ShiftCountOverflow","`%s'",subexpression);
1821  FxReturn(0.0);
1822  }
1823  *beta=(double) ((size_t) (alpha+0.5) >> (size_t) (gamma+0.5));
1824  FxReturn(*beta);
1825  }
1826  case '<':
1827  {
1828  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1829  exception);
1830  FxReturn(alpha < *beta ? 1.0 : 0.0);
1831  }
1832  case LessThanEqualOperator:
1833  {
1834  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1835  exception);
1836  FxReturn(alpha <= *beta ? 1.0 : 0.0);
1837  }
1838  case '>':
1839  {
1840  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1841  exception);
1842  FxReturn(alpha > *beta ? 1.0 : 0.0);
1843  }
1845  {
1846  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1847  exception);
1848  FxReturn(alpha >= *beta ? 1.0 : 0.0);
1849  }
1850  case EqualOperator:
1851  {
1852  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1853  exception);
1854  FxReturn(fabs(alpha-(*beta)) < MagickEpsilon ? 1.0 : 0.0);
1855  }
1856  case NotEqualOperator:
1857  {
1858  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1859  exception);
1860  FxReturn(fabs(alpha-(*beta)) >= MagickEpsilon ? 1.0 : 0.0);
1861  }
1862  case '&':
1863  {
1864  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1865  exception);
1866  *beta=(double) ((size_t) (alpha+0.5) & (size_t) (gamma+0.5));
1867  FxReturn(*beta);
1868  }
1869  case '|':
1870  {
1871  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1872  exception);
1873  *beta=(double) ((size_t) (alpha+0.5) | (size_t) (gamma+0.5));
1874  FxReturn(*beta);
1875  }
1876  case LogicalAndOperator:
1877  {
1878  p++;
1879  if (alpha <= 0.0)
1880  {
1881  *beta=0.0;
1882  FxReturn(*beta);
1883  }
1884  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1885  exception);
1886  *beta=(gamma > 0.0) ? 1.0 : 0.0;
1887  FxReturn(*beta);
1888  }
1889  case LogicalOrOperator:
1890  {
1891  p++;
1892  if (alpha > 0.0)
1893  {
1894  *beta=1.0;
1895  FxReturn(*beta);
1896  }
1897  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1898  exception);
1899  *beta=(gamma > 0.0) ? 1.0 : 0.0;
1900  FxReturn(*beta);
1901  }
1902  case '?':
1903  {
1904  (void) CopyMagickString(subexpression,++p,MagickPathExtent-1);
1905  FxParseConditional(subexpression,':',p,q);
1906  if (fabs(alpha) >= MagickEpsilon)
1907  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1908  exception);
1909  else
1910  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
1911  exception);
1912  FxReturn(gamma);
1913  }
1914  case '=':
1915  {
1916  q=subexpression;
1917  while (isalpha((int) ((unsigned char) *q)) != 0)
1918  q++;
1919  if (*q != '\0')
1920  {
1921  (void) ThrowMagickException(exception,GetMagickModule(),
1922  OptionError,"UnableToParseExpression","`%s'",subexpression);
1923  FxReturn(0.0);
1924  }
1925  ClearMagickException(exception);
1926  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1927  exception);
1928  value=(*beta);
1929  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1930  return(0.0);
1931  FxReturn(*beta);
1932  }
1933  case ',':
1934  {
1935  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1936  exception);
1937  FxReturn(alpha);
1938  }
1939  case ';':
1940  {
1941  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1942  exception);
1943  FxReturn(*beta);
1944  }
1945  default:
1946  {
1947  gamma=alpha*FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,
1948  beta,exception);
1949  FxReturn(gamma);
1950  }
1951  }
1952  }
1953  if (strchr("(",(int) *expression) != (char *) NULL)
1954  {
1955  size_t
1956  length;
1957 
1958  if (depth >= FxMaxParenthesisDepth)
1960  "ParenthesisNestedTooDeeply","`%s'",expression);
1961  length=CopyMagickString(subexpression,expression+1,MagickPathExtent);
1962  if (length != 0)
1963  subexpression[length-1]='\0';
1964  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,depth+1,
1965  beta,exception);
1966  FxReturn(gamma);
1967  }
1968  switch (*expression)
1969  {
1970  case '+':
1971  {
1972  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1973  beta,exception);
1974  FxReturn(1.0*gamma);
1975  }
1976  case '-':
1977  {
1978  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1979  beta,exception);
1980  FxReturn(-1.0*gamma);
1981  }
1982  case '~':
1983  {
1984  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1985  beta,exception);
1986  FxReturn((double) (~(size_t) (gamma+0.5)));
1987  }
1988  case 'A':
1989  case 'a':
1990  {
1991  if (IsFxFunction(expression,"abs",3) != MagickFalse)
1992  {
1993  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
1994  depth+1,beta,exception);
1995  FxReturn(fabs(alpha));
1996  }
1997 #if defined(MAGICKCORE_HAVE_ACOSH)
1998  if (IsFxFunction(expression,"acosh",5) != MagickFalse)
1999  {
2000  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2001  depth+1,beta,exception);
2002  FxReturn(acosh(alpha));
2003  }
2004 #endif
2005  if (IsFxFunction(expression,"acos",4) != MagickFalse)
2006  {
2007  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2008  depth+1,beta,exception);
2009  FxReturn(acos(alpha));
2010  }
2011 #if defined(MAGICKCORE_HAVE_J1)
2012  if (IsFxFunction(expression,"airy",4) != MagickFalse)
2013  {
2014  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2015  depth+1,beta,exception);
2016  if (alpha == 0.0)
2017  FxReturn(1.0);
2018  gamma=2.0*j1((MagickPI*alpha))/(MagickPI*alpha);
2019  FxReturn(gamma*gamma);
2020  }
2021 #endif
2022 #if defined(MAGICKCORE_HAVE_ASINH)
2023  if (IsFxFunction(expression,"asinh",5) != MagickFalse)
2024  {
2025  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2026  depth+1,beta,exception);
2027  FxReturn(asinh(alpha));
2028  }
2029 #endif
2030  if (IsFxFunction(expression,"asin",4) != MagickFalse)
2031  {
2032  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2033  depth+1,beta,exception);
2034  FxReturn(asin(alpha));
2035  }
2036  if (IsFxFunction(expression,"alt",3) != MagickFalse)
2037  {
2038  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2039  depth+1,beta,exception);
2040  FxReturn(((ssize_t) alpha) & 0x01 ? -1.0 : 1.0);
2041  }
2042  if (IsFxFunction(expression,"atan2",5) != MagickFalse)
2043  {
2044  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2045  depth+1,beta,exception);
2046  FxReturn(atan2(alpha,*beta));
2047  }
2048 #if defined(MAGICKCORE_HAVE_ATANH)
2049  if (IsFxFunction(expression,"atanh",5) != MagickFalse)
2050  {
2051  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2052  depth+1,beta,exception);
2053  FxReturn(atanh(alpha));
2054  }
2055 #endif
2056  if (IsFxFunction(expression,"atan",4) != MagickFalse)
2057  {
2058  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2059  depth+1,beta,exception);
2060  FxReturn(atan(alpha));
2061  }
2062  if (LocaleCompare(expression,"a") == 0)
2063  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2064  break;
2065  }
2066  case 'B':
2067  case 'b':
2068  {
2069  if (LocaleCompare(expression,"b") == 0)
2070  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2071  break;
2072  }
2073  case 'C':
2074  case 'c':
2075  {
2076  if (IsFxFunction(expression,"ceil",4) != MagickFalse)
2077  {
2078  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2079  depth+1,beta,exception);
2080  FxReturn(ceil(alpha));
2081  }
2082  if (IsFxFunction(expression,"clamp",5) != MagickFalse)
2083  {
2084  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2085  depth+1,beta,exception);
2086  if (alpha < 0.0)
2087  FxReturn(0.0);
2088  if (alpha > 1.0)
2089  FxReturn(1.0);
2090  FxReturn(alpha);
2091  }
2092  if (IsFxFunction(expression,"cosh",4) != MagickFalse)
2093  {
2094  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2095  depth+1,beta,exception);
2096  FxReturn(cosh(alpha));
2097  }
2098  if (IsFxFunction(expression,"cos",3) != MagickFalse)
2099  {
2100  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2101  depth+1,beta,exception);
2102  FxReturn(cos(alpha));
2103  }
2104  if (LocaleCompare(expression,"c") == 0)
2105  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2106  break;
2107  }
2108  case 'D':
2109  case 'd':
2110  {
2111  if (IsFxFunction(expression,"debug",5) != MagickFalse)
2112  {
2113  const char
2114  *type;
2115 
2116  size_t
2117  length;
2118 
2119  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2120  depth+1,beta,exception);
2121  switch (fx_info->images->colorspace)
2122  {
2123  case CMYKColorspace:
2124  {
2125  switch (channel)
2126  {
2127  case CyanPixelChannel: type="cyan"; break;
2128  case MagentaPixelChannel: type="magenta"; break;
2129  case YellowPixelChannel: type="yellow"; break;
2130  case AlphaPixelChannel: type="alpha"; break;
2131  case BlackPixelChannel: type="black"; break;
2132  default: type="unknown"; break;
2133  }
2134  break;
2135  }
2136  case GRAYColorspace:
2137  {
2138  switch (channel)
2139  {
2140  case RedPixelChannel: type="gray"; break;
2141  case AlphaPixelChannel: type="alpha"; break;
2142  default: type="unknown"; break;
2143  }
2144  break;
2145  }
2146  default:
2147  {
2148  switch (channel)
2149  {
2150  case RedPixelChannel: type="red"; break;
2151  case GreenPixelChannel: type="green"; break;
2152  case BluePixelChannel: type="blue"; break;
2153  case AlphaPixelChannel: type="alpha"; break;
2154  default: type="unknown"; break;
2155  }
2156  break;
2157  }
2158  }
2159  *subexpression='\0';
2160  length=1;
2161  if (strlen(expression) > 6)
2162  length=CopyMagickString(subexpression,expression+6,
2164  if (length != 0)
2165  subexpression[length-1]='\0';
2166  if (fx_info->file != (FILE *) NULL)
2167  (void) FormatLocaleFile(fx_info->file,"%s[%.20g,%.20g].%s: "
2168  "%s=%.*g\n",fx_info->images->filename,(double) x,(double) y,type,
2169  subexpression,GetMagickPrecision(),alpha);
2170  FxReturn(alpha);
2171  }
2172  if (IsFxFunction(expression,"do",2) != MagickFalse)
2173  {
2174  size_t
2175  length;
2176 
2177  /*
2178  Parse do(expression,condition test).
2179  */
2180  length=CopyMagickString(subexpression,expression+3,
2181  MagickPathExtent-1);
2182  if (length != 0)
2183  subexpression[length-1]='\0';
2184  FxParseConditional(subexpression,',',p,q);
2185  for (alpha=0.0; ; )
2186  {
2187  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2188  exception);
2189  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2190  exception);
2191  if (fabs(gamma) < MagickEpsilon)
2192  break;
2193  }
2194  FxReturn(alpha);
2195  }
2196  if (IsFxFunction(expression,"drc",3) != MagickFalse)
2197  {
2198  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2199  depth+1,beta,exception);
2200  FxReturn((alpha/(*beta*(alpha-1.0)+1.0)));
2201  }
2202  break;
2203  }
2204  case 'E':
2205  case 'e':
2206  {
2207  if (LocaleCompare(expression,"epsilon") == 0)
2209 #if defined(MAGICKCORE_HAVE_ERF)
2210  if (IsFxFunction(expression,"erf",3) != MagickFalse)
2211  {
2212  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2213  depth+1,beta,exception);
2214  FxReturn(erf(alpha));
2215  }
2216 #endif
2217  if (IsFxFunction(expression,"exp",3) != MagickFalse)
2218  {
2219  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2220  depth+1,beta,exception);
2221  FxReturn(exp(alpha));
2222  }
2223  if (LocaleCompare(expression,"e") == 0)
2224  FxReturn(2.7182818284590452354);
2225  break;
2226  }
2227  case 'F':
2228  case 'f':
2229  {
2230  if (IsFxFunction(expression,"floor",5) != MagickFalse)
2231  {
2232  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2233  depth+1,beta,exception);
2234  FxReturn(floor(alpha));
2235  }
2236  if (IsFxFunction(expression,"for",3) != MagickFalse)
2237  {
2238  size_t
2239  length;
2240 
2241  /*
2242  Parse for(initialization, condition test, expression).
2243  */
2244  length=CopyMagickString(subexpression,expression+4,
2245  MagickPathExtent-1);
2246  if (length != 0)
2247  subexpression[length-1]='\0';
2248  FxParseConditional(subexpression,',',p,q);
2249  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2250  exception);
2251  (void) CopyMagickString(subexpression,q+1,MagickPathExtent-1);
2252  FxParseConditional(subexpression,',',p,q);
2253  for (alpha=0.0; ; )
2254  {
2255  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2256  exception);
2257  if (fabs(gamma) < MagickEpsilon)
2258  break;
2259  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2260  exception);
2261  }
2262  FxReturn(alpha);
2263  }
2264  break;
2265  }
2266  case 'G':
2267  case 'g':
2268  {
2269  if (IsFxFunction(expression,"gauss",5) != MagickFalse)
2270  {
2271  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2272  depth+1,beta,exception);
2273  FxReturn(exp((-alpha*alpha/2.0))/sqrt(2.0*MagickPI));
2274  }
2275  if (IsFxFunction(expression,"gcd",3) != MagickFalse)
2276  {
2277  double
2278  gcd;
2279 
2280  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2281  depth+1,beta,exception);
2282  if (IsNaN(alpha))
2283  FxReturn(alpha);
2284  gcd=FxGCD(alpha,*beta);
2285  FxReturn(gcd);
2286  }
2287  if (LocaleCompare(expression,"g") == 0)
2288  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2289  break;
2290  }
2291  case 'H':
2292  case 'h':
2293  {
2294  if (LocaleCompare(expression,"h") == 0)
2295  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2296  if (LocaleCompare(expression,"hue") == 0)
2297  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2298  if (IsFxFunction(expression,"hypot",5) != MagickFalse)
2299  {
2300  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2301  depth+1,beta,exception);
2302  FxReturn(hypot(alpha,*beta));
2303  }
2304  break;
2305  }
2306  case 'K':
2307  case 'k':
2308  {
2309  if (LocaleCompare(expression,"k") == 0)
2310  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2311  break;
2312  }
2313  case 'I':
2314  case 'i':
2315  {
2316  if (IsFxFunction(expression,"if",2) != MagickFalse)
2317  {
2318  size_t
2319  length;
2320 
2321  /*
2322  Parse if(condition test, true-expression, false-expression).
2323  */
2324  length=CopyMagickString(subexpression,expression+3,
2325  MagickPathExtent-1);
2326  if (length != 0)
2327  subexpression[length-1]='\0';
2328  FxParseConditional(subexpression,',',p,q);
2329  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2330  exception);
2331  (void) CopyMagickString(subexpression,q+1,MagickPathExtent-1);
2332  FxParseConditional(subexpression,',',p,q);
2333  if (fabs(alpha) >= MagickEpsilon)
2334  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
2335  exception);
2336  else
2337  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2338  exception);
2339  FxReturn(alpha);
2340  }
2341  if (LocaleCompare(expression,"intensity") == 0)
2342  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2343  if (IsFxFunction(expression,"int",3) != MagickFalse)
2344  {
2345  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2346  depth+1,beta,exception);
2347  FxReturn(floor(alpha));
2348  }
2349  if (IsFxFunction(expression,"isnan",5) != MagickFalse)
2350  {
2351  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2352  depth+1,beta,exception);
2353  FxReturn((double) !!IsNaN(alpha));
2354  }
2355  if (LocaleCompare(expression,"i") == 0)
2356  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2357  break;
2358  }
2359  case 'J':
2360  case 'j':
2361  {
2362  if (LocaleCompare(expression,"j") == 0)
2363  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2364 #if defined(MAGICKCORE_HAVE_J0)
2365  if (IsFxFunction(expression,"j0",2) != MagickFalse)
2366  {
2367  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2368  depth+1,beta,exception);
2369  FxReturn(j0(alpha));
2370  }
2371 #endif
2372 #if defined(MAGICKCORE_HAVE_J1)
2373  if (IsFxFunction(expression,"j1",2) != MagickFalse)
2374  {
2375  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2376  depth+1,beta,exception);
2377  FxReturn(j1(alpha));
2378  }
2379 #endif
2380 #if defined(MAGICKCORE_HAVE_J1)
2381  if (IsFxFunction(expression,"jinc",4) != MagickFalse)
2382  {
2383  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2384  depth+1,beta,exception);
2385  if (alpha == 0.0)
2386  FxReturn(1.0);
2387  FxReturn((2.0*j1((MagickPI*alpha))/(MagickPI*alpha)));
2388  }
2389 #endif
2390  break;
2391  }
2392  case 'L':
2393  case 'l':
2394  {
2395  if (IsFxFunction(expression,"ln",2) != MagickFalse)
2396  {
2397  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2398  depth+1,beta,exception);
2399  FxReturn(log(alpha));
2400  }
2401  if (IsFxFunction(expression,"logtwo",6) != MagickFalse)
2402  {
2403  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,
2404  depth+1,beta,exception);
2405  FxReturn(log10(alpha)/log10(2.0));
2406  }
2407  if (IsFxFunction(expression,"log",3) != MagickFalse)
2408  {
2409  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2410  depth+1,beta,exception);
2411  FxReturn(log10(alpha));
2412  }
2413  if (LocaleCompare(expression,"lightness") == 0)
2414  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2415  break;
2416  }
2417  case 'M':
2418  case 'm':
2419  {
2420  if (LocaleCompare(expression,"MaxRGB") == 0)
2422  if (LocaleNCompare(expression,"maxima",6) == 0)
2423  break;
2424  if (IsFxFunction(expression,"max",3) != MagickFalse)
2425  {
2426  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2427  depth+1,beta,exception);
2428  FxReturn(alpha > *beta ? alpha : *beta);
2429  }
2430  if (LocaleNCompare(expression,"minima",6) == 0)
2431  break;
2432  if (IsFxFunction(expression,"min",3) != MagickFalse)
2433  {
2434  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2435  depth+1,beta,exception);
2436  FxReturn(alpha < *beta ? alpha : *beta);
2437  }
2438  if (IsFxFunction(expression,"mod",3) != MagickFalse)
2439  {
2440  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2441  depth+1,beta,exception);
2442  FxReturn(alpha-floor((alpha*PerceptibleReciprocal(*beta)))*(*beta));
2443  }
2444  if (LocaleCompare(expression,"m") == 0)
2445  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2446  break;
2447  }
2448  case 'N':
2449  case 'n':
2450  {
2451  if (IsFxFunction(expression,"not",3) != MagickFalse)
2452  {
2453  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2454  depth+1,beta,exception);
2455  FxReturn((double) (alpha < MagickEpsilon));
2456  }
2457  if (LocaleCompare(expression,"n") == 0)
2458  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2459  break;
2460  }
2461  case 'O':
2462  case 'o':
2463  {
2464  if (LocaleCompare(expression,"Opaque") == 0)
2465  FxReturn(1.0);
2466  if (LocaleCompare(expression,"o") == 0)
2467  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2468  break;
2469  }
2470  case 'P':
2471  case 'p':
2472  {
2473  if (LocaleCompare(expression,"phi") == 0)
2475  if (LocaleCompare(expression,"pi") == 0)
2476  FxReturn(MagickPI);
2477  if (IsFxFunction(expression,"pow",3) != MagickFalse)
2478  {
2479  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2480  depth+1,beta,exception);
2481  FxReturn(pow(alpha,*beta));
2482  }
2483  if (LocaleCompare(expression,"p") == 0)
2484  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2485  break;
2486  }
2487  case 'Q':
2488  case 'q':
2489  {
2490  if (LocaleCompare(expression,"QuantumRange") == 0)
2492  if (LocaleCompare(expression,"QuantumScale") == 0)
2494  break;
2495  }
2496  case 'R':
2497  case 'r':
2498  {
2499  if (IsFxFunction(expression,"rand",4) != MagickFalse)
2500  {
2501 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2502  #pragma omp critical (MagickCore_FxEvaluateSubexpression)
2503 #endif
2504  alpha=GetPseudoRandomValue(fx_info->random_info);
2505  FxReturn(alpha);
2506  }
2507  if (IsFxFunction(expression,"round",5) != MagickFalse)
2508  {
2509  /*
2510  Round the fraction to nearest integer.
2511  */
2512  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2513  depth+1,beta,exception);
2514  if ((alpha-floor(alpha)) < (ceil(alpha)-alpha))
2515  FxReturn(floor(alpha));
2516  FxReturn(ceil(alpha));
2517  }
2518  if (LocaleCompare(expression,"r") == 0)
2519  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2520  break;
2521  }
2522  case 'S':
2523  case 's':
2524  {
2525  if (LocaleCompare(expression,"saturation") == 0)
2526  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2527  if (IsFxFunction(expression,"sign",4) != MagickFalse)
2528  {
2529  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2530  depth+1,beta,exception);
2531  FxReturn(alpha < 0.0 ? -1.0 : 1.0);
2532  }
2533  if (IsFxFunction(expression,"sinc",4) != MagickFalse)
2534  {
2535  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2536  depth+1,beta,exception);
2537  if (alpha == 0)
2538  FxReturn(1.0);
2539  FxReturn(sin((MagickPI*alpha))/(MagickPI*alpha));
2540  }
2541  if (IsFxFunction(expression,"sinh",4) != MagickFalse)
2542  {
2543  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2544  depth+1,beta,exception);
2545  FxReturn(sinh(alpha));
2546  }
2547  if (IsFxFunction(expression,"sin",3) != MagickFalse)
2548  {
2549  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2550  depth+1,beta,exception);
2551  FxReturn(sin(alpha));
2552  }
2553  if (IsFxFunction(expression,"sqrt",4) != MagickFalse)
2554  {
2555  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2556  depth+1,beta,exception);
2557  FxReturn(sqrt(alpha));
2558  }
2559  if (IsFxFunction(expression,"squish",6) != MagickFalse)
2560  {
2561  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,
2562  depth+1,beta,exception);
2563  FxReturn((1.0/(1.0+exp(-alpha))));
2564  }
2565  if (LocaleCompare(expression,"s") == 0)
2566  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2567  break;
2568  }
2569  case 'T':
2570  case 't':
2571  {
2572  if (IsFxFunction(expression,"tanh",4) != MagickFalse)
2573  {
2574  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2575  depth+1,beta,exception);
2576  FxReturn(tanh(alpha));
2577  }
2578  if (IsFxFunction(expression,"tan",3) != MagickFalse)
2579  {
2580  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2581  depth+1,beta,exception);
2582  FxReturn(tan(alpha));
2583  }
2584  if (LocaleCompare(expression,"Transparent") == 0)
2585  FxReturn(0.0);
2586  if (IsFxFunction(expression,"trunc",5) != MagickFalse)
2587  {
2588  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2589  depth+1,beta,exception);
2590  if (alpha >= 0.0)
2591  FxReturn(floor(alpha));
2592  FxReturn(ceil(alpha));
2593  }
2594  if (LocaleCompare(expression,"t") == 0)
2595  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2596  break;
2597  }
2598  case 'U':
2599  case 'u':
2600  {
2601  if (LocaleCompare(expression,"u") == 0)
2602  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2603  break;
2604  }
2605  case 'V':
2606  case 'v':
2607  {
2608  if (LocaleCompare(expression,"v") == 0)
2609  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2610  break;
2611  }
2612  case 'W':
2613  case 'w':
2614  {
2615  if (IsFxFunction(expression,"while",5) != MagickFalse)
2616  {
2617  size_t
2618  length;
2619 
2620  /*
2621  Parse while(condition test, expression).
2622  */
2623  length=CopyMagickString(subexpression,expression+6,
2624  MagickPathExtent-1);
2625  if (length != 0)
2626  subexpression[length-1]='\0';
2627  FxParseConditional(subexpression,',',p,q);
2628  for (alpha=0.0; ; )
2629  {
2630  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2631  exception);
2632  if (fabs(gamma) < MagickEpsilon)
2633  break;
2634  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,
2635  beta,exception);
2636  }
2637  FxReturn(alpha);
2638  }
2639  if (LocaleCompare(expression,"w") == 0)
2640  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2641  break;
2642  }
2643  case 'Y':
2644  case 'y':
2645  {
2646  if (LocaleCompare(expression,"y") == 0)
2647  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2648  break;
2649  }
2650  case 'Z':
2651  case 'z':
2652  {
2653  if (LocaleCompare(expression,"z") == 0)
2654  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2655  break;
2656  }
2657  default:
2658  break;
2659  }
2660  subexpression=DestroyString(subexpression);
2661  q=(char *) expression;
2662  alpha=InterpretSiPrefixValue(expression,&q);
2663  if (q == expression)
2664  alpha=FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception);
2665  FxReturn(alpha);
2666 }
2667 
2669  double *alpha,ExceptionInfo *exception)
2670 {
2672  status;
2673 
2674  status=FxEvaluateChannelExpression(fx_info,GrayPixelChannel,0,0,alpha,
2675  exception);
2676  return(status);
2677 }
2678 
2680  double *alpha,ExceptionInfo *exception)
2681 {
2682  FILE
2683  *file;
2684 
2686  status;
2687 
2688  file=fx_info->file;
2689  fx_info->file=(FILE *) NULL;
2690  status=FxEvaluateChannelExpression(fx_info,GrayPixelChannel,0,0,alpha,
2691  exception);
2692  fx_info->file=file;
2693  return(status);
2694 }
2695 
2697  const PixelChannel channel,const ssize_t x,const ssize_t y,
2698  double *alpha,ExceptionInfo *exception)
2699 {
2700  double
2701  beta;
2702 
2703  beta=0.0;
2704  *alpha=FxEvaluateSubexpression(fx_info,channel,x,y,fx_info->expression,0,
2705  &beta,exception);
2706  return(exception->severity == OptionError ? MagickFalse : MagickTrue);
2707 }
2708 
2709 /*
2710 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2711 % %
2712 % %
2713 % %
2714 % F x I m a g e %
2715 % %
2716 % %
2717 % %
2718 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2719 %
2720 % FxImage() applies a mathematical expression to the specified image.
2721 %
2722 % The format of the FxImage method is:
2723 %
2724 % Image *FxImage(const Image *image,const char *expression,
2725 % ExceptionInfo *exception)
2726 %
2727 % A description of each parameter follows:
2728 %
2729 % o image: the image.
2730 %
2731 % o expression: A mathematical expression.
2732 %
2733 % o exception: return any errors or warnings in this structure.
2734 %
2735 */
2736 
2737 static FxInfo **DestroyFxThreadSet(FxInfo **fx_info)
2738 {
2739  ssize_t
2740  i;
2741 
2742  assert(fx_info != (FxInfo **) NULL);
2743  for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
2744  if (fx_info[i] != (FxInfo *) NULL)
2745  fx_info[i]=DestroyFxInfo(fx_info[i]);
2746  fx_info=(FxInfo **) RelinquishMagickMemory(fx_info);
2747  return(fx_info);
2748 }
2749 
2750 static FxInfo **AcquireFxThreadSet(const Image *image,const char *expression,
2751  ExceptionInfo *exception)
2752 {
2753  char
2754  *fx_expression;
2755 
2756  double
2757  alpha;
2758 
2759  FxInfo
2760  **fx_info;
2761 
2762  ssize_t
2763  i;
2764 
2765  size_t
2766  number_threads;
2767 
2768  number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
2769  fx_info=(FxInfo **) AcquireQuantumMemory(number_threads,sizeof(*fx_info));
2770  if (fx_info == (FxInfo **) NULL)
2771  {
2772  (void) ThrowMagickException(exception,GetMagickModule(),
2773  ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
2774  return((FxInfo **) NULL);
2775  }
2776  (void) memset(fx_info,0,number_threads*sizeof(*fx_info));
2777  if (*expression != '@')
2778  fx_expression=ConstantString(expression);
2779  else
2780  fx_expression=FileToString(expression+1,~0UL,exception);
2781  for (i=0; i < (ssize_t) number_threads; i++)
2782  {
2784  status;
2785 
2786  fx_info[i]=AcquireFxInfo(image,fx_expression,exception);
2787  if (fx_info[i] == (FxInfo *) NULL)
2788  break;
2789  status=FxPreprocessExpression(fx_info[i],&alpha,exception);
2790  if (status == MagickFalse)
2791  break;
2792  }
2793  fx_expression=DestroyString(fx_expression);
2794  if (i < (ssize_t) number_threads)
2795  fx_info=DestroyFxThreadSet(fx_info);
2796  return(fx_info);
2797 }
2798 
2799 MagickExport Image *FxImage(const Image *image,const char *expression,
2800  ExceptionInfo *exception)
2801 {
2802 #define FxImageTag "Fx/Image"
2803 
2804  CacheView
2805  *fx_view,
2806  *image_view;
2807 
2808  FxInfo
2809  **magick_restrict fx_info;
2810 
2811  Image
2812  *fx_image;
2813 
2815  status;
2816 
2818  progress;
2819 
2820  ssize_t
2821  y;
2822 
2823  assert(image != (Image *) NULL);
2824  assert(image->signature == MagickCoreSignature);
2825  if (image->debug != MagickFalse)
2826  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2827  if (expression == (const char *) NULL)
2828  return(CloneImage(image,0,0,MagickTrue,exception));
2829  fx_info=AcquireFxThreadSet(image,expression,exception);
2830  if (fx_info == (FxInfo **) NULL)
2831  return((Image *) NULL);
2832  fx_image=CloneImage(image,0,0,MagickTrue,exception);
2833  if (fx_image == (Image *) NULL)
2834  {
2835  fx_info=DestroyFxThreadSet(fx_info);
2836  return((Image *) NULL);
2837  }
2838  if (SetImageStorageClass(fx_image,DirectClass,exception) == MagickFalse)
2839  {
2840  fx_info=DestroyFxThreadSet(fx_info);
2841  fx_image=DestroyImage(fx_image);
2842  return((Image *) NULL);
2843  }
2844  /*
2845  Fx image.
2846  */
2847  status=MagickTrue;
2848  progress=0;
2849  image_view=AcquireVirtualCacheView(image,exception);
2850  fx_view=AcquireAuthenticCacheView(fx_image,exception);
2851 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2852  #pragma omp parallel for schedule(dynamic) shared(progress,status) \
2853  magick_number_threads(image,fx_image,fx_image->rows, \
2854  GlobExpression(fx_info[0]->expression,"debug(",MagickTrue) == 0 ? 1 : 0)
2855 #endif
2856  for (y=0; y < (ssize_t) fx_image->rows; y++)
2857  {
2858  const int
2859  id = GetOpenMPThreadId();
2860 
2861  const Quantum
2862  *magick_restrict p;
2863 
2864  Quantum
2865  *magick_restrict q;
2866 
2867  ssize_t
2868  x;
2869 
2870  if (status == MagickFalse)
2871  continue;
2872  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2873  q=QueueCacheViewAuthenticPixels(fx_view,0,y,fx_image->columns,1,exception);
2874  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2875  {
2876  status=MagickFalse;
2877  continue;
2878  }
2879  for (x=0; x < (ssize_t) fx_image->columns; x++)
2880  {
2881  ssize_t
2882  i;
2883 
2884  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2885  {
2886  double
2887  alpha;
2888 
2889  PixelChannel channel = GetPixelChannelChannel(image,i);
2890  PixelTrait traits = GetPixelChannelTraits(image,channel);
2891  PixelTrait fx_traits=GetPixelChannelTraits(fx_image,channel);
2892  if ((traits == UndefinedPixelTrait) ||
2893  (fx_traits == UndefinedPixelTrait))
2894  continue;
2895  if ((fx_traits & CopyPixelTrait) != 0)
2896  {
2897  SetPixelChannel(fx_image,channel,p[i],q);
2898  continue;
2899  }
2900  alpha=0.0;
2901  (void) FxEvaluateChannelExpression(fx_info[id],channel,x,y,&alpha,
2902  exception);
2903  q[i]=ClampToQuantum(QuantumRange*alpha);
2904  }
2905  p+=GetPixelChannels(image);
2906  q+=GetPixelChannels(fx_image);
2907  }
2908  if (SyncCacheViewAuthenticPixels(fx_view,exception) == MagickFalse)
2909  status=MagickFalse;
2910  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2911  {
2913  proceed;
2914 
2915 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2916  #pragma omp atomic
2917 #endif
2918  progress++;
2919  proceed=SetImageProgress(image,FxImageTag,progress,image->rows);
2920  if (proceed == MagickFalse)
2921  status=MagickFalse;
2922  }
2923  }
2924  fx_view=DestroyCacheView(fx_view);
2925  image_view=DestroyCacheView(image_view);
2926  fx_info=DestroyFxThreadSet(fx_info);
2927  if (status == MagickFalse)
2928  fx_image=DestroyImage(fx_image);
2929  return(fx_image);
2930 }
double psi
Definition: geometry.h:107
size_t rows
Definition: image.h:172
#define magick_restrict
Definition: MagickCore.h:41
MagickExport double InterpretSiPrefixValue(const char *magick_restrict string, char **magick_restrict sentinal)
Definition: string.c:1297
MagickExport CacheView * DestroyCacheView(CacheView *cache_view)
Definition: cache-view.c:252
MagickExport void ConvertRGBToHSL(const double red, const double green, const double blue, double *hue, double *saturation, double *lightness)
Definition: gem.c:1105
static double FxEvaluateSubexpression(FxInfo *, const PixelChannel, const ssize_t, const ssize_t, const char *, const size_t, double *, ExceptionInfo *)
Definition: fx.c:1445
MagickExport MagickBooleanType AddValueToSplayTree(SplayTreeInfo *splay_tree, const void *key, const void *value)
Definition: splay-tree.c:154
MagickProgressMonitor progress_monitor
Definition: image.h:303
MagickPrivate FxInfo * DestroyFxInfo(FxInfo *fx_info)
Definition: fx.c:297
PixelTrait alpha_trait
Definition: pixel.h:181
MagickExport ssize_t ParseCommandOption(const CommandOption option, const MagickBooleanType list, const char *options)
Definition: option.c:3055
MagickExport Image * GetImageFromList(const Image *images, const ssize_t index)
Definition: list.c:620
#define ThrowFatalException(severity, tag)
PixelInterpolateMethod interpolate
Definition: image.h:255
static const double * GetFxSymbolValue(FxInfo *magick_restrict fx_info, const char *symbol)
Definition: fx.c:350
double rho
Definition: geometry.h:107
SplayTreeInfo * symbols
Definition: fx.c:141
static FxInfo ** DestroyFxThreadSet(FxInfo **fx_info)
Definition: fx.c:2737
MagickExport const char * GetImageArtifact(const Image *image, const char *artifact)
Definition: artifact.c:273
MagickRealType red
Definition: pixel.h:193
MagickExport size_t StripMagickString(char *message)
Definition: string.c:2518
static PixelTrait GetPixelChannelTraits(const Image *magick_restrict image, const PixelChannel channel)
#define MagickPI
Definition: image-private.h:40
MagickExport ExceptionInfo * AcquireExceptionInfo(void)
Definition: exception.c:115
MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image, const CacheView_ *image_view, const PixelInterpolateMethod method, const double x, const double y, PixelInfo *pixel, ExceptionInfo *exception)
Definition: pixel.c:5474
MagickExport ssize_t FormatLocaleString(char *magick_restrict string, const size_t length, const char *magick_restrict format,...)
Definition: locale.c:463
static void SetPixelViaPixelInfo(const Image *magick_restrict image, const PixelInfo *magick_restrict pixel_info, Quantum *magick_restrict pixel)
MagickExport size_t CopyMagickString(char *magick_restrict destination, const char *magick_restrict source, const size_t length)
Definition: string.c:731
MagickExport const Quantum * GetCacheViewVirtualPixels(const CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:651
MagickRealType alpha
Definition: pixel.h:193
#define MagickEpsilon
Definition: magick-type.h:114
double sigma
Definition: geometry.h:107
size_t width
Definition: geometry.h:131
#define FxImageTag
Definition: log.h:52
MagickExport char * FileToString(const char *filename, const size_t extent, ExceptionInfo *exception)
Definition: string.c:965
ssize_t MagickOffsetType
Definition: magick-type.h:133
static Quantum ClampToQuantum(const MagickRealType quantum)
Definition: quantum.h:85
MagickExport void GetPixelInfo(const Image *image, PixelInfo *pixel)
Definition: pixel.c:2170
Definition: image.h:151
MagickExport RandomInfo * DestroyRandomInfo(RandomInfo *random_info)
Definition: random.c:274
MagickPrivate MagickBooleanType FxEvaluateChannelExpression(FxInfo *fx_info, const PixelChannel channel, const ssize_t x, const ssize_t y, double *alpha, ExceptionInfo *exception)
Definition: fx.c:2696
double x
Definition: geometry.h:124
#define MagickCoreSignature
#define FxReturn(value)
MagickExport Image * GetFirstImageInList(const Image *images)
Definition: list.c:576
MagickExport ssize_t FormatLocaleFile(FILE *file, const char *magick_restrict format,...)
Definition: locale.c:368
MagickBooleanType
Definition: magick-type.h:165
ExceptionInfo * exception
Definition: fx.c:151
unsigned int MagickStatusType
Definition: magick-type.h:125
MagickExport char * AcquireString(const char *source)
Definition: string.c:94
static double PerceptibleReciprocal(const double x)
MagickExport void * AcquireCriticalMemory(const size_t size)
Definition: memory.c:626
MagickExport void * AcquireQuantumMemory(const size_t count, const size_t quantum)
Definition: memory.c:665
MagickExport int LocaleNCompare(const char *p, const char *q, const size_t length)
Definition: locale.c:1523
double y
Definition: geometry.h:124
static int GetOpenMPThreadId(void)
static const char * FxOperatorPrecedence(const char *expression, ExceptionInfo *exception)
Definition: fx.c:1172
#define MagickPHI
Definition: image-private.h:38
static double FxGetSymbol(FxInfo *fx_info, const PixelChannel channel, const ssize_t x, const ssize_t y, const char *expression, const size_t depth, ExceptionInfo *exception)
Definition: fx.c:560
RectangleInfo page
Definition: image.h:212
RandomInfo * random_info
Definition: fx.c:148
CacheView ** view
Definition: fx.c:145
MagickExport SplayTreeInfo * DestroySplayTree(SplayTreeInfo *splay_tree)
Definition: splay-tree.c:682
#define MagickPathExtent
static FxInfo ** AcquireFxThreadSet(const Image *image, const char *expression, ExceptionInfo *exception)
Definition: fx.c:2750
MagickExport int GetMagickPrecision(void)
Definition: magick.c:942
MagickRealType blue
Definition: pixel.h:193
MagickExport ChannelType SetPixelChannelMask(Image *image, const ChannelType channel_mask)
Definition: pixel.c:6269
MagickExport SplayTreeInfo * NewSplayTree(int(*compare)(const void *, const void *), void *(*relinquish_key)(void *), void *(*relinquish_value)(void *))
Definition: splay-tree.c:1141
MagickExport MagickBooleanType FxPreprocessExpression(FxInfo *fx_info, double *alpha, ExceptionInfo *exception)
Definition: fx.c:2679
const Image * images
Definition: fx.c:132
MagickExport Quantum * QueueCacheViewAuthenticPixels(CacheView *cache_view, const ssize_t x, const ssize_t y, const size_t columns, const size_t rows, ExceptionInfo *exception)
Definition: cache-view.c:977
#define FxMaxSubexpressionDepth
MagickExport MagickBooleanType ThrowMagickException(ExceptionInfo *exception, const char *module, const char *function, const size_t line, const ExceptionType severity, const char *tag, const char *format,...)
Definition: exception.c:1145
MagickExport MagickBooleanType LogMagickEvent(const LogEventType type, const char *module, const char *function, const size_t line, const char *format,...)
Definition: log.c:1660
Definition: fx.c:129
size_t signature
Definition: image.h:354
MagickExport RandomInfo * AcquireRandomInfo(void)
Definition: random.c:163
MagickExport MagickSizeType GetMagickResourceLimit(const ResourceType type)
Definition: resource.c:793
size_t columns
Definition: image.h:172
#define QuantumScale
Definition: magick-type.h:119
MagickExport MagickBooleanType SubstituteString(char **string, const char *search, const char *replace)
Definition: string.c:2583
MagickBooleanType(* MagickProgressMonitor)(const char *, const MagickOffsetType, const MagickSizeType, void *)
Definition: monitor.h:26
ssize_t x
Definition: geometry.h:135
struct _Image * next
Definition: image.h:348
size_t height
Definition: geometry.h:131
FILE * file
Definition: fx.c:138
MagickExport MagickBooleanType GetImageRange(const Image *image, double *minima, double *maxima, ExceptionInfo *exception)
Definition: statistic.c:1865
MagickExport MagickBooleanType QueryColorCompliance(const char *name, const ComplianceType compliance, PixelInfo *color, ExceptionInfo *exception)
Definition: color.c:2265
ChannelType
Definition: pixel.h:33
MagickExport MagickBooleanType SetImageStorageClass(Image *image, const ClassType storage_class, ExceptionInfo *exception)
Definition: image.c:2614
MagickPrivate MagickBooleanType FxEvaluateExpression(FxInfo *fx_info, double *alpha, ExceptionInfo *exception)
Definition: fx.c:2668
MagickExport MagickBooleanType GetImageKurtosis(const Image *image, double *kurtosis, double *skewness, ExceptionInfo *exception)
Definition: statistic.c:1291
MagickExport const void * GetValueFromSplayTree(SplayTreeInfo *splay_tree, const void *key)
Definition: splay-tree.c:921
static double FxGCD(const double alpha, const double beta)
Definition: fx.c:524
PixelChannel
Definition: pixel.h:70
MagickExport MagickBooleanType GetImageMean(const Image *image, double *mean, double *standard_deviation, ExceptionInfo *exception)
Definition: statistic.c:1341
size_t quality
Definition: image.h:163
MagickExport PixelInfo * ClonePixelInfo(const PixelInfo *pixel)
Definition: pixel.c:170
static size_t GetPixelChannels(const Image *magick_restrict image)
static double FxChannelStatistics(FxInfo *fx_info, Image *image, PixelChannel channel, const char *symbol, ExceptionInfo *exception)
Definition: fx.c:381
MagickExport int LocaleCompare(const char *p, const char *q)
Definition: locale.c:1399
#define IsNaN(a)
Definition: magick-type.h:188
char filename[MagickPathExtent]
Definition: image.h:319
#define GetMagickModule()
Definition: log.h:28
double chi
Definition: geometry.h:107
MagickExport int CompareSplayTreeString(const void *target, const void *source)
Definition: splay-tree.c:412
static PixelChannel GetPixelChannelChannel(const Image *magick_restrict image, const ssize_t offset)
MagickExport CacheView * AcquireVirtualCacheView(const Image *image, ExceptionInfo *exception)
Definition: cache-view.c:149
FxOperator
Definition: fx.c:104
MagickExport void ClearMagickException(ExceptionInfo *exception)
Definition: exception.c:164
MagickExport MagickSizeType GetBlobSize(const Image *image)
Definition: blob.c:1844
#define FxMaxParenthesisDepth
MagickExport size_t GetImageDepth(const Image *image, ExceptionInfo *exception)
Definition: attribute.c:887
unsigned short Quantum
Definition: magick-type.h:86
double xi
Definition: geometry.h:107
MagickExport ssize_t GetImageIndexInList(const Image *images)
Definition: list.c:672
MagickRealType black
Definition: pixel.h:193
char * expression
Definition: fx.c:135
MagickExport char * DestroyString(char *string)
Definition: string.c:788
MagickExport void * AcquireMagickMemory(const size_t size)
Definition: memory.c:552
#define FxParseConditional(subexpression, sentinal, p, q)
MagickExport double GetPseudoRandomValue(RandomInfo *magick_restrict random_info)
Definition: random.c:584
MagickExport MagickStatusType ParseGeometry(const char *geometry, GeometryInfo *geometry_info)
Definition: geometry.c:860
static void SetPixelChannel(const Image *magick_restrict image, const PixelChannel channel, const Quantum quantum, Quantum *magick_restrict pixel)
static const char * FxSubexpression(const char *expression, ExceptionInfo *exception)
Definition: fx.c:533
static double StringToDouble(const char *magick_restrict string, char *magick_restrict *sentinal)
MagickExport void * RelinquishMagickMemory(void *memory)
Definition: memory.c:1162
#define MaxPixelChannels
Definition: pixel.h:27
PointInfo resolution
Definition: image.h:209
MagickPrivate FxInfo * AcquireFxInfo(const Image *images, const char *expression, ExceptionInfo *exception)
Definition: fx.c:181
MagickRealType green
Definition: pixel.h:193
#define MagickPrivate
#define MagickExport
MagickSizeType extent
Definition: image.h:270
MagickExport MagickBooleanType SyncCacheViewAuthenticPixels(CacheView *magick_restrict cache_view, ExceptionInfo *exception)
Definition: cache-view.c:1100
ssize_t y
Definition: geometry.h:135
MagickExport CacheView * AcquireAuthenticCacheView(const Image *image, ExceptionInfo *exception)
Definition: cache-view.c:112
MagickExport MagickBooleanType GetImageMedian(const Image *image, double *median, ExceptionInfo *exception)
Definition: statistic.c:1389
static MagickBooleanType SetFxSymbolValue(FxInfo *magick_restrict fx_info, const char *magick_restrict symbol, double const value)
Definition: fx.c:356
PixelTrait
Definition: pixel.h:137
MagickExport MagickRealType GetPixelIntensity(const Image *magick_restrict image, const Quantum *magick_restrict pixel)
Definition: pixel.c:2358
MagickExport size_t GetImageListLength(const Image *images)
Definition: list.c:711
SplayTreeInfo * colors
Definition: fx.c:141
MagickExport Image * DestroyImage(Image *image)
Definition: image.c:1177
MagickExport char * ConstantString(const char *source)
Definition: string.c:678
MagickExport Image * CloneImage(const Image *image, const size_t columns, const size_t rows, const MagickBooleanType detach, ExceptionInfo *exception)
Definition: image.c:788
static MagickBooleanType IsFxFunction(const char *expression, const char *name, const size_t length)
Definition: fx.c:505
ColorspaceType colorspace
Definition: image.h:157
MagickExport Image * FxImage(const Image *image, const char *expression, ExceptionInfo *exception)
Definition: fx.c:2799
#define QuantumRange
Definition: magick-type.h:87
MagickExport MagickBooleanType SetImageProgress(const Image *image, const char *tag, const MagickOffsetType offset, const MagickSizeType extent)
Definition: monitor.c:136
MagickBooleanType debug
Definition: image.h:334
MagickExport ExceptionInfo * DestroyExceptionInfo(ExceptionInfo *exception)
Definition: exception.c:418
ExceptionType severity
Definition: exception.h:104