MagickCore  6.9.13-44
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/license/ %
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) (~CastDoubleToSizeT(*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) (CastDoubleToSizeT(alpha+0.5) & CastDoubleToSizeT(*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) (CastDoubleToSizeT(alpha+0.5) |
1574  CastDoubleToSizeT(*beta+0.5));
1575  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1576  return(0.0);
1577  FxReturn(*beta);
1578  }
1579  case LeftShiftAssignmentOperator:
1580  {
1581  q=subexpression;
1582  while (isalpha((int) ((unsigned char) *q)) != 0)
1583  q++;
1584  if (*q != '\0')
1585  {
1586  (void) ThrowMagickException(exception,GetMagickModule(),
1587  OptionError,"UnableToParseExpression","`%s'",subexpression);
1588  FxReturn(0.0);
1589  }
1590  ClearMagickException(exception);
1591  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1592  exception);
1593  if (CastDoubleToSizeT(*beta+0.5) >= (8*sizeof(size_t)))
1594  {
1595  (void) ThrowMagickException(exception,GetMagickModule(),
1596  OptionError,"ShiftCountOverflow","`%s'",subexpression);
1597  FxReturn(0.0);
1598  }
1599  value=(double) (CastDoubleToSizeT(alpha+0.5) <<
1600  CastDoubleToSizeT(*beta+0.5));
1601  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1602  return(0.0);
1603  FxReturn(*beta);
1604  }
1605  case RightShiftAssignmentOperator:
1606  {
1607  q=subexpression;
1608  while (isalpha((int) ((unsigned char) *q)) != 0)
1609  q++;
1610  if (*q != '\0')
1611  {
1612  (void) ThrowMagickException(exception,GetMagickModule(),
1613  OptionError,"UnableToParseExpression","`%s'",subexpression);
1614  FxReturn(0.0);
1615  }
1616  ClearMagickException(exception);
1617  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1618  exception);
1619  if (CastDoubleToSizeT(*beta+0.5) >= (8*sizeof(size_t)))
1620  {
1621  (void) ThrowMagickException(exception,GetMagickModule(),
1622  OptionError,"ShiftCountOverflow","`%s'",subexpression);
1623  FxReturn(0.0);
1624  }
1625  value=(double) (CastDoubleToSizeT(alpha+0.5) >>
1626  CastDoubleToSizeT(*beta+0.5));
1627  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1628  return(0.0);
1629  FxReturn(*beta);
1630  }
1631  case PowerAssignmentOperator:
1632  {
1633  q=subexpression;
1634  while (isalpha((int) ((unsigned char) *q)) != 0)
1635  q++;
1636  if (*q != '\0')
1637  {
1638  (void) ThrowMagickException(exception,GetMagickModule(),
1639  OptionError,"UnableToParseExpression","`%s'",subexpression);
1640  FxReturn(0.0);
1641  }
1642  ClearMagickException(exception);
1643  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1644  exception);
1645  value=pow(alpha,*beta);
1646  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1647  return(0.0);
1648  FxReturn(*beta);
1649  }
1650  case ModuloAssignmentOperator:
1651  {
1652  q=subexpression;
1653  while (isalpha((int) ((unsigned char) *q)) != 0)
1654  q++;
1655  if (*q != '\0')
1656  {
1657  (void) ThrowMagickException(exception,GetMagickModule(),
1658  OptionError,"UnableToParseExpression","`%s'",subexpression);
1659  FxReturn(0.0);
1660  }
1661  ClearMagickException(exception);
1662  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1663  exception);
1664  value=fmod(alpha,*beta);
1665  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1666  return(0.0);
1667  FxReturn(*beta);
1668  }
1669  case PlusAssignmentOperator:
1670  {
1671  q=subexpression;
1672  while (isalpha((int) ((unsigned char) *q)) != 0)
1673  q++;
1674  if (*q != '\0')
1675  {
1676  (void) ThrowMagickException(exception,GetMagickModule(),
1677  OptionError,"UnableToParseExpression","`%s'",subexpression);
1678  FxReturn(0.0);
1679  }
1680  ClearMagickException(exception);
1681  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1682  exception);
1683  value=alpha+(*beta);
1684  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1685  return(0.0);
1686  FxReturn(*beta);
1687  }
1688  case SubtractAssignmentOperator:
1689  {
1690  q=subexpression;
1691  while (isalpha((int) ((unsigned char) *q)) != 0)
1692  q++;
1693  if (*q != '\0')
1694  {
1695  (void) ThrowMagickException(exception,GetMagickModule(),
1696  OptionError,"UnableToParseExpression","`%s'",subexpression);
1697  FxReturn(0.0);
1698  }
1699  ClearMagickException(exception);
1700  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1701  exception);
1702  value=alpha-(*beta);
1703  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1704  return(0.0);
1705  FxReturn(*beta);
1706  }
1707  case MultiplyAssignmentOperator:
1708  {
1709  q=subexpression;
1710  while (isalpha((int) ((unsigned char) *q)) != 0)
1711  q++;
1712  if (*q != '\0')
1713  {
1714  (void) ThrowMagickException(exception,GetMagickModule(),
1715  OptionError,"UnableToParseExpression","`%s'",subexpression);
1716  FxReturn(0.0);
1717  }
1718  ClearMagickException(exception);
1719  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1720  exception);
1721  value=alpha*(*beta);
1722  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1723  return(0.0);
1724  FxReturn(*beta);
1725  }
1726  case DivideAssignmentOperator:
1727  {
1728  q=subexpression;
1729  while (isalpha((int) ((unsigned char) *q)) != 0)
1730  q++;
1731  if (*q != '\0')
1732  {
1733  (void) ThrowMagickException(exception,GetMagickModule(),
1734  OptionError,"UnableToParseExpression","`%s'",subexpression);
1735  FxReturn(0.0);
1736  }
1737  ClearMagickException(exception);
1738  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1739  exception);
1740  value=alpha/(*beta);
1741  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1742  return(0.0);
1743  FxReturn(*beta);
1744  }
1745  case IncrementAssignmentOperator:
1746  {
1747  if (*subexpression == '\0')
1748  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1749  exception);
1750  value=alpha+1.0;
1751  if (*subexpression == '\0')
1752  {
1753  if (SetFxSymbolValue(fx_info,p,value) == MagickFalse)
1754  return(0.0);
1755  }
1756  else
1757  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1758  return(0.0);
1759  FxReturn(*beta);
1760  }
1761  case DecrementAssignmentOperator:
1762  {
1763  if (*subexpression == '\0')
1764  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1765  exception);
1766  value=alpha-1.0;
1767  if (*subexpression == '\0')
1768  {
1769  if (SetFxSymbolValue(fx_info,p,value) == MagickFalse)
1770  return(0.0);
1771  }
1772  else
1773  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1774  return(0.0);
1775  FxReturn(*beta);
1776  }
1777  case LeftShiftOperator:
1778  {
1779  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1780  exception);
1781  if (CastDoubleToSizeT(gamma+0.5) >= (8*sizeof(size_t)))
1782  {
1783  (void) ThrowMagickException(exception,GetMagickModule(),
1784  OptionError,"ShiftCountOverflow","`%s'",subexpression);
1785  FxReturn(0.0);
1786  }
1787  *beta=(double) (CastDoubleToSizeT(alpha+0.5) <<
1788  CastDoubleToSizeT(gamma+0.5));
1789  FxReturn(*beta);
1790  }
1791  case RightShiftOperator:
1792  {
1793  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1794  exception);
1795  if (CastDoubleToSizeT(gamma+0.5) >= (8*sizeof(size_t)))
1796  {
1797  (void) ThrowMagickException(exception,GetMagickModule(),
1798  OptionError,"ShiftCountOverflow","`%s'",subexpression);
1799  FxReturn(0.0);
1800  }
1801  *beta=(double) (CastDoubleToSizeT(alpha+0.5) >> CastDoubleToSizeT(gamma+0.5));
1802  FxReturn(*beta);
1803  }
1804  case '<':
1805  {
1806  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1807  exception);
1808  FxReturn(alpha < *beta ? 1.0 : 0.0);
1809  }
1810  case LessThanEqualOperator:
1811  {
1812  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1813  exception);
1814  FxReturn(alpha <= *beta ? 1.0 : 0.0);
1815  }
1816  case '>':
1817  {
1818  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1819  exception);
1820  FxReturn(alpha > *beta ? 1.0 : 0.0);
1821  }
1822  case GreaterThanEqualOperator:
1823  {
1824  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1825  exception);
1826  FxReturn(alpha >= *beta ? 1.0 : 0.0);
1827  }
1828  case EqualOperator:
1829  {
1830  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1831  exception);
1832  FxReturn(fabs(alpha-(*beta)) < MagickEpsilon ? 1.0 : 0.0);
1833  }
1834  case NotEqualOperator:
1835  {
1836  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1837  exception);
1838  FxReturn(fabs(alpha-(*beta)) >= MagickEpsilon ? 1.0 : 0.0);
1839  }
1840  case '&':
1841  {
1842  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1843  exception);
1844  *beta=(double) (CastDoubleToSizeT(alpha+0.5) & CastDoubleToSizeT(gamma+0.5));
1845  FxReturn(*beta);
1846  }
1847  case '|':
1848  {
1849  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1850  exception);
1851  *beta=(double) (CastDoubleToSizeT(alpha+0.5) | CastDoubleToSizeT(gamma+0.5));
1852  FxReturn(*beta);
1853  }
1854  case LogicalAndOperator:
1855  {
1856  p++;
1857  if (alpha <= 0.0)
1858  {
1859  *beta=0.0;
1860  FxReturn(*beta);
1861  }
1862  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1863  exception);
1864  *beta=(gamma > 0.0) ? 1.0 : 0.0;
1865  FxReturn(*beta);
1866  }
1867  case LogicalOrOperator:
1868  {
1869  p++;
1870  if (alpha > 0.0)
1871  {
1872  *beta=1.0;
1873  FxReturn(*beta);
1874  }
1875  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1876  exception);
1877  *beta=(gamma > 0.0) ? 1.0 : 0.0;
1878  FxReturn(*beta);
1879  }
1880  case '?':
1881  {
1882  double
1883  gamma;
1884 
1885  (void) CopyMagickString(subexpression,++p,MaxTextExtent-1);
1886  FxParseConditional(subexpression,':',p,q);
1887  if (fabs(alpha) >= MagickEpsilon)
1888  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1889  exception);
1890  else
1891  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
1892  exception);
1893  FxReturn(gamma);
1894  }
1895  case '=':
1896  {
1897  q=subexpression;
1898  while (isalpha((int) ((unsigned char) *q)) != 0)
1899  q++;
1900  if (*q != '\0')
1901  {
1902  (void) ThrowMagickException(exception,GetMagickModule(),
1903  OptionError,"UnableToParseExpression","`%s'",subexpression);
1904  FxReturn(0.0);
1905  }
1906  ClearMagickException(exception);
1907  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1908  exception);
1909  value=(*beta);
1910  if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1911  return(0.0);
1912  FxReturn(*beta);
1913  }
1914  case ',':
1915  {
1916  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1917  exception);
1918  FxReturn(alpha);
1919  }
1920  case ';':
1921  {
1922  *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1923  exception);
1924  if (*p == '\0')
1925  FxReturn(alpha);
1926  FxReturn(*beta);
1927  }
1928  default:
1929  {
1930  gamma=alpha*FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,
1931  beta,exception);
1932  FxReturn(gamma);
1933  }
1934  }
1935  }
1936  if (strchr("(",(int) *expression) != (char *) NULL)
1937  {
1938  size_t
1939  length;
1940 
1941  if (depth >= FxMaxParenthesisDepth)
1942  (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1943  "ParenthesisNestedTooDeeply","`%s'",expression);
1944  length=CopyMagickString(subexpression,expression+1,MaxTextExtent);
1945  if (length != 0)
1946  subexpression[length-1]='\0';
1947  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,depth+1,
1948  beta,exception);
1949  FxReturn(gamma);
1950  }
1951  switch (*expression)
1952  {
1953  case '+':
1954  {
1955  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1956  beta,exception);
1957  FxReturn(1.0*gamma);
1958  }
1959  case '-':
1960  {
1961  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1962  beta,exception);
1963  FxReturn(-1.0*gamma);
1964  }
1965  case '~':
1966  {
1967  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1968  beta,exception);
1969  FxReturn((double) (~CastDoubleToSizeT(gamma+0.5)));
1970  }
1971  case 'A':
1972  case 'a':
1973  {
1974  if (IsFxFunction(expression,"abs",3) != MagickFalse)
1975  {
1976  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
1977  depth+1,beta,exception);
1978  FxReturn(fabs(alpha));
1979  }
1980 #if defined(MAGICKCORE_HAVE_ACOSH)
1981  if (IsFxFunction(expression,"acosh",5) != MagickFalse)
1982  {
1983  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
1984  depth+1,beta,exception);
1985  FxReturn(acosh(alpha));
1986  }
1987 #endif
1988  if (IsFxFunction(expression,"acos",4) != MagickFalse)
1989  {
1990  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
1991  depth+1,beta,exception);
1992  FxReturn(acos(alpha));
1993  }
1994 #if defined(MAGICKCORE_HAVE_J1)
1995  if (IsFxFunction(expression,"airy",4) != MagickFalse)
1996  {
1997  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
1998  depth+1,beta,exception);
1999  if (alpha == 0.0)
2000  FxReturn(1.0);
2001  gamma=2.0*j1((MagickPI*alpha))/(MagickPI*alpha);
2002  FxReturn(gamma*gamma);
2003  }
2004 #endif
2005 #if defined(MAGICKCORE_HAVE_ASINH)
2006  if (IsFxFunction(expression,"asinh",5) != MagickFalse)
2007  {
2008  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2009  depth+1,beta,exception);
2010  FxReturn(asinh(alpha));
2011  }
2012 #endif
2013  if (IsFxFunction(expression,"asin",4) != MagickFalse)
2014  {
2015  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2016  depth+1,beta,exception);
2017  FxReturn(asin(alpha));
2018  }
2019  if (IsFxFunction(expression,"alt",3) != MagickFalse)
2020  {
2021  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2022  depth+1,beta,exception);
2023  FxReturn(((ssize_t) alpha) & 0x01 ? -1.0 : 1.0);
2024  }
2025  if (IsFxFunction(expression,"atan2",5) != MagickFalse)
2026  {
2027  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2028  depth+1,beta,exception);
2029  FxReturn(atan2(alpha,*beta));
2030  }
2031 #if defined(MAGICKCORE_HAVE_ATANH)
2032  if (IsFxFunction(expression,"atanh",5) != MagickFalse)
2033  {
2034  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2035  depth+1,beta,exception);
2036  FxReturn(atanh(alpha));
2037  }
2038 #endif
2039  if (IsFxFunction(expression,"atan",4) != MagickFalse)
2040  {
2041  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2042  depth+1,beta,exception);
2043  FxReturn(atan(alpha));
2044  }
2045  if (LocaleCompare(expression,"a") == 0)
2046  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2047  break;
2048  }
2049  case 'B':
2050  case 'b':
2051  {
2052  if (LocaleCompare(expression,"b") == 0)
2053  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2054  break;
2055  }
2056  case 'C':
2057  case 'c':
2058  {
2059  if (IsFxFunction(expression,"ceil",4) != MagickFalse)
2060  {
2061  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2062  depth+1,beta,exception);
2063  FxReturn(ceil(alpha));
2064  }
2065  if (IsFxFunction(expression,"clamp",5) != MagickFalse)
2066  {
2067  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2068  depth+1,beta,exception);
2069  if (alpha < 0.0)
2070  FxReturn(0.0);
2071  if (alpha > 1.0)
2072  FxReturn(1.0);
2073  FxReturn(alpha);
2074  }
2075  if (IsFxFunction(expression,"cosh",4) != MagickFalse)
2076  {
2077  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2078  depth+1,beta,exception);
2079  FxReturn(cosh(alpha));
2080  }
2081  if (IsFxFunction(expression,"cos",3) != MagickFalse)
2082  {
2083  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2084  depth+1,beta,exception);
2085  FxReturn(cos(alpha));
2086  }
2087  if (LocaleCompare(expression,"c") == 0)
2088  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2089  break;
2090  }
2091  case 'D':
2092  case 'd':
2093  {
2094  if (IsFxFunction(expression,"debug",5) != MagickFalse)
2095  {
2096  const char
2097  *type;
2098 
2099  size_t
2100  length;
2101 
2102  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2103  depth+1,beta,exception);
2104  switch (fx_info->images->colorspace)
2105  {
2106  case CMYKColorspace:
2107  {
2108  switch (channel)
2109  {
2110  case CyanChannel: type="cyan"; break;
2111  case MagentaChannel: type="magenta"; break;
2112  case YellowChannel: type="yellow"; break;
2113  case AlphaChannel: type="alpha"; break;
2114  case BlackChannel: type="black"; break;
2115  default: type="unknown"; break;
2116  }
2117  break;
2118  }
2119  case GRAYColorspace:
2120  {
2121  switch (channel)
2122  {
2123  case RedChannel: type="gray"; break;
2124  case AlphaChannel: type="alpha"; break;
2125  default: type="unknown"; break;
2126  }
2127  break;
2128  }
2129  default:
2130  {
2131  switch (channel)
2132  {
2133  case RedChannel: type="red"; break;
2134  case GreenChannel: type="green"; break;
2135  case BlueChannel: type="blue"; break;
2136  case AlphaChannel: type="alpha"; break;
2137  default: type="unknown"; break;
2138  }
2139  break;
2140  }
2141  }
2142  *subexpression='\0';
2143  length=1;
2144  if (strlen(expression) > 6)
2145  length=CopyMagickString(subexpression,expression+6,MaxTextExtent);
2146  if (length != 0)
2147  subexpression[length-1]='\0';
2148  if (fx_info->file != (FILE *) NULL)
2149  (void) FormatLocaleFile(fx_info->file,
2150  "%s[%.20g,%.20g].%s: %s=%.*g\n",fx_info->images->filename,
2151  (double) x,(double) y,type,subexpression,GetMagickPrecision(),
2152  (double) alpha);
2153  FxReturn(alpha);
2154  }
2155  if (IsFxFunction(expression,"do",2) != MagickFalse)
2156  {
2157  size_t
2158  length;
2159 
2160  /*
2161  Parse do(expression,condition test).
2162  */
2163  length=CopyMagickString(subexpression,expression+6,
2164  MagickPathExtent-1);
2165  if (length != 0)
2166  subexpression[length-1]='\0';
2167  FxParseConditional(subexpression,',',p,q);
2168  for (alpha=0.0; ; )
2169  {
2170  if (IsImageTTLExpired(fx_info->images) != MagickFalse)
2171  (void) ThrowMagickException(exception,GetMagickModule(),
2172  ResourceLimitFatalError,"TimeLimitExceeded","`%s'",
2173  fx_info->images->filename);
2174  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2175  exception);
2176  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2177  exception);
2178  if (fabs(gamma) < MagickEpsilon)
2179  break;
2180  }
2181  FxReturn(alpha);
2182  }
2183  if (IsFxFunction(expression,"drc",3) != MagickFalse)
2184  {
2185  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2186  depth+1,beta,exception);
2187  FxReturn(alpha/(*beta*(alpha-1.0)+1.0));
2188  }
2189  break;
2190  }
2191  case 'E':
2192  case 'e':
2193  {
2194  if (LocaleCompare(expression,"epsilon") == 0)
2195  FxReturn(MagickEpsilon);
2196 #if defined(MAGICKCORE_HAVE_ERF)
2197  if (IsFxFunction(expression,"erf",3) != MagickFalse)
2198  {
2199  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2200  depth+1,beta,exception);
2201  FxReturn(erf(alpha));
2202  }
2203 #endif
2204  if (IsFxFunction(expression,"exp",3) != MagickFalse)
2205  {
2206  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2207  depth+1,beta,exception);
2208  FxReturn(exp(alpha));
2209  }
2210  if (LocaleCompare(expression,"e") == 0)
2211  FxReturn(2.7182818284590452354);
2212  break;
2213  }
2214  case 'F':
2215  case 'f':
2216  {
2217  if (IsFxFunction(expression,"floor",5) != MagickFalse)
2218  {
2219  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2220  depth+1,beta,exception);
2221  FxReturn(floor(alpha));
2222  }
2223  if (IsFxFunction(expression,"for",3) != MagickFalse)
2224  {
2225  double
2226  sans = 0.0;
2227 
2228  size_t
2229  length;
2230 
2231  /*
2232  Parse for(initialization, condition test, expression).
2233  */
2234  length=CopyMagickString(subexpression,expression+4,
2235  MagickPathExtent-1);
2236  if (length != 0)
2237  subexpression[length-1]='\0';
2238  FxParseConditional(subexpression,',',p,q);
2239  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2240  exception);
2241  (void) CopyMagickString(subexpression,q+1,MagickPathExtent-1);
2242  FxParseConditional(subexpression,',',p,q);
2243  for (alpha=0.0; ; )
2244  {
2245  if (IsImageTTLExpired(fx_info->images) != MagickFalse)
2246  (void) ThrowMagickException(exception,GetMagickModule(),
2247  ResourceLimitFatalError,"TimeLimitExceeded","`%s'",
2248  fx_info->images->filename);
2249  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2250  exception);
2251  if (fabs(gamma) < MagickEpsilon)
2252  break;
2253  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2254  exception);
2255  }
2256  FxReturn(alpha);
2257  }
2258  break;
2259  }
2260  case 'G':
2261  case 'g':
2262  {
2263  if (IsFxFunction(expression,"gauss",5) != MagickFalse)
2264  {
2265  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2266  depth+1,beta,exception);
2267  FxReturn(exp((-alpha*alpha/2.0))/sqrt(2.0*MagickPI));
2268  }
2269  if (IsFxFunction(expression,"gcd",3) != MagickFalse)
2270  {
2271  double
2272  gcd;
2273 
2274  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2275  depth+1,beta,exception);
2276  if (IsNaN(alpha))
2277  FxReturn(alpha);
2278  gcd=FxGCD(alpha,*beta,0);
2279  FxReturn(gcd);
2280  }
2281  if (LocaleCompare(expression,"g") == 0)
2282  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2283  break;
2284  }
2285  case 'H':
2286  case 'h':
2287  {
2288  if (LocaleCompare(expression,"h") == 0)
2289  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2290  if (LocaleCompare(expression,"hue") == 0)
2291  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2292  if (IsFxFunction(expression,"hypot",5) != MagickFalse)
2293  {
2294  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2295  depth+1,beta,exception);
2296  FxReturn(hypot(alpha,*beta));
2297  }
2298  break;
2299  }
2300  case 'K':
2301  case 'k':
2302  {
2303  if (LocaleCompare(expression,"k") == 0)
2304  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2305  break;
2306  }
2307  case 'I':
2308  case 'i':
2309  {
2310  if (IsFxFunction(expression,"if",2) != MagickFalse)
2311  {
2312  double
2313  sans = 0.0;
2314 
2315  size_t
2316  length;
2317 
2318  /*
2319  Parse if(condition test, true-expression, false-expression).
2320  */
2321  length=CopyMagickString(subexpression,expression+3,
2322  MagickPathExtent-1);
2323  if (length != 0)
2324  subexpression[length-1]='\0';
2325  FxParseConditional(subexpression,',',p,q);
2326  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2327  exception);
2328  (void) CopyMagickString(subexpression,q+1,MagickPathExtent-1);
2329  FxParseConditional(subexpression,',',p,q);
2330  if (fabs(alpha) >= MagickEpsilon)
2331  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
2332  exception);
2333  else
2334  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2335  exception);
2336  FxReturn(alpha);
2337  }
2338  if (LocaleCompare(expression,"intensity") == 0)
2339  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2340  if (IsFxFunction(expression,"int",3) != MagickFalse)
2341  {
2342  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2343  depth+1,beta,exception);
2344  FxReturn(floor(alpha));
2345  }
2346  if (IsFxFunction(expression,"isnan",5) != MagickFalse)
2347  {
2348  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2349  depth+1,beta,exception);
2350  FxReturn((double) !!IsNaN(alpha));
2351  }
2352  if (LocaleCompare(expression,"i") == 0)
2353  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2354  break;
2355  }
2356  case 'J':
2357  case 'j':
2358  {
2359  if (LocaleCompare(expression,"j") == 0)
2360  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2361 #if defined(MAGICKCORE_HAVE_J0)
2362  if (IsFxFunction(expression,"j0",2) != MagickFalse)
2363  {
2364  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2365  depth+1,beta,exception);
2366  FxReturn(j0(alpha));
2367  }
2368 #endif
2369 #if defined(MAGICKCORE_HAVE_J1)
2370  if (IsFxFunction(expression,"j1",2) != MagickFalse)
2371  {
2372  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2373  depth+1,beta,exception);
2374  FxReturn(j1(alpha));
2375  }
2376 #endif
2377 #if defined(MAGICKCORE_HAVE_J1)
2378  if (IsFxFunction(expression,"jinc",4) != MagickFalse)
2379  {
2380  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2381  depth+1,beta,exception);
2382  if (alpha == 0.0)
2383  FxReturn(1.0);
2384  FxReturn((2.0*j1((MagickPI*alpha))/(MagickPI*alpha)));
2385  }
2386 #endif
2387  break;
2388  }
2389  case 'L':
2390  case 'l':
2391  {
2392  if (IsFxFunction(expression,"ln",2) != MagickFalse)
2393  {
2394  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2395  depth+1,beta,exception);
2396  FxReturn(log(alpha));
2397  }
2398  if (IsFxFunction(expression,"logtwo",6) != MagickFalse)
2399  {
2400  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,
2401  depth+1,beta,exception);
2402  FxReturn(log10(alpha)/log10(2.0));
2403  }
2404  if (IsFxFunction(expression,"log",3) != MagickFalse)
2405  {
2406  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2407  depth+1,beta,exception);
2408  FxReturn(log10(alpha));
2409  }
2410  if (LocaleCompare(expression,"lightness") == 0)
2411  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2412  break;
2413  }
2414  case 'M':
2415  case 'm':
2416  {
2417  if (LocaleCompare(expression,"MaxRGB") == 0)
2418  FxReturn((double) QuantumRange);
2419  if (LocaleNCompare(expression,"maxima",6) == 0)
2420  break;
2421  if (IsFxFunction(expression,"max",3) != MagickFalse)
2422  {
2423  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2424  depth+1,beta,exception);
2425  FxReturn(alpha > *beta ? alpha : *beta);
2426  }
2427  if (LocaleNCompare(expression,"minima",6) == 0)
2428  break;
2429  if (IsFxFunction(expression,"min",3) != MagickFalse)
2430  {
2431  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2432  depth+1,beta,exception);
2433  FxReturn(alpha < *beta ? alpha : *beta);
2434  }
2435  if (IsFxFunction(expression,"mod",3) != MagickFalse)
2436  {
2437  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2438  depth+1,beta,exception);
2439  if (*beta == 0.0)
2440  FxReturn(0.0);
2441  FxReturn(alpha-floor((double) (alpha/(*beta))*(*beta)));
2442  }
2443  if (LocaleCompare(expression,"m") == 0)
2444  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2445  break;
2446  }
2447  case 'N':
2448  case 'n':
2449  {
2450  if (IsFxFunction(expression,"not",3) != MagickFalse)
2451  {
2452  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2453  depth+1,beta,exception);
2454  FxReturn((double) (alpha < MagickEpsilon));
2455  }
2456  if (LocaleCompare(expression,"n") == 0)
2457  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2458  break;
2459  }
2460  case 'O':
2461  case 'o':
2462  {
2463  if (LocaleCompare(expression,"Opaque") == 0)
2464  FxReturn(1.0);
2465  if (LocaleCompare(expression,"o") == 0)
2466  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2467  break;
2468  }
2469  case 'P':
2470  case 'p':
2471  {
2472  if (LocaleCompare(expression,"phi") == 0)
2473  FxReturn(MagickPHI);
2474  if (LocaleCompare(expression,"pi") == 0)
2475  FxReturn(MagickPI);
2476  if (IsFxFunction(expression,"pow",3) != MagickFalse)
2477  {
2478  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2479  depth+1,beta,exception);
2480  FxReturn(pow(alpha,*beta));
2481  }
2482  if (LocaleCompare(expression,"p") == 0)
2483  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2484  break;
2485  }
2486  case 'Q':
2487  case 'q':
2488  {
2489  if (LocaleCompare(expression,"QuantumRange") == 0)
2490  FxReturn((double) QuantumRange);
2491  if (LocaleCompare(expression,"QuantumScale") == 0)
2492  FxReturn(QuantumScale);
2493  break;
2494  }
2495  case 'R':
2496  case 'r':
2497  {
2498  if (IsFxFunction(expression,"rand",4) != MagickFalse)
2499  {
2500  double
2501  alpha;
2502 
2503 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2504  #pragma omp critical (MagickCore_FxEvaluateSubexpression)
2505 #endif
2506  alpha=GetPseudoRandomValue(fx_info->random_info);
2507  FxReturn(alpha);
2508  }
2509  if (IsFxFunction(expression,"round",5) != MagickFalse)
2510  {
2511  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2512  depth+1,beta,exception);
2513  if ((alpha-floor(alpha)) < (ceil(alpha)-alpha))
2514  FxReturn(floor(alpha));
2515  FxReturn(ceil(alpha));
2516  }
2517  if (LocaleCompare(expression,"r") == 0)
2518  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2519  break;
2520  }
2521  case 'S':
2522  case 's':
2523  {
2524  if (LocaleCompare(expression,"saturation") == 0)
2525  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2526  if (IsFxFunction(expression,"sign",4) != MagickFalse)
2527  {
2528  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2529  depth+1,beta,exception);
2530  FxReturn(alpha < 0.0 ? -1.0 : 1.0);
2531  }
2532  if (IsFxFunction(expression,"sinc",4) != MagickFalse)
2533  {
2534  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2535  depth+1,beta,exception);
2536  if (alpha == 0)
2537  FxReturn(1.0);
2538  FxReturn(sin((MagickPI*alpha))/(MagickPI*alpha));
2539  }
2540  if (IsFxFunction(expression,"sinh",4) != MagickFalse)
2541  {
2542  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2543  depth+1,beta,exception);
2544  FxReturn(sinh(alpha));
2545  }
2546  if (IsFxFunction(expression,"sin",3) != MagickFalse)
2547  {
2548  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2549  depth+1,beta,exception);
2550  FxReturn(sin(alpha));
2551  }
2552  if (IsFxFunction(expression,"sqrt",4) != MagickFalse)
2553  {
2554  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2555  depth+1,beta,exception);
2556  FxReturn(sqrt(alpha));
2557  }
2558  if (IsFxFunction(expression,"squish",6) != MagickFalse)
2559  {
2560  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,
2561  depth+1,beta,exception);
2562  FxReturn((1.0/(1.0+exp(-alpha))));
2563  }
2564  if (LocaleCompare(expression,"s") == 0)
2565  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2566  break;
2567  }
2568  case 'T':
2569  case 't':
2570  {
2571  if (IsFxFunction(expression,"tanh",4) != MagickFalse)
2572  {
2573  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2574  depth+1,beta,exception);
2575  FxReturn(tanh(alpha));
2576  }
2577  if (IsFxFunction(expression,"tan",3) != MagickFalse)
2578  {
2579  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2580  depth+1,beta,exception);
2581  FxReturn(tan(alpha));
2582  }
2583  if (LocaleCompare(expression,"Transparent") == 0)
2584  FxReturn(0.0);
2585  if (IsFxFunction(expression,"trunc",5) != MagickFalse)
2586  {
2587  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2588  depth+1,beta,exception);
2589  if (alpha >= 0.0)
2590  FxReturn(floor(alpha));
2591  FxReturn(ceil(alpha));
2592  }
2593  if (LocaleCompare(expression,"t") == 0)
2594  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2595  break;
2596  }
2597  case 'U':
2598  case 'u':
2599  {
2600  if (LocaleCompare(expression,"u") == 0)
2601  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2602  break;
2603  }
2604  case 'V':
2605  case 'v':
2606  {
2607  if (LocaleCompare(expression,"v") == 0)
2608  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2609  break;
2610  }
2611  case 'W':
2612  case 'w':
2613  {
2614  if (IsFxFunction(expression,"while",5) != MagickFalse)
2615  {
2616  size_t
2617  length;
2618 
2619  /*
2620  Parse while(condition,expression).
2621  */
2622  length=CopyMagickString(subexpression,expression+6,
2623  MagickPathExtent-1);
2624  if (length != 0)
2625  subexpression[length-1]='\0';
2626  FxParseConditional(subexpression,',',p,q);
2627  for (alpha=0.0; ; )
2628  {
2629  if (IsImageTTLExpired(fx_info->images) != MagickFalse)
2630  (void) ThrowMagickException(exception,GetMagickModule(),
2631  ResourceLimitFatalError,"TimeLimitExceeded","`%s'",
2632  fx_info->images->filename);
2633  gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
2634  exception);
2635  if (fabs(gamma) < MagickEpsilon)
2636  break;
2637  alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2638  exception);
2639  }
2640  FxReturn(alpha);
2641  }
2642  if (LocaleCompare(expression,"w") == 0)
2643  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2644  break;
2645  }
2646  case 'Y':
2647  case 'y':
2648  {
2649  if (LocaleCompare(expression,"y") == 0)
2650  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2651  break;
2652  }
2653  case 'Z':
2654  case 'z':
2655  {
2656  if (LocaleCompare(expression,"z") == 0)
2657  FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2658  break;
2659  }
2660  default:
2661  break;
2662  }
2663  q=(char *) expression;
2664  alpha=InterpretSiPrefixValue(expression,&q);
2665  if (q == expression)
2666  alpha=FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception);
2667  if (*q == ')')
2668  (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2669  "UnbalancedParenthesis","`%s'",expression);
2670  FxReturn(alpha);
2671 }
2672 
2673 MagickExport MagickBooleanType FxEvaluateExpression(FxInfo *fx_info,
2674  double *alpha,ExceptionInfo *exception)
2675 {
2676  MagickBooleanType
2677  status;
2678 
2679  status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
2680  return(status);
2681 }
2682 
2683 MagickExport MagickBooleanType FxPreprocessExpression(FxInfo *fx_info,
2684  double *alpha,ExceptionInfo *exception)
2685 {
2686  FILE
2687  *file;
2688 
2689  MagickBooleanType
2690  status;
2691 
2692  file=fx_info->file;
2693  fx_info->file=(FILE *) NULL;
2694  status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
2695  fx_info->file=file;
2696  return(status);
2697 }
2698 
2699 MagickExport MagickBooleanType FxEvaluateChannelExpression(FxInfo *fx_info,
2700  const ChannelType channel,const ssize_t x,const ssize_t y,double *alpha,
2701  ExceptionInfo *exception)
2702 {
2703  double
2704  beta;
2705 
2706  beta=0.0;
2707  *alpha=FxEvaluateSubexpression(fx_info,channel,x,y,fx_info->expression,0,
2708  &beta,exception);
2709  return(exception->severity == OptionError ? MagickFalse : MagickTrue);
2710 }
2711 
2712 /*
2713 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2714 % %
2715 % %
2716 % %
2717 % F x I m a g e %
2718 % %
2719 % %
2720 % %
2721 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2722 %
2723 % FxImage() applies a mathematical expression to the specified image.
2724 %
2725 % The format of the FxImage method is:
2726 %
2727 % Image *FxImage(const Image *image,const char *expression,
2728 % ExceptionInfo *exception)
2729 % Image *FxImageChannel(const Image *image,const ChannelType channel,
2730 % const char *expression,ExceptionInfo *exception)
2731 %
2732 % A description of each parameter follows:
2733 %
2734 % o image: the image.
2735 %
2736 % o channel: the channel.
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 **DestroyFxTLS(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 **AcquireFxTLS(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,~0UL,exception);
2788  for (i=0; i < (ssize_t) number_threads; i++)
2789  {
2790  MagickBooleanType
2791  status;
2792 
2793  fx_info[i]=AcquireFxInfo(image,fx_expression);
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=DestroyFxTLS(fx_info);
2803  return(fx_info);
2804 }
2805 
2806 MagickExport Image *FxImage(const Image *image,const char *expression,
2807  ExceptionInfo *exception)
2808 {
2809  Image
2810  *fx_image;
2811 
2812  fx_image=FxImageChannel(image,GrayChannel,expression,exception);
2813  return(fx_image);
2814 }
2815 
2816 MagickExport Image *FxImageChannel(const Image *image,const ChannelType channel,
2817  const char *expression,ExceptionInfo *exception)
2818 {
2819 #define FxImageTag "Fx/Image"
2820 
2821  CacheView
2822  *fx_view;
2823 
2824  FxInfo
2825  **magick_restrict fx_info;
2826 
2827  Image
2828  *fx_image;
2829 
2830  MagickBooleanType
2831  status;
2832 
2833  MagickOffsetType
2834  progress;
2835 
2836  ssize_t
2837  y;
2838 
2839  assert(image != (Image *) NULL);
2840  assert(image->signature == MagickCoreSignature);
2841  if (IsEventLogging() != MagickFalse)
2842  (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
2843  if (expression == (const char *) NULL)
2844  return(CloneImage(image,0,0,MagickTrue,exception));
2845  fx_info=AcquireFxTLS(image,expression,exception);
2846  if (fx_info == (FxInfo **) NULL)
2847  return((Image *) NULL);
2848  fx_image=CloneImage(image,0,0,MagickTrue,exception);
2849  if (fx_image == (Image *) NULL)
2850  {
2851  fx_info=DestroyFxTLS(fx_info);
2852  return((Image *) NULL);
2853  }
2854  if (SetImageStorageClass(fx_image,DirectClass) == MagickFalse)
2855  {
2856  InheritException(exception,&fx_image->exception);
2857  fx_info=DestroyFxTLS(fx_info);
2858  fx_image=DestroyImage(fx_image);
2859  return((Image *) NULL);
2860  }
2861  /*
2862  Fx image.
2863  */
2864  status=MagickTrue;
2865  progress=0;
2866  fx_view=AcquireAuthenticCacheView(fx_image,exception);
2867 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2868  #pragma omp parallel for schedule(dynamic) shared(progress,status) \
2869  magick_number_threads(image,fx_image,fx_image->rows, \
2870  GlobExpression(fx_info[0]->expression,"*debug(*",MagickTrue) == 0 ? 1 : 0)
2871 #endif
2872  for (y=0; y < (ssize_t) fx_image->rows; y++)
2873  {
2874  const int
2875  id = GetOpenMPThreadId();
2876 
2877  double
2878  alpha;
2879 
2880  IndexPacket
2881  *magick_restrict fx_indexes;
2882 
2883  ssize_t
2884  x;
2885 
2886  PixelPacket
2887  *magick_restrict q;
2888 
2889  if (status == MagickFalse)
2890  continue;
2891  q=GetCacheViewAuthenticPixels(fx_view,0,y,fx_image->columns,1,exception);
2892  if (q == (PixelPacket *) NULL)
2893  {
2894  status=MagickFalse;
2895  continue;
2896  }
2897  fx_indexes=GetCacheViewAuthenticIndexQueue(fx_view);
2898  alpha=0.0;
2899  for (x=0; x < (ssize_t) fx_image->columns; x++)
2900  {
2901  if ((channel & RedChannel) != 0)
2902  {
2903  (void) FxEvaluateChannelExpression(fx_info[id],RedChannel,x,y,
2904  &alpha,exception);
2905  SetPixelRed(q,ClampToQuantum((MagickRealType) QuantumRange*alpha));
2906  }
2907  if ((channel & GreenChannel) != 0)
2908  {
2909  (void) FxEvaluateChannelExpression(fx_info[id],GreenChannel,x,y,
2910  &alpha,exception);
2911  SetPixelGreen(q,ClampToQuantum((MagickRealType) QuantumRange*alpha));
2912  }
2913  if ((channel & BlueChannel) != 0)
2914  {
2915  (void) FxEvaluateChannelExpression(fx_info[id],BlueChannel,x,y,
2916  &alpha,exception);
2917  SetPixelBlue(q,ClampToQuantum((MagickRealType) QuantumRange*alpha));
2918  }
2919  if ((channel & OpacityChannel) != 0)
2920  {
2921  (void) FxEvaluateChannelExpression(fx_info[id],OpacityChannel,x,y,
2922  &alpha,exception);
2923  if (image->matte == MagickFalse)
2924  SetPixelOpacity(q,ClampToQuantum((MagickRealType) QuantumRange*
2925  alpha));
2926  else
2927  SetPixelOpacity(q,ClampToQuantum((MagickRealType) QuantumRange-
2928  (MagickRealType) QuantumRange*alpha));
2929  }
2930  if (((channel & IndexChannel) != 0) &&
2931  (fx_image->colorspace == CMYKColorspace))
2932  {
2933  (void) FxEvaluateChannelExpression(fx_info[id],IndexChannel,x,y,
2934  &alpha,exception);
2935  SetPixelIndex(fx_indexes+x,ClampToQuantum((MagickRealType)
2936  QuantumRange*alpha));
2937  }
2938  q++;
2939  }
2940  if (SyncCacheViewAuthenticPixels(fx_view,exception) == MagickFalse)
2941  status=MagickFalse;
2942  if (image->progress_monitor != (MagickProgressMonitor) NULL)
2943  {
2944  MagickBooleanType
2945  proceed;
2946 
2947 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2948  #pragma omp atomic
2949 #endif
2950  progress++;
2951  proceed=SetImageProgress(image,FxImageTag,progress,image->rows);
2952  if (proceed == MagickFalse)
2953  status=MagickFalse;
2954  }
2955  }
2956  fx_view=DestroyCacheView(fx_view);
2957  fx_info=DestroyFxTLS(fx_info);
2958  if (status == MagickFalse)
2959  fx_image=DestroyImage(fx_image);
2960  return(fx_image);
2961 }
Definition: image.h:133
Definition: fx.c:130