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