43 #include "magick/studio.h"
44 #include "magick/accelerate-private.h"
45 #include "magick/annotate.h"
46 #include "magick/artifact.h"
47 #include "magick/attribute.h"
48 #include "magick/cache.h"
49 #include "magick/cache-view.h"
50 #include "magick/channel.h"
51 #include "magick/color.h"
52 #include "magick/color-private.h"
53 #include "magick/colorspace.h"
54 #include "magick/colorspace-private.h"
55 #include "magick/composite.h"
56 #include "magick/decorate.h"
57 #include "magick/distort.h"
58 #include "magick/draw.h"
59 #include "magick/effect.h"
60 #include "magick/enhance.h"
61 #include "magick/exception.h"
62 #include "magick/exception-private.h"
63 #include "magick/fx.h"
64 #include "magick/fx-private.h"
65 #include "magick/gem.h"
66 #include "magick/geometry.h"
67 #include "magick/layer.h"
68 #include "magick/list.h"
69 #include "magick/log.h"
70 #include "magick/image.h"
71 #include "magick/image-private.h"
72 #include "magick/magick.h"
73 #include "magick/memory_.h"
74 #include "magick/memory-private.h"
75 #include "magick/monitor.h"
76 #include "magick/monitor-private.h"
77 #include "magick/opencl-private.h"
78 #include "magick/option.h"
79 #include "magick/pixel-accessor.h"
80 #include "magick/pixel-private.h"
81 #include "magick/property.h"
82 #include "magick/quantum.h"
83 #include "magick/quantum-private.h"
84 #include "magick/random_.h"
85 #include "magick/random-private.h"
86 #include "magick/resample.h"
87 #include "magick/resample-private.h"
88 #include "magick/resize.h"
89 #include "magick/resource_.h"
90 #include "magick/splay-tree.h"
91 #include "magick/statistic.h"
92 #include "magick/statistic-private.h"
93 #include "magick/string_.h"
94 #include "magick/string-private.h"
95 #include "magick/thread-private.h"
96 #include "magick/threshold.h"
97 #include "magick/token.h"
98 #include "magick/transform.h"
99 #include "magick/utility.h"
106 BitwiseAndAssignmentOperator = 0xd9U,
107 BitwiseOrAssignmentOperator,
108 LeftShiftAssignmentOperator,
109 RightShiftAssignmentOperator,
110 PowerAssignmentOperator,
111 ModuloAssignmentOperator,
112 PlusAssignmentOperator,
113 SubtractAssignmentOperator,
114 MultiplyAssignmentOperator,
115 DivideAssignmentOperator,
116 IncrementAssignmentOperator,
117 DecrementAssignmentOperator,
120 LessThanEqualOperator,
121 GreaterThanEqualOperator,
178 MagickExport
FxInfo *AcquireFxInfo(
const Image *images,
const char *expression)
192 fx_info=(
FxInfo *) AcquireCriticalMemory(
sizeof(*fx_info));
193 (void) memset(fx_info,0,
sizeof(*fx_info));
194 fx_info->exception=AcquireExceptionInfo();
195 fx_info->images=images;
196 fx_info->colors=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
197 RelinquishMagickMemory);
198 fx_info->symbols=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
199 RelinquishMagickMemory);
200 fx_info->view=(
CacheView **) AcquireQuantumMemory(GetImageListLength(
201 fx_info->images),
sizeof(*fx_info->view));
202 if (fx_info->view == (
CacheView **) NULL)
203 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
205 next=GetFirstImageInList(fx_info->images);
206 for ( ; next != (
Image *) NULL; next=next->next)
208 fx_info->view[i]=AcquireVirtualCacheView(next,fx_info->exception);
211 fx_info->random_info=AcquireRandomInfo();
212 fx_info->expression=ConstantString(expression);
213 fx_info->file=stderr;
218 *fx_op=(
unsigned char) BitwiseAndAssignmentOperator;
219 (void) SubstituteString(&fx_info->expression,
"&=",(
char *) fx_op);
220 *fx_op=(
unsigned char) BitwiseOrAssignmentOperator;
221 (void) SubstituteString(&fx_info->expression,
"|=",(
char *) fx_op);
222 *fx_op=(
unsigned char) LeftShiftAssignmentOperator;
223 (void) SubstituteString(&fx_info->expression,
"<<=",(
char *) fx_op);
224 *fx_op=(
unsigned char) RightShiftAssignmentOperator;
225 (void) SubstituteString(&fx_info->expression,
">>=",(
char *) fx_op);
226 *fx_op=(
unsigned char) PowerAssignmentOperator;
227 (void) SubstituteString(&fx_info->expression,
"^=",(
char *) fx_op);
228 *fx_op=(
unsigned char) ModuloAssignmentOperator;
229 (void) SubstituteString(&fx_info->expression,
"%=",(
char *) fx_op);
230 *fx_op=(
unsigned char) PlusAssignmentOperator;
231 (void) SubstituteString(&fx_info->expression,
"+=",(
char *) fx_op);
232 *fx_op=(
unsigned char) SubtractAssignmentOperator;
233 (void) SubstituteString(&fx_info->expression,
"-=",(
char *) fx_op);
234 *fx_op=(
unsigned char) MultiplyAssignmentOperator;
235 (void) SubstituteString(&fx_info->expression,
"*=",(
char *) fx_op);
236 *fx_op=(
unsigned char) DivideAssignmentOperator;
237 (void) SubstituteString(&fx_info->expression,
"/=",(
char *) fx_op);
238 *fx_op=(
unsigned char) IncrementAssignmentOperator;
239 (void) SubstituteString(&fx_info->expression,
"++",(
char *) fx_op);
240 *fx_op=(
unsigned char) DecrementAssignmentOperator;
241 (void) SubstituteString(&fx_info->expression,
"--",(
char *) fx_op);
242 *fx_op=(
unsigned char) LeftShiftOperator;
243 (void) SubstituteString(&fx_info->expression,
"<<",(
char *) fx_op);
244 *fx_op=(
unsigned char) RightShiftOperator;
245 (void) SubstituteString(&fx_info->expression,
">>",(
char *) fx_op);
246 *fx_op=(
unsigned char) LessThanEqualOperator;
247 (void) SubstituteString(&fx_info->expression,
"<=",(
char *) fx_op);
248 *fx_op=(
unsigned char) GreaterThanEqualOperator;
249 (void) SubstituteString(&fx_info->expression,
">=",(
char *) fx_op);
250 *fx_op=(
unsigned char) EqualOperator;
251 (void) SubstituteString(&fx_info->expression,
"==",(
char *) fx_op);
252 *fx_op=(
unsigned char) NotEqualOperator;
253 (void) SubstituteString(&fx_info->expression,
"!=",(
char *) fx_op);
254 *fx_op=(
unsigned char) LogicalAndOperator;
255 (void) SubstituteString(&fx_info->expression,
"&&",(
char *) fx_op);
256 *fx_op=(
unsigned char) LogicalOrOperator;
257 (void) SubstituteString(&fx_info->expression,
"||",(
char *) fx_op);
258 *fx_op=(
unsigned char) ExponentialNotation;
259 (void) SubstituteString(&fx_info->expression,
"**",(
char *) fx_op);
263 (void) SubstituteString(&fx_info->expression,
"-",
"-1.0*");
264 (void) SubstituteString(&fx_info->expression,
"^-1.0*",
"^-");
265 (void) SubstituteString(&fx_info->expression,
"E-1.0*",
"E-");
266 (void) SubstituteString(&fx_info->expression,
"e-1.0*",
"e-");
267 (void) SubstituteString(&fx_info->expression,
" ",
"");
298 fx_info->exception=DestroyExceptionInfo(fx_info->exception);
299 fx_info->expression=DestroyString(fx_info->expression);
300 fx_info->symbols=DestroySplayTree(fx_info->symbols);
301 fx_info->colors=DestroySplayTree(fx_info->colors);
302 for (i=(ssize_t) GetImageListLength(fx_info->images)-1; i >= 0; i--)
303 fx_info->view[i]=DestroyCacheView(fx_info->view[i]);
304 fx_info->view=(
CacheView **) RelinquishMagickMemory(fx_info->view);
305 fx_info->random_info=DestroyRandomInfo(fx_info->random_info);
306 fx_info=(
FxInfo *) RelinquishMagickMemory(fx_info);
346 static inline const double *GetFxSymbolValue(
FxInfo *fx_info,
const char *symbol)
348 return((
const double *) GetValueFromSplayTree(fx_info->symbols,symbol));
351 static inline MagickBooleanType SetFxSymbolValue(
352 FxInfo *magick_restrict fx_info,
const char *magick_restrict symbol,
358 object=(
double *) GetValueFromSplayTree(fx_info->symbols,symbol);
359 if (
object != (
double *) NULL)
364 object=(
double *) AcquireMagickMemory(
sizeof(*
object));
365 if (
object == (
double *) NULL)
367 (void) ThrowMagickException(fx_info->exception,GetMagickModule(),
368 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
369 fx_info->images->filename);
373 return(AddValueToSplayTree(fx_info->symbols,ConstantString(symbol),object));
376 static double FxChannelStatistics(
FxInfo *fx_info,
const Image *image,
377 ChannelType channel,
const char *symbol,
ExceptionInfo *exception)
380 channel_symbol[MaxTextExtent],
392 for (p=symbol; (*p !=
'.') && (*p !=
'\0'); p++) ;
393 *channel_symbol=
'\0';
399 (void) CopyMagickString(channel_symbol,p+1,MaxTextExtent);
400 option=ParseCommandOption(MagickChannelOptions,MagickTrue,channel_symbol);
402 channel=(ChannelType) option;
404 (void) FormatLocaleString(key,MaxTextExtent,
"%p.%.20g.%s",(
void *) image,
405 (double) channel,symbol);
406 value=GetFxSymbolValue(fx_info,key);
407 if (value != (
const double *) NULL)
408 return(QuantumScale*(*value));
410 if (LocaleNCompare(symbol,
"depth",5) == 0)
415 depth=GetImageChannelDepth(image,channel,exception);
416 statistic=(double) depth;
418 if (LocaleNCompare(symbol,
"kurtosis",8) == 0)
424 (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
428 if (LocaleNCompare(symbol,
"maxima",6) == 0)
434 (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
437 if (LocaleNCompare(symbol,
"mean",4) == 0)
443 (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
447 if (LocaleNCompare(symbol,
"minima",6) == 0)
453 (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
456 if (LocaleNCompare(symbol,
"skewness",8) == 0)
462 (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
466 if (LocaleNCompare(symbol,
"standard_deviation",18) == 0)
472 (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
474 statistic=standard_deviation;
476 if (SetFxSymbolValue(fx_info,key,statistic) == MagickFalse)
478 return(QuantumScale*statistic);
482 FxEvaluateSubexpression(
FxInfo *,
const ChannelType,
const ssize_t,
483 const ssize_t,
const char *,
const size_t,
double *,
ExceptionInfo *);
485 static inline MagickBooleanType IsFxFunction(
const char *expression,
486 const char *name,
const size_t length)
494 for (i=0; i <= length; i++)
495 if (expression[i] ==
'\0')
497 c=expression[length];
498 if ((LocaleNCompare(expression,name,length) == 0) &&
499 ((isspace((
int) ((
unsigned char) c)) == 0) || (c ==
'(')))
504 static inline double FxGCD(
const double alpha,
const double beta,
507 #define FxMaxFunctionDepth 200
510 return(FxGCD(beta,alpha,depth+1));
511 if ((fabs(beta) < 0.001) || (depth >= FxMaxFunctionDepth))
513 return(FxGCD(beta,alpha-beta*floor(alpha/beta),depth+1));
516 static inline const char *FxSubexpression(
const char *expression,
526 subexpression=expression;
527 while ((*subexpression !=
'\0') &&
528 ((level != 1) || (strchr(
")",(
int) *subexpression) == (
char *) NULL)))
530 if (strchr(
"(",(
int) *subexpression) != (
char *) NULL)
533 if (strchr(
")",(
int) *subexpression) != (
char *) NULL)
537 if (*subexpression ==
'\0')
538 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
539 "UnbalancedParenthesis",
"`%s'",expression);
540 return(subexpression);
543 static double FxGetSymbol(
FxInfo *fx_info,
const ChannelType channel,
544 const ssize_t x,
const ssize_t y,
const char *expression,
const size_t depth,
549 symbol[MaxTextExtent];
581 i=GetImageIndexInList(fx_info->images);
585 if (isalpha((
int) ((
unsigned char) *(p+1))) == 0)
590 subexpression=AcquireString(expression);
591 if (strchr(
"suv",(
int) *p) != (
char *) NULL)
598 i=GetImageIndexInList(fx_info->images);
601 case 'u': i=0;
break;
602 case 'v': i=1;
break;
609 for (p++; *p !=
'\0'; )
623 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
624 depth,&beta,exception);
632 if ((*p ==
'p') && (isalpha((
int) ((
unsigned char) *(p+1))) == 0))
639 for (p++; *p !=
'\0'; )
653 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
654 depth,&beta,exception);
665 for (p++; *p !=
'\0'; )
679 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
680 depth,&beta,exception);
689 subexpression=DestroyString(subexpression);
691 image=GetImageFromList(fx_info->images,i);
692 if (image == (
Image *) NULL)
694 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
695 "NoSuchImage",
"`%s'",expression);
698 i=GetImageIndexInList(image);
699 GetMagickPixelPacket(image,&pixel);
700 status=InterpolateMagickPixelPacket(image,fx_info->view[i],image->interpolate,
701 point.x,point.y,&pixel,exception);
703 if ((*p !=
'\0') && (*(p+1) !=
'\0') && (*(p+2) !=
'\0') &&
704 (LocaleCompare(p,
"intensity") != 0) && (LocaleCompare(p,
"luma") != 0) &&
705 (LocaleCompare(p,
"luminance") != 0) && (LocaleCompare(p,
"hue") != 0) &&
706 (LocaleCompare(p,
"saturation") != 0) &&
707 (LocaleCompare(p,
"lightness") != 0))
715 (void) CopyMagickString(name,p,MaxTextExtent);
717 for (q=name+length-1; q > name; q--)
728 if ((*q !=
'\0') && (*(q+1) !=
'\0') && (*(q+2) !=
'\0') &&
729 (GetFxSymbolValue(fx_info,name) == (
const double *) NULL))
742 if (QueryMagickColor(name,&pixel,fx_info->exception) != MagickFalse)
744 (void) AddValueToSplayTree(fx_info->colors,ConstantString(name),
745 CloneMagickPixelPacket(&pixel));
750 (void) CopyMagickString(symbol,p,MaxTextExtent);
756 case RedChannel:
return(QuantumScale*pixel.red);
757 case GreenChannel:
return(QuantumScale*pixel.green);
758 case BlueChannel:
return(QuantumScale*pixel.blue);
764 if (pixel.matte == MagickFalse)
766 alpha=(double) (QuantumScale*GetPixelAlpha(&pixel));
771 if (image->colorspace != CMYKColorspace)
773 (void) ThrowMagickException(exception,GetMagickModule(),
774 ImageError,
"ColorSeparatedImageRequired",
"`%s'",
778 return(QuantumScale*pixel.index);
780 case DefaultChannels:
781 return(QuantumScale*GetMagickPixelIntensity(image,&pixel));
785 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
786 "UnableToParseExpression",
"`%s'",p);
794 if (LocaleCompare(symbol,
"a") == 0)
795 return((
double) (QuantumScale*GetPixelAlpha(&pixel)));
801 if (LocaleCompare(symbol,
"b") == 0)
802 return(QuantumScale*pixel.blue);
808 if (IsFxFunction(symbol,
"channel",7) != MagickFalse)
816 flags=ParseGeometry(symbol+7,&channel_info);
817 if (image->colorspace == CMYKColorspace)
822 if ((flags & RhoValue) == 0)
824 return(channel_info.rho);
828 if ((flags & SigmaValue) == 0)
830 return(channel_info.sigma);
834 if ((flags & XiValue) == 0)
836 return(channel_info.xi);
840 if ((flags & PsiValue) == 0)
842 return(channel_info.psi);
846 if ((flags & ChiValue) == 0)
848 return(channel_info.chi);
857 if ((flags & RhoValue) == 0)
859 return(channel_info.rho);
863 if ((flags & SigmaValue) == 0)
865 return(channel_info.sigma);
869 if ((flags & XiValue) == 0)
871 return(channel_info.xi);
875 if ((flags & PsiValue) == 0)
877 return(channel_info.psi);
881 if ((flags & ChiValue) == 0)
883 return(channel_info.chi);
889 if (LocaleCompare(symbol,
"c") == 0)
890 return(QuantumScale*pixel.red);
896 if (LocaleNCompare(symbol,
"depth",5) == 0)
897 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
903 if (LocaleCompare(symbol,
"extent") == 0)
905 if (image->extent != 0)
906 return((
double) image->extent);
907 return((
double) GetBlobSize(image));
914 if (LocaleCompare(symbol,
"g") == 0)
915 return(QuantumScale*pixel.green);
921 if (LocaleNCompare(symbol,
"kurtosis",8) == 0)
922 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
923 if (LocaleCompare(symbol,
"k") == 0)
925 if (image->colorspace != CMYKColorspace)
927 (void) ThrowMagickException(exception,GetMagickModule(),
928 OptionError,
"ColorSeparatedImageRequired",
"`%s'",
932 return(QuantumScale*pixel.index);
939 if (LocaleCompare(symbol,
"h") == 0)
940 return((
double) image->rows);
941 if (LocaleCompare(symbol,
"hue") == 0)
948 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
949 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
957 if ((LocaleCompare(symbol,
"image.depth") == 0) ||
958 (LocaleCompare(symbol,
"image.minima") == 0) ||
959 (LocaleCompare(symbol,
"image.maxima") == 0) ||
960 (LocaleCompare(symbol,
"image.mean") == 0) ||
961 (LocaleCompare(symbol,
"image.kurtosis") == 0) ||
962 (LocaleCompare(symbol,
"image.skewness") == 0) ||
963 (LocaleCompare(symbol,
"image.standard_deviation") == 0))
964 return(FxChannelStatistics(fx_info,image,channel,symbol+6,exception));
965 if (LocaleCompare(symbol,
"image.resolution.x") == 0)
966 return(image->x_resolution);
967 if (LocaleCompare(symbol,
"image.resolution.y") == 0)
968 return(image->y_resolution);
969 if (LocaleCompare(symbol,
"intensity") == 0)
970 return(QuantumScale*GetMagickPixelIntensity(image,&pixel));
971 if (LocaleCompare(symbol,
"i") == 0)
978 if (LocaleCompare(symbol,
"j") == 0)
985 if (LocaleCompare(symbol,
"lightness") == 0)
992 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
993 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
996 if (LocaleCompare(symbol,
"luma") == 0)
1001 luma=0.212656*pixel.red+0.715158*pixel.green+0.072186*pixel.blue;
1002 return(QuantumScale*luma);
1004 if (LocaleCompare(symbol,
"luminance") == 0)
1009 luminance=0.212656*pixel.red+0.715158*pixel.green+0.072186*pixel.blue;
1010 return(QuantumScale*luminance);
1017 if (LocaleNCompare(symbol,
"maxima",6) == 0)
1018 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1019 if (LocaleNCompare(symbol,
"mean",4) == 0)
1020 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1021 if (LocaleNCompare(symbol,
"minima",6) == 0)
1022 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1023 if (LocaleCompare(symbol,
"m") == 0)
1024 return(QuantumScale*pixel.green);
1030 if (LocaleCompare(symbol,
"n") == 0)
1031 return((
double) GetImageListLength(fx_info->images));
1037 if (LocaleCompare(symbol,
"o") == 0)
1038 return(QuantumScale*pixel.opacity);
1044 if (LocaleCompare(symbol,
"page.height") == 0)
1045 return((
double) image->page.height);
1046 if (LocaleCompare(symbol,
"page.width") == 0)
1047 return((
double) image->page.width);
1048 if (LocaleCompare(symbol,
"page.x") == 0)
1049 return((
double) image->page.x);
1050 if (LocaleCompare(symbol,
"page.y") == 0)
1051 return((
double) image->page.y);
1052 if (LocaleCompare(symbol,
"printsize.x") == 0)
1053 return(PerceptibleReciprocal(image->x_resolution)*image->columns);
1054 if (LocaleCompare(symbol,
"printsize.y") == 0)
1055 return(PerceptibleReciprocal(image->y_resolution)*image->rows);
1061 if (LocaleCompare(symbol,
"quality") == 0)
1062 return((
double) image->quality);
1068 if (LocaleCompare(symbol,
"resolution.x") == 0)
1069 return(image->x_resolution);
1070 if (LocaleCompare(symbol,
"resolution.y") == 0)
1071 return(image->y_resolution);
1072 if (LocaleCompare(symbol,
"r") == 0)
1073 return(QuantumScale*pixel.red);
1079 if (LocaleCompare(symbol,
"saturation") == 0)
1086 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
1087 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
1090 if (LocaleNCompare(symbol,
"skewness",8) == 0)
1091 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1092 if (LocaleNCompare(symbol,
"standard_deviation",18) == 0)
1093 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1099 if (LocaleCompare(symbol,
"t") == 0)
1100 return((
double) GetImageIndexInList(fx_info->images));
1106 if (LocaleCompare(symbol,
"w") == 0)
1107 return((
double) image->columns);
1113 if (LocaleCompare(symbol,
"y") == 0)
1114 return(QuantumScale*pixel.blue);
1120 if (LocaleCompare(symbol,
"z") == 0)
1125 depth=(double) GetImageChannelDepth(image,channel,fx_info->exception);
1133 value=GetFxSymbolValue(fx_info,symbol);
1134 if (value != (
const double *) NULL)
1136 artifact=GetImageArtifact(image,symbol);
1137 if (artifact != (
const char *) NULL)
1138 return(StringToDouble(artifact,(
char **) NULL));
1139 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1140 "UndefinedVariable",
"`%s'",symbol);
1141 (void) SetFxSymbolValue(fx_info,symbol,0.0);
1145 static const char *FxOperatorPrecedence(
const char *expression,
1150 UndefinedPrecedence,
1152 BitwiseComplementPrecedence,
1154 ExponentialNotationPrecedence,
1158 RelationalPrecedence,
1159 EquivalencyPrecedence,
1160 BitwiseAndPrecedence,
1161 BitwiseOrPrecedence,
1162 LogicalAndPrecedence,
1163 LogicalOrPrecedence,
1165 AssignmentPrecedence,
1185 subexpression=(
const char *) NULL;
1186 target=NullPrecedence;
1187 while ((c !=
'\0') && (*expression !=
'\0'))
1189 precedence=UndefinedPrecedence;
1190 if ((isspace((
int) ((
unsigned char) *expression)) != 0) || (c == (int)
'@'))
1195 switch (*expression)
1200 #if defined(MAGICKCORE_HAVE_ACOSH)
1201 if (IsFxFunction(expression,
"acosh",5) != MagickFalse)
1207 #if defined(MAGICKCORE_HAVE_ASINH)
1208 if (IsFxFunction(expression,
"asinh",5) != MagickFalse)
1214 #if defined(MAGICKCORE_HAVE_ATANH)
1215 if (IsFxFunction(expression,
"atanh",5) != MagickFalse)
1221 if (IsFxFunction(expression,
"atan2",5) != MagickFalse)
1231 if ((isdigit((
int) ((
unsigned char) c)) != 0) &&
1232 ((LocaleNCompare(expression,
"E+",2) == 0) ||
1233 (LocaleNCompare(expression,
"E-",2) == 0)))
1243 if ((IsFxFunction(expression,
"j0",2) != MagickFalse) ||
1244 (IsFxFunction(expression,
"j1",2) != MagickFalse))
1253 while (isxdigit((
int) ((
unsigned char) *(expression+1))) != 0)
1260 if ((c == (
int)
'{') || (c == (
int)
'['))
1263 if ((c == (
int)
'}') || (c == (
int)
']'))
1266 switch ((
unsigned char) *expression)
1271 precedence=BitwiseComplementPrecedence;
1277 precedence=ExponentPrecedence;
1282 if (((c != 0) && ((isdigit((
int) ((
unsigned char) c)) != 0) ||
1283 (strchr(
")",c) != (
char *) NULL))) &&
1284 (((islower((
int) ((
unsigned char) *expression)) != 0) ||
1285 (strchr(
"(",(
int) ((
unsigned char) *expression)) != (
char *) NULL)) ||
1286 ((isdigit((
int) ((
unsigned char) c)) == 0) &&
1287 (isdigit((
int) ((
unsigned char) *expression)) != 0))) &&
1288 (strchr(
"xy",(
int) ((
unsigned char) *expression)) == (
char *) NULL))
1289 precedence=MultiplyPrecedence;
1296 precedence=MultiplyPrecedence;
1302 if ((strchr(
"(+-/*%:&^|<>~,",c) == (
char *) NULL) ||
1303 (isalpha((
int) ((
unsigned char) c)) != 0))
1304 precedence=AdditionPrecedence;
1307 case BitwiseAndAssignmentOperator:
1308 case BitwiseOrAssignmentOperator:
1309 case LeftShiftAssignmentOperator:
1310 case RightShiftAssignmentOperator:
1311 case PowerAssignmentOperator:
1312 case ModuloAssignmentOperator:
1313 case PlusAssignmentOperator:
1314 case SubtractAssignmentOperator:
1315 case MultiplyAssignmentOperator:
1316 case DivideAssignmentOperator:
1317 case IncrementAssignmentOperator:
1318 case DecrementAssignmentOperator:
1320 precedence=AssignmentPrecedence;
1323 case LeftShiftOperator:
1324 case RightShiftOperator:
1326 precedence=ShiftPrecedence;
1330 case LessThanEqualOperator:
1331 case GreaterThanEqualOperator:
1334 precedence=RelationalPrecedence;
1338 case NotEqualOperator:
1340 precedence=EquivalencyPrecedence;
1345 precedence=BitwiseAndPrecedence;
1350 precedence=BitwiseOrPrecedence;
1353 case LogicalAndOperator:
1355 precedence=LogicalAndPrecedence;
1358 case LogicalOrOperator:
1360 precedence=LogicalOrPrecedence;
1363 case ExponentialNotation:
1365 precedence=ExponentialNotationPrecedence;
1371 precedence=TernaryPrecedence;
1376 precedence=AssignmentPrecedence;
1381 precedence=CommaPrecedence;
1386 precedence=SeparatorPrecedence;
1390 if ((precedence == BitwiseComplementPrecedence) ||
1391 (precedence == TernaryPrecedence) ||
1392 (precedence == AssignmentPrecedence))
1394 if (precedence > target)
1400 subexpression=expression;
1404 if (precedence >= target)
1410 subexpression=expression;
1412 if (strchr(
"(",(
int) *expression) != (
char *) NULL)
1413 expression=FxSubexpression(expression,exception);
1414 c=(int) (*expression++);
1416 return(subexpression);
1419 static double FxEvaluateSubexpression(
FxInfo *fx_info,
const ChannelType channel,
1420 const ssize_t x,
const ssize_t y,
const char *expression,
const size_t depth,
1423 #define FxMaxParenthesisDepth 58
1424 #define FxMaxSubexpressionDepth 200
1425 #define FxReturn(value) \
1427 subexpression=DestroyString(subexpression); \
1430 #define FxParseConditional(subexpression,sentinal,p,q) \
1433 for (q=(char *) p; (*q != (sentinal)) && (*q != '\0'); q++) \
1436 for (q++; (*q != ')') && (*q != '\0'); q++); \
1442 (void) ThrowMagickException(exception,GetMagickModule(), \
1443 OptionError,"UnableToParseExpression","`%s'",subexpression); \
1446 if (strlen(q) == 1) \
1466 subexpression=AcquireString(expression);
1467 *subexpression=
'\0';
1468 if (depth > FxMaxSubexpressionDepth)
1470 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1471 "UnableToParseExpression",
"`%s'",expression);
1474 if (exception->severity >= ErrorException)
1476 while (isspace((
int) ((
unsigned char) *expression)) != 0)
1478 if (*expression ==
'\0')
1480 p=FxOperatorPrecedence(expression,exception);
1481 if (p != (
const char *) NULL)
1483 (void) CopyMagickString(subexpression,expression,(
size_t)
1485 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,depth+1,
1487 switch ((
unsigned char) *p)
1491 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1493 *beta=(double) (~(
size_t) *beta);
1498 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1500 FxReturn(*beta == 0.0 ? 1.0 : 0.0);
1504 *beta=pow(alpha,FxEvaluateSubexpression(fx_info,channel,x,y,++p,
1505 depth+1,beta,exception));
1509 case ExponentialNotation:
1511 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1513 FxReturn(alpha*(*beta));
1517 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1519 FxReturn(PerceptibleReciprocal(*beta)*alpha);
1523 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1525 FxReturn(fmod(alpha,*beta));
1529 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1531 FxReturn(alpha+(*beta));
1535 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1537 FxReturn(alpha-(*beta));
1539 case BitwiseAndAssignmentOperator:
1542 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1546 (void) ThrowMagickException(exception,GetMagickModule(),
1547 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1550 ClearMagickException(exception);
1551 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1553 value=(double) ((
size_t) (alpha+0.5) & (size_t) (*beta+0.5));
1554 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1558 case BitwiseOrAssignmentOperator:
1561 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1565 (void) ThrowMagickException(exception,GetMagickModule(),
1566 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1569 ClearMagickException(exception);
1570 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1572 value=(double) ((
size_t) (alpha+0.5) | (size_t) (*beta+0.5));
1573 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1577 case LeftShiftAssignmentOperator:
1580 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1584 (void) ThrowMagickException(exception,GetMagickModule(),
1585 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1588 ClearMagickException(exception);
1589 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1591 if ((
size_t) (*beta+0.5) >= (8*
sizeof(
size_t)))
1593 (void) ThrowMagickException(exception,GetMagickModule(),
1594 OptionError,
"ShiftCountOverflow",
"`%s'",subexpression);
1597 value=(double) ((
size_t) (alpha+0.5) << (size_t) (*beta+0.5));
1598 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1602 case RightShiftAssignmentOperator:
1605 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1609 (void) ThrowMagickException(exception,GetMagickModule(),
1610 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1613 ClearMagickException(exception);
1614 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1616 if ((
size_t) (*beta+0.5) >= (8*
sizeof(
size_t)))
1618 (void) ThrowMagickException(exception,GetMagickModule(),
1619 OptionError,
"ShiftCountOverflow",
"`%s'",subexpression);
1622 value=(double) ((
size_t) (alpha+0.5) >> (size_t) (*beta+0.5));
1623 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1627 case PowerAssignmentOperator:
1630 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1634 (void) ThrowMagickException(exception,GetMagickModule(),
1635 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1638 ClearMagickException(exception);
1639 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1641 value=pow(alpha,*beta);
1642 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1646 case ModuloAssignmentOperator:
1649 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1653 (void) ThrowMagickException(exception,GetMagickModule(),
1654 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1657 ClearMagickException(exception);
1658 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1660 value=fmod(alpha,*beta);
1661 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1665 case PlusAssignmentOperator:
1668 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1672 (void) ThrowMagickException(exception,GetMagickModule(),
1673 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1676 ClearMagickException(exception);
1677 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1679 value=alpha+(*beta);
1680 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1684 case SubtractAssignmentOperator:
1687 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1691 (void) ThrowMagickException(exception,GetMagickModule(),
1692 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1695 ClearMagickException(exception);
1696 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1698 value=alpha-(*beta);
1699 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1703 case MultiplyAssignmentOperator:
1706 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1710 (void) ThrowMagickException(exception,GetMagickModule(),
1711 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1714 ClearMagickException(exception);
1715 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1717 value=alpha*(*beta);
1718 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1722 case DivideAssignmentOperator:
1725 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1729 (void) ThrowMagickException(exception,GetMagickModule(),
1730 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1733 ClearMagickException(exception);
1734 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1736 value=alpha*PerceptibleReciprocal(*beta);
1737 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1741 case IncrementAssignmentOperator:
1743 if (*subexpression ==
'\0')
1744 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1747 if (*subexpression ==
'\0')
1749 if (SetFxSymbolValue(fx_info,p,value) == MagickFalse)
1753 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1757 case DecrementAssignmentOperator:
1759 if (*subexpression ==
'\0')
1760 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1763 if (*subexpression ==
'\0')
1765 if (SetFxSymbolValue(fx_info,p,value) == MagickFalse)
1769 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1773 case LeftShiftOperator:
1775 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1777 if ((
size_t) (gamma+0.5) >= (8*
sizeof(
size_t)))
1779 (void) ThrowMagickException(exception,GetMagickModule(),
1780 OptionError,
"ShiftCountOverflow",
"`%s'",subexpression);
1783 *beta=(double) ((
size_t) (alpha+0.5) << (size_t) (gamma+0.5));
1786 case RightShiftOperator:
1788 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1790 if ((
size_t) (gamma+0.5) >= (8*
sizeof(
size_t)))
1792 (void) ThrowMagickException(exception,GetMagickModule(),
1793 OptionError,
"ShiftCountOverflow",
"`%s'",subexpression);
1796 *beta=(double) ((
size_t) (alpha+0.5) >> (size_t) (gamma+0.5));
1801 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1803 FxReturn(alpha < *beta ? 1.0 : 0.0);
1805 case LessThanEqualOperator:
1807 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1809 FxReturn(alpha <= *beta ? 1.0 : 0.0);
1813 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1815 FxReturn(alpha > *beta ? 1.0 : 0.0);
1817 case GreaterThanEqualOperator:
1819 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1821 FxReturn(alpha >= *beta ? 1.0 : 0.0);
1825 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1827 FxReturn(fabs(alpha-(*beta)) < MagickEpsilon ? 1.0 : 0.0);
1829 case NotEqualOperator:
1831 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1833 FxReturn(fabs(alpha-(*beta)) >= MagickEpsilon ? 1.0 : 0.0);
1837 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1839 *beta=(double) ((
size_t) (alpha+0.5) & (size_t) (gamma+0.5));
1844 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1846 *beta=(double) ((
size_t) (alpha+0.5) | (size_t) (gamma+0.5));
1849 case LogicalAndOperator:
1857 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1859 *beta=(gamma > 0.0) ? 1.0 : 0.0;
1862 case LogicalOrOperator:
1870 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1872 *beta=(gamma > 0.0) ? 1.0 : 0.0;
1880 (void) CopyMagickString(subexpression,++p,MaxTextExtent-1);
1881 FxParseConditional(subexpression,
':',p,q);
1882 if (fabs(alpha) >= MagickEpsilon)
1883 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1886 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
1893 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1897 (void) ThrowMagickException(exception,GetMagickModule(),
1898 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1901 ClearMagickException(exception);
1902 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1905 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1911 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1917 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1925 gamma=alpha*FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,
1931 if (strchr(
"(",(
int) *expression) != (
char *) NULL)
1936 if (depth >= FxMaxParenthesisDepth)
1937 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1938 "ParenthesisNestedTooDeeply",
"`%s'",expression);
1939 length=CopyMagickString(subexpression,expression+1,MaxTextExtent);
1941 subexpression[length-1]=
'\0';
1942 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,depth+1,
1946 switch (*expression)
1950 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1952 FxReturn(1.0*gamma);
1956 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1958 FxReturn(-1.0*gamma);
1962 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1964 FxReturn((
double) (~(
size_t) (gamma+0.5)));
1969 if (IsFxFunction(expression,
"abs",3) != MagickFalse)
1971 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
1972 depth+1,beta,exception);
1973 FxReturn(fabs(alpha));
1975 #if defined(MAGICKCORE_HAVE_ACOSH)
1976 if (IsFxFunction(expression,
"acosh",5) != MagickFalse)
1978 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
1979 depth+1,beta,exception);
1980 FxReturn(acosh(alpha));
1983 if (IsFxFunction(expression,
"acos",4) != MagickFalse)
1985 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
1986 depth+1,beta,exception);
1987 FxReturn(acos(alpha));
1989 #if defined(MAGICKCORE_HAVE_J1)
1990 if (IsFxFunction(expression,
"airy",4) != MagickFalse)
1992 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
1993 depth+1,beta,exception);
1996 gamma=2.0*j1((MagickPI*alpha))/(MagickPI*alpha);
1997 FxReturn(gamma*gamma);
2000 #if defined(MAGICKCORE_HAVE_ASINH)
2001 if (IsFxFunction(expression,
"asinh",5) != MagickFalse)
2003 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2004 depth+1,beta,exception);
2005 FxReturn(asinh(alpha));
2008 if (IsFxFunction(expression,
"asin",4) != MagickFalse)
2010 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2011 depth+1,beta,exception);
2012 FxReturn(asin(alpha));
2014 if (IsFxFunction(expression,
"alt",3) != MagickFalse)
2016 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2017 depth+1,beta,exception);
2018 FxReturn(((ssize_t) alpha) & 0x01 ? -1.0 : 1.0);
2020 if (IsFxFunction(expression,
"atan2",5) != MagickFalse)
2022 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2023 depth+1,beta,exception);
2024 FxReturn(atan2(alpha,*beta));
2026 #if defined(MAGICKCORE_HAVE_ATANH)
2027 if (IsFxFunction(expression,
"atanh",5) != MagickFalse)
2029 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2030 depth+1,beta,exception);
2031 FxReturn(atanh(alpha));
2034 if (IsFxFunction(expression,
"atan",4) != MagickFalse)
2036 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2037 depth+1,beta,exception);
2038 FxReturn(atan(alpha));
2040 if (LocaleCompare(expression,
"a") == 0)
2041 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2047 if (LocaleCompare(expression,
"b") == 0)
2048 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2054 if (IsFxFunction(expression,
"ceil",4) != MagickFalse)
2056 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2057 depth+1,beta,exception);
2058 FxReturn(ceil(alpha));
2060 if (IsFxFunction(expression,
"clamp",5) != MagickFalse)
2062 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2063 depth+1,beta,exception);
2070 if (IsFxFunction(expression,
"cosh",4) != MagickFalse)
2072 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2073 depth+1,beta,exception);
2074 FxReturn(cosh(alpha));
2076 if (IsFxFunction(expression,
"cos",3) != MagickFalse)
2078 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2079 depth+1,beta,exception);
2080 FxReturn(cos(alpha));
2082 if (LocaleCompare(expression,
"c") == 0)
2083 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2089 if (IsFxFunction(expression,
"debug",5) != MagickFalse)
2097 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2098 depth+1,beta,exception);
2099 switch (fx_info->images->colorspace)
2101 case CMYKColorspace:
2105 case CyanChannel: type=
"cyan";
break;
2106 case MagentaChannel: type=
"magenta";
break;
2107 case YellowChannel: type=
"yellow";
break;
2108 case AlphaChannel: type=
"alpha";
break;
2109 case BlackChannel: type=
"black";
break;
2110 default: type=
"unknown";
break;
2114 case GRAYColorspace:
2118 case RedChannel: type=
"gray";
break;
2119 case AlphaChannel: type=
"alpha";
break;
2120 default: type=
"unknown";
break;
2128 case RedChannel: type=
"red";
break;
2129 case GreenChannel: type=
"green";
break;
2130 case BlueChannel: type=
"blue";
break;
2131 case AlphaChannel: type=
"alpha";
break;
2132 default: type=
"unknown";
break;
2137 *subexpression=
'\0';
2139 if (strlen(expression) > 6)
2140 length=CopyMagickString(subexpression,expression+6,MaxTextExtent);
2142 subexpression[length-1]=
'\0';
2143 if (fx_info->file != (FILE *) NULL)
2144 (void) FormatLocaleFile(fx_info->file,
2145 "%s[%.20g,%.20g].%s: %s=%.*g\n",fx_info->images->filename,
2146 (
double) x,(double) y,type,subexpression,GetMagickPrecision(),
2150 if (IsFxFunction(expression,
"do",2) != MagickFalse)
2158 length=CopyMagickString(subexpression,expression+6,
2159 MagickPathExtent-1);
2161 subexpression[length-1]=
'\0';
2162 FxParseConditional(subexpression,
',',p,q);
2165 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2167 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2169 if (fabs(gamma) < MagickEpsilon)
2174 if (IsFxFunction(expression,
"drc",3) != MagickFalse)
2176 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2177 depth+1,beta,exception);
2178 FxReturn(alpha*PerceptibleReciprocal(*beta*(alpha-1.0)+1.0));
2185 if (LocaleCompare(expression,
"epsilon") == 0)
2186 FxReturn(MagickEpsilon);
2187 #if defined(MAGICKCORE_HAVE_ERF)
2188 if (IsFxFunction(expression,
"erf",3) != MagickFalse)
2190 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2191 depth+1,beta,exception);
2192 FxReturn(erf(alpha));
2195 if (IsFxFunction(expression,
"exp",3) != MagickFalse)
2197 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2198 depth+1,beta,exception);
2199 FxReturn(exp(alpha));
2201 if (LocaleCompare(expression,
"e") == 0)
2202 FxReturn(2.7182818284590452354);
2208 if (IsFxFunction(expression,
"floor",5) != MagickFalse)
2210 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2211 depth+1,beta,exception);
2212 FxReturn(floor(alpha));
2214 if (IsFxFunction(expression,
"for",3) != MagickFalse)
2225 length=CopyMagickString(subexpression,expression+4,
2226 MagickPathExtent-1);
2228 subexpression[length-1]=
'\0';
2229 FxParseConditional(subexpression,
',',p,q);
2230 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2232 (void) CopyMagickString(subexpression,q+1,MagickPathExtent-1);
2233 FxParseConditional(subexpression,
',',p,q);
2236 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2238 if (fabs(gamma) < MagickEpsilon)
2240 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2250 if (IsFxFunction(expression,
"gauss",5) != MagickFalse)
2252 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2253 depth+1,beta,exception);
2254 FxReturn(exp((-alpha*alpha/2.0))/sqrt(2.0*MagickPI));
2256 if (IsFxFunction(expression,
"gcd",3) != MagickFalse)
2261 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2262 depth+1,beta,exception);
2265 gcd=FxGCD(alpha,*beta,0);
2268 if (LocaleCompare(expression,
"g") == 0)
2269 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2275 if (LocaleCompare(expression,
"h") == 0)
2276 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2277 if (LocaleCompare(expression,
"hue") == 0)
2278 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2279 if (IsFxFunction(expression,
"hypot",5) != MagickFalse)
2281 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2282 depth+1,beta,exception);
2283 FxReturn(hypot(alpha,*beta));
2290 if (LocaleCompare(expression,
"k") == 0)
2291 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2297 if (IsFxFunction(expression,
"if",2) != MagickFalse)
2308 length=CopyMagickString(subexpression,expression+3,
2309 MagickPathExtent-1);
2311 subexpression[length-1]=
'\0';
2312 FxParseConditional(subexpression,
',',p,q);
2313 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2315 (void) CopyMagickString(subexpression,q+1,MagickPathExtent-1);
2316 FxParseConditional(subexpression,
',',p,q);
2317 if (fabs(alpha) >= MagickEpsilon)
2318 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
2321 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2325 if (LocaleCompare(expression,
"intensity") == 0)
2326 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2327 if (IsFxFunction(expression,
"int",3) != MagickFalse)
2329 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2330 depth+1,beta,exception);
2331 FxReturn(floor(alpha));
2333 if (IsFxFunction(expression,
"isnan",5) != MagickFalse)
2335 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2336 depth+1,beta,exception);
2337 FxReturn((
double) !!IsNaN(alpha));
2339 if (LocaleCompare(expression,
"i") == 0)
2340 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2346 if (LocaleCompare(expression,
"j") == 0)
2347 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2348 #if defined(MAGICKCORE_HAVE_J0)
2349 if (IsFxFunction(expression,
"j0",2) != MagickFalse)
2351 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2352 depth+1,beta,exception);
2353 FxReturn(j0(alpha));
2356 #if defined(MAGICKCORE_HAVE_J1)
2357 if (IsFxFunction(expression,
"j1",2) != MagickFalse)
2359 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2360 depth+1,beta,exception);
2361 FxReturn(j1(alpha));
2364 #if defined(MAGICKCORE_HAVE_J1)
2365 if (IsFxFunction(expression,
"jinc",4) != MagickFalse)
2367 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2368 depth+1,beta,exception);
2371 FxReturn((2.0*j1((MagickPI*alpha))/(MagickPI*alpha)));
2379 if (IsFxFunction(expression,
"ln",2) != MagickFalse)
2381 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2382 depth+1,beta,exception);
2383 FxReturn(log(alpha));
2385 if (IsFxFunction(expression,
"logtwo",6) != MagickFalse)
2387 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,
2388 depth+1,beta,exception);
2389 FxReturn(MagickLog10(alpha)/log10(2.0));
2391 if (IsFxFunction(expression,
"log",3) != MagickFalse)
2393 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2394 depth+1,beta,exception);
2395 FxReturn(MagickLog10(alpha));
2397 if (LocaleCompare(expression,
"lightness") == 0)
2398 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2404 if (LocaleCompare(expression,
"MaxRGB") == 0)
2405 FxReturn((
double) QuantumRange);
2406 if (LocaleNCompare(expression,
"maxima",6) == 0)
2408 if (IsFxFunction(expression,
"max",3) != MagickFalse)
2410 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2411 depth+1,beta,exception);
2412 FxReturn(alpha > *beta ? alpha : *beta);
2414 if (LocaleNCompare(expression,
"minima",6) == 0)
2416 if (IsFxFunction(expression,
"min",3) != MagickFalse)
2418 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2419 depth+1,beta,exception);
2420 FxReturn(alpha < *beta ? alpha : *beta);
2422 if (IsFxFunction(expression,
"mod",3) != MagickFalse)
2424 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2425 depth+1,beta,exception);
2426 FxReturn(alpha-floor((alpha*PerceptibleReciprocal(*beta)))*(*beta));
2428 if (LocaleCompare(expression,
"m") == 0)
2429 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2435 if (IsFxFunction(expression,
"not",3) != MagickFalse)
2437 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2438 depth+1,beta,exception);
2439 FxReturn((
double) (alpha < MagickEpsilon));
2441 if (LocaleCompare(expression,
"n") == 0)
2442 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2448 if (LocaleCompare(expression,
"Opaque") == 0)
2450 if (LocaleCompare(expression,
"o") == 0)
2451 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2457 if (LocaleCompare(expression,
"phi") == 0)
2458 FxReturn(MagickPHI);
2459 if (LocaleCompare(expression,
"pi") == 0)
2461 if (IsFxFunction(expression,
"pow",3) != MagickFalse)
2463 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2464 depth+1,beta,exception);
2465 FxReturn(pow(alpha,*beta));
2467 if (LocaleCompare(expression,
"p") == 0)
2468 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2474 if (LocaleCompare(expression,
"QuantumRange") == 0)
2475 FxReturn((
double) QuantumRange);
2476 if (LocaleCompare(expression,
"QuantumScale") == 0)
2477 FxReturn(QuantumScale);
2483 if (IsFxFunction(expression,
"rand",4) != MagickFalse)
2488 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2489 #pragma omp critical (MagickCore_FxEvaluateSubexpression)
2491 alpha=GetPseudoRandomValue(fx_info->random_info);
2494 if (IsFxFunction(expression,
"round",5) != MagickFalse)
2496 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2497 depth+1,beta,exception);
2498 if ((alpha-floor(alpha)) < (ceil(alpha)-alpha))
2499 FxReturn(floor(alpha));
2500 FxReturn(ceil(alpha));
2502 if (LocaleCompare(expression,
"r") == 0)
2503 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2509 if (LocaleCompare(expression,
"saturation") == 0)
2510 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2511 if (IsFxFunction(expression,
"sign",4) != MagickFalse)
2513 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2514 depth+1,beta,exception);
2515 FxReturn(alpha < 0.0 ? -1.0 : 1.0);
2517 if (IsFxFunction(expression,
"sinc",4) != MagickFalse)
2519 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2520 depth+1,beta,exception);
2523 FxReturn(sin((MagickPI*alpha))/(MagickPI*alpha));
2525 if (IsFxFunction(expression,
"sinh",4) != MagickFalse)
2527 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2528 depth+1,beta,exception);
2529 FxReturn(sinh(alpha));
2531 if (IsFxFunction(expression,
"sin",3) != MagickFalse)
2533 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2534 depth+1,beta,exception);
2535 FxReturn(sin(alpha));
2537 if (IsFxFunction(expression,
"sqrt",4) != MagickFalse)
2539 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2540 depth+1,beta,exception);
2541 FxReturn(sqrt(alpha));
2543 if (IsFxFunction(expression,
"squish",6) != MagickFalse)
2545 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,
2546 depth+1,beta,exception);
2547 FxReturn((1.0/(1.0+exp(-alpha))));
2549 if (LocaleCompare(expression,
"s") == 0)
2550 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2556 if (IsFxFunction(expression,
"tanh",4) != MagickFalse)
2558 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2559 depth+1,beta,exception);
2560 FxReturn(tanh(alpha));
2562 if (IsFxFunction(expression,
"tan",3) != MagickFalse)
2564 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2565 depth+1,beta,exception);
2566 FxReturn(tan(alpha));
2568 if (LocaleCompare(expression,
"Transparent") == 0)
2570 if (IsFxFunction(expression,
"trunc",5) != MagickFalse)
2572 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2573 depth+1,beta,exception);
2575 FxReturn(floor(alpha));
2576 FxReturn(ceil(alpha));
2578 if (LocaleCompare(expression,
"t") == 0)
2579 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2585 if (LocaleCompare(expression,
"u") == 0)
2586 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2592 if (LocaleCompare(expression,
"v") == 0)
2593 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2599 if (IsFxFunction(expression,
"while",5) != MagickFalse)
2607 length=CopyMagickString(subexpression,expression+6,
2608 MagickPathExtent-1);
2610 subexpression[length-1]=
'\0';
2611 FxParseConditional(subexpression,
',',p,q);
2614 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
2616 if (fabs(gamma) < MagickEpsilon)
2618 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2623 if (LocaleCompare(expression,
"w") == 0)
2624 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2630 if (LocaleCompare(expression,
"y") == 0)
2631 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2637 if (LocaleCompare(expression,
"z") == 0)
2638 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2644 q=(
char *) expression;
2645 alpha=InterpretSiPrefixValue(expression,&q);
2646 if (q == expression)
2647 alpha=FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception);
2649 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2650 "UnbalancedParenthesis",
"`%s'",expression);
2654 MagickExport MagickBooleanType FxEvaluateExpression(
FxInfo *fx_info,
2660 status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
2664 MagickExport MagickBooleanType FxPreprocessExpression(
FxInfo *fx_info,
2674 fx_info->file=(FILE *) NULL;
2675 status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
2680 MagickExport MagickBooleanType FxEvaluateChannelExpression(
FxInfo *fx_info,
2681 const ChannelType channel,
const ssize_t x,
const ssize_t y,
double *alpha,
2688 *alpha=FxEvaluateSubexpression(fx_info,channel,x,y,fx_info->expression,0,
2690 return(exception->severity == OptionError ? MagickFalse : MagickTrue);
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);
2738 static FxInfo **AcquireFxTLS(
const Image *image,
const char *expression,
2756 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
2757 fx_info=(
FxInfo **) AcquireQuantumMemory(number_threads,
sizeof(*fx_info));
2758 if (fx_info == (
FxInfo **) NULL)
2760 (void) ThrowMagickException(exception,GetMagickModule(),
2761 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
2762 return((
FxInfo **) NULL);
2764 (void) memset(fx_info,0,number_threads*
sizeof(*fx_info));
2765 if (*expression !=
'@')
2766 fx_expression=ConstantString(expression);
2768 fx_expression=FileToString(expression+1,~0UL,exception);
2769 for (i=0; i < (ssize_t) number_threads; i++)
2774 fx_info[i]=AcquireFxInfo(image,fx_expression);
2775 if (fx_info[i] == (
FxInfo *) NULL)
2777 status=FxPreprocessExpression(fx_info[i],&alpha,exception);
2778 if (status == MagickFalse)
2781 fx_expression=DestroyString(fx_expression);
2782 if (i < (ssize_t) number_threads)
2783 fx_info=DestroyFxTLS(fx_info);
2787 MagickExport
Image *FxImage(
const Image *image,
const char *expression,
2793 fx_image=FxImageChannel(image,GrayChannel,expression,exception);
2797 MagickExport
Image *FxImageChannel(
const Image *image,
const ChannelType channel,
2800 #define FxImageTag "Fx/Image"
2806 **magick_restrict fx_info;
2820 assert(image != (
Image *) NULL);
2821 assert(image->signature == MagickCoreSignature);
2822 if (IsEventLogging() != MagickFalse)
2823 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2824 if (expression == (
const char *) NULL)
2825 return(CloneImage(image,0,0,MagickTrue,exception));
2826 fx_info=AcquireFxTLS(image,expression,exception);
2827 if (fx_info == (
FxInfo **) NULL)
2828 return((
Image *) NULL);
2829 fx_image=CloneImage(image,0,0,MagickTrue,exception);
2830 if (fx_image == (
Image *) NULL)
2832 fx_info=DestroyFxTLS(fx_info);
2833 return((
Image *) NULL);
2835 if (SetImageStorageClass(fx_image,DirectClass) == MagickFalse)
2837 InheritException(exception,&fx_image->exception);
2838 fx_info=DestroyFxTLS(fx_info);
2839 fx_image=DestroyImage(fx_image);
2840 return((
Image *) NULL);
2847 fx_view=AcquireAuthenticCacheView(fx_image,exception);
2848 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2849 #pragma omp parallel for schedule(dynamic) shared(progress,status) \
2850 magick_number_threads(image,fx_image,fx_image->rows, \
2851 GlobExpression(fx_info[0]->expression,"*debug(*",MagickTrue) == 0 ? 1 : 0)
2853 for (y=0; y < (ssize_t) fx_image->rows; y++)
2856 id = GetOpenMPThreadId();
2862 *magick_restrict fx_indexes;
2870 if (status == MagickFalse)
2872 q=GetCacheViewAuthenticPixels(fx_view,0,y,fx_image->columns,1,exception);
2878 fx_indexes=GetCacheViewAuthenticIndexQueue(fx_view);
2880 for (x=0; x < (ssize_t) fx_image->columns; x++)
2882 if ((channel & RedChannel) != 0)
2884 (void) FxEvaluateChannelExpression(fx_info[
id],RedChannel,x,y,
2886 SetPixelRed(q,ClampToQuantum((MagickRealType) QuantumRange*alpha));
2888 if ((channel & GreenChannel) != 0)
2890 (void) FxEvaluateChannelExpression(fx_info[
id],GreenChannel,x,y,
2892 SetPixelGreen(q,ClampToQuantum((MagickRealType) QuantumRange*alpha));
2894 if ((channel & BlueChannel) != 0)
2896 (void) FxEvaluateChannelExpression(fx_info[
id],BlueChannel,x,y,
2898 SetPixelBlue(q,ClampToQuantum((MagickRealType) QuantumRange*alpha));
2900 if ((channel & OpacityChannel) != 0)
2902 (void) FxEvaluateChannelExpression(fx_info[
id],OpacityChannel,x,y,
2904 if (image->matte == MagickFalse)
2905 SetPixelOpacity(q,ClampToQuantum((MagickRealType) QuantumRange*
2908 SetPixelOpacity(q,ClampToQuantum((MagickRealType) (QuantumRange-
2909 QuantumRange*alpha)));
2911 if (((channel & IndexChannel) != 0) &&
2912 (fx_image->colorspace == CMYKColorspace))
2914 (void) FxEvaluateChannelExpression(fx_info[
id],IndexChannel,x,y,
2916 SetPixelIndex(fx_indexes+x,ClampToQuantum((MagickRealType)
2917 QuantumRange*alpha));
2921 if (SyncCacheViewAuthenticPixels(fx_view,exception) == MagickFalse)
2923 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2928 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2932 proceed=SetImageProgress(image,FxImageTag,progress,image->rows);
2933 if (proceed == MagickFalse)
2937 fx_view=DestroyCacheView(fx_view);
2938 fx_info=DestroyFxTLS(fx_info);
2939 if (status == MagickFalse)
2940 fx_image=DestroyImage(fx_image);