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