43 #include "magick/studio.h"
44 #include "magick/accelerate-private.h"
45 #include "magick/annotate.h"
46 #include "magick/artifact.h"
47 #include "magick/attribute.h"
48 #include "magick/cache.h"
49 #include "magick/cache-view.h"
50 #include "magick/channel.h"
51 #include "magick/color.h"
52 #include "magick/color-private.h"
53 #include "magick/colorspace.h"
54 #include "magick/colorspace-private.h"
55 #include "magick/composite.h"
56 #include "magick/decorate.h"
57 #include "magick/distort.h"
58 #include "magick/draw.h"
59 #include "magick/effect.h"
60 #include "magick/enhance.h"
61 #include "magick/exception.h"
62 #include "magick/exception-private.h"
63 #include "magick/fx.h"
64 #include "magick/fx-private.h"
65 #include "magick/gem.h"
66 #include "magick/geometry.h"
67 #include "magick/layer.h"
68 #include "magick/list.h"
69 #include "magick/log.h"
70 #include "magick/image.h"
71 #include "magick/image-private.h"
72 #include "magick/magick.h"
73 #include "magick/memory_.h"
74 #include "magick/memory-private.h"
75 #include "magick/monitor.h"
76 #include "magick/monitor-private.h"
77 #include "magick/opencl-private.h"
78 #include "magick/option.h"
79 #include "magick/pixel-accessor.h"
80 #include "magick/pixel-private.h"
81 #include "magick/property.h"
82 #include "magick/quantum.h"
83 #include "magick/quantum-private.h"
84 #include "magick/random_.h"
85 #include "magick/random-private.h"
86 #include "magick/resample.h"
87 #include "magick/resample-private.h"
88 #include "magick/resize.h"
89 #include "magick/resource_.h"
90 #include "magick/splay-tree.h"
91 #include "magick/statistic.h"
92 #include "magick/string_.h"
93 #include "magick/string-private.h"
94 #include "magick/thread-private.h"
95 #include "magick/threshold.h"
96 #include "magick/token.h"
97 #include "magick/transform.h"
98 #include "magick/utility.h"
105 BitwiseAndAssignmentOperator = 0xd9U,
106 BitwiseOrAssignmentOperator,
107 LeftShiftAssignmentOperator,
108 RightShiftAssignmentOperator,
109 PowerAssignmentOperator,
110 ModuloAssignmentOperator,
111 PlusAssignmentOperator,
112 SubtractAssignmentOperator,
113 MultiplyAssignmentOperator,
114 DivideAssignmentOperator,
115 IncrementAssignmentOperator,
116 DecrementAssignmentOperator,
119 LessThanEqualOperator,
120 GreaterThanEqualOperator,
177 MagickExport
FxInfo *AcquireFxInfo(
const Image *images,
const char *expression)
191 fx_info=(
FxInfo *) AcquireCriticalMemory(
sizeof(*fx_info));
192 (void) memset(fx_info,0,
sizeof(*fx_info));
193 fx_info->exception=AcquireExceptionInfo();
194 fx_info->images=images;
195 fx_info->colors=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
196 RelinquishMagickMemory);
197 fx_info->symbols=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
198 RelinquishMagickMemory);
199 fx_info->view=(
CacheView **) AcquireQuantumMemory(GetImageListLength(
200 fx_info->images),
sizeof(*fx_info->view));
201 if (fx_info->view == (
CacheView **) NULL)
202 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
204 next=GetFirstImageInList(fx_info->images);
205 for ( ; next != (
Image *) NULL; next=next->next)
207 fx_info->view[i]=AcquireVirtualCacheView(next,fx_info->exception);
210 fx_info->random_info=AcquireRandomInfo();
211 fx_info->expression=ConstantString(expression);
212 fx_info->file=stderr;
217 *fx_op=(
unsigned char) BitwiseAndAssignmentOperator;
218 (void) SubstituteString(&fx_info->expression,
"&=",(
char *) fx_op);
219 *fx_op=(
unsigned char) BitwiseOrAssignmentOperator;
220 (void) SubstituteString(&fx_info->expression,
"|=",(
char *) fx_op);
221 *fx_op=(
unsigned char) LeftShiftAssignmentOperator;
222 (void) SubstituteString(&fx_info->expression,
"<<=",(
char *) fx_op);
223 *fx_op=(
unsigned char) RightShiftAssignmentOperator;
224 (void) SubstituteString(&fx_info->expression,
">>=",(
char *) fx_op);
225 *fx_op=(
unsigned char) PowerAssignmentOperator;
226 (void) SubstituteString(&fx_info->expression,
"^=",(
char *) fx_op);
227 *fx_op=(
unsigned char) ModuloAssignmentOperator;
228 (void) SubstituteString(&fx_info->expression,
"%=",(
char *) fx_op);
229 *fx_op=(
unsigned char) PlusAssignmentOperator;
230 (void) SubstituteString(&fx_info->expression,
"+=",(
char *) fx_op);
231 *fx_op=(
unsigned char) SubtractAssignmentOperator;
232 (void) SubstituteString(&fx_info->expression,
"-=",(
char *) fx_op);
233 *fx_op=(
unsigned char) MultiplyAssignmentOperator;
234 (void) SubstituteString(&fx_info->expression,
"*=",(
char *) fx_op);
235 *fx_op=(
unsigned char) DivideAssignmentOperator;
236 (void) SubstituteString(&fx_info->expression,
"/=",(
char *) fx_op);
237 *fx_op=(
unsigned char) IncrementAssignmentOperator;
238 (void) SubstituteString(&fx_info->expression,
"++",(
char *) fx_op);
239 *fx_op=(
unsigned char) DecrementAssignmentOperator;
240 (void) SubstituteString(&fx_info->expression,
"--",(
char *) fx_op);
241 *fx_op=(
unsigned char) LeftShiftOperator;
242 (void) SubstituteString(&fx_info->expression,
"<<",(
char *) fx_op);
243 *fx_op=(
unsigned char) RightShiftOperator;
244 (void) SubstituteString(&fx_info->expression,
">>",(
char *) fx_op);
245 *fx_op=(
unsigned char) LessThanEqualOperator;
246 (void) SubstituteString(&fx_info->expression,
"<=",(
char *) fx_op);
247 *fx_op=(
unsigned char) GreaterThanEqualOperator;
248 (void) SubstituteString(&fx_info->expression,
">=",(
char *) fx_op);
249 *fx_op=(
unsigned char) EqualOperator;
250 (void) SubstituteString(&fx_info->expression,
"==",(
char *) fx_op);
251 *fx_op=(
unsigned char) NotEqualOperator;
252 (void) SubstituteString(&fx_info->expression,
"!=",(
char *) fx_op);
253 *fx_op=(
unsigned char) LogicalAndOperator;
254 (void) SubstituteString(&fx_info->expression,
"&&",(
char *) fx_op);
255 *fx_op=(
unsigned char) LogicalOrOperator;
256 (void) SubstituteString(&fx_info->expression,
"||",(
char *) fx_op);
257 *fx_op=(
unsigned char) ExponentialNotation;
258 (void) SubstituteString(&fx_info->expression,
"**",(
char *) fx_op);
262 (void) SubstituteString(&fx_info->expression,
"-",
"-1.0*");
263 (void) SubstituteString(&fx_info->expression,
"^-1.0*",
"^-");
264 (void) SubstituteString(&fx_info->expression,
"E-1.0*",
"E-");
265 (void) SubstituteString(&fx_info->expression,
"e-1.0*",
"e-");
266 (void) SubstituteString(&fx_info->expression,
" ",
"");
297 fx_info->exception=DestroyExceptionInfo(fx_info->exception);
298 fx_info->expression=DestroyString(fx_info->expression);
299 fx_info->symbols=DestroySplayTree(fx_info->symbols);
300 fx_info->colors=DestroySplayTree(fx_info->colors);
301 for (i=(ssize_t) GetImageListLength(fx_info->images)-1; i >= 0; i--)
302 fx_info->view[i]=DestroyCacheView(fx_info->view[i]);
303 fx_info->view=(
CacheView **) RelinquishMagickMemory(fx_info->view);
304 fx_info->random_info=DestroyRandomInfo(fx_info->random_info);
305 fx_info=(
FxInfo *) RelinquishMagickMemory(fx_info);
345 static inline const double *GetFxSymbolValue(
FxInfo *fx_info,
const char *symbol)
347 return((
const double *) GetValueFromSplayTree(fx_info->symbols,symbol));
350 static inline MagickBooleanType SetFxSymbolValue(
351 FxInfo *magick_restrict fx_info,
const char *magick_restrict symbol,
357 object=(
double *) GetValueFromSplayTree(fx_info->symbols,symbol);
358 if (
object != (
double *) NULL)
363 object=(
double *) AcquireMagickMemory(
sizeof(*
object));
364 if (
object == (
double *) NULL)
366 (void) ThrowMagickException(fx_info->exception,GetMagickModule(),
367 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
368 fx_info->images->filename);
372 return(AddValueToSplayTree(fx_info->symbols,ConstantString(symbol),object));
375 static double FxChannelStatistics(
FxInfo *fx_info,
const Image *image,
376 ChannelType channel,
const char *symbol,
ExceptionInfo *exception)
379 channel_symbol[MaxTextExtent],
391 for (p=symbol; (*p !=
'.') && (*p !=
'\0'); p++) ;
392 *channel_symbol=
'\0';
398 (void) CopyMagickString(channel_symbol,p+1,MaxTextExtent);
399 option=ParseCommandOption(MagickChannelOptions,MagickTrue,channel_symbol);
401 channel=(ChannelType) option;
403 (void) FormatLocaleString(key,MaxTextExtent,
"%p.%.20g.%s",(
void *) image,
404 (double) channel,symbol);
405 value=GetFxSymbolValue(fx_info,key);
406 if (value != (
const double *) NULL)
407 return(QuantumScale*(*value));
409 if (LocaleNCompare(symbol,
"depth",5) == 0)
414 depth=GetImageChannelDepth(image,channel,exception);
415 statistic=(double) depth;
417 if (LocaleNCompare(symbol,
"kurtosis",8) == 0)
423 (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
427 if (LocaleNCompare(symbol,
"maxima",6) == 0)
433 (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
436 if (LocaleNCompare(symbol,
"mean",4) == 0)
442 (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
446 if (LocaleNCompare(symbol,
"minima",6) == 0)
452 (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
455 if (LocaleNCompare(symbol,
"skewness",8) == 0)
461 (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
465 if (LocaleNCompare(symbol,
"standard_deviation",18) == 0)
471 (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
473 statistic=standard_deviation;
475 if (SetFxSymbolValue(fx_info,key,statistic) == MagickFalse)
477 return(QuantumScale*statistic);
481 FxEvaluateSubexpression(
FxInfo *,
const ChannelType,
const ssize_t,
482 const ssize_t,
const char *,
const size_t,
double *,
ExceptionInfo *);
484 static inline MagickBooleanType IsFxFunction(
const char *expression,
485 const char *name,
const size_t length)
493 for (i=0; i <= length; i++)
494 if (expression[i] ==
'\0')
496 c=expression[length];
497 if ((LocaleNCompare(expression,name,length) == 0) &&
498 ((isspace((
int) ((
unsigned char) c)) == 0) || (c ==
'(')))
503 static inline double FxGCD(
const double alpha,
const double beta,
506 #define FxMaxFunctionDepth 200
509 return(FxGCD(beta,alpha,depth+1));
510 if ((fabs(beta) < 0.001) || (depth >= FxMaxFunctionDepth))
512 return(FxGCD(beta,alpha-beta*floor(alpha/beta),depth+1));
515 static inline const char *FxSubexpression(
const char *expression,
525 subexpression=expression;
526 while ((*subexpression !=
'\0') &&
527 ((level != 1) || (strchr(
")",(
int) *subexpression) == (
char *) NULL)))
529 if (strchr(
"(",(
int) *subexpression) != (
char *) NULL)
532 if (strchr(
")",(
int) *subexpression) != (
char *) NULL)
536 if (*subexpression ==
'\0')
537 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
538 "UnbalancedParenthesis",
"`%s'",expression);
539 return(subexpression);
542 static double FxGetSymbol(
FxInfo *fx_info,
const ChannelType channel,
543 const ssize_t x,
const ssize_t y,
const char *expression,
const size_t depth,
548 symbol[MaxTextExtent];
580 i=GetImageIndexInList(fx_info->images);
584 if (isalpha((
int) ((
unsigned char) *(p+1))) == 0)
589 subexpression=AcquireString(expression);
590 if (strchr(
"suv",(
int) *p) != (
char *) NULL)
597 i=GetImageIndexInList(fx_info->images);
600 case 'u': i=0;
break;
601 case 'v': i=1;
break;
608 for (p++; *p !=
'\0'; )
622 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
623 depth,&beta,exception);
631 if ((*p ==
'p') && (isalpha((
int) ((
unsigned char) *(p+1))) == 0))
638 for (p++; *p !=
'\0'; )
652 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
653 depth,&beta,exception);
664 for (p++; *p !=
'\0'; )
678 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
679 depth,&beta,exception);
688 subexpression=DestroyString(subexpression);
690 image=GetImageFromList(fx_info->images,i);
691 if (image == (
Image *) NULL)
693 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
694 "NoSuchImage",
"`%s'",expression);
697 i=GetImageIndexInList(image);
698 GetMagickPixelPacket(image,&pixel);
699 status=InterpolateMagickPixelPacket(image,fx_info->view[i],image->interpolate,
700 point.x,point.y,&pixel,exception);
702 if ((*p !=
'\0') && (*(p+1) !=
'\0') && (*(p+2) !=
'\0') &&
703 (LocaleCompare(p,
"intensity") != 0) && (LocaleCompare(p,
"luma") != 0) &&
704 (LocaleCompare(p,
"luminance") != 0) && (LocaleCompare(p,
"hue") != 0) &&
705 (LocaleCompare(p,
"saturation") != 0) &&
706 (LocaleCompare(p,
"lightness") != 0))
714 (void) CopyMagickString(name,p,MaxTextExtent);
716 for (q=name+length-1; q > name; q--)
727 if ((*q !=
'\0') && (*(q+1) !=
'\0') && (*(q+2) !=
'\0') &&
728 (GetFxSymbolValue(fx_info,name) == (
const double *) NULL))
741 if (QueryMagickColor(name,&pixel,fx_info->exception) != MagickFalse)
743 (void) AddValueToSplayTree(fx_info->colors,ConstantString(name),
744 CloneMagickPixelPacket(&pixel));
749 (void) CopyMagickString(symbol,p,MaxTextExtent);
755 case RedChannel:
return(QuantumScale*pixel.red);
756 case GreenChannel:
return(QuantumScale*pixel.green);
757 case BlueChannel:
return(QuantumScale*pixel.blue);
763 if (pixel.matte == MagickFalse)
765 alpha=(double) (QuantumScale*GetPixelAlpha(&pixel));
770 if (image->colorspace != CMYKColorspace)
772 (void) ThrowMagickException(exception,GetMagickModule(),
773 ImageError,
"ColorSeparatedImageRequired",
"`%s'",
777 return(QuantumScale*pixel.index);
779 case DefaultChannels:
780 return(QuantumScale*GetMagickPixelIntensity(image,&pixel));
784 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
785 "UnableToParseExpression",
"`%s'",p);
793 if (LocaleCompare(symbol,
"a") == 0)
794 return((
double) (QuantumScale*GetPixelAlpha(&pixel)));
800 if (LocaleCompare(symbol,
"b") == 0)
801 return(QuantumScale*pixel.blue);
807 if (IsFxFunction(symbol,
"channel",7) != MagickFalse)
815 flags=ParseGeometry(symbol+7,&channel_info);
816 if (image->colorspace == CMYKColorspace)
821 if ((flags & RhoValue) == 0)
823 return(channel_info.rho);
827 if ((flags & SigmaValue) == 0)
829 return(channel_info.sigma);
833 if ((flags & XiValue) == 0)
835 return(channel_info.xi);
839 if ((flags & PsiValue) == 0)
841 return(channel_info.psi);
845 if ((flags & ChiValue) == 0)
847 return(channel_info.chi);
856 if ((flags & RhoValue) == 0)
858 return(channel_info.rho);
862 if ((flags & SigmaValue) == 0)
864 return(channel_info.sigma);
868 if ((flags & XiValue) == 0)
870 return(channel_info.xi);
874 if ((flags & PsiValue) == 0)
876 return(channel_info.psi);
880 if ((flags & ChiValue) == 0)
882 return(channel_info.chi);
888 if (LocaleCompare(symbol,
"c") == 0)
889 return(QuantumScale*pixel.red);
895 if (LocaleNCompare(symbol,
"depth",5) == 0)
896 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
902 if (LocaleCompare(symbol,
"extent") == 0)
904 if (image->extent != 0)
905 return((
double) image->extent);
906 return((
double) GetBlobSize(image));
913 if (LocaleCompare(symbol,
"g") == 0)
914 return(QuantumScale*pixel.green);
920 if (LocaleNCompare(symbol,
"kurtosis",8) == 0)
921 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
922 if (LocaleCompare(symbol,
"k") == 0)
924 if (image->colorspace != CMYKColorspace)
926 (void) ThrowMagickException(exception,GetMagickModule(),
927 OptionError,
"ColorSeparatedImageRequired",
"`%s'",
931 return(QuantumScale*pixel.index);
938 if (LocaleCompare(symbol,
"h") == 0)
939 return((
double) image->rows);
940 if (LocaleCompare(symbol,
"hue") == 0)
947 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
948 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
956 if ((LocaleCompare(symbol,
"image.depth") == 0) ||
957 (LocaleCompare(symbol,
"image.minima") == 0) ||
958 (LocaleCompare(symbol,
"image.maxima") == 0) ||
959 (LocaleCompare(symbol,
"image.mean") == 0) ||
960 (LocaleCompare(symbol,
"image.kurtosis") == 0) ||
961 (LocaleCompare(symbol,
"image.skewness") == 0) ||
962 (LocaleCompare(symbol,
"image.standard_deviation") == 0))
963 return(FxChannelStatistics(fx_info,image,channel,symbol+6,exception));
964 if (LocaleCompare(symbol,
"image.resolution.x") == 0)
965 return(image->x_resolution);
966 if (LocaleCompare(symbol,
"image.resolution.y") == 0)
967 return(image->y_resolution);
968 if (LocaleCompare(symbol,
"intensity") == 0)
969 return(QuantumScale*GetMagickPixelIntensity(image,&pixel));
970 if (LocaleCompare(symbol,
"i") == 0)
977 if (LocaleCompare(symbol,
"j") == 0)
984 if (LocaleCompare(symbol,
"lightness") == 0)
991 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
992 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
995 if (LocaleCompare(symbol,
"luma") == 0)
1000 luma=0.212656*pixel.red+0.715158*pixel.green+0.072186*pixel.blue;
1001 return(QuantumScale*luma);
1003 if (LocaleCompare(symbol,
"luminance") == 0)
1008 luminance=0.212656*pixel.red+0.715158*pixel.green+0.072186*pixel.blue;
1009 return(QuantumScale*luminance);
1016 if (LocaleNCompare(symbol,
"maxima",6) == 0)
1017 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1018 if (LocaleNCompare(symbol,
"mean",4) == 0)
1019 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1020 if (LocaleNCompare(symbol,
"minima",6) == 0)
1021 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1022 if (LocaleCompare(symbol,
"m") == 0)
1023 return(QuantumScale*pixel.green);
1029 if (LocaleCompare(symbol,
"n") == 0)
1030 return((
double) GetImageListLength(fx_info->images));
1036 if (LocaleCompare(symbol,
"o") == 0)
1037 return(QuantumScale*pixel.opacity);
1043 if (LocaleCompare(symbol,
"page.height") == 0)
1044 return((
double) image->page.height);
1045 if (LocaleCompare(symbol,
"page.width") == 0)
1046 return((
double) image->page.width);
1047 if (LocaleCompare(symbol,
"page.x") == 0)
1048 return((
double) image->page.x);
1049 if (LocaleCompare(symbol,
"page.y") == 0)
1050 return((
double) image->page.y);
1051 if (LocaleCompare(symbol,
"printsize.x") == 0)
1052 return(PerceptibleReciprocal(image->x_resolution)*image->columns);
1053 if (LocaleCompare(symbol,
"printsize.y") == 0)
1054 return(PerceptibleReciprocal(image->y_resolution)*image->rows);
1060 if (LocaleCompare(symbol,
"quality") == 0)
1061 return((
double) image->quality);
1067 if (LocaleCompare(symbol,
"resolution.x") == 0)
1068 return(image->x_resolution);
1069 if (LocaleCompare(symbol,
"resolution.y") == 0)
1070 return(image->y_resolution);
1071 if (LocaleCompare(symbol,
"r") == 0)
1072 return(QuantumScale*pixel.red);
1078 if (LocaleCompare(symbol,
"saturation") == 0)
1085 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
1086 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
1089 if (LocaleNCompare(symbol,
"skewness",8) == 0)
1090 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1091 if (LocaleNCompare(symbol,
"standard_deviation",18) == 0)
1092 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1098 if (LocaleCompare(symbol,
"t") == 0)
1099 return((
double) GetImageIndexInList(fx_info->images));
1105 if (LocaleCompare(symbol,
"w") == 0)
1106 return((
double) image->columns);
1112 if (LocaleCompare(symbol,
"y") == 0)
1113 return(QuantumScale*pixel.blue);
1119 if (LocaleCompare(symbol,
"z") == 0)
1124 depth=(double) GetImageChannelDepth(image,channel,fx_info->exception);
1132 value=GetFxSymbolValue(fx_info,symbol);
1133 if (value != (
const double *) NULL)
1135 artifact=GetImageArtifact(image,symbol);
1136 if (artifact != (
const char *) NULL)
1137 return(StringToDouble(artifact,(
char **) NULL));
1138 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1139 "UndefinedVariable",
"`%s'",symbol);
1140 (void) SetFxSymbolValue(fx_info,symbol,0.0);
1144 static const char *FxOperatorPrecedence(
const char *expression,
1149 UndefinedPrecedence,
1151 BitwiseComplementPrecedence,
1153 ExponentialNotationPrecedence,
1157 RelationalPrecedence,
1158 EquivalencyPrecedence,
1159 BitwiseAndPrecedence,
1160 BitwiseOrPrecedence,
1161 LogicalAndPrecedence,
1162 LogicalOrPrecedence,
1164 AssignmentPrecedence,
1184 subexpression=(
const char *) NULL;
1185 target=NullPrecedence;
1186 while ((c !=
'\0') && (*expression !=
'\0'))
1188 precedence=UndefinedPrecedence;
1189 if ((isspace((
int) ((
unsigned char) *expression)) != 0) || (c == (int)
'@'))
1194 switch (*expression)
1199 #if defined(MAGICKCORE_HAVE_ACOSH)
1200 if (IsFxFunction(expression,
"acosh",5) != MagickFalse)
1206 #if defined(MAGICKCORE_HAVE_ASINH)
1207 if (IsFxFunction(expression,
"asinh",5) != MagickFalse)
1213 #if defined(MAGICKCORE_HAVE_ATANH)
1214 if (IsFxFunction(expression,
"atanh",5) != MagickFalse)
1220 if (IsFxFunction(expression,
"atan2",5) != MagickFalse)
1230 if ((isdigit((
int) ((
unsigned char) c)) != 0) &&
1231 ((LocaleNCompare(expression,
"E+",2) == 0) ||
1232 (LocaleNCompare(expression,
"E-",2) == 0)))
1242 if ((IsFxFunction(expression,
"j0",2) != MagickFalse) ||
1243 (IsFxFunction(expression,
"j1",2) != MagickFalse))
1252 while (isxdigit((
int) ((
unsigned char) *(expression+1))) != 0)
1259 if ((c == (
int)
'{') || (c == (
int)
'['))
1262 if ((c == (
int)
'}') || (c == (
int)
']'))
1265 switch ((
unsigned char) *expression)
1270 precedence=BitwiseComplementPrecedence;
1276 precedence=ExponentPrecedence;
1281 if (((c != 0) && ((isdigit((
int) ((
unsigned char) c)) != 0) ||
1282 (strchr(
")",c) != (
char *) NULL))) &&
1283 (((islower((
int) ((
unsigned char) *expression)) != 0) ||
1284 (strchr(
"(",(
int) ((
unsigned char) *expression)) != (
char *) NULL)) ||
1285 ((isdigit((
int) ((
unsigned char) c)) == 0) &&
1286 (isdigit((
int) ((
unsigned char) *expression)) != 0))) &&
1287 (strchr(
"xy",(
int) ((
unsigned char) *expression)) == (
char *) NULL))
1288 precedence=MultiplyPrecedence;
1295 precedence=MultiplyPrecedence;
1301 if ((strchr(
"(+-/*%:&^|<>~,",c) == (
char *) NULL) ||
1302 (isalpha((
int) ((
unsigned char) c)) != 0))
1303 precedence=AdditionPrecedence;
1306 case BitwiseAndAssignmentOperator:
1307 case BitwiseOrAssignmentOperator:
1308 case LeftShiftAssignmentOperator:
1309 case RightShiftAssignmentOperator:
1310 case PowerAssignmentOperator:
1311 case ModuloAssignmentOperator:
1312 case PlusAssignmentOperator:
1313 case SubtractAssignmentOperator:
1314 case MultiplyAssignmentOperator:
1315 case DivideAssignmentOperator:
1316 case IncrementAssignmentOperator:
1317 case DecrementAssignmentOperator:
1319 precedence=AssignmentPrecedence;
1322 case LeftShiftOperator:
1323 case RightShiftOperator:
1325 precedence=ShiftPrecedence;
1329 case LessThanEqualOperator:
1330 case GreaterThanEqualOperator:
1333 precedence=RelationalPrecedence;
1337 case NotEqualOperator:
1339 precedence=EquivalencyPrecedence;
1344 precedence=BitwiseAndPrecedence;
1349 precedence=BitwiseOrPrecedence;
1352 case LogicalAndOperator:
1354 precedence=LogicalAndPrecedence;
1357 case LogicalOrOperator:
1359 precedence=LogicalOrPrecedence;
1362 case ExponentialNotation:
1364 precedence=ExponentialNotationPrecedence;
1370 precedence=TernaryPrecedence;
1375 precedence=AssignmentPrecedence;
1380 precedence=CommaPrecedence;
1385 precedence=SeparatorPrecedence;
1389 if ((precedence == BitwiseComplementPrecedence) ||
1390 (precedence == TernaryPrecedence) ||
1391 (precedence == AssignmentPrecedence))
1393 if (precedence > target)
1399 subexpression=expression;
1403 if (precedence >= target)
1409 subexpression=expression;
1411 if (strchr(
"(",(
int) *expression) != (
char *) NULL)
1412 expression=FxSubexpression(expression,exception);
1413 c=(int) (*expression++);
1415 return(subexpression);
1418 static double FxEvaluateSubexpression(
FxInfo *fx_info,
const ChannelType channel,
1419 const ssize_t x,
const ssize_t y,
const char *expression,
const size_t depth,
1422 #define FxMaxParenthesisDepth 58
1423 #define FxMaxSubexpressionDepth 200
1424 #define FxReturn(value) \
1426 subexpression=DestroyString(subexpression); \
1429 #define FxParseConditional(subexpression,sentinal,p,q) \
1432 for (q=(char *) p; (*q != (sentinal)) && (*q != '\0'); q++) \
1435 for (q++; (*q != ')') && (*q != '\0'); q++); \
1441 (void) ThrowMagickException(exception,GetMagickModule(), \
1442 OptionError,"UnableToParseExpression","`%s'",subexpression); \
1445 if (strlen(q) == 1) \
1465 subexpression=AcquireString(expression);
1466 *subexpression=
'\0';
1467 if (depth > FxMaxSubexpressionDepth)
1469 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1470 "UnableToParseExpression",
"`%s'",expression);
1473 if (exception->severity >= ErrorException)
1475 while (isspace((
int) ((
unsigned char) *expression)) != 0)
1477 if (*expression ==
'\0')
1479 p=FxOperatorPrecedence(expression,exception);
1480 if (p != (
const char *) NULL)
1482 (void) CopyMagickString(subexpression,expression,(
size_t)
1484 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,depth+1,
1486 switch ((
unsigned char) *p)
1490 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1492 *beta=(double) (~(
size_t) *beta);
1497 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1499 FxReturn(*beta == 0.0 ? 1.0 : 0.0);
1503 *beta=pow(alpha,FxEvaluateSubexpression(fx_info,channel,x,y,++p,
1504 depth+1,beta,exception));
1508 case ExponentialNotation:
1510 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1512 FxReturn(alpha*(*beta));
1516 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1518 FxReturn(PerceptibleReciprocal(*beta)*alpha);
1522 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1524 FxReturn(fmod(alpha,*beta));
1528 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1530 FxReturn(alpha+(*beta));
1534 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1536 FxReturn(alpha-(*beta));
1538 case BitwiseAndAssignmentOperator:
1541 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1545 (void) ThrowMagickException(exception,GetMagickModule(),
1546 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1549 ClearMagickException(exception);
1550 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1552 value=(double) ((
size_t) (alpha+0.5) & (size_t) (*beta+0.5));
1553 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1557 case BitwiseOrAssignmentOperator:
1560 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1564 (void) ThrowMagickException(exception,GetMagickModule(),
1565 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1568 ClearMagickException(exception);
1569 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1571 value=(double) ((
size_t) (alpha+0.5) | (size_t) (*beta+0.5));
1572 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1576 case LeftShiftAssignmentOperator:
1579 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1583 (void) ThrowMagickException(exception,GetMagickModule(),
1584 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1587 ClearMagickException(exception);
1588 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1590 if ((
size_t) (*beta+0.5) >= (8*
sizeof(
size_t)))
1592 (void) ThrowMagickException(exception,GetMagickModule(),
1593 OptionError,
"ShiftCountOverflow",
"`%s'",subexpression);
1596 value=(double) ((
size_t) (alpha+0.5) << (size_t) (*beta+0.5));
1597 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1601 case RightShiftAssignmentOperator:
1604 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1608 (void) ThrowMagickException(exception,GetMagickModule(),
1609 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1612 ClearMagickException(exception);
1613 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1615 if ((
size_t) (*beta+0.5) >= (8*
sizeof(
size_t)))
1617 (void) ThrowMagickException(exception,GetMagickModule(),
1618 OptionError,
"ShiftCountOverflow",
"`%s'",subexpression);
1621 value=(double) ((
size_t) (alpha+0.5) >> (size_t) (*beta+0.5));
1622 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1626 case PowerAssignmentOperator:
1629 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1633 (void) ThrowMagickException(exception,GetMagickModule(),
1634 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1637 ClearMagickException(exception);
1638 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1640 value=pow(alpha,*beta);
1641 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1645 case ModuloAssignmentOperator:
1648 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1652 (void) ThrowMagickException(exception,GetMagickModule(),
1653 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1656 ClearMagickException(exception);
1657 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1659 value=fmod(alpha,*beta);
1660 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1664 case PlusAssignmentOperator:
1667 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1671 (void) ThrowMagickException(exception,GetMagickModule(),
1672 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1675 ClearMagickException(exception);
1676 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1678 value=alpha+(*beta);
1679 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1683 case SubtractAssignmentOperator:
1686 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1690 (void) ThrowMagickException(exception,GetMagickModule(),
1691 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1694 ClearMagickException(exception);
1695 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1697 value=alpha-(*beta);
1698 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1702 case MultiplyAssignmentOperator:
1705 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1709 (void) ThrowMagickException(exception,GetMagickModule(),
1710 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1713 ClearMagickException(exception);
1714 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1716 value=alpha*(*beta);
1717 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1721 case DivideAssignmentOperator:
1724 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1728 (void) ThrowMagickException(exception,GetMagickModule(),
1729 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1732 ClearMagickException(exception);
1733 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1735 value=alpha*PerceptibleReciprocal(*beta);
1736 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1740 case IncrementAssignmentOperator:
1742 if (*subexpression ==
'\0')
1743 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1746 if (*subexpression ==
'\0')
1748 if (SetFxSymbolValue(fx_info,p,value) == MagickFalse)
1752 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1756 case DecrementAssignmentOperator:
1758 if (*subexpression ==
'\0')
1759 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1762 if (*subexpression ==
'\0')
1764 if (SetFxSymbolValue(fx_info,p,value) == MagickFalse)
1768 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1772 case LeftShiftOperator:
1774 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1776 if ((
size_t) (gamma+0.5) >= (8*
sizeof(
size_t)))
1778 (void) ThrowMagickException(exception,GetMagickModule(),
1779 OptionError,
"ShiftCountOverflow",
"`%s'",subexpression);
1782 *beta=(double) ((
size_t) (alpha+0.5) << (size_t) (gamma+0.5));
1785 case RightShiftOperator:
1787 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1789 if ((
size_t) (gamma+0.5) >= (8*
sizeof(
size_t)))
1791 (void) ThrowMagickException(exception,GetMagickModule(),
1792 OptionError,
"ShiftCountOverflow",
"`%s'",subexpression);
1795 *beta=(double) ((
size_t) (alpha+0.5) >> (size_t) (gamma+0.5));
1800 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1802 FxReturn(alpha < *beta ? 1.0 : 0.0);
1804 case LessThanEqualOperator:
1806 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1808 FxReturn(alpha <= *beta ? 1.0 : 0.0);
1812 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1814 FxReturn(alpha > *beta ? 1.0 : 0.0);
1816 case GreaterThanEqualOperator:
1818 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1820 FxReturn(alpha >= *beta ? 1.0 : 0.0);
1824 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1826 FxReturn(fabs(alpha-(*beta)) < MagickEpsilon ? 1.0 : 0.0);
1828 case NotEqualOperator:
1830 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1832 FxReturn(fabs(alpha-(*beta)) >= MagickEpsilon ? 1.0 : 0.0);
1836 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1838 *beta=(double) ((
size_t) (alpha+0.5) & (size_t) (gamma+0.5));
1843 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1845 *beta=(double) ((
size_t) (alpha+0.5) | (size_t) (gamma+0.5));
1848 case LogicalAndOperator:
1856 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1858 *beta=(gamma > 0.0) ? 1.0 : 0.0;
1861 case LogicalOrOperator:
1869 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1871 *beta=(gamma > 0.0) ? 1.0 : 0.0;
1879 (void) CopyMagickString(subexpression,++p,MaxTextExtent-1);
1880 FxParseConditional(subexpression,
':',p,q);
1881 if (fabs(alpha) >= MagickEpsilon)
1882 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1885 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
1892 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1896 (void) ThrowMagickException(exception,GetMagickModule(),
1897 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1900 ClearMagickException(exception);
1901 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1904 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1910 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1916 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1924 gamma=alpha*FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,
1930 if (strchr(
"(",(
int) *expression) != (
char *) NULL)
1935 if (depth >= FxMaxParenthesisDepth)
1936 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1937 "ParenthesisNestedTooDeeply",
"`%s'",expression);
1938 length=CopyMagickString(subexpression,expression+1,MaxTextExtent);
1940 subexpression[length-1]=
'\0';
1941 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,depth+1,
1945 switch (*expression)
1949 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1951 FxReturn(1.0*gamma);
1955 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1957 FxReturn(-1.0*gamma);
1961 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1963 FxReturn((
double) (~(
size_t) (gamma+0.5)));
1968 if (IsFxFunction(expression,
"abs",3) != MagickFalse)
1970 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
1971 depth+1,beta,exception);
1972 FxReturn(fabs(alpha));
1974 #if defined(MAGICKCORE_HAVE_ACOSH)
1975 if (IsFxFunction(expression,
"acosh",5) != MagickFalse)
1977 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
1978 depth+1,beta,exception);
1979 FxReturn(acosh(alpha));
1982 if (IsFxFunction(expression,
"acos",4) != MagickFalse)
1984 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
1985 depth+1,beta,exception);
1986 FxReturn(acos(alpha));
1988 #if defined(MAGICKCORE_HAVE_J1)
1989 if (IsFxFunction(expression,
"airy",4) != MagickFalse)
1991 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
1992 depth+1,beta,exception);
1995 gamma=2.0*j1((MagickPI*alpha))/(MagickPI*alpha);
1996 FxReturn(gamma*gamma);
1999 #if defined(MAGICKCORE_HAVE_ASINH)
2000 if (IsFxFunction(expression,
"asinh",5) != MagickFalse)
2002 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2003 depth+1,beta,exception);
2004 FxReturn(asinh(alpha));
2007 if (IsFxFunction(expression,
"asin",4) != MagickFalse)
2009 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2010 depth+1,beta,exception);
2011 FxReturn(asin(alpha));
2013 if (IsFxFunction(expression,
"alt",3) != MagickFalse)
2015 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2016 depth+1,beta,exception);
2017 FxReturn(((ssize_t) alpha) & 0x01 ? -1.0 : 1.0);
2019 if (IsFxFunction(expression,
"atan2",5) != MagickFalse)
2021 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2022 depth+1,beta,exception);
2023 FxReturn(atan2(alpha,*beta));
2025 #if defined(MAGICKCORE_HAVE_ATANH)
2026 if (IsFxFunction(expression,
"atanh",5) != MagickFalse)
2028 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2029 depth+1,beta,exception);
2030 FxReturn(atanh(alpha));
2033 if (IsFxFunction(expression,
"atan",4) != MagickFalse)
2035 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2036 depth+1,beta,exception);
2037 FxReturn(atan(alpha));
2039 if (LocaleCompare(expression,
"a") == 0)
2040 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2046 if (LocaleCompare(expression,
"b") == 0)
2047 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2053 if (IsFxFunction(expression,
"ceil",4) != MagickFalse)
2055 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2056 depth+1,beta,exception);
2057 FxReturn(ceil(alpha));
2059 if (IsFxFunction(expression,
"clamp",5) != MagickFalse)
2061 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2062 depth+1,beta,exception);
2069 if (IsFxFunction(expression,
"cosh",4) != MagickFalse)
2071 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2072 depth+1,beta,exception);
2073 FxReturn(cosh(alpha));
2075 if (IsFxFunction(expression,
"cos",3) != MagickFalse)
2077 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2078 depth+1,beta,exception);
2079 FxReturn(cos(alpha));
2081 if (LocaleCompare(expression,
"c") == 0)
2082 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2088 if (IsFxFunction(expression,
"debug",5) != MagickFalse)
2096 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2097 depth+1,beta,exception);
2098 switch (fx_info->images->colorspace)
2100 case CMYKColorspace:
2104 case CyanChannel: type=
"cyan";
break;
2105 case MagentaChannel: type=
"magenta";
break;
2106 case YellowChannel: type=
"yellow";
break;
2107 case AlphaChannel: type=
"alpha";
break;
2108 case BlackChannel: type=
"black";
break;
2109 default: type=
"unknown";
break;
2113 case GRAYColorspace:
2117 case RedChannel: type=
"gray";
break;
2118 case AlphaChannel: type=
"alpha";
break;
2119 default: type=
"unknown";
break;
2127 case RedChannel: type=
"red";
break;
2128 case GreenChannel: type=
"green";
break;
2129 case BlueChannel: type=
"blue";
break;
2130 case AlphaChannel: type=
"alpha";
break;
2131 default: type=
"unknown";
break;
2136 *subexpression=
'\0';
2138 if (strlen(expression) > 6)
2139 length=CopyMagickString(subexpression,expression+6,MaxTextExtent);
2141 subexpression[length-1]=
'\0';
2142 if (fx_info->file != (FILE *) NULL)
2143 (void) FormatLocaleFile(fx_info->file,
2144 "%s[%.20g,%.20g].%s: %s=%.*g\n",fx_info->images->filename,
2145 (
double) x,(double) y,type,subexpression,GetMagickPrecision(),
2149 if (IsFxFunction(expression,
"do",2) != MagickFalse)
2157 length=CopyMagickString(subexpression,expression+6,
2158 MagickPathExtent-1);
2160 subexpression[length-1]=
'\0';
2161 FxParseConditional(subexpression,
',',p,q);
2164 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2166 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2168 if (fabs(gamma) < MagickEpsilon)
2173 if (IsFxFunction(expression,
"drc",3) != MagickFalse)
2175 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2176 depth+1,beta,exception);
2177 FxReturn(alpha*PerceptibleReciprocal(*beta*(alpha-1.0)+1.0));
2184 if (LocaleCompare(expression,
"epsilon") == 0)
2185 FxReturn(MagickEpsilon);
2186 #if defined(MAGICKCORE_HAVE_ERF)
2187 if (IsFxFunction(expression,
"erf",3) != MagickFalse)
2189 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2190 depth+1,beta,exception);
2191 FxReturn(erf(alpha));
2194 if (IsFxFunction(expression,
"exp",3) != MagickFalse)
2196 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2197 depth+1,beta,exception);
2198 FxReturn(exp(alpha));
2200 if (LocaleCompare(expression,
"e") == 0)
2201 FxReturn(2.7182818284590452354);
2207 if (IsFxFunction(expression,
"floor",5) != MagickFalse)
2209 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2210 depth+1,beta,exception);
2211 FxReturn(floor(alpha));
2213 if (IsFxFunction(expression,
"for",3) != MagickFalse)
2224 length=CopyMagickString(subexpression,expression+4,
2225 MagickPathExtent-1);
2227 subexpression[length-1]=
'\0';
2228 FxParseConditional(subexpression,
',',p,q);
2229 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2231 (void) CopyMagickString(subexpression,q+1,MagickPathExtent-1);
2232 FxParseConditional(subexpression,
',',p,q);
2235 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2237 if (fabs(gamma) < MagickEpsilon)
2239 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2249 if (IsFxFunction(expression,
"gauss",5) != MagickFalse)
2251 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2252 depth+1,beta,exception);
2253 FxReturn(exp((-alpha*alpha/2.0))/sqrt(2.0*MagickPI));
2255 if (IsFxFunction(expression,
"gcd",3) != MagickFalse)
2260 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2261 depth+1,beta,exception);
2264 gcd=FxGCD(alpha,*beta,0);
2267 if (LocaleCompare(expression,
"g") == 0)
2268 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2274 if (LocaleCompare(expression,
"h") == 0)
2275 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2276 if (LocaleCompare(expression,
"hue") == 0)
2277 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2278 if (IsFxFunction(expression,
"hypot",5) != MagickFalse)
2280 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2281 depth+1,beta,exception);
2282 FxReturn(hypot(alpha,*beta));
2289 if (LocaleCompare(expression,
"k") == 0)
2290 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2296 if (IsFxFunction(expression,
"if",2) != MagickFalse)
2307 length=CopyMagickString(subexpression,expression+3,
2308 MagickPathExtent-1);
2310 subexpression[length-1]=
'\0';
2311 FxParseConditional(subexpression,
',',p,q);
2312 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2314 (void) CopyMagickString(subexpression,q+1,MagickPathExtent-1);
2315 FxParseConditional(subexpression,
',',p,q);
2316 if (fabs(alpha) >= MagickEpsilon)
2317 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
2320 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2324 if (LocaleCompare(expression,
"intensity") == 0)
2325 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2326 if (IsFxFunction(expression,
"int",3) != MagickFalse)
2328 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2329 depth+1,beta,exception);
2330 FxReturn(floor(alpha));
2332 if (IsFxFunction(expression,
"isnan",5) != MagickFalse)
2334 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2335 depth+1,beta,exception);
2336 FxReturn((
double) !!IsNaN(alpha));
2338 if (LocaleCompare(expression,
"i") == 0)
2339 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2345 if (LocaleCompare(expression,
"j") == 0)
2346 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2347 #if defined(MAGICKCORE_HAVE_J0)
2348 if (IsFxFunction(expression,
"j0",2) != MagickFalse)
2350 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2351 depth+1,beta,exception);
2352 FxReturn(j0(alpha));
2355 #if defined(MAGICKCORE_HAVE_J1)
2356 if (IsFxFunction(expression,
"j1",2) != MagickFalse)
2358 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2359 depth+1,beta,exception);
2360 FxReturn(j1(alpha));
2363 #if defined(MAGICKCORE_HAVE_J1)
2364 if (IsFxFunction(expression,
"jinc",4) != MagickFalse)
2366 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2367 depth+1,beta,exception);
2370 FxReturn((2.0*j1((MagickPI*alpha))/(MagickPI*alpha)));
2378 if (IsFxFunction(expression,
"ln",2) != MagickFalse)
2380 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2381 depth+1,beta,exception);
2382 FxReturn(log(alpha));
2384 if (IsFxFunction(expression,
"logtwo",6) != MagickFalse)
2386 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,
2387 depth+1,beta,exception);
2388 FxReturn(log10(alpha)/log10(2.0));
2390 if (IsFxFunction(expression,
"log",3) != MagickFalse)
2392 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2393 depth+1,beta,exception);
2394 FxReturn(log10(alpha));
2396 if (LocaleCompare(expression,
"lightness") == 0)
2397 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2403 if (LocaleCompare(expression,
"MaxRGB") == 0)
2404 FxReturn((
double) QuantumRange);
2405 if (LocaleNCompare(expression,
"maxima",6) == 0)
2407 if (IsFxFunction(expression,
"max",3) != MagickFalse)
2409 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2410 depth+1,beta,exception);
2411 FxReturn(alpha > *beta ? alpha : *beta);
2413 if (LocaleNCompare(expression,
"minima",6) == 0)
2415 if (IsFxFunction(expression,
"min",3) != MagickFalse)
2417 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2418 depth+1,beta,exception);
2419 FxReturn(alpha < *beta ? alpha : *beta);
2421 if (IsFxFunction(expression,
"mod",3) != MagickFalse)
2423 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2424 depth+1,beta,exception);
2425 FxReturn(alpha-floor((alpha*PerceptibleReciprocal(*beta)))*(*beta));
2427 if (LocaleCompare(expression,
"m") == 0)
2428 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2434 if (IsFxFunction(expression,
"not",3) != MagickFalse)
2436 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2437 depth+1,beta,exception);
2438 FxReturn((
double) (alpha < MagickEpsilon));
2440 if (LocaleCompare(expression,
"n") == 0)
2441 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2447 if (LocaleCompare(expression,
"Opaque") == 0)
2449 if (LocaleCompare(expression,
"o") == 0)
2450 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2456 if (LocaleCompare(expression,
"phi") == 0)
2457 FxReturn(MagickPHI);
2458 if (LocaleCompare(expression,
"pi") == 0)
2460 if (IsFxFunction(expression,
"pow",3) != MagickFalse)
2462 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2463 depth+1,beta,exception);
2464 FxReturn(pow(alpha,*beta));
2466 if (LocaleCompare(expression,
"p") == 0)
2467 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2473 if (LocaleCompare(expression,
"QuantumRange") == 0)
2474 FxReturn((
double) QuantumRange);
2475 if (LocaleCompare(expression,
"QuantumScale") == 0)
2476 FxReturn(QuantumScale);
2482 if (IsFxFunction(expression,
"rand",4) != MagickFalse)
2487 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2488 #pragma omp critical (MagickCore_FxEvaluateSubexpression)
2490 alpha=GetPseudoRandomValue(fx_info->random_info);
2493 if (IsFxFunction(expression,
"round",5) != MagickFalse)
2495 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2496 depth+1,beta,exception);
2497 if ((alpha-floor(alpha)) < (ceil(alpha)-alpha))
2498 FxReturn(floor(alpha));
2499 FxReturn(ceil(alpha));
2501 if (LocaleCompare(expression,
"r") == 0)
2502 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2508 if (LocaleCompare(expression,
"saturation") == 0)
2509 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2510 if (IsFxFunction(expression,
"sign",4) != MagickFalse)
2512 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2513 depth+1,beta,exception);
2514 FxReturn(alpha < 0.0 ? -1.0 : 1.0);
2516 if (IsFxFunction(expression,
"sinc",4) != MagickFalse)
2518 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2519 depth+1,beta,exception);
2522 FxReturn(sin((MagickPI*alpha))/(MagickPI*alpha));
2524 if (IsFxFunction(expression,
"sinh",4) != MagickFalse)
2526 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2527 depth+1,beta,exception);
2528 FxReturn(sinh(alpha));
2530 if (IsFxFunction(expression,
"sin",3) != MagickFalse)
2532 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2533 depth+1,beta,exception);
2534 FxReturn(sin(alpha));
2536 if (IsFxFunction(expression,
"sqrt",4) != MagickFalse)
2538 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2539 depth+1,beta,exception);
2540 FxReturn(sqrt(alpha));
2542 if (IsFxFunction(expression,
"squish",6) != MagickFalse)
2544 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,
2545 depth+1,beta,exception);
2546 FxReturn((1.0/(1.0+exp(-alpha))));
2548 if (LocaleCompare(expression,
"s") == 0)
2549 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2555 if (IsFxFunction(expression,
"tanh",4) != MagickFalse)
2557 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2558 depth+1,beta,exception);
2559 FxReturn(tanh(alpha));
2561 if (IsFxFunction(expression,
"tan",3) != MagickFalse)
2563 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2564 depth+1,beta,exception);
2565 FxReturn(tan(alpha));
2567 if (LocaleCompare(expression,
"Transparent") == 0)
2569 if (IsFxFunction(expression,
"trunc",5) != MagickFalse)
2571 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2572 depth+1,beta,exception);
2574 FxReturn(floor(alpha));
2575 FxReturn(ceil(alpha));
2577 if (LocaleCompare(expression,
"t") == 0)
2578 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2584 if (LocaleCompare(expression,
"u") == 0)
2585 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2591 if (LocaleCompare(expression,
"v") == 0)
2592 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2598 if (IsFxFunction(expression,
"while",5) != MagickFalse)
2606 length=CopyMagickString(subexpression,expression+6,
2607 MagickPathExtent-1);
2609 subexpression[length-1]=
'\0';
2610 FxParseConditional(subexpression,
',',p,q);
2613 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
2615 if (fabs(gamma) < MagickEpsilon)
2617 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2622 if (LocaleCompare(expression,
"w") == 0)
2623 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2629 if (LocaleCompare(expression,
"y") == 0)
2630 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2636 if (LocaleCompare(expression,
"z") == 0)
2637 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2643 q=(
char *) expression;
2644 alpha=InterpretSiPrefixValue(expression,&q);
2645 if (q == expression)
2646 alpha=FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception);
2648 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2649 "UnbalancedParenthesis",
"`%s'",expression);
2653 MagickExport MagickBooleanType FxEvaluateExpression(
FxInfo *fx_info,
2659 status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
2663 MagickExport MagickBooleanType FxPreprocessExpression(
FxInfo *fx_info,
2673 fx_info->file=(FILE *) NULL;
2674 status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
2679 MagickExport MagickBooleanType FxEvaluateChannelExpression(
FxInfo *fx_info,
2680 const ChannelType channel,
const ssize_t x,
const ssize_t y,
double *alpha,
2687 *alpha=FxEvaluateSubexpression(fx_info,channel,x,y,fx_info->expression,0,
2689 return(exception->severity == OptionError ? MagickFalse : MagickTrue);
2729 assert(fx_info != (
FxInfo **) NULL);
2730 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
2731 if (fx_info[i] != (
FxInfo *) NULL)
2732 fx_info[i]=DestroyFxInfo(fx_info[i]);
2733 fx_info=(
FxInfo **) RelinquishMagickMemory(fx_info);
2737 static FxInfo **AcquireFxTLS(
const Image *image,
const char *expression,
2755 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
2756 fx_info=(
FxInfo **) AcquireQuantumMemory(number_threads,
sizeof(*fx_info));
2757 if (fx_info == (
FxInfo **) NULL)
2759 (void) ThrowMagickException(exception,GetMagickModule(),
2760 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
2761 return((
FxInfo **) NULL);
2763 (void) memset(fx_info,0,number_threads*
sizeof(*fx_info));
2764 if (*expression !=
'@')
2765 fx_expression=ConstantString(expression);
2767 fx_expression=FileToString(expression+1,~0UL,exception);
2768 for (i=0; i < (ssize_t) number_threads; i++)
2773 fx_info[i]=AcquireFxInfo(image,fx_expression);
2774 if (fx_info[i] == (
FxInfo *) NULL)
2776 status=FxPreprocessExpression(fx_info[i],&alpha,exception);
2777 if (status == MagickFalse)
2780 fx_expression=DestroyString(fx_expression);
2781 if (i < (ssize_t) number_threads)
2782 fx_info=DestroyFxTLS(fx_info);
2786 MagickExport
Image *FxImage(
const Image *image,
const char *expression,
2792 fx_image=FxImageChannel(image,GrayChannel,expression,exception);
2796 MagickExport
Image *FxImageChannel(
const Image *image,
const ChannelType channel,
2799 #define FxImageTag "Fx/Image"
2805 **magick_restrict fx_info;
2819 assert(image != (
Image *) NULL);
2820 assert(image->signature == MagickCoreSignature);
2821 if (IsEventLogging() != MagickFalse)
2822 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2823 if (expression == (
const char *) NULL)
2824 return(CloneImage(image,0,0,MagickTrue,exception));
2825 fx_info=AcquireFxTLS(image,expression,exception);
2826 if (fx_info == (
FxInfo **) NULL)
2827 return((
Image *) NULL);
2828 fx_image=CloneImage(image,0,0,MagickTrue,exception);
2829 if (fx_image == (
Image *) NULL)
2831 fx_info=DestroyFxTLS(fx_info);
2832 return((
Image *) NULL);
2834 if (SetImageStorageClass(fx_image,DirectClass) == MagickFalse)
2836 InheritException(exception,&fx_image->exception);
2837 fx_info=DestroyFxTLS(fx_info);
2838 fx_image=DestroyImage(fx_image);
2839 return((
Image *) NULL);
2846 fx_view=AcquireAuthenticCacheView(fx_image,exception);
2847 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2848 #pragma omp parallel for schedule(dynamic) shared(progress,status) \
2849 magick_number_threads(image,fx_image,fx_image->rows, \
2850 GlobExpression(fx_info[0]->expression,"*debug(*",MagickTrue) == 0 ? 1 : 0)
2852 for (y=0; y < (ssize_t) fx_image->rows; y++)
2855 id = GetOpenMPThreadId();
2861 *magick_restrict fx_indexes;
2869 if (status == MagickFalse)
2871 q=GetCacheViewAuthenticPixels(fx_view,0,y,fx_image->columns,1,exception);
2877 fx_indexes=GetCacheViewAuthenticIndexQueue(fx_view);
2879 for (x=0; x < (ssize_t) fx_image->columns; x++)
2881 if ((channel & RedChannel) != 0)
2883 (void) FxEvaluateChannelExpression(fx_info[
id],RedChannel,x,y,
2885 SetPixelRed(q,ClampToQuantum((MagickRealType) QuantumRange*alpha));
2887 if ((channel & GreenChannel) != 0)
2889 (void) FxEvaluateChannelExpression(fx_info[
id],GreenChannel,x,y,
2891 SetPixelGreen(q,ClampToQuantum((MagickRealType) QuantumRange*alpha));
2893 if ((channel & BlueChannel) != 0)
2895 (void) FxEvaluateChannelExpression(fx_info[
id],BlueChannel,x,y,
2897 SetPixelBlue(q,ClampToQuantum((MagickRealType) QuantumRange*alpha));
2899 if ((channel & OpacityChannel) != 0)
2901 (void) FxEvaluateChannelExpression(fx_info[
id],OpacityChannel,x,y,
2903 if (image->matte == MagickFalse)
2904 SetPixelOpacity(q,ClampToQuantum((MagickRealType) QuantumRange*
2907 SetPixelOpacity(q,ClampToQuantum((MagickRealType) (QuantumRange-
2908 QuantumRange*alpha)));
2910 if (((channel & IndexChannel) != 0) &&
2911 (fx_image->colorspace == CMYKColorspace))
2913 (void) FxEvaluateChannelExpression(fx_info[
id],IndexChannel,x,y,
2915 SetPixelIndex(fx_indexes+x,ClampToQuantum((MagickRealType)
2916 QuantumRange*alpha));
2920 if (SyncCacheViewAuthenticPixels(fx_view,exception) == MagickFalse)
2922 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2927 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2931 proceed=SetImageProgress(image,FxImageTag,progress,image->rows);
2932 if (proceed == MagickFalse)
2936 fx_view=DestroyCacheView(fx_view);
2937 fx_info=DestroyFxTLS(fx_info);
2938 if (status == MagickFalse)
2939 fx_image=DestroyImage(fx_image);