MagickCore  7.0.10
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  {
760  status;
761 
762  status=QueryColorCompliance(name,AllCompliance,&pixel,
763  fx_info->exception);
764  if (status != MagickFalse)
765  {
766  (void) AddValueToSplayTree(fx_info->colors,
767  ConstantString(name),ClonePixelInfo(&pixel));
768  p+=length;
769  }
770  }
771  }
772  }
773  (void) CopyMagickString(symbol,p,MagickPathExtent);
774  StripString(symbol);
775  if (*symbol == '\0')
776  {
777  switch (channel)
778  {
779  case RedPixelChannel: return(QuantumScale*pixel.red);
780  case GreenPixelChannel: return(QuantumScale*pixel.green);
781  case BluePixelChannel: return(QuantumScale*pixel.blue);
782  case BlackPixelChannel:
783  {
784  if (image->colorspace != CMYKColorspace)
785  {
786  (void) ThrowMagickException(exception,GetMagickModule(),
787  ImageError,"ColorSeparatedImageRequired","`%s'",
788  image->filename);
789  return(0.0);
790  }
791  return(QuantumScale*pixel.black);
792  }
793  case AlphaPixelChannel:
794  {
795  if (pixel.alpha_trait == UndefinedPixelTrait)
796  return(1.0);
797  alpha=(double) (QuantumScale*pixel.alpha);
798  return(alpha);
799  }
801  {
802  Quantum
803  quantum_pixel[MaxPixelChannels];
804 
805  SetPixelViaPixelInfo(image,&pixel,quantum_pixel);
806  return(QuantumScale*GetPixelIntensity(image,quantum_pixel));
807  }
808  case IndexPixelChannel:
809  return(0.0);
810  default:
811  break;
812  }
814  "UnableToParseExpression","`%s'",p);
815  return(0.0);
816  }
817  switch (*symbol)
818  {
819  case 'A':
820  case 'a':
821  {
822  if (LocaleCompare(symbol,"a") == 0)
823  return((QuantumScale*pixel.alpha));
824  break;
825  }
826  case 'B':
827  case 'b':
828  {
829  if (LocaleCompare(symbol,"b") == 0)
830  return(QuantumScale*pixel.blue);
831  break;
832  }
833  case 'C':
834  case 'c':
835  {
836  if (IsFxFunction(symbol,"channel",7) != MagickFalse)
837  {
839  channel_info;
840 
842  flags;
843 
844  flags=ParseGeometry(symbol+7,&channel_info);
845  if (image->colorspace == CMYKColorspace)
846  switch (channel)
847  {
848  case CyanPixelChannel:
849  {
850  if ((flags & RhoValue) == 0)
851  return(0.0);
852  return(channel_info.rho);
853  }
854  case MagentaPixelChannel:
855  {
856  if ((flags & SigmaValue) == 0)
857  return(0.0);
858  return(channel_info.sigma);
859  }
860  case YellowPixelChannel:
861  {
862  if ((flags & XiValue) == 0)
863  return(0.0);
864  return(channel_info.xi);
865  }
866  case BlackPixelChannel:
867  {
868  if ((flags & PsiValue) == 0)
869  return(0.0);
870  return(channel_info.psi);
871  }
872  case AlphaPixelChannel:
873  {
874  if ((flags & ChiValue) == 0)
875  return(0.0);
876  return(channel_info.chi);
877  }
878  default:
879  return(0.0);
880  }
881  switch (channel)
882  {
883  case RedPixelChannel:
884  {
885  if ((flags & RhoValue) == 0)
886  return(0.0);
887  return(channel_info.rho);
888  }
889  case GreenPixelChannel:
890  {
891  if ((flags & SigmaValue) == 0)
892  return(0.0);
893  return(channel_info.sigma);
894  }
895  case BluePixelChannel:
896  {
897  if ((flags & XiValue) == 0)
898  return(0.0);
899  return(channel_info.xi);
900  }
901  case BlackPixelChannel:
902  {
903  if ((flags & ChiValue) == 0)
904  return(0.0);
905  return(channel_info.chi);
906  }
907  case AlphaPixelChannel:
908  {
909  if ((flags & PsiValue) == 0)
910  return(0.0);
911  return(channel_info.psi);
912  }
913  default:
914  return(0.0);
915  }
916  }
917  if (LocaleCompare(symbol,"c") == 0)
918  return(QuantumScale*pixel.red);
919  break;
920  }
921  case 'D':
922  case 'd':
923  {
924  if (LocaleNCompare(symbol,"depth",5) == 0)
925  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
926  break;
927  }
928  case 'E':
929  case 'e':
930  {
931  if (LocaleCompare(symbol,"extent") == 0)
932  {
933  if (image->extent != 0)
934  return((double) image->extent);
935  return((double) GetBlobSize(image));
936  }
937  break;
938  }
939  case 'G':
940  case 'g':
941  {
942  if (LocaleCompare(symbol,"g") == 0)
943  return(QuantumScale*pixel.green);
944  break;
945  }
946  case 'K':
947  case 'k':
948  {
949  if (LocaleNCompare(symbol,"kurtosis",8) == 0)
950  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
951  if (LocaleCompare(symbol,"k") == 0)
952  {
953  if (image->colorspace != CMYKColorspace)
954  {
955  (void) ThrowMagickException(exception,GetMagickModule(),
956  OptionError,"ColorSeparatedImageRequired","`%s'",
957  image->filename);
958  return(0.0);
959  }
960  return(QuantumScale*pixel.black);
961  }
962  break;
963  }
964  case 'H':
965  case 'h':
966  {
967  if (LocaleCompare(symbol,"h") == 0)
968  return((double) image->rows);
969  if (LocaleCompare(symbol,"hue") == 0)
970  {
971  double
972  hue,
973  lightness,
974  saturation;
975 
976  ConvertRGBToHSL(pixel.red,pixel.green,pixel.blue,&hue,&saturation,
977  &lightness);
978  return(hue);
979  }
980  break;
981  }
982  case 'I':
983  case 'i':
984  {
985  if ((LocaleCompare(symbol,"image.depth") == 0) ||
986  (LocaleCompare(symbol,"image.minima") == 0) ||
987  (LocaleCompare(symbol,"image.maxima") == 0) ||
988  (LocaleCompare(symbol,"image.mean") == 0) ||
989  (LocaleCompare(symbol,"image.kurtosis") == 0) ||
990  (LocaleCompare(symbol,"image.skewness") == 0) ||
991  (LocaleCompare(symbol,"image.standard_deviation") == 0))
992  return(FxChannelStatistics(fx_info,image,channel,symbol+6,exception));
993  if (LocaleCompare(symbol,"image.resolution.x") == 0)
994  return(image->resolution.x);
995  if (LocaleCompare(symbol,"image.resolution.y") == 0)
996  return(image->resolution.y);
997  if (LocaleCompare(symbol,"intensity") == 0)
998  {
999  Quantum
1000  quantum_pixel[MaxPixelChannels];
1001 
1002  SetPixelViaPixelInfo(image,&pixel,quantum_pixel);
1003  return(QuantumScale*GetPixelIntensity(image,quantum_pixel));
1004  }
1005  if (LocaleCompare(symbol,"i") == 0)
1006  return((double) x);
1007  break;
1008  }
1009  case 'J':
1010  case 'j':
1011  {
1012  if (LocaleCompare(symbol,"j") == 0)
1013  return((double) y);
1014  break;
1015  }
1016  case 'L':
1017  case 'l':
1018  {
1019  if (LocaleCompare(symbol,"lightness") == 0)
1020  {
1021  double
1022  hue,
1023  lightness,
1024  saturation;
1025 
1026  ConvertRGBToHSL(pixel.red,pixel.green,pixel.blue,&hue,&saturation,
1027  &lightness);
1028  return(lightness);
1029  }
1030  if (LocaleCompare(symbol,"luma") == 0)
1031  {
1032  double
1033  luma;
1034 
1035  luma=0.212656*pixel.red+0.715158*pixel.green+0.072186*pixel.blue;
1036  return(QuantumScale*luma);
1037  }
1038  if (LocaleCompare(symbol,"luminance") == 0)
1039  {
1040  double
1041  luminence;
1042 
1043  luminence=0.212656*pixel.red+0.715158*pixel.green+0.072186*pixel.blue;
1044  return(QuantumScale*luminence);
1045  }
1046  break;
1047  }
1048  case 'M':
1049  case 'm':
1050  {
1051  if (LocaleNCompare(symbol,"maxima",6) == 0)
1052  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1053  if (LocaleNCompare(symbol,"mean",4) == 0)
1054  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1055  if (LocaleNCompare(symbol,"median",6) == 0)
1056  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1057  if (LocaleNCompare(symbol,"minima",6) == 0)
1058  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1059  if (LocaleCompare(symbol,"m") == 0)
1060  return(QuantumScale*pixel.green);
1061  break;
1062  }
1063  case 'N':
1064  case 'n':
1065  {
1066  if (LocaleCompare(symbol,"n") == 0)
1067  return((double) GetImageListLength(fx_info->images));
1068  break;
1069  }
1070  case 'O':
1071  case 'o':
1072  {
1073  if (LocaleCompare(symbol,"o") == 0)
1074  return(QuantumScale*pixel.alpha);
1075  break;
1076  }
1077  case 'P':
1078  case 'p':
1079  {
1080  if (LocaleCompare(symbol,"page.height") == 0)
1081  return((double) image->page.height);
1082  if (LocaleCompare(symbol,"page.width") == 0)
1083  return((double) image->page.width);
1084  if (LocaleCompare(symbol,"page.x") == 0)
1085  return((double) image->page.x);
1086  if (LocaleCompare(symbol,"page.y") == 0)
1087  return((double) image->page.y);
1088  if (LocaleCompare(symbol,"printsize.x") == 0)
1089  return(PerceptibleReciprocal(image->resolution.x)*image->columns);
1090  if (LocaleCompare(symbol,"printsize.y") == 0)
1091  return(PerceptibleReciprocal(image->resolution.y)*image->rows);
1092  break;
1093  }
1094  case 'Q':
1095  case 'q':
1096  {
1097  if (LocaleCompare(symbol,"quality") == 0)
1098  return((double) image->quality);
1099  break;
1100  }
1101  case 'R':
1102  case 'r':
1103  {
1104  if (LocaleCompare(symbol,"resolution.x") == 0)
1105  return(image->resolution.x);
1106  if (LocaleCompare(symbol,"resolution.y") == 0)
1107  return(image->resolution.y);
1108  if (LocaleCompare(symbol,"r") == 0)
1109  return(QuantumScale*pixel.red);
1110  break;
1111  }
1112  case 'S':
1113  case 's':
1114  {
1115  if (LocaleCompare(symbol,"saturation") == 0)
1116  {
1117  double
1118  hue,
1119  lightness,
1120  saturation;
1121 
1122  ConvertRGBToHSL(pixel.red,pixel.green,pixel.blue,&hue,&saturation,
1123  &lightness);
1124  return(saturation);
1125  }
1126  if (LocaleNCompare(symbol,"skewness",8) == 0)
1127  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1128  if (LocaleNCompare(symbol,"standard_deviation",18) == 0)
1129  return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1130  break;
1131  }
1132  case 'T':
1133  case 't':
1134  {
1135  if (LocaleCompare(symbol,"t") == 0)
1136  return((double) GetImageIndexInList(fx_info->images));
1137  break;
1138  }
1139  case 'W':
1140  case 'w':
1141  {
1142  if (LocaleCompare(symbol,"w") == 0)
1143  return((double) image->columns);
1144  break;
1145  }
1146  case 'Y':
1147  case 'y':
1148  {
1149  if (LocaleCompare(symbol,"y") == 0)
1150  return(QuantumScale*pixel.blue);
1151  break;
1152  }
1153  case 'Z':
1154  case 'z':
1155  {
1156  if (LocaleCompare(symbol,"z") == 0)
1157  return((double) GetImageDepth(image,fx_info->exception));
1158  break;
1159  }
1160  default:
1161  break;
1162  }
1163  value=GetFxSymbolValue(fx_info,symbol);
1164  if (value != (const double *) NULL)
1165  return(*value);
1166  artifact=GetImageArtifact(image,symbol);
1167  if (artifact != (const char *) NULL)
1168  return(StringToDouble(artifact,(char **) NULL));
1170  "UndefinedVariable","`%s'",symbol);
1171  (void) SetFxSymbolValue(fx_info,symbol,0.0);
1172  return(0.0);
1173 }
1174 
1175 static const char *FxOperatorPrecedence(const char *expression,
1176  ExceptionInfo *exception)
1177 {
1178  typedef enum
1179  {
1180  UndefinedPrecedence,
1181  NullPrecedence,
1182  BitwiseComplementPrecedence,
1183  ExponentPrecedence,
1184  ExponentialNotationPrecedence,
1185  MultiplyPrecedence,
1186  AdditionPrecedence,
1187  ShiftPrecedence,
1188  RelationalPrecedence,
1189  EquivalencyPrecedence,
1190  BitwiseAndPrecedence,
1191  BitwiseOrPrecedence,
1192  LogicalAndPrecedence,
1193  LogicalOrPrecedence,
1194  TernaryPrecedence,
1195  AssignmentPrecedence,
1196  CommaPrecedence,
1197  SeparatorPrecedence
1198  } FxPrecedence;
1199 
1200  FxPrecedence
1201  precedence,
1202  target;
1203 
1204  const char
1205  *subexpression;
1206 
1207  int
1208  c;
1209 
1210  size_t
1211  level;
1212 
1213  c=(-1);
1214  level=0;
1215  subexpression=(const char *) NULL;
1216  target=NullPrecedence;
1217  while ((c != '\0') && (*expression != '\0'))
1218  {
1219  precedence=UndefinedPrecedence;
1220  if ((isspace((int) ((unsigned char) *expression)) != 0) || (c == (int) '@'))
1221  {
1222  expression++;
1223  continue;
1224  }
1225  switch (*expression)
1226  {
1227  case 'A':
1228  case 'a':
1229  {
1230 #if defined(MAGICKCORE_HAVE_ACOSH)
1231  if (IsFxFunction(expression,"acosh",5) != MagickFalse)
1232  {
1233  expression+=5;
1234  break;
1235  }
1236 #endif
1237 #if defined(MAGICKCORE_HAVE_ASINH)
1238  if (IsFxFunction(expression,"asinh",5) != MagickFalse)
1239  {
1240  expression+=5;
1241  break;
1242  }
1243 #endif
1244 #if defined(MAGICKCORE_HAVE_ATANH)
1245  if (IsFxFunction(expression,"atanh",5) != MagickFalse)
1246  {
1247  expression+=5;
1248  break;
1249  }
1250 #endif
1251  if (IsFxFunction(expression,"atan2",5) != MagickFalse)
1252  {
1253  expression+=5;
1254  break;
1255  }
1256  break;
1257  }
1258  case 'E':
1259  case 'e':
1260  {
1261  if ((isdigit((int) ((unsigned char) c)) != 0) &&
1262  ((LocaleNCompare(expression,"E+",2) == 0) ||
1263  (LocaleNCompare(expression,"E-",2) == 0)))
1264  {
1265  expression+=2; /* scientific notation */
1266  break;
1267  }
1268  }
1269  case 'J':
1270  case 'j':
1271  {
1272  if ((IsFxFunction(expression,"j0",2) != MagickFalse) ||
1273  (IsFxFunction(expression,"j1",2) != MagickFalse))
1274  {
1275  expression+=2;
1276  break;
1277  }
1278  break;
1279  }
1280  case '#':
1281  {
1282  while (isxdigit((int) ((unsigned char) *(expression+1))) != 0)
1283  expression++;
1284  break;
1285  }
1286  default:
1287  break;
1288  }
1289  if ((c == (int) '{') || (c == (int) '['))
1290  level++;
1291  else
1292  if ((c == (int) '}') || (c == (int) ']'))
1293  level--;
1294  if (level == 0)
1295  switch ((unsigned char) *expression)
1296  {
1297  case '~':
1298  case '!':
1299  {
1300  precedence=BitwiseComplementPrecedence;
1301  break;
1302  }
1303  case '^':
1304  case '@':
1305  {
1306  precedence=ExponentPrecedence;
1307  break;
1308  }
1309  default:
1310  {
1311  if (((c != 0) && ((isdigit((int) ((unsigned char) c)) != 0) ||
1312  (strchr(")",c) != (char *) NULL))) &&
1313  (((islower((int) ((unsigned char) *expression)) != 0) ||
1314  (strchr("(",(int) ((unsigned char) *expression)) != (char *) NULL)) ||
1315  ((isdigit((int) ((unsigned char) c)) == 0) &&
1316  (isdigit((int) ((unsigned char) *expression)) != 0))) &&
1317  (strchr("xy",(int) ((unsigned char) *expression)) == (char *) NULL))
1318  precedence=MultiplyPrecedence;
1319  break;
1320  }
1321  case '*':
1322  case '/':
1323  case '%':
1324  {
1325  precedence=MultiplyPrecedence;
1326  break;
1327  }
1328  case '+':
1329  case '-':
1330  {
1331  if ((strchr("(+-/*%:&^|<>~,",c) == (char *) NULL) ||
1332  (isalpha((int) ((unsigned char) c)) != 0))
1333  precedence=AdditionPrecedence;
1334  break;
1335  }
1348  {
1349  precedence=AssignmentPrecedence;
1350  break;
1351  }
1352  case LeftShiftOperator:
1353  case RightShiftOperator:
1354  {
1355  precedence=ShiftPrecedence;
1356  break;
1357  }
1358  case '<':
1359  case LessThanEqualOperator:
1361  case '>':
1362  {
1363  precedence=RelationalPrecedence;
1364  break;
1365  }
1366  case EqualOperator:
1367  case NotEqualOperator:
1368  {
1369  precedence=EquivalencyPrecedence;
1370  break;
1371  }
1372  case '&':
1373  {
1374  precedence=BitwiseAndPrecedence;
1375  break;
1376  }
1377  case '|':
1378  {
1379  precedence=BitwiseOrPrecedence;
1380  break;
1381  }
1382  case LogicalAndOperator:
1383  {
1384  precedence=LogicalAndPrecedence;
1385  break;
1386  }
1387  case LogicalOrOperator:
1388  {
1389  precedence=LogicalOrPrecedence;
1390  break;
1391  }
1392  case ExponentialNotation:
1393  {
1394  precedence=ExponentialNotationPrecedence;
1395  break;
1396  }
1397  case ':':
1398  case '?':
1399  {
1400  precedence=TernaryPrecedence;
1401  break;
1402  }
1403  case '=':
1404  {
1405  precedence=AssignmentPrecedence;
1406  break;
1407  }
1408  case ',':
1409  {
1410  precedence=CommaPrecedence;
1411  break;
1412  }
1413  case ';':
1414  {
1415  precedence=SeparatorPrecedence;
1416  break;
1417  }
1418  }
1419  if ((precedence == BitwiseComplementPrecedence) ||
1420  (precedence == TernaryPrecedence) ||
1421  (precedence == AssignmentPrecedence))
1422  {
1423  if (precedence > target)
1424  {
1425  /*
1426  Right-to-left associativity.
1427  */
1428  target=precedence;
1429  subexpression=expression;
1430  }
1431  }
1432  else
1433  if (precedence >= target)
1434  {
1435  /*
1436  Left-to-right associativity.
1437  */
1438  target=precedence;
1439  subexpression=expression;
1440  }
1441  if (strchr("(",(int) *expression) != (char *) NULL)
1442  expression=FxSubexpression(expression,exception);
1443  c=(int) (*expression++);
1444  }
1445  return(subexpression);
1446 }
1447 
1448 static double FxEvaluateSubexpression(FxInfo *fx_info,
1449  const PixelChannel channel,const ssize_t x,const ssize_t y,
1450  const char *expression,const size_t depth,double *beta,
1451  ExceptionInfo *exception)
1452 {
1453 #define FxMaxParenthesisDepth 58
1454 #define FxMaxSubexpressionDepth 200
1455 #define FxReturn(value) \
1456 { \
1457  subexpression=DestroyString(subexpression); \
1458  return(value); \
1459 }
1460 #define FxParseConditional(subexpression,sentinal,p,q) \
1461 { \
1462  p=subexpression; \
1463  for (q=(char *) p; (*q != (sentinal)) && (*q != '\0'); q++) \
1464  if (*q == '(') \
1465  { \
1466  for (q++; (*q != ')') && (*q != '\0'); q++); \
1467  if (*q == '\0') \
1468  break; \
1469  } \
1470  if (*q == '\0') \
1471  { \
1472  (void) ThrowMagickException(exception,GetMagickModule(), \
1473  OptionError,"UnableToParseExpression","`%s'",subexpression); \
1474  FxReturn(0.0); \
1475  } \
1476  if (strlen(q) == 1) \
1477  *(q+1)='\0'; \
1478  *q='\0'; \
1479 }
1480 
1481  char
1482  *q,
1483  *subexpression;
1484 
1485  double
1486  alpha,
1487  gamma,
1488  sans,
1489  value;
1490 
1491  const char
1492  *p;
1493 
1494  *beta=0.0;
1495  sans=0.0;
1496  subexpression=AcquireString(expression);
1497  *subexpression='\0';
1498  if (depth > FxMaxSubexpressionDepth)
1499  {
1501  "UnableToParseExpression","`%s'",expression);
1502  FxReturn(0.0);
1503  }
1504  if (exception->severity >= ErrorException)
1505  FxReturn(0.0);
1506  while (isspace((int) ((unsigned char) *expression)) != 0)
1507  expression++;
1508  if (*expression == '\0')
1509  FxReturn(0.0);
1510  p=FxOperatorPrecedence(expression,exception);
1511  if (p != (const char *) NULL)
1512  {
1513  (void) CopyMagickString(subexpression,expression,(size_t)
1514  (p-expression+1));
1515  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,depth+1,
1516  beta,exception);
1517  switch ((unsigned char) *p)
1518  {
1519  case '~':
1520  {
1521  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1522  exception);
1523  *beta=(double) (~(size_t) *beta);
1524  FxReturn(*beta);
1525  }
1526  case '!':
1527  {
1528  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1529  exception);
1530  FxReturn(*beta == 0.0 ? 1.0 : 0.0);
1531  }
1532  case '^':
1533  {
1534  *beta=pow(alpha,FxEvaluateSubexpression(fx_info,channel,x,y,++p,
1535  depth+1,beta,exception));
1536  FxReturn(*beta);
1537  }
1538  case '*':
1539  case ExponentialNotation:
1540  {
1541  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1542  exception);
1543  FxReturn(alpha*(*beta));
1544  }
1545  case '/':
1546  {
1547  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1548  exception);
1549  FxReturn(PerceptibleReciprocal(*beta)*alpha);
1550  }
1551  case '%':
1552  {
1553  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1554  exception);
1555  FxReturn(fmod(alpha,*beta));
1556  }
1557  case '+':
1558  {
1559  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1560  exception);
1561  FxReturn(alpha+(*beta));
1562  }
1563  case '-':
1564  {
1565  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1566  exception);
1567  FxReturn(alpha-(*beta));
1568  }
1570  {
1571  q=subexpression;
1572  while (isalpha((int) ((unsigned char) *q)) != 0)
1573  q++;
1574  if (*q != '\0')
1575  {
1576  (void) ThrowMagickException(exception,GetMagickModule(),
1577  OptionError,"UnableToParseExpression","`%s'",subexpression);
1578  FxReturn(0.0);
1579  }
1580  ClearMagickException(exception);
1581  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1582  exception);
1583  value=(double) ((size_t) (alpha+0.5) & (size_t) (*beta+0.5));
1584  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1585  return(0.0);
1586  FxReturn(*beta);
1587  }
1589  {
1590  q=subexpression;
1591  while (isalpha((int) ((unsigned char) *q)) != 0)
1592  q++;
1593  if (*q != '\0')
1594  {
1595  (void) ThrowMagickException(exception,GetMagickModule(),
1596  OptionError,"UnableToParseExpression","`%s'",subexpression);
1597  FxReturn(0.0);
1598  }
1599  ClearMagickException(exception);
1600  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1601  exception);
1602  value=(double) ((size_t) (alpha+0.5) | (size_t) (*beta+0.5));
1603  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1604  return(0.0);
1605  FxReturn(*beta);
1606  }
1608  {
1609  q=subexpression;
1610  while (isalpha((int) ((unsigned char) *q)) != 0)
1611  q++;
1612  if (*q != '\0')
1613  {
1614  (void) ThrowMagickException(exception,GetMagickModule(),
1615  OptionError,"UnableToParseExpression","`%s'",subexpression);
1616  FxReturn(0.0);
1617  }
1618  ClearMagickException(exception);
1619  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1620  exception);
1621  if ((size_t) (*beta+0.5) >= (8*sizeof(size_t)))
1622  {
1623  (void) ThrowMagickException(exception,GetMagickModule(),
1624  OptionError,"ShiftCountOverflow","`%s'",subexpression);
1625  FxReturn(0.0);
1626  }
1627  value=(double) ((size_t) (alpha+0.5) << (size_t) (*beta+0.5));
1628  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1629  return(0.0);
1630  FxReturn(*beta);
1631  }
1633  {
1634  q=subexpression;
1635  while (isalpha((int) ((unsigned char) *q)) != 0)
1636  q++;
1637  if (*q != '\0')
1638  {
1639  (void) ThrowMagickException(exception,GetMagickModule(),
1640  OptionError,"UnableToParseExpression","`%s'",subexpression);
1641  FxReturn(0.0);
1642  }
1643  ClearMagickException(exception);
1644  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1645  exception);
1646  if ((size_t) (*beta+0.5) >= (8*sizeof(size_t)))
1647  {
1648  (void) ThrowMagickException(exception,GetMagickModule(),
1649  OptionError,"ShiftCountOverflow","`%s'",subexpression);
1650  FxReturn(0.0);
1651  }
1652  value=(double) ((size_t) (alpha+0.5) >> (size_t) (*beta+0.5));
1653  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1654  return(0.0);
1655  FxReturn(*beta);
1656  }
1658  {
1659  q=subexpression;
1660  while (isalpha((int) ((unsigned char) *q)) != 0)
1661  q++;
1662  if (*q != '\0')
1663  {
1664  (void) ThrowMagickException(exception,GetMagickModule(),
1665  OptionError,"UnableToParseExpression","`%s'",subexpression);
1666  FxReturn(0.0);
1667  }
1668  ClearMagickException(exception);
1669  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1670  exception);
1671  value=pow(alpha,*beta);
1672  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1673  return(0.0);
1674  FxReturn(*beta);
1675  }
1677  {
1678  q=subexpression;
1679  while (isalpha((int) ((unsigned char) *q)) != 0)
1680  q++;
1681  if (*q != '\0')
1682  {
1683  (void) ThrowMagickException(exception,GetMagickModule(),
1684  OptionError,"UnableToParseExpression","`%s'",subexpression);
1685  FxReturn(0.0);
1686  }
1687  ClearMagickException(exception);
1688  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1689  exception);
1690  value=fmod(alpha,*beta);
1691  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1692  return(0.0);
1693  FxReturn(*beta);
1694  }
1696  {
1697  q=subexpression;
1698  while (isalpha((int) ((unsigned char) *q)) != 0)
1699  q++;
1700  if (*q != '\0')
1701  {
1702  (void) ThrowMagickException(exception,GetMagickModule(),
1703  OptionError,"UnableToParseExpression","`%s'",subexpression);
1704  FxReturn(0.0);
1705  }
1706  ClearMagickException(exception);
1707  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1708  exception);
1709  value=alpha+(*beta);
1710  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1711  return(0.0);
1712  FxReturn(*beta);
1713  }
1715  {
1716  q=subexpression;
1717  while (isalpha((int) ((unsigned char) *q)) != 0)
1718  q++;
1719  if (*q != '\0')
1720  {
1721  (void) ThrowMagickException(exception,GetMagickModule(),
1722  OptionError,"UnableToParseExpression","`%s'",subexpression);
1723  FxReturn(0.0);
1724  }
1725  ClearMagickException(exception);
1726  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1727  exception);
1728  value=alpha-(*beta);
1729  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1730  return(0.0);
1731  FxReturn(*beta);
1732  }
1734  {
1735  q=subexpression;
1736  while (isalpha((int) ((unsigned char) *q)) != 0)
1737  q++;
1738  if (*q != '\0')
1739  {
1740  (void) ThrowMagickException(exception,GetMagickModule(),
1741  OptionError,"UnableToParseExpression","`%s'",subexpression);
1742  FxReturn(0.0);
1743  }
1744  ClearMagickException(exception);
1745  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1746  exception);
1747  value=alpha*(*beta);
1748  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1749  return(0.0);
1750  FxReturn(*beta);
1751  }
1753  {
1754  q=subexpression;
1755  while (isalpha((int) ((unsigned char) *q)) != 0)
1756  q++;
1757  if (*q != '\0')
1758  {
1759  (void) ThrowMagickException(exception,GetMagickModule(),
1760  OptionError,"UnableToParseExpression","`%s'",subexpression);
1761  FxReturn(0.0);
1762  }
1763  ClearMagickException(exception);
1764  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1765  exception);
1766  value=alpha*PerceptibleReciprocal(*beta);
1767  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1768  return(0.0);
1769  FxReturn(*beta);
1770  }
1772  {
1773  if (*subexpression == '\0')
1774  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1775  exception);
1776  value=alpha+1.0;
1777  if (*subexpression == '\0')
1778  {
1779  if (SetFxSymbolValue(fx_info,p,value) == MagickFalse)
1780  return(0.0);
1781  }
1782  else
1783  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1784  return(0.0);
1785  FxReturn(*beta);
1786  }
1788  {
1789  if (*subexpression == '\0')
1790  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1791  exception);
1792  value=alpha-1.0;
1793  if (*subexpression == '\0')
1794  {
1795  if (SetFxSymbolValue(fx_info,p,value) == MagickFalse)
1796  return(0.0);
1797  }
1798  else
1799  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1800  return(0.0);
1801  FxReturn(*beta);
1802  }
1803  case LeftShiftOperator:
1804  {
1805  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1806  exception);
1807  if ((size_t) (gamma+0.5) >= (8*sizeof(size_t)))
1808  {
1809  (void) ThrowMagickException(exception,GetMagickModule(),
1810  OptionError,"ShiftCountOverflow","`%s'",subexpression);
1811  FxReturn(0.0);
1812  }
1813  *beta=(double) ((size_t) (alpha+0.5) << (size_t) (gamma+0.5));
1814  FxReturn(*beta);
1815  }
1816  case RightShiftOperator:
1817  {
1818  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1819  exception);
1820  if ((size_t) (gamma+0.5) >= (8*sizeof(size_t)))
1821  {
1822  (void) ThrowMagickException(exception,GetMagickModule(),
1823  OptionError,"ShiftCountOverflow","`%s'",subexpression);
1824  FxReturn(0.0);
1825  }
1826  *beta=(double) ((size_t) (alpha+0.5) >> (size_t) (gamma+0.5));
1827  FxReturn(*beta);
1828  }
1829  case '<':
1830  {
1831  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1832  exception);
1833  FxReturn(alpha < *beta ? 1.0 : 0.0);
1834  }
1835  case LessThanEqualOperator:
1836  {
1837  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1838  exception);
1839  FxReturn(alpha <= *beta ? 1.0 : 0.0);
1840  }
1841  case '>':
1842  {
1843  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1844  exception);
1845  FxReturn(alpha > *beta ? 1.0 : 0.0);
1846  }
1848  {
1849  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1850  exception);
1851  FxReturn(alpha >= *beta ? 1.0 : 0.0);
1852  }
1853  case EqualOperator:
1854  {
1855  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1856  exception);
1857  FxReturn(fabs(alpha-(*beta)) < MagickEpsilon ? 1.0 : 0.0);
1858  }
1859  case NotEqualOperator:
1860  {
1861  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1862  exception);
1863  FxReturn(fabs(alpha-(*beta)) >= MagickEpsilon ? 1.0 : 0.0);
1864  }
1865  case '&':
1866  {
1867  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1868  exception);
1869  *beta=(double) ((size_t) (alpha+0.5) & (size_t) (gamma+0.5));
1870  FxReturn(*beta);
1871  }
1872  case '|':
1873  {
1874  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1875  exception);
1876  *beta=(double) ((size_t) (alpha+0.5) | (size_t) (gamma+0.5));
1877  FxReturn(*beta);
1878  }
1879  case LogicalAndOperator:
1880  {
1881  p++;
1882  if (alpha <= 0.0)
1883  {
1884  *beta=0.0;
1885  FxReturn(*beta);
1886  }
1887  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1888  exception);
1889  *beta=(gamma > 0.0) ? 1.0 : 0.0;
1890  FxReturn(*beta);
1891  }
1892  case LogicalOrOperator:
1893  {
1894  p++;
1895  if (alpha > 0.0)
1896  {
1897  *beta=1.0;
1898  FxReturn(*beta);
1899  }
1900  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1901  exception);
1902  *beta=(gamma > 0.0) ? 1.0 : 0.0;
1903  FxReturn(*beta);
1904  }
1905  case '?':
1906  {
1907  (void) CopyMagickString(subexpression,++p,MagickPathExtent-1);
1908  FxParseConditional(subexpression,':',p,q);
1909  if (fabs(alpha) >= MagickEpsilon)
1910  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1911  exception);
1912  else
1913  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
1914  exception);
1915  FxReturn(gamma);
1916  }
1917  case '=':
1918  {
1919  q=subexpression;
1920  while (isalpha((int) ((unsigned char) *q)) != 0)
1921  q++;
1922  if (*q != '\0')
1923  {
1924  (void) ThrowMagickException(exception,GetMagickModule(),
1925  OptionError,"UnableToParseExpression","`%s'",subexpression);
1926  FxReturn(0.0);
1927  }
1928  ClearMagickException(exception);
1929  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1930  exception);
1931  value=(*beta);
1932  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1933  return(0.0);
1934  FxReturn(*beta);
1935  }
1936  case ',':
1937  {
1938  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1939  exception);
1940  FxReturn(alpha);
1941  }
1942  case ';':
1943  {
1944  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1945  exception);
1946  FxReturn(*beta);
1947  }
1948  default:
1949  {
1950  gamma=alpha*FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,
1951  beta,exception);
1952  FxReturn(gamma);
1953  }
1954  }
1955  }
1956  if (strchr("(",(int) *expression) != (char *) NULL)
1957  {
1958  size_t
1959  length;
1960 
1961  if (depth >= FxMaxParenthesisDepth)
1963  "ParenthesisNestedTooDeeply","`%s'",expression);
1964  length=CopyMagickString(subexpression,expression+1,MagickPathExtent);
1965  if (length != 0)
1966  subexpression[length-1]='\0';
1967  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,depth+1,
1968  beta,exception);
1969  FxReturn(gamma);
1970  }
1971  switch (*expression)
1972  {
1973  case '+':
1974  {
1975  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1976  beta,exception);
1977  FxReturn(1.0*gamma);
1978  }
1979  case '-':
1980  {
1981  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1982  beta,exception);
1983  FxReturn(-1.0*gamma);
1984  }
1985  case '~':
1986  {
1987  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1988  beta,exception);
1989  FxReturn((double) (~(size_t) (gamma+0.5)));
1990  }
1991  case 'A':
1992  case 'a':
1993  {
1994  if (IsFxFunction(expression,"abs",3) != MagickFalse)
1995  {
1996  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
1997  depth+1,beta,exception);
1998  FxReturn(fabs(alpha));
1999  }
2000 #if defined(MAGICKCORE_HAVE_ACOSH)
2001  if (IsFxFunction(expression,"acosh",5) != MagickFalse)
2002  {
2003  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2004  depth+1,beta,exception);
2005  FxReturn(acosh(alpha));
2006  }
2007 #endif
2008  if (IsFxFunction(expression,"acos",4) != MagickFalse)
2009  {
2010  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2011  depth+1,beta,exception);
2012  FxReturn(acos(alpha));
2013  }
2014 #if defined(MAGICKCORE_HAVE_J1)
2015  if (IsFxFunction(expression,"airy",4) != MagickFalse)
2016  {
2017  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2018  depth+1,beta,exception);
2019  if (alpha == 0.0)
2020  FxReturn(1.0);
2021  gamma=2.0*j1((MagickPI*alpha))/(MagickPI*alpha);
2022  FxReturn(gamma*gamma);
2023  }
2024 #endif
2025 #if defined(MAGICKCORE_HAVE_ASINH)
2026  if (IsFxFunction(expression,"asinh",5) != MagickFalse)
2027  {
2028  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2029  depth+1,beta,exception);
2030  FxReturn(asinh(alpha));
2031  }
2032 #endif
2033  if (IsFxFunction(expression,"asin",4) != MagickFalse)
2034  {
2035  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2036  depth+1,beta,exception);
2037  FxReturn(asin(alpha));
2038  }
2039  if (IsFxFunction(expression,"alt",3) != MagickFalse)
2040  {
2041  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2042  depth+1,beta,exception);
2043  FxReturn(((ssize_t) alpha) & 0x01 ? -1.0 : 1.0);
2044  }
2045  if (IsFxFunction(expression,"atan2",5) != MagickFalse)
2046  {
2047  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2048  depth+1,beta,exception);
2049  FxReturn(atan2(alpha,*beta));
2050  }
2051 #if defined(MAGICKCORE_HAVE_ATANH)
2052  if (IsFxFunction(expression,"atanh",5) != MagickFalse)
2053  {
2054  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2055  depth+1,beta,exception);
2056  FxReturn(atanh(alpha));
2057  }
2058 #endif
2059  if (IsFxFunction(expression,"atan",4) != MagickFalse)
2060  {
2061  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2062  depth+1,beta,exception);
2063  FxReturn(atan(alpha));
2064  }
2065  if (LocaleCompare(expression,"a") == 0)
2066  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2067  break;
2068  }
2069  case 'B':
2070  case 'b':
2071  {
2072  if (LocaleCompare(expression,"b") == 0)
2073  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2074  break;
2075  }
2076  case 'C':
2077  case 'c':
2078  {
2079  if (IsFxFunction(expression,"ceil",4) != MagickFalse)
2080  {
2081  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2082  depth+1,beta,exception);
2083  FxReturn(ceil(alpha));
2084  }
2085  if (IsFxFunction(expression,"clamp",5) != MagickFalse)
2086  {
2087  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2088  depth+1,beta,exception);
2089  if (alpha < 0.0)
2090  FxReturn(0.0);
2091  if (alpha > 1.0)
2092  FxReturn(1.0);
2093  FxReturn(alpha);
2094  }
2095  if (IsFxFunction(expression,"cosh",4) != MagickFalse)
2096  {
2097  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2098  depth+1,beta,exception);
2099  FxReturn(cosh(alpha));
2100  }
2101  if (IsFxFunction(expression,"cos",3) != MagickFalse)
2102  {
2103  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2104  depth+1,beta,exception);
2105  FxReturn(cos(alpha));
2106  }
2107  if (LocaleCompare(expression,"c") == 0)
2108  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2109  break;
2110  }
2111  case 'D':
2112  case 'd':
2113  {
2114  if (IsFxFunction(expression,"debug",5) != MagickFalse)
2115  {
2116  const char
2117  *type;
2118 
2119  size_t
2120  length;
2121 
2122  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2123  depth+1,beta,exception);
2124  switch (fx_info->images->colorspace)
2125  {
2126  case CMYKColorspace:
2127  {
2128  switch (channel)
2129  {
2130  case CyanPixelChannel: type="cyan"; break;
2131  case MagentaPixelChannel: type="magenta"; break;
2132  case YellowPixelChannel: type="yellow"; break;
2133  case AlphaPixelChannel: type="alpha"; break;
2134  case BlackPixelChannel: type="black"; break;
2135  default: type="unknown"; break;
2136  }
2137  break;
2138  }
2139  case GRAYColorspace:
2140  {
2141  switch (channel)
2142  {
2143  case RedPixelChannel: type="gray"; break;
2144  case AlphaPixelChannel: type="alpha"; break;
2145  default: type="unknown"; break;
2146  }
2147  break;
2148  }
2149  default:
2150  {
2151  switch (channel)
2152  {
2153  case RedPixelChannel: type="red"; break;
2154  case GreenPixelChannel: type="green"; break;
2155  case BluePixelChannel: type="blue"; break;
2156  case AlphaPixelChannel: type="alpha"; break;
2157  default: type="unknown"; break;
2158  }
2159  break;
2160  }
2161  }
2162  *subexpression='\0';
2163  length=1;
2164  if (strlen(expression) > 6)
2165  length=CopyMagickString(subexpression,expression+6,
2167  if (length != 0)
2168  subexpression[length-1]='\0';
2169  if (fx_info->file != (FILE *) NULL)
2170  (void) FormatLocaleFile(fx_info->file,"%s[%.20g,%.20g].%s: "
2171  "%s=%.*g\n",fx_info->images->filename,(double) x,(double) y,type,
2172  subexpression,GetMagickPrecision(),alpha);
2173  FxReturn(alpha);
2174  }
2175  if (IsFxFunction(expression,"do",2) != MagickFalse)
2176  {
2177  size_t
2178  length;
2179 
2180  /*
2181  Parse do(expression,condition test).
2182  */
2183  length=CopyMagickString(subexpression,expression+3,
2184  MagickPathExtent-1);
2185  if (length != 0)
2186  subexpression[length-1]='\0';
2187  FxParseConditional(subexpression,',',p,q);
2188  for (alpha=0.0; ; )
2189  {
2190  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2191  exception);
2192  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2193  exception);
2194  if (fabs(gamma) < MagickEpsilon)
2195  break;
2196  }
2197  FxReturn(alpha);
2198  }
2199  if (IsFxFunction(expression,"drc",3) != MagickFalse)
2200  {
2201  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2202  depth+1,beta,exception);
2203  FxReturn((alpha/(*beta*(alpha-1.0)+1.0)));
2204  }
2205  break;
2206  }
2207  case 'E':
2208  case 'e':
2209  {
2210  if (LocaleCompare(expression,"epsilon") == 0)
2212 #if defined(MAGICKCORE_HAVE_ERF)
2213  if (IsFxFunction(expression,"erf",3) != MagickFalse)
2214  {
2215  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2216  depth+1,beta,exception);
2217  FxReturn(erf(alpha));
2218  }
2219 #endif
2220  if (IsFxFunction(expression,"exp",3) != MagickFalse)
2221  {
2222  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2223  depth+1,beta,exception);
2224  FxReturn(exp(alpha));
2225  }
2226  if (LocaleCompare(expression,"e") == 0)
2227  FxReturn(2.7182818284590452354);
2228  break;
2229  }
2230  case 'F':
2231  case 'f':
2232  {
2233  if (IsFxFunction(expression,"floor",5) != MagickFalse)
2234  {
2235  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2236  depth+1,beta,exception);
2237  FxReturn(floor(alpha));
2238  }
2239  if (IsFxFunction(expression,"for",3) != MagickFalse)
2240  {
2241  double
2242  sans = 0.0;
2243 
2244  size_t
2245  length;
2246 
2247  /*
2248  Parse for(initialization, condition test, expression).
2249  */
2250  length=CopyMagickString(subexpression,expression+4,
2251  MagickPathExtent-1);
2252  if (length != 0)
2253  subexpression[length-1]='\0';
2254  FxParseConditional(subexpression,',',p,q);
2255  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2256  exception);
2257  (void) CopyMagickString(subexpression,q+1,MagickPathExtent-1);
2258  FxParseConditional(subexpression,',',p,q);
2259  for (alpha=0.0; ; )
2260  {
2261  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2262  exception);
2263  if (fabs(gamma) < MagickEpsilon)
2264  break;
2265  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2266  exception);
2267  }
2268  FxReturn(alpha);
2269  }
2270  break;
2271  }
2272  case 'G':
2273  case 'g':
2274  {
2275  if (IsFxFunction(expression,"gauss",5) != MagickFalse)
2276  {
2277  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2278  depth+1,beta,exception);
2279  FxReturn(exp((-alpha*alpha/2.0))/sqrt(2.0*MagickPI));
2280  }
2281  if (IsFxFunction(expression,"gcd",3) != MagickFalse)
2282  {
2283  double
2284  gcd;
2285 
2286  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2287  depth+1,beta,exception);
2288  gcd=FxGCD(alpha,*beta);
2289  FxReturn(gcd);
2290  }
2291  if (LocaleCompare(expression,"g") == 0)
2292  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2293  break;
2294  }
2295  case 'H':
2296  case 'h':
2297  {
2298  if (LocaleCompare(expression,"h") == 0)
2299  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2300  if (LocaleCompare(expression,"hue") == 0)
2301  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2302  if (IsFxFunction(expression,"hypot",5) != MagickFalse)
2303  {
2304  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2305  depth+1,beta,exception);
2306  FxReturn(hypot(alpha,*beta));
2307  }
2308  break;
2309  }
2310  case 'K':
2311  case 'k':
2312  {
2313  if (LocaleCompare(expression,"k") == 0)
2314  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2315  break;
2316  }
2317  case 'I':
2318  case 'i':
2319  {
2320  if (IsFxFunction(expression,"if",2) != MagickFalse)
2321  {
2322  double
2323  sans = 0.0;
2324 
2325  size_t
2326  length;
2327 
2328  /*
2329  Parse if(condition test, true-expression, false-expression).
2330  */
2331  length=CopyMagickString(subexpression,expression+3,
2332  MagickPathExtent-1);
2333  if (length != 0)
2334  subexpression[length-1]='\0';
2335  FxParseConditional(subexpression,',',p,q);
2336  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2337  exception);
2338  (void) CopyMagickString(subexpression,q+1,MagickPathExtent-1);
2339  FxParseConditional(subexpression,',',p,q);
2340  if (fabs(alpha) >= MagickEpsilon)
2341  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
2342  exception);
2343  else
2344  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2345  exception);
2346  FxReturn(alpha);
2347  }
2348  if (LocaleCompare(expression,"intensity") == 0)
2349  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2350  if (IsFxFunction(expression,"int",3) != MagickFalse)
2351  {
2352  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2353  depth+1,beta,exception);
2354  FxReturn(floor(alpha));
2355  }
2356  if (IsFxFunction(expression,"isnan",5) != MagickFalse)
2357  {
2358  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2359  depth+1,beta,exception);
2360  FxReturn((double) !!IsNaN(alpha));
2361  }
2362  if (LocaleCompare(expression,"i") == 0)
2363  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2364  break;
2365  }
2366  case 'J':
2367  case 'j':
2368  {
2369  if (LocaleCompare(expression,"j") == 0)
2370  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2371 #if defined(MAGICKCORE_HAVE_J0)
2372  if (IsFxFunction(expression,"j0",2) != MagickFalse)
2373  {
2374  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2375  depth+1,beta,exception);
2376  FxReturn(j0(alpha));
2377  }
2378 #endif
2379 #if defined(MAGICKCORE_HAVE_J1)
2380  if (IsFxFunction(expression,"j1",2) != MagickFalse)
2381  {
2382  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2383  depth+1,beta,exception);
2384  FxReturn(j1(alpha));
2385  }
2386 #endif
2387 #if defined(MAGICKCORE_HAVE_J1)
2388  if (IsFxFunction(expression,"jinc",4) != MagickFalse)
2389  {
2390  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2391  depth+1,beta,exception);
2392  if (alpha == 0.0)
2393  FxReturn(1.0);
2394  FxReturn((2.0*j1((MagickPI*alpha))/(MagickPI*alpha)));
2395  }
2396 #endif
2397  break;
2398  }
2399  case 'L':
2400  case 'l':
2401  {
2402  if (IsFxFunction(expression,"ln",2) != MagickFalse)
2403  {
2404  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2405  depth+1,beta,exception);
2406  FxReturn(log(alpha));
2407  }
2408  if (IsFxFunction(expression,"logtwo",6) != MagickFalse)
2409  {
2410  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,
2411  depth+1,beta,exception);
2412  FxReturn(log10(alpha)/log10(2.0));
2413  }
2414  if (IsFxFunction(expression,"log",3) != MagickFalse)
2415  {
2416  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2417  depth+1,beta,exception);
2418  FxReturn(log10(alpha));
2419  }
2420  if (LocaleCompare(expression,"lightness") == 0)
2421  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2422  break;
2423  }
2424  case 'M':
2425  case 'm':
2426  {
2427  if (LocaleCompare(expression,"MaxRGB") == 0)
2429  if (LocaleNCompare(expression,"maxima",6) == 0)
2430  break;
2431  if (IsFxFunction(expression,"max",3) != MagickFalse)
2432  {
2433  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2434  depth+1,beta,exception);
2435  FxReturn(alpha > *beta ? alpha : *beta);
2436  }
2437  if (LocaleNCompare(expression,"minima",6) == 0)
2438  break;
2439  if (IsFxFunction(expression,"min",3) != MagickFalse)
2440  {
2441  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2442  depth+1,beta,exception);
2443  FxReturn(alpha < *beta ? alpha : *beta);
2444  }
2445  if (IsFxFunction(expression,"mod",3) != MagickFalse)
2446  {
2447  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2448  depth+1,beta,exception);
2449  FxReturn(alpha-floor((alpha*PerceptibleReciprocal(*beta)))*(*beta));
2450  }
2451  if (LocaleCompare(expression,"m") == 0)
2452  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2453  break;
2454  }
2455  case 'N':
2456  case 'n':
2457  {
2458  if (IsFxFunction(expression,"not",3) != MagickFalse)
2459  {
2460  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2461  depth+1,beta,exception);
2462  FxReturn((double) (alpha < MagickEpsilon));
2463  }
2464  if (LocaleCompare(expression,"n") == 0)
2465  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2466  break;
2467  }
2468  case 'O':
2469  case 'o':
2470  {
2471  if (LocaleCompare(expression,"Opaque") == 0)
2472  FxReturn(1.0);
2473  if (LocaleCompare(expression,"o") == 0)
2474  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2475  break;
2476  }
2477  case 'P':
2478  case 'p':
2479  {
2480  if (LocaleCompare(expression,"phi") == 0)
2482  if (LocaleCompare(expression,"pi") == 0)
2483  FxReturn(MagickPI);
2484  if (IsFxFunction(expression,"pow",3) != MagickFalse)
2485  {
2486  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2487  depth+1,beta,exception);
2488  FxReturn(pow(alpha,*beta));
2489  }
2490  if (LocaleCompare(expression,"p") == 0)
2491  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2492  break;
2493  }
2494  case 'Q':
2495  case 'q':
2496  {
2497  if (LocaleCompare(expression,"QuantumRange") == 0)
2499  if (LocaleCompare(expression,"QuantumScale") == 0)
2501  break;
2502  }
2503  case 'R':
2504  case 'r':
2505  {
2506  if (IsFxFunction(expression,"rand",4) != MagickFalse)
2507  {
2508 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2509  #pragma omp critical (MagickCore_FxEvaluateSubexpression)
2510 #endif
2511  alpha=GetPseudoRandomValue(fx_info->random_info);
2512  FxReturn(alpha);
2513  }
2514  if (IsFxFunction(expression,"round",5) != MagickFalse)
2515  {
2516  /*
2517  Round the fraction to nearest integer.
2518  */
2519  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2520  depth+1,beta,exception);
2521  if ((alpha-floor(alpha)) < (ceil(alpha)-alpha))
2522  FxReturn(floor(alpha));
2523  FxReturn(ceil(alpha));
2524  }
2525  if (LocaleCompare(expression,"r") == 0)
2526  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2527  break;
2528  }
2529  case 'S':
2530  case 's':
2531  {
2532  if (LocaleCompare(expression,"saturation") == 0)
2533  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2534  if (IsFxFunction(expression,"sign",4) != MagickFalse)
2535  {
2536  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2537  depth+1,beta,exception);
2538  FxReturn(alpha < 0.0 ? -1.0 : 1.0);
2539  }
2540  if (IsFxFunction(expression,"sinc",4) != MagickFalse)
2541  {
2542  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2543  depth+1,beta,exception);
2544  if (alpha == 0)
2545  FxReturn(1.0);
2546  FxReturn(sin((MagickPI*alpha))/(MagickPI*alpha));
2547  }
2548  if (IsFxFunction(expression,"sinh",4) != MagickFalse)
2549  {
2550  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2551  depth+1,beta,exception);
2552  FxReturn(sinh(alpha));
2553  }
2554  if (IsFxFunction(expression,"sin",3) != MagickFalse)
2555  {
2556  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2557  depth+1,beta,exception);
2558  FxReturn(sin(alpha));
2559  }
2560  if (IsFxFunction(expression,"sqrt",4) != MagickFalse)
2561  {
2562  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2563  depth+1,beta,exception);
2564  FxReturn(sqrt(alpha));
2565  }
2566  if (IsFxFunction(expression,"squish",6) != MagickFalse)
2567  {
2568  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,
2569  depth+1,beta,exception);
2570  FxReturn((1.0/(1.0+exp(-alpha))));
2571  }
2572  if (LocaleCompare(expression,"s") == 0)
2573  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2574  break;
2575  }
2576  case 'T':
2577  case 't':
2578  {
2579  if (IsFxFunction(expression,"tanh",4) != MagickFalse)
2580  {
2581  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2582  depth+1,beta,exception);
2583  FxReturn(tanh(alpha));
2584  }
2585  if (IsFxFunction(expression,"tan",3) != MagickFalse)
2586  {
2587  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2588  depth+1,beta,exception);
2589  FxReturn(tan(alpha));
2590  }
2591  if (LocaleCompare(expression,"Transparent") == 0)
2592  FxReturn(0.0);
2593  if (IsFxFunction(expression,"trunc",5) != MagickFalse)
2594  {
2595  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2596  depth+1,beta,exception);
2597  if (alpha >= 0.0)
2598  FxReturn(floor(alpha));
2599  FxReturn(ceil(alpha));
2600  }
2601  if (LocaleCompare(expression,"t") == 0)
2602  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2603  break;
2604  }
2605  case 'U':
2606  case 'u':
2607  {
2608  if (LocaleCompare(expression,"u") == 0)
2609  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2610  break;
2611  }
2612  case 'V':
2613  case 'v':
2614  {
2615  if (LocaleCompare(expression,"v") == 0)
2616  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2617  break;
2618  }
2619  case 'W':
2620  case 'w':
2621  {
2622  if (IsFxFunction(expression,"while",5) != MagickFalse)
2623  {
2624  size_t
2625  length;
2626 
2627  /*
2628  Parse while(condition test, expression).
2629  */
2630  length=CopyMagickString(subexpression,expression+6,
2631  MagickPathExtent-1);
2632  if (length != 0)
2633  subexpression[length-1]='\0';
2634  FxParseConditional(subexpression,',',p,q);
2635  for (alpha=0.0; ; )
2636  {
2637  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2638  exception);
2639  if (fabs(gamma) < MagickEpsilon)
2640  break;
2641  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,
2642  beta,exception);
2643  }
2644  FxReturn(alpha);
2645  }
2646  if (LocaleCompare(expression,"w") == 0)
2647  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2648  break;
2649  }
2650  case 'Y':
2651  case 'y':
2652  {
2653  if (LocaleCompare(expression,"y") == 0)
2654  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2655  break;
2656  }
2657  case 'Z':
2658  case 'z':
2659  {
2660  if (LocaleCompare(expression,"z") == 0)
2661  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2662  break;
2663  }
2664  default:
2665  break;
2666  }
2667  subexpression=DestroyString(subexpression);
2668  q=(char *) expression;
2669  alpha=InterpretSiPrefixValue(expression,&q);
2670  if (q == expression)
2671  alpha=FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception);
2672  FxReturn(alpha);
2673 }
2674 
2676  double *alpha,ExceptionInfo *exception)
2677 {
2679  status;
2680 
2681  status=FxEvaluateChannelExpression(fx_info,GrayPixelChannel,0,0,alpha,
2682  exception);
2683  return(status);
2684 }
2685 
2687  double *alpha,ExceptionInfo *exception)
2688 {
2689  FILE
2690  *file;
2691 
2693  status;
2694 
2695  file=fx_info->file;
2696  fx_info->file=(FILE *) NULL;
2697  status=FxEvaluateChannelExpression(fx_info,GrayPixelChannel,0,0,alpha,
2698  exception);
2699  fx_info->file=file;
2700  return(status);
2701 }
2702 
2704  const PixelChannel channel,const ssize_t x,const ssize_t y,
2705  double *alpha,ExceptionInfo *exception)
2706 {
2707  double
2708  beta;
2709 
2710  beta=0.0;
2711  *alpha=FxEvaluateSubexpression(fx_info,channel,x,y,fx_info->expression,0,
2712  &beta,exception);
2713  return(exception->severity == OptionError ? MagickFalse : MagickTrue);
2714 }
2715 
2716 /*
2717 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2718 % %
2719 % %
2720 % %
2721 % F x I m a g e %
2722 % %
2723 % %
2724 % %
2725 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2726 %
2727 % FxImage() applies a mathematical expression to the specified image.
2728 %
2729 % The format of the FxImage method is:
2730 %
2731 % Image *FxImage(const Image *image,const char *expression,
2732 % ExceptionInfo *exception)
2733 %
2734 % A description of each parameter follows:
2735 %
2736 % o image: the image.
2737 %
2738 % o expression: A mathematical expression.
2739 %
2740 % o exception: return any errors or warnings in this structure.
2741 %
2742 */
2743 
2744 static FxInfo **DestroyFxThreadSet(FxInfo **fx_info)
2745 {
2746  ssize_t
2747  i;
2748 
2749  assert(fx_info != (FxInfo **) NULL);
2750  for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
2751  if (fx_info[i] != (FxInfo *) NULL)
2752  fx_info[i]=DestroyFxInfo(fx_info[i]);
2753  fx_info=(FxInfo **) RelinquishMagickMemory(fx_info);
2754  return(fx_info);
2755 }
2756 
2757 static FxInfo **AcquireFxThreadSet(const Image *image,const char *expression,
2758  ExceptionInfo *exception)
2759 {
2760  char
2761  *fx_expression;
2762 
2763  double
2764  alpha;
2765 
2766  FxInfo
2767  **fx_info;
2768 
2769  ssize_t
2770  i;
2771 
2772  size_t
2773  number_threads;
2774 
2775  number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
2776  fx_info=(FxInfo **) AcquireQuantumMemory(number_threads,sizeof(*fx_info));
2777  if (fx_info == (FxInfo **) NULL)
2778  {
2779  (void) ThrowMagickException(exception,GetMagickModule(),
2780  ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
2781  return((FxInfo **) NULL);
2782  }
2783  (void) memset(fx_info,0,number_threads*sizeof(*fx_info));
2784  if (*expression != '@')
2785  fx_expression=ConstantString(expression);
2786  else
2787  fx_expression=FileToString(expression+1,~0UL,exception);
2788  for (i=0; i < (ssize_t) number_threads; i++)
2789  {
2791  status;
2792 
2793  fx_info[i]=AcquireFxInfo(image,fx_expression,exception);
2794  if (fx_info[i] == (FxInfo *) NULL)
2795  break;
2796  status=FxPreprocessExpression(fx_info[i],&alpha,exception);
2797  if (status == MagickFalse)
2798  break;
2799  }
2800  fx_expression=DestroyString(fx_expression);
2801  if (i < (ssize_t) number_threads)
2802  fx_info=DestroyFxThreadSet(fx_info);
2803  return(fx_info);
2804 }
2805 
2806 MagickExport Image *FxImage(const Image *image,const char *expression,
2807  ExceptionInfo *exception)
2808 {
2809 #define FxImageTag "Fx/Image"
2810 
2811  CacheView
2812  *fx_view,
2813  *image_view;
2814 
2815  FxInfo
2816  **magick_restrict fx_info;
2817 
2818  Image
2819  *fx_image;
2820 
2822  status;
2823 
2825  progress;
2826 
2827  ssize_t
2828  y;
2829 
2830  assert(image != (Image *) NULL);
2831  assert(image->signature == MagickCoreSignature);
2832  if (image->debug != MagickFalse)
2833  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2834  if (expression == (const char *) NULL)
2835  return(CloneImage(image,0,0,MagickTrue,exception));
2836  fx_info=AcquireFxThreadSet(image,expression,exception);
2837  if (fx_info == (FxInfo **) NULL)
2838  return((Image *) NULL);
2839  fx_image=CloneImage(image,0,0,MagickTrue,exception);
2840  if (fx_image == (Image *) NULL)
2841  {
2842  fx_info=DestroyFxThreadSet(fx_info);
2843  return((Image *) NULL);
2844  }
2845  if (SetImageStorageClass(fx_image,DirectClass,exception) == MagickFalse)
2846  {
2847  fx_info=DestroyFxThreadSet(fx_info);
2848  fx_image=DestroyImage(fx_image);
2849  return((Image *) NULL);
2850  }
2851  /*
2852  Fx image.
2853  */
2854  status=MagickTrue;
2855  progress=0;
2856  image_view=AcquireVirtualCacheView(image,exception);
2857  fx_view=AcquireAuthenticCacheView(fx_image,exception);
2858 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2859  #pragma omp parallel for schedule(dynamic) shared(progress,status) \
2860  magick_number_threads(image,fx_image,fx_image->rows, \
2861  GlobExpression(fx_info[0]->expression,"debug(",MagickTrue) == 0 ? 1 : 0)
2862 #endif
2863  for (y=0; y < (ssize_t) fx_image->rows; y++)
2864  {
2865  const int
2866  id = GetOpenMPThreadId();
2867 
2868  const Quantum
2869  *magick_restrict p;
2870 
2871  Quantum
2872  *magick_restrict q;
2873 
2874  ssize_t
2875  x;
2876 
2877  if (status == MagickFalse)
2878  continue;
2879  p=GetCacheViewVirtualPixels(image_view,0,y,image->columns,1,exception);
2880  q=QueueCacheViewAuthenticPixels(fx_view,0,y,fx_image->columns,1,exception);
2881  if ((p == (const Quantum *) NULL) || (q == (Quantum *) NULL))
2882  {
2883  status=MagickFalse;
2884  continue;
2885  }
2886  for (x=0; x < (ssize_t) fx_image->columns; x++)
2887  {
2888  ssize_t
2889  i;
2890 
2891  for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
2892  {
2893  double
2894  alpha;
2895 
2896  PixelChannel channel = GetPixelChannelChannel(image,i);
2897  PixelTrait traits = GetPixelChannelTraits(image,channel);
2898  PixelTrait fx_traits=GetPixelChannelTraits(fx_image,channel);
2899  if ((traits == UndefinedPixelTrait) ||
2900  (fx_traits == UndefinedPixelTrait))
2901  continue;
2902  if ((fx_traits & CopyPixelTrait) != 0)
2903  {
2904  SetPixelChannel(fx_image,channel,p[i],q);
2905  continue;
2906  }
2907  alpha=0.0;
2908  (void) FxEvaluateChannelExpression(fx_info[id],channel,x,y,&alpha,
2909  exception);
2910  q[i]=ClampToQuantum(QuantumRange*alpha);
2911  }
2912  p+=GetPixelChannels(image);
2913  q+=GetPixelChannels(fx_image);
2914  }
2915  if (SyncCacheViewAuthenticPixels(fx_view,exception) == MagickFalse)
2916  status=MagickFalse;
2917  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2918  {
2920  proceed;
2921 
2922 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2923  #pragma omp atomic
2924 #endif
2925  progress++;
2926  proceed=SetImageProgress(image,FxImageTag,progress,image->rows);
2927  if (proceed == MagickFalse)
2928  status=MagickFalse;
2929  }
2930  }
2931  fx_view=DestroyCacheView(fx_view);
2932  image_view=DestroyCacheView(image_view);
2933  fx_info=DestroyFxThreadSet(fx_info);
2934  if (status == MagickFalse)
2935  fx_image=DestroyImage(fx_image);
2936  return(fx_image);
2937 }
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:1289
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:1099
static double FxEvaluateSubexpression(FxInfo *, const PixelChannel, const ssize_t, const ssize_t, const char *, const size_t, double *, ExceptionInfo *)
Definition: fx.c:1448
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:3031
MagickExport Image * GetImageFromList(const Image *images, const ssize_t index)
Definition: list.c:618
#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:2744
MagickExport const char * GetImageArtifact(const Image *image, const char *artifact)
Definition: artifact.c:273
MagickRealType red
Definition: pixel.h:193
static double StringToDouble(const char *magick_restrict string, char **magick_restrict sentinal)
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:467
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:719
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:118
double sigma
Definition: geometry.h:107
MagickExport void StripString(char *message)
Definition: string.c:2466
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:953
ssize_t MagickOffsetType
Definition: magick-type.h:137
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:2703
double x
Definition: geometry.h:124
#define MagickCoreSignature
#define FxReturn(value)
MagickExport Image * GetFirstImageInList(const Image *images)
Definition: list.c:574
MagickExport ssize_t FormatLocaleFile(FILE *file, const char *magick_restrict format,...)
Definition: locale.c:372
MagickBooleanType
Definition: magick-type.h:173
ExceptionInfo * exception
Definition: fx.c:151
unsigned int MagickStatusType
Definition: magick-type.h:129
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:1527
double y
Definition: geometry.h:124
static int GetOpenMPThreadId(void)
static const char * FxOperatorPrecedence(const char *expression, ExceptionInfo *exception)
Definition: fx.c:1175
#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:2757
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:6271
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:2686
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:123
MagickExport MagickBooleanType SubstituteString(char **string, const char *search, const char *replace)
Definition: string.c:2528
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:1876
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:2603
MagickPrivate MagickBooleanType FxEvaluateExpression(FxInfo *fx_info, double *alpha, ExceptionInfo *exception)
Definition: fx.c:2675
MagickExport MagickBooleanType GetImageKurtosis(const Image *image, double *kurtosis, double *skewness, ExceptionInfo *exception)
Definition: statistic.c:1289
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:1339
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:1403
#define IsNaN(a)
Definition: magick-type.h:196
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:871
unsigned short Quantum
Definition: magick-type.h:90
double xi
Definition: geometry.h:107
MagickExport ssize_t GetImageIndexInList(const Image *images)
Definition: list.c:670
MagickRealType black
Definition: pixel.h:193
char * expression
Definition: fx.c:135
MagickExport char * DestroyString(char *string)
Definition: string.c:776
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
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:1387
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:709
SplayTreeInfo * colors
Definition: fx.c:141
MagickExport Image * DestroyImage(Image *image)
Definition: image.c:1168
MagickExport char * ConstantString(const char *source)
Definition: string.c:666
MagickExport Image * CloneImage(const Image *image, const size_t columns, const size_t rows, const MagickBooleanType detach, ExceptionInfo *exception)
Definition: image.c:779
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:2806
#define QuantumRange
Definition: magick-type.h:91
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