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