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"
64#include "magick/fx-private.h"
65#include "magick/gem.h"
66#include "magick/geometry.h"
67#include "magick/layer.h"
68#include "magick/list.h"
69#include "magick/log.h"
70#include "magick/image.h"
71#include "magick/image-private.h"
72#include "magick/magick.h"
73#include "magick/memory_.h"
74#include "magick/memory-private.h"
75#include "magick/monitor.h"
76#include "magick/monitor-private.h"
77#include "magick/opencl-private.h"
78#include "magick/option.h"
79#include "magick/pixel-accessor.h"
80#include "magick/pixel-private.h"
81#include "magick/property.h"
82#include "magick/quantum.h"
83#include "magick/quantum-private.h"
84#include "magick/random_.h"
85#include "magick/random-private.h"
86#include "magick/resample.h"
87#include "magick/resample-private.h"
88#include "magick/resize.h"
89#include "magick/resource_.h"
90#include "magick/splay-tree.h"
91#include "magick/statistic.h"
92#include "magick/statistic-private.h"
93#include "magick/string_.h"
94#include "magick/string-private.h"
95#include "magick/thread-private.h"
96#include "magick/timer-private.h"
97#include "magick/threshold.h"
98#include "magick/token.h"
99#include "magick/transform.h"
100#include "magick/utility.h"
107 BitwiseAndAssignmentOperator = 0xd9U,
108 BitwiseOrAssignmentOperator,
109 LeftShiftAssignmentOperator,
110 RightShiftAssignmentOperator,
111 PowerAssignmentOperator,
112 ModuloAssignmentOperator,
113 PlusAssignmentOperator,
114 SubtractAssignmentOperator,
115 MultiplyAssignmentOperator,
116 DivideAssignmentOperator,
117 IncrementAssignmentOperator,
118 DecrementAssignmentOperator,
121 LessThanEqualOperator,
122 GreaterThanEqualOperator,
179MagickExport
FxInfo *AcquireFxInfo(
const Image *images,
const char *expression)
193 fx_info=(
FxInfo *) AcquireCriticalMemory(
sizeof(*fx_info));
194 (void) memset(fx_info,0,
sizeof(*fx_info));
195 fx_info->exception=AcquireExceptionInfo();
196 fx_info->images=images;
197 fx_info->colors=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
198 RelinquishMagickMemory);
199 fx_info->symbols=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
200 RelinquishMagickMemory);
201 fx_info->view=(
CacheView **) AcquireQuantumMemory(GetImageListLength(
202 fx_info->images),
sizeof(*fx_info->view));
203 if (fx_info->view == (
CacheView **) NULL)
204 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
206 next=GetFirstImageInList(fx_info->images);
207 for ( ; next != (
Image *) NULL; next=next->next)
209 fx_info->view[i]=AcquireVirtualCacheView(next,fx_info->exception);
212 fx_info->random_info=AcquireRandomInfo();
213 fx_info->expression=ConstantString(expression);
214 fx_info->file=stderr;
219 *fx_op=(
unsigned char) BitwiseAndAssignmentOperator;
220 (void) SubstituteString(&fx_info->expression,
"&=",(
char *) fx_op);
221 *fx_op=(
unsigned char) BitwiseOrAssignmentOperator;
222 (void) SubstituteString(&fx_info->expression,
"|=",(
char *) fx_op);
223 *fx_op=(
unsigned char) LeftShiftAssignmentOperator;
224 (void) SubstituteString(&fx_info->expression,
"<<=",(
char *) fx_op);
225 *fx_op=(
unsigned char) RightShiftAssignmentOperator;
226 (void) SubstituteString(&fx_info->expression,
">>=",(
char *) fx_op);
227 *fx_op=(
unsigned char) PowerAssignmentOperator;
228 (void) SubstituteString(&fx_info->expression,
"^=",(
char *) fx_op);
229 *fx_op=(
unsigned char) ModuloAssignmentOperator;
230 (void) SubstituteString(&fx_info->expression,
"%=",(
char *) fx_op);
231 *fx_op=(
unsigned char) PlusAssignmentOperator;
232 (void) SubstituteString(&fx_info->expression,
"+=",(
char *) fx_op);
233 *fx_op=(
unsigned char) SubtractAssignmentOperator;
234 (void) SubstituteString(&fx_info->expression,
"-=",(
char *) fx_op);
235 *fx_op=(
unsigned char) MultiplyAssignmentOperator;
236 (void) SubstituteString(&fx_info->expression,
"*=",(
char *) fx_op);
237 *fx_op=(
unsigned char) DivideAssignmentOperator;
238 (void) SubstituteString(&fx_info->expression,
"/=",(
char *) fx_op);
239 *fx_op=(
unsigned char) IncrementAssignmentOperator;
240 (void) SubstituteString(&fx_info->expression,
"++",(
char *) fx_op);
241 *fx_op=(
unsigned char) DecrementAssignmentOperator;
242 (void) SubstituteString(&fx_info->expression,
"--",(
char *) fx_op);
243 *fx_op=(
unsigned char) LeftShiftOperator;
244 (void) SubstituteString(&fx_info->expression,
"<<",(
char *) fx_op);
245 *fx_op=(
unsigned char) RightShiftOperator;
246 (void) SubstituteString(&fx_info->expression,
">>",(
char *) fx_op);
247 *fx_op=(
unsigned char) LessThanEqualOperator;
248 (void) SubstituteString(&fx_info->expression,
"<=",(
char *) fx_op);
249 *fx_op=(
unsigned char) GreaterThanEqualOperator;
250 (void) SubstituteString(&fx_info->expression,
">=",(
char *) fx_op);
251 *fx_op=(
unsigned char) EqualOperator;
252 (void) SubstituteString(&fx_info->expression,
"==",(
char *) fx_op);
253 *fx_op=(
unsigned char) NotEqualOperator;
254 (void) SubstituteString(&fx_info->expression,
"!=",(
char *) fx_op);
255 *fx_op=(
unsigned char) LogicalAndOperator;
256 (void) SubstituteString(&fx_info->expression,
"&&",(
char *) fx_op);
257 *fx_op=(
unsigned char) LogicalOrOperator;
258 (void) SubstituteString(&fx_info->expression,
"||",(
char *) fx_op);
259 *fx_op=(
unsigned char) ExponentialNotation;
260 (void) SubstituteString(&fx_info->expression,
"**",(
char *) fx_op);
264 (void) SubstituteString(&fx_info->expression,
"-",
"-1.0*");
265 (void) SubstituteString(&fx_info->expression,
"^-1.0*",
"^-");
266 (void) SubstituteString(&fx_info->expression,
"E-1.0*",
"E-");
267 (void) SubstituteString(&fx_info->expression,
"e-1.0*",
"e-");
268 (void) SubstituteString(&fx_info->expression,
" ",
"");
299 fx_info->exception=DestroyExceptionInfo(fx_info->exception);
300 fx_info->expression=DestroyString(fx_info->expression);
301 fx_info->symbols=DestroySplayTree(fx_info->symbols);
302 fx_info->colors=DestroySplayTree(fx_info->colors);
303 for (i=(ssize_t) GetImageListLength(fx_info->images)-1; i >= 0; i--)
304 fx_info->view[i]=DestroyCacheView(fx_info->view[i]);
305 fx_info->view=(
CacheView **) RelinquishMagickMemory(fx_info->view);
306 fx_info->random_info=DestroyRandomInfo(fx_info->random_info);
307 fx_info=(
FxInfo *) RelinquishMagickMemory(fx_info);
347static inline const double *GetFxSymbolValue(
FxInfo *fx_info,
const char *symbol)
349 return((
const double *) GetValueFromSplayTree(fx_info->symbols,symbol));
352static inline MagickBooleanType SetFxSymbolValue(
353 FxInfo *magick_restrict fx_info,
const char *magick_restrict symbol,
359 object=(
double *) GetValueFromSplayTree(fx_info->symbols,symbol);
360 if (
object != (
double *) NULL)
365 object=(
double *) AcquireMagickMemory(
sizeof(*
object));
366 if (
object == (
double *) NULL)
368 (void) ThrowMagickException(fx_info->exception,GetMagickModule(),
369 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
370 fx_info->images->filename);
374 return(AddValueToSplayTree(fx_info->symbols,ConstantString(symbol),
object));
377static double FxChannelStatistics(
FxInfo *fx_info,
const Image *image,
378 ChannelType channel,
const char *symbol,
ExceptionInfo *exception)
381 channel_symbol[MaxTextExtent],
393 for (p=symbol; (*p !=
'.') && (*p !=
'\0'); p++) ;
394 *channel_symbol=
'\0';
400 (void) CopyMagickString(channel_symbol,p+1,MaxTextExtent);
401 option=ParseCommandOption(MagickChannelOptions,MagickTrue,channel_symbol);
403 channel=(ChannelType) option;
405 (void) FormatLocaleString(key,MaxTextExtent,
"%p.%.20g.%s",(
void *) image,
406 (
double) channel,symbol);
407 value=GetFxSymbolValue(fx_info,key);
408 if (value != (
const double *) NULL)
409 return(QuantumScale*(*value));
411 if (LocaleNCompare(symbol,
"depth",5) == 0)
416 depth=GetImageChannelDepth(image,channel,exception);
417 statistic=(double) depth;
419 if (LocaleNCompare(symbol,
"kurtosis",8) == 0)
425 (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
427 statistic=QuantumRange*kurtosis;
429 if (LocaleNCompare(symbol,
"maxima",6) == 0)
435 (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
438 if (LocaleNCompare(symbol,
"mean",4) == 0)
444 (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
448 if (LocaleNCompare(symbol,
"minima",6) == 0)
454 (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
457 if (LocaleNCompare(symbol,
"skewness",8) == 0)
463 (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
465 statistic=QuantumRange*skewness;
467 if (LocaleNCompare(symbol,
"standard_deviation",18) == 0)
473 (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
475 statistic=standard_deviation;
477 if (SetFxSymbolValue(fx_info,key,statistic) == MagickFalse)
479 return(QuantumScale*statistic);
483 FxEvaluateSubexpression(
FxInfo *,
const ChannelType,
const ssize_t,
484 const ssize_t,
const char *,
const size_t,
double *,
ExceptionInfo *);
486static inline MagickBooleanType IsFxFunction(
const char *expression,
487 const char *name,
const size_t length)
495 for (i=0; i <= length; i++)
496 if (expression[i] ==
'\0')
498 c=expression[length];
499 if ((LocaleNCompare(expression,name,length) == 0) &&
500 ((isspace((
int) ((
unsigned char) c)) == 0) || (c ==
'(')))
505static inline double FxGCD(
const double alpha,
const double beta,
508#define FxMaxFunctionDepth 200
511 return(FxGCD(beta,alpha,depth+1));
512 if ((fabs(beta) < 0.001) || (depth >= FxMaxFunctionDepth))
514 return(FxGCD(beta,alpha-beta*floor(alpha/beta),depth+1));
517static inline const char *FxSubexpression(
const char *expression,
527 subexpression=expression;
528 while ((*subexpression !=
'\0') &&
529 ((level != 1) || (strchr(
")",(
int) *subexpression) == (
char *) NULL)))
531 if (strchr(
"(",(
int) *subexpression) != (
char *) NULL)
534 if (strchr(
")",(
int) *subexpression) != (
char *) NULL)
538 if (*subexpression ==
'\0')
539 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
540 "UnbalancedParenthesis",
"`%s'",expression);
541 return(subexpression);
544static double FxGetSymbol(
FxInfo *fx_info,
const ChannelType channel,
545 const ssize_t x,
const ssize_t y,
const char *expression,
const size_t depth,
550 symbol[MaxTextExtent];
582 i=GetImageIndexInList(fx_info->images);
586 if (isalpha((
int) ((
unsigned char) *(p+1))) == 0)
591 subexpression=AcquireString(expression);
592 if (strchr(
"suv",(
int) *p) != (
char *) NULL)
599 i=GetImageIndexInList(fx_info->images);
602 case 'u': i=0;
break;
603 case 'v': i=1;
break;
610 for (p++; *p !=
'\0'; )
624 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
625 depth,&beta,exception);
633 if ((*p ==
'p') && (isalpha((
int) ((
unsigned char) *(p+1))) == 0))
640 for (p++; *p !=
'\0'; )
654 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
655 depth,&beta,exception);
666 for (p++; *p !=
'\0'; )
680 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
681 depth,&beta,exception);
690 subexpression=DestroyString(subexpression);
692 image=GetImageFromList(fx_info->images,i);
693 if (image == (
Image *) NULL)
695 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
696 "NoSuchImage",
"`%s'",expression);
699 i=GetImageIndexInList(image);
700 GetMagickPixelPacket(image,&pixel);
701 status=InterpolateMagickPixelPacket(image,fx_info->view[i],image->interpolate,
702 point.x,point.y,&pixel,exception);
704 if ((*p !=
'\0') && (*(p+1) !=
'\0') && (*(p+2) !=
'\0') &&
705 (LocaleCompare(p,
"intensity") != 0) && (LocaleCompare(p,
"luma") != 0) &&
706 (LocaleCompare(p,
"luminance") != 0) && (LocaleCompare(p,
"hue") != 0) &&
707 (LocaleCompare(p,
"saturation") != 0) &&
708 (LocaleCompare(p,
"lightness") != 0))
716 (void) CopyMagickString(name,p,MaxTextExtent);
718 for (q=name+length-1; q > name; q--)
729 if ((*q !=
'\0') && (*(q+1) !=
'\0') && (*(q+2) !=
'\0') &&
730 (GetFxSymbolValue(fx_info,name) == (
const double *) NULL))
740 p+=(ptrdiff_t) length;
743 if (QueryMagickColor(name,&pixel,fx_info->exception) != MagickFalse)
745 (void) AddValueToSplayTree(fx_info->colors,ConstantString(name),
746 CloneMagickPixelPacket(&pixel));
747 p+=(ptrdiff_t) length;
751 (void) CopyMagickString(symbol,p,MaxTextExtent);
757 case RedChannel:
return(QuantumScale*pixel.red);
758 case GreenChannel:
return(QuantumScale*pixel.green);
759 case BlueChannel:
return(QuantumScale*pixel.blue);
765 if (pixel.matte == MagickFalse)
767 alpha=(double) (QuantumScale*GetPixelAlpha(&pixel));
772 if (image->colorspace != CMYKColorspace)
774 (void) ThrowMagickException(exception,GetMagickModule(),
775 ImageError,
"ColorSeparatedImageRequired",
"`%s'",
779 return(QuantumScale*pixel.index);
781 case DefaultChannels:
782 return(QuantumScale*GetMagickPixelIntensity(image,&pixel));
786 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
787 "UnableToParseExpression",
"`%s'",p);
795 if (LocaleCompare(symbol,
"a") == 0)
796 return((
double) (QuantumScale*GetPixelAlpha(&pixel)));
802 if (LocaleCompare(symbol,
"b") == 0)
803 return(QuantumScale*pixel.blue);
809 if (IsFxFunction(symbol,
"channel",7) != MagickFalse)
817 flags=ParseGeometry(symbol+7,&channel_info);
818 if (image->colorspace == CMYKColorspace)
823 if ((flags & RhoValue) == 0)
825 return(channel_info.rho);
829 if ((flags & SigmaValue) == 0)
831 return(channel_info.sigma);
835 if ((flags & XiValue) == 0)
837 return(channel_info.xi);
841 if ((flags & PsiValue) == 0)
843 return(channel_info.psi);
847 if ((flags & ChiValue) == 0)
849 return(channel_info.chi);
858 if ((flags & RhoValue) == 0)
860 return(channel_info.rho);
864 if ((flags & SigmaValue) == 0)
866 return(channel_info.sigma);
870 if ((flags & XiValue) == 0)
872 return(channel_info.xi);
876 if ((flags & PsiValue) == 0)
878 return(channel_info.psi);
882 if ((flags & ChiValue) == 0)
884 return(channel_info.chi);
890 if (LocaleCompare(symbol,
"c") == 0)
891 return(QuantumScale*pixel.red);
897 if (LocaleNCompare(symbol,
"depth",5) == 0)
898 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
904 if (LocaleCompare(symbol,
"extent") == 0)
906 if (image->extent != 0)
907 return((
double) image->extent);
908 return((
double) GetBlobSize(image));
915 if (LocaleCompare(symbol,
"g") == 0)
916 return(QuantumScale*pixel.green);
922 if (LocaleNCompare(symbol,
"kurtosis",8) == 0)
923 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
924 if (LocaleCompare(symbol,
"k") == 0)
926 if (image->colorspace != CMYKColorspace)
928 (void) ThrowMagickException(exception,GetMagickModule(),
929 OptionError,
"ColorSeparatedImageRequired",
"`%s'",
933 return(QuantumScale*pixel.index);
940 if (LocaleCompare(symbol,
"h") == 0)
941 return((
double) image->rows);
942 if (LocaleCompare(symbol,
"hue") == 0)
949 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
950 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
958 if ((LocaleCompare(symbol,
"image.depth") == 0) ||
959 (LocaleCompare(symbol,
"image.minima") == 0) ||
960 (LocaleCompare(symbol,
"image.maxima") == 0) ||
961 (LocaleCompare(symbol,
"image.mean") == 0) ||
962 (LocaleCompare(symbol,
"image.kurtosis") == 0) ||
963 (LocaleCompare(symbol,
"image.skewness") == 0) ||
964 (LocaleCompare(symbol,
"image.standard_deviation") == 0))
965 return(FxChannelStatistics(fx_info,image,channel,symbol+6,exception));
966 if (LocaleCompare(symbol,
"image.resolution.x") == 0)
967 return(image->x_resolution);
968 if (LocaleCompare(symbol,
"image.resolution.y") == 0)
969 return(image->y_resolution);
970 if (LocaleCompare(symbol,
"intensity") == 0)
971 return(QuantumScale*GetMagickPixelIntensity(image,&pixel));
972 if (LocaleCompare(symbol,
"i") == 0)
979 if (LocaleCompare(symbol,
"j") == 0)
986 if (LocaleCompare(symbol,
"lightness") == 0)
993 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
994 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
997 if (LocaleCompare(symbol,
"luma") == 0)
1002 luma=0.212656*pixel.red+0.715158*pixel.green+0.072186*pixel.blue;
1003 return(QuantumScale*luma);
1005 if (LocaleCompare(symbol,
"luminance") == 0)
1010 luminance=0.212656*pixel.red+0.715158*pixel.green+0.072186*pixel.blue;
1011 return(QuantumScale*luminance);
1018 if (LocaleNCompare(symbol,
"maxima",6) == 0)
1019 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1020 if (LocaleNCompare(symbol,
"mean",4) == 0)
1021 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1022 if (LocaleNCompare(symbol,
"minima",6) == 0)
1023 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1024 if (LocaleCompare(symbol,
"m") == 0)
1025 return(QuantumScale*pixel.green);
1031 if (LocaleCompare(symbol,
"n") == 0)
1032 return((
double) GetImageListLength(fx_info->images));
1038 if (LocaleCompare(symbol,
"o") == 0)
1039 return(QuantumScale*pixel.opacity);
1045 if (LocaleCompare(symbol,
"page.height") == 0)
1046 return((
double) image->page.height);
1047 if (LocaleCompare(symbol,
"page.width") == 0)
1048 return((
double) image->page.width);
1049 if (LocaleCompare(symbol,
"page.x") == 0)
1050 return((
double) image->page.x);
1051 if (LocaleCompare(symbol,
"page.y") == 0)
1052 return((
double) image->page.y);
1053 if (LocaleCompare(symbol,
"printsize.x") == 0)
1054 return(PerceptibleReciprocal(image->x_resolution)*image->columns);
1055 if (LocaleCompare(symbol,
"printsize.y") == 0)
1056 return(PerceptibleReciprocal(image->y_resolution)*image->rows);
1062 if (LocaleCompare(symbol,
"quality") == 0)
1063 return((
double) image->quality);
1069 if (LocaleCompare(symbol,
"resolution.x") == 0)
1070 return(image->x_resolution);
1071 if (LocaleCompare(symbol,
"resolution.y") == 0)
1072 return(image->y_resolution);
1073 if (LocaleCompare(symbol,
"r") == 0)
1074 return(QuantumScale*pixel.red);
1080 if (LocaleCompare(symbol,
"saturation") == 0)
1087 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
1088 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
1091 if (LocaleNCompare(symbol,
"skewness",8) == 0)
1092 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1093 if (LocaleNCompare(symbol,
"standard_deviation",18) == 0)
1094 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1100 if (LocaleCompare(symbol,
"t") == 0)
1101 return((
double) GetImageIndexInList(fx_info->images));
1107 if (LocaleCompare(symbol,
"w") == 0)
1108 return((
double) image->columns);
1114 if (LocaleCompare(symbol,
"y") == 0)
1115 return(QuantumScale*pixel.blue);
1121 if (LocaleCompare(symbol,
"z") == 0)
1126 depth=(double) GetImageChannelDepth(image,channel,fx_info->exception);
1134 value=GetFxSymbolValue(fx_info,symbol);
1135 if (value != (
const double *) NULL)
1137 artifact=GetImageArtifact(image,symbol);
1138 if (artifact != (
const char *) NULL)
1139 return(StringToDouble(artifact,(
char **) NULL));
1140 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1141 "UndefinedVariable",
"`%s'",symbol);
1142 (void) SetFxSymbolValue(fx_info,symbol,0.0);
1146static const char *FxOperatorPrecedence(
const char *expression,
1151 UndefinedPrecedence,
1153 BitwiseComplementPrecedence,
1155 ExponentialNotationPrecedence,
1159 RelationalPrecedence,
1160 EquivalencyPrecedence,
1161 BitwiseAndPrecedence,
1162 BitwiseOrPrecedence,
1163 LogicalAndPrecedence,
1164 LogicalOrPrecedence,
1166 AssignmentPrecedence,
1186 subexpression=(
const char *) NULL;
1187 target=NullPrecedence;
1188 while ((c !=
'\0') && (*expression !=
'\0'))
1190 precedence=UndefinedPrecedence;
1191 if ((isspace((
int) ((
unsigned char) *expression)) != 0) || (c == (
int)
'@'))
1196 switch (*expression)
1201#if defined(MAGICKCORE_HAVE_ACOSH)
1202 if (IsFxFunction(expression,
"acosh",5) != MagickFalse)
1208#if defined(MAGICKCORE_HAVE_ASINH)
1209 if (IsFxFunction(expression,
"asinh",5) != MagickFalse)
1215#if defined(MAGICKCORE_HAVE_ATANH)
1216 if (IsFxFunction(expression,
"atanh",5) != MagickFalse)
1222 if (IsFxFunction(expression,
"atan2",5) != MagickFalse)
1232 if ((isdigit((
int) ((
unsigned char) c)) != 0) &&
1233 ((LocaleNCompare(expression,
"E+",2) == 0) ||
1234 (LocaleNCompare(expression,
"E-",2) == 0)))
1244 if ((IsFxFunction(expression,
"j0",2) != MagickFalse) ||
1245 (IsFxFunction(expression,
"j1",2) != MagickFalse))
1254 while (isxdigit((
int) ((
unsigned char) *(expression+1))) != 0)
1261 if ((c == (
int)
'{') || (c == (
int)
'['))
1264 if ((c == (
int)
'}') || (c == (
int)
']'))
1267 switch ((
unsigned char) *expression)
1272 precedence=BitwiseComplementPrecedence;
1278 precedence=ExponentPrecedence;
1283 if (((c != 0) && ((isdigit((
int) ((
unsigned char) c)) != 0) ||
1284 (strchr(
")",c) != (
char *) NULL))) &&
1285 (((islower((
int) ((
unsigned char) *expression)) != 0) ||
1286 (strchr(
"(",(
int) ((
unsigned char) *expression)) != (
char *) NULL)) ||
1287 ((isdigit((
int) ((
unsigned char) c)) == 0) &&
1288 (isdigit((
int) ((
unsigned char) *expression)) != 0))) &&
1289 (strchr(
"xy",(
int) ((
unsigned char) *expression)) == (
char *) NULL))
1290 precedence=MultiplyPrecedence;
1297 precedence=MultiplyPrecedence;
1303 if ((strchr(
"(+-/*%:&^|<>~,",c) == (
char *) NULL) ||
1304 (isalpha((
int) ((
unsigned char) c)) != 0))
1305 precedence=AdditionPrecedence;
1308 case BitwiseAndAssignmentOperator:
1309 case BitwiseOrAssignmentOperator:
1310 case LeftShiftAssignmentOperator:
1311 case RightShiftAssignmentOperator:
1312 case PowerAssignmentOperator:
1313 case ModuloAssignmentOperator:
1314 case PlusAssignmentOperator:
1315 case SubtractAssignmentOperator:
1316 case MultiplyAssignmentOperator:
1317 case DivideAssignmentOperator:
1318 case IncrementAssignmentOperator:
1319 case DecrementAssignmentOperator:
1321 precedence=AssignmentPrecedence;
1324 case LeftShiftOperator:
1325 case RightShiftOperator:
1327 precedence=ShiftPrecedence;
1331 case LessThanEqualOperator:
1332 case GreaterThanEqualOperator:
1335 precedence=RelationalPrecedence;
1339 case NotEqualOperator:
1341 precedence=EquivalencyPrecedence;
1346 precedence=BitwiseAndPrecedence;
1351 precedence=BitwiseOrPrecedence;
1354 case LogicalAndOperator:
1356 precedence=LogicalAndPrecedence;
1359 case LogicalOrOperator:
1361 precedence=LogicalOrPrecedence;
1364 case ExponentialNotation:
1366 precedence=ExponentialNotationPrecedence;
1372 precedence=TernaryPrecedence;
1377 precedence=AssignmentPrecedence;
1382 precedence=CommaPrecedence;
1387 precedence=SeparatorPrecedence;
1391 if ((precedence == BitwiseComplementPrecedence) ||
1392 (precedence == TernaryPrecedence) ||
1393 (precedence == AssignmentPrecedence))
1395 if (precedence > target)
1401 subexpression=expression;
1405 if (precedence >= target)
1411 subexpression=expression;
1413 if (strchr(
"(",(
int) *expression) != (
char *) NULL)
1414 expression=FxSubexpression(expression,exception);
1415 c=(int) (*expression++);
1417 return(subexpression);
1420static double FxEvaluateSubexpression(
FxInfo *fx_info,
const ChannelType channel,
1421 const ssize_t x,
const ssize_t y,
const char *expression,
const size_t depth,
1424#define FxMaxParenthesisDepth 58
1425#define FxMaxSubexpressionDepth 200
1426#define FxReturn(value) \
1428 subexpression=DestroyString(subexpression); \
1431#define FxParseConditional(subexpression,sentinal,p,q) \
1434 for (q=(char *) p; (*q != (sentinal)) && (*q != '\0'); q++) \
1437 for (q++; (*q != ')') && (*q != '\0'); q++); \
1443 (void) ThrowMagickException(exception,GetMagickModule(), \
1444 OptionError,"UnableToParseExpression","`%s'",subexpression); \
1447 if (strlen(q) == 1) \
1467 subexpression=AcquireString(expression);
1468 *subexpression=
'\0';
1469 if (depth > FxMaxSubexpressionDepth)
1471 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1472 "UnableToParseExpression",
"`%s'",expression);
1475 if (exception->severity >= ErrorException)
1477 while (isspace((
int) ((
unsigned char) *expression)) != 0)
1479 if (*expression ==
'\0')
1481 p=FxOperatorPrecedence(expression,exception);
1482 if (p != (
const char *) NULL)
1484 (void) CopyMagickString(subexpression,expression,(
size_t)
1486 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,depth+1,
1488 switch ((
unsigned char) *p)
1492 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1494 *beta=(double) (~(
size_t) *beta);
1499 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1501 FxReturn(*beta == 0.0 ? 1.0 : 0.0);
1505 *beta=pow(alpha,FxEvaluateSubexpression(fx_info,channel,x,y,++p,
1506 depth+1,beta,exception));
1510 case ExponentialNotation:
1512 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1514 FxReturn(alpha*(*beta));
1518 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1520 FxReturn(PerceptibleReciprocal(*beta)*alpha);
1524 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1526 FxReturn(fmod(alpha,*beta));
1530 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1532 FxReturn(alpha+(*beta));
1536 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1538 FxReturn(alpha-(*beta));
1540 case BitwiseAndAssignmentOperator:
1543 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1547 (void) ThrowMagickException(exception,GetMagickModule(),
1548 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1551 ClearMagickException(exception);
1552 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1554 value=(double) ((
size_t) (alpha+0.5) & (
size_t) (*beta+0.5));
1555 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1559 case BitwiseOrAssignmentOperator:
1562 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1566 (void) ThrowMagickException(exception,GetMagickModule(),
1567 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1570 ClearMagickException(exception);
1571 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1573 value=(double) ((
size_t) (alpha+0.5) | (
size_t) (*beta+0.5));
1574 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1578 case LeftShiftAssignmentOperator:
1581 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1585 (void) ThrowMagickException(exception,GetMagickModule(),
1586 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1589 ClearMagickException(exception);
1590 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1592 if ((
size_t) (*beta+0.5) >= (8*
sizeof(
size_t)))
1594 (void) ThrowMagickException(exception,GetMagickModule(),
1595 OptionError,
"ShiftCountOverflow",
"`%s'",subexpression);
1598 value=(double) ((
size_t) (alpha+0.5) << (
size_t) (*beta+0.5));
1599 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1603 case RightShiftAssignmentOperator:
1606 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1610 (void) ThrowMagickException(exception,GetMagickModule(),
1611 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1614 ClearMagickException(exception);
1615 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1617 if ((
size_t) (*beta+0.5) >= (8*
sizeof(
size_t)))
1619 (void) ThrowMagickException(exception,GetMagickModule(),
1620 OptionError,
"ShiftCountOverflow",
"`%s'",subexpression);
1623 value=(double) ((
size_t) (alpha+0.5) >> (
size_t) (*beta+0.5));
1624 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1628 case PowerAssignmentOperator:
1631 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1635 (void) ThrowMagickException(exception,GetMagickModule(),
1636 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1639 ClearMagickException(exception);
1640 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1642 value=pow(alpha,*beta);
1643 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1647 case ModuloAssignmentOperator:
1650 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1654 (void) ThrowMagickException(exception,GetMagickModule(),
1655 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1658 ClearMagickException(exception);
1659 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1661 value=fmod(alpha,*beta);
1662 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1666 case PlusAssignmentOperator:
1669 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1673 (void) ThrowMagickException(exception,GetMagickModule(),
1674 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1677 ClearMagickException(exception);
1678 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1680 value=alpha+(*beta);
1681 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1685 case SubtractAssignmentOperator:
1688 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1692 (void) ThrowMagickException(exception,GetMagickModule(),
1693 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1696 ClearMagickException(exception);
1697 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1699 value=alpha-(*beta);
1700 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1704 case MultiplyAssignmentOperator:
1707 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1711 (void) ThrowMagickException(exception,GetMagickModule(),
1712 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1715 ClearMagickException(exception);
1716 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1718 value=alpha*(*beta);
1719 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1723 case DivideAssignmentOperator:
1726 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1730 (void) ThrowMagickException(exception,GetMagickModule(),
1731 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1734 ClearMagickException(exception);
1735 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1737 value=alpha*PerceptibleReciprocal(*beta);
1738 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1742 case IncrementAssignmentOperator:
1744 if (*subexpression ==
'\0')
1745 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1748 if (*subexpression ==
'\0')
1750 if (SetFxSymbolValue(fx_info,p,value) == MagickFalse)
1754 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1758 case DecrementAssignmentOperator:
1760 if (*subexpression ==
'\0')
1761 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1764 if (*subexpression ==
'\0')
1766 if (SetFxSymbolValue(fx_info,p,value) == MagickFalse)
1770 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1774 case LeftShiftOperator:
1776 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1778 if ((
size_t) (gamma+0.5) >= (8*
sizeof(
size_t)))
1780 (void) ThrowMagickException(exception,GetMagickModule(),
1781 OptionError,
"ShiftCountOverflow",
"`%s'",subexpression);
1784 *beta=(double) ((
size_t) (alpha+0.5) << (
size_t) (gamma+0.5));
1787 case RightShiftOperator:
1789 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1791 if ((
size_t) (gamma+0.5) >= (8*
sizeof(
size_t)))
1793 (void) ThrowMagickException(exception,GetMagickModule(),
1794 OptionError,
"ShiftCountOverflow",
"`%s'",subexpression);
1797 *beta=(double) ((
size_t) (alpha+0.5) >> (
size_t) (gamma+0.5));
1802 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1804 FxReturn(alpha < *beta ? 1.0 : 0.0);
1806 case LessThanEqualOperator:
1808 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1810 FxReturn(alpha <= *beta ? 1.0 : 0.0);
1814 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1816 FxReturn(alpha > *beta ? 1.0 : 0.0);
1818 case GreaterThanEqualOperator:
1820 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1822 FxReturn(alpha >= *beta ? 1.0 : 0.0);
1826 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1828 FxReturn(fabs(alpha-(*beta)) < MagickEpsilon ? 1.0 : 0.0);
1830 case NotEqualOperator:
1832 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1834 FxReturn(fabs(alpha-(*beta)) >= MagickEpsilon ? 1.0 : 0.0);
1838 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1840 *beta=(double) ((
size_t) (alpha+0.5) & (
size_t) (gamma+0.5));
1845 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1847 *beta=(double) ((
size_t) (alpha+0.5) | (
size_t) (gamma+0.5));
1850 case LogicalAndOperator:
1858 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1860 *beta=(gamma > 0.0) ? 1.0 : 0.0;
1863 case LogicalOrOperator:
1871 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1873 *beta=(gamma > 0.0) ? 1.0 : 0.0;
1881 (void) CopyMagickString(subexpression,++p,MaxTextExtent-1);
1882 FxParseConditional(subexpression,
':',p,q);
1883 if (fabs(alpha) >= MagickEpsilon)
1884 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1887 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
1894 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1898 (void) ThrowMagickException(exception,GetMagickModule(),
1899 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1902 ClearMagickException(exception);
1903 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1906 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1912 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1918 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1926 gamma=alpha*FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,
1932 if (strchr(
"(",(
int) *expression) != (
char *) NULL)
1937 if (depth >= FxMaxParenthesisDepth)
1938 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1939 "ParenthesisNestedTooDeeply",
"`%s'",expression);
1940 length=CopyMagickString(subexpression,expression+1,MaxTextExtent);
1942 subexpression[length-1]=
'\0';
1943 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,depth+1,
1947 switch (*expression)
1951 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1953 FxReturn(1.0*gamma);
1957 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1959 FxReturn(-1.0*gamma);
1963 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1965 FxReturn((
double) (~(
size_t) (gamma+0.5)));
1970 if (IsFxFunction(expression,
"abs",3) != MagickFalse)
1972 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
1973 depth+1,beta,exception);
1974 FxReturn(fabs(alpha));
1976#if defined(MAGICKCORE_HAVE_ACOSH)
1977 if (IsFxFunction(expression,
"acosh",5) != MagickFalse)
1979 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
1980 depth+1,beta,exception);
1981 FxReturn(acosh(alpha));
1984 if (IsFxFunction(expression,
"acos",4) != MagickFalse)
1986 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
1987 depth+1,beta,exception);
1988 FxReturn(acos(alpha));
1990#if defined(MAGICKCORE_HAVE_J1)
1991 if (IsFxFunction(expression,
"airy",4) != MagickFalse)
1993 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
1994 depth+1,beta,exception);
1997 gamma=2.0*j1((MagickPI*alpha))/(MagickPI*alpha);
1998 FxReturn(gamma*gamma);
2001#if defined(MAGICKCORE_HAVE_ASINH)
2002 if (IsFxFunction(expression,
"asinh",5) != MagickFalse)
2004 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2005 depth+1,beta,exception);
2006 FxReturn(asinh(alpha));
2009 if (IsFxFunction(expression,
"asin",4) != MagickFalse)
2011 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2012 depth+1,beta,exception);
2013 FxReturn(asin(alpha));
2015 if (IsFxFunction(expression,
"alt",3) != MagickFalse)
2017 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2018 depth+1,beta,exception);
2019 FxReturn(((ssize_t) alpha) & 0x01 ? -1.0 : 1.0);
2021 if (IsFxFunction(expression,
"atan2",5) != MagickFalse)
2023 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2024 depth+1,beta,exception);
2025 FxReturn(atan2(alpha,*beta));
2027#if defined(MAGICKCORE_HAVE_ATANH)
2028 if (IsFxFunction(expression,
"atanh",5) != MagickFalse)
2030 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2031 depth+1,beta,exception);
2032 FxReturn(atanh(alpha));
2035 if (IsFxFunction(expression,
"atan",4) != MagickFalse)
2037 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2038 depth+1,beta,exception);
2039 FxReturn(atan(alpha));
2041 if (LocaleCompare(expression,
"a") == 0)
2042 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2048 if (LocaleCompare(expression,
"b") == 0)
2049 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2055 if (IsFxFunction(expression,
"ceil",4) != MagickFalse)
2057 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2058 depth+1,beta,exception);
2059 FxReturn(ceil(alpha));
2061 if (IsFxFunction(expression,
"clamp",5) != MagickFalse)
2063 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2064 depth+1,beta,exception);
2071 if (IsFxFunction(expression,
"cosh",4) != MagickFalse)
2073 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2074 depth+1,beta,exception);
2075 FxReturn(cosh(alpha));
2077 if (IsFxFunction(expression,
"cos",3) != MagickFalse)
2079 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2080 depth+1,beta,exception);
2081 FxReturn(cos(alpha));
2083 if (LocaleCompare(expression,
"c") == 0)
2084 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2090 if (IsFxFunction(expression,
"debug",5) != MagickFalse)
2098 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2099 depth+1,beta,exception);
2100 switch (fx_info->images->colorspace)
2102 case CMYKColorspace:
2106 case CyanChannel: type=
"cyan";
break;
2107 case MagentaChannel: type=
"magenta";
break;
2108 case YellowChannel: type=
"yellow";
break;
2109 case AlphaChannel: type=
"alpha";
break;
2110 case BlackChannel: type=
"black";
break;
2111 default: type=
"unknown";
break;
2115 case GRAYColorspace:
2119 case RedChannel: type=
"gray";
break;
2120 case AlphaChannel: type=
"alpha";
break;
2121 default: type=
"unknown";
break;
2129 case RedChannel: type=
"red";
break;
2130 case GreenChannel: type=
"green";
break;
2131 case BlueChannel: type=
"blue";
break;
2132 case AlphaChannel: type=
"alpha";
break;
2133 default: type=
"unknown";
break;
2138 *subexpression=
'\0';
2140 if (strlen(expression) > 6)
2141 length=CopyMagickString(subexpression,expression+6,MaxTextExtent);
2143 subexpression[length-1]=
'\0';
2144 if (fx_info->file != (FILE *) NULL)
2145 (void) FormatLocaleFile(fx_info->file,
2146 "%s[%.20g,%.20g].%s: %s=%.*g\n",fx_info->images->filename,
2147 (
double) x,(
double) y,type,subexpression,GetMagickPrecision(),
2151 if (IsFxFunction(expression,
"do",2) != MagickFalse)
2159 length=CopyMagickString(subexpression,expression+6,
2160 MagickPathExtent-1);
2162 subexpression[length-1]=
'\0';
2163 FxParseConditional(subexpression,
',',p,q);
2166 if (IsImageTTLExpired(fx_info->images) != MagickFalse)
2167 (void) ThrowMagickException(exception,GetMagickModule(),
2168 ResourceLimitFatalError,
"TimeLimitExceeded",
"`%s'",
2169 fx_info->images->filename);
2170 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2172 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2174 if (fabs(gamma) < MagickEpsilon)
2179 if (IsFxFunction(expression,
"drc",3) != MagickFalse)
2181 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2182 depth+1,beta,exception);
2183 FxReturn(alpha*PerceptibleReciprocal(*beta*(alpha-1.0)+1.0));
2190 if (LocaleCompare(expression,
"epsilon") == 0)
2191 FxReturn(MagickEpsilon);
2192#if defined(MAGICKCORE_HAVE_ERF)
2193 if (IsFxFunction(expression,
"erf",3) != MagickFalse)
2195 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2196 depth+1,beta,exception);
2197 FxReturn(erf(alpha));
2200 if (IsFxFunction(expression,
"exp",3) != MagickFalse)
2202 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2203 depth+1,beta,exception);
2204 FxReturn(exp(alpha));
2206 if (LocaleCompare(expression,
"e") == 0)
2207 FxReturn(2.7182818284590452354);
2213 if (IsFxFunction(expression,
"floor",5) != MagickFalse)
2215 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2216 depth+1,beta,exception);
2217 FxReturn(floor(alpha));
2219 if (IsFxFunction(expression,
"for",3) != MagickFalse)
2230 length=CopyMagickString(subexpression,expression+4,
2231 MagickPathExtent-1);
2233 subexpression[length-1]=
'\0';
2234 FxParseConditional(subexpression,
',',p,q);
2235 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2237 (void) CopyMagickString(subexpression,q+1,MagickPathExtent-1);
2238 FxParseConditional(subexpression,
',',p,q);
2241 if (IsImageTTLExpired(fx_info->images) != MagickFalse)
2242 (void) ThrowMagickException(exception,GetMagickModule(),
2243 ResourceLimitFatalError,
"TimeLimitExceeded",
"`%s'",
2244 fx_info->images->filename);
2245 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2247 if (fabs(gamma) < MagickEpsilon)
2249 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2259 if (IsFxFunction(expression,
"gauss",5) != MagickFalse)
2261 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2262 depth+1,beta,exception);
2263 FxReturn(exp((-alpha*alpha/2.0))/sqrt(2.0*MagickPI));
2265 if (IsFxFunction(expression,
"gcd",3) != MagickFalse)
2270 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2271 depth+1,beta,exception);
2274 gcd=FxGCD(alpha,*beta,0);
2277 if (LocaleCompare(expression,
"g") == 0)
2278 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2284 if (LocaleCompare(expression,
"h") == 0)
2285 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2286 if (LocaleCompare(expression,
"hue") == 0)
2287 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2288 if (IsFxFunction(expression,
"hypot",5) != MagickFalse)
2290 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2291 depth+1,beta,exception);
2292 FxReturn(hypot(alpha,*beta));
2299 if (LocaleCompare(expression,
"k") == 0)
2300 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2306 if (IsFxFunction(expression,
"if",2) != MagickFalse)
2317 length=CopyMagickString(subexpression,expression+3,
2318 MagickPathExtent-1);
2320 subexpression[length-1]=
'\0';
2321 FxParseConditional(subexpression,
',',p,q);
2322 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2324 (void) CopyMagickString(subexpression,q+1,MagickPathExtent-1);
2325 FxParseConditional(subexpression,
',',p,q);
2326 if (fabs(alpha) >= MagickEpsilon)
2327 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
2330 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2334 if (LocaleCompare(expression,
"intensity") == 0)
2335 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2336 if (IsFxFunction(expression,
"int",3) != MagickFalse)
2338 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2339 depth+1,beta,exception);
2340 FxReturn(floor(alpha));
2342 if (IsFxFunction(expression,
"isnan",5) != MagickFalse)
2344 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2345 depth+1,beta,exception);
2346 FxReturn((
double) !!IsNaN(alpha));
2348 if (LocaleCompare(expression,
"i") == 0)
2349 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2355 if (LocaleCompare(expression,
"j") == 0)
2356 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2357#if defined(MAGICKCORE_HAVE_J0)
2358 if (IsFxFunction(expression,
"j0",2) != MagickFalse)
2360 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2361 depth+1,beta,exception);
2362 FxReturn(j0(alpha));
2365#if defined(MAGICKCORE_HAVE_J1)
2366 if (IsFxFunction(expression,
"j1",2) != MagickFalse)
2368 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2369 depth+1,beta,exception);
2370 FxReturn(j1(alpha));
2373#if defined(MAGICKCORE_HAVE_J1)
2374 if (IsFxFunction(expression,
"jinc",4) != MagickFalse)
2376 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2377 depth+1,beta,exception);
2380 FxReturn((2.0*j1((MagickPI*alpha))/(MagickPI*alpha)));
2388 if (IsFxFunction(expression,
"ln",2) != MagickFalse)
2390 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2391 depth+1,beta,exception);
2392 FxReturn(log(alpha));
2394 if (IsFxFunction(expression,
"logtwo",6) != MagickFalse)
2396 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,
2397 depth+1,beta,exception);
2398 FxReturn(MagickLog10(alpha)/log10(2.0));
2400 if (IsFxFunction(expression,
"log",3) != MagickFalse)
2402 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2403 depth+1,beta,exception);
2404 FxReturn(MagickLog10(alpha));
2406 if (LocaleCompare(expression,
"lightness") == 0)
2407 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2413 if (LocaleCompare(expression,
"MaxRGB") == 0)
2414 FxReturn((
double) QuantumRange);
2415 if (LocaleNCompare(expression,
"maxima",6) == 0)
2417 if (IsFxFunction(expression,
"max",3) != MagickFalse)
2419 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2420 depth+1,beta,exception);
2421 FxReturn(alpha > *beta ? alpha : *beta);
2423 if (LocaleNCompare(expression,
"minima",6) == 0)
2425 if (IsFxFunction(expression,
"min",3) != MagickFalse)
2427 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2428 depth+1,beta,exception);
2429 FxReturn(alpha < *beta ? alpha : *beta);
2431 if (IsFxFunction(expression,
"mod",3) != MagickFalse)
2433 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2434 depth+1,beta,exception);
2435 FxReturn(alpha-floor((alpha*PerceptibleReciprocal(*beta)))*(*beta));
2437 if (LocaleCompare(expression,
"m") == 0)
2438 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2444 if (IsFxFunction(expression,
"not",3) != MagickFalse)
2446 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2447 depth+1,beta,exception);
2448 FxReturn((
double) (alpha < MagickEpsilon));
2450 if (LocaleCompare(expression,
"n") == 0)
2451 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2457 if (LocaleCompare(expression,
"Opaque") == 0)
2459 if (LocaleCompare(expression,
"o") == 0)
2460 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2466 if (LocaleCompare(expression,
"phi") == 0)
2467 FxReturn(MagickPHI);
2468 if (LocaleCompare(expression,
"pi") == 0)
2470 if (IsFxFunction(expression,
"pow",3) != MagickFalse)
2472 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2473 depth+1,beta,exception);
2474 FxReturn(pow(alpha,*beta));
2476 if (LocaleCompare(expression,
"p") == 0)
2477 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2483 if (LocaleCompare(expression,
"QuantumRange") == 0)
2484 FxReturn((
double) QuantumRange);
2485 if (LocaleCompare(expression,
"QuantumScale") == 0)
2486 FxReturn(QuantumScale);
2492 if (IsFxFunction(expression,
"rand",4) != MagickFalse)
2497#if defined(MAGICKCORE_OPENMP_SUPPORT)
2498 #pragma omp critical (MagickCore_FxEvaluateSubexpression)
2500 alpha=GetPseudoRandomValue(fx_info->random_info);
2503 if (IsFxFunction(expression,
"round",5) != MagickFalse)
2505 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2506 depth+1,beta,exception);
2507 if ((alpha-floor(alpha)) < (ceil(alpha)-alpha))
2508 FxReturn(floor(alpha));
2509 FxReturn(ceil(alpha));
2511 if (LocaleCompare(expression,
"r") == 0)
2512 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2518 if (LocaleCompare(expression,
"saturation") == 0)
2519 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2520 if (IsFxFunction(expression,
"sign",4) != MagickFalse)
2522 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2523 depth+1,beta,exception);
2524 FxReturn(alpha < 0.0 ? -1.0 : 1.0);
2526 if (IsFxFunction(expression,
"sinc",4) != MagickFalse)
2528 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2529 depth+1,beta,exception);
2532 FxReturn(sin((MagickPI*alpha))/(MagickPI*alpha));
2534 if (IsFxFunction(expression,
"sinh",4) != MagickFalse)
2536 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2537 depth+1,beta,exception);
2538 FxReturn(sinh(alpha));
2540 if (IsFxFunction(expression,
"sin",3) != MagickFalse)
2542 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2543 depth+1,beta,exception);
2544 FxReturn(sin(alpha));
2546 if (IsFxFunction(expression,
"sqrt",4) != MagickFalse)
2548 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2549 depth+1,beta,exception);
2550 FxReturn(sqrt(alpha));
2552 if (IsFxFunction(expression,
"squish",6) != MagickFalse)
2554 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,
2555 depth+1,beta,exception);
2556 FxReturn((1.0/(1.0+exp(-alpha))));
2558 if (LocaleCompare(expression,
"s") == 0)
2559 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2565 if (IsFxFunction(expression,
"tanh",4) != MagickFalse)
2567 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2568 depth+1,beta,exception);
2569 FxReturn(tanh(alpha));
2571 if (IsFxFunction(expression,
"tan",3) != MagickFalse)
2573 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2574 depth+1,beta,exception);
2575 FxReturn(tan(alpha));
2577 if (LocaleCompare(expression,
"Transparent") == 0)
2579 if (IsFxFunction(expression,
"trunc",5) != MagickFalse)
2581 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2582 depth+1,beta,exception);
2584 FxReturn(floor(alpha));
2585 FxReturn(ceil(alpha));
2587 if (LocaleCompare(expression,
"t") == 0)
2588 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2594 if (LocaleCompare(expression,
"u") == 0)
2595 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2601 if (LocaleCompare(expression,
"v") == 0)
2602 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2608 if (IsFxFunction(expression,
"while",5) != MagickFalse)
2616 length=CopyMagickString(subexpression,expression+6,
2617 MagickPathExtent-1);
2619 subexpression[length-1]=
'\0';
2620 FxParseConditional(subexpression,
',',p,q);
2623 if (IsImageTTLExpired(fx_info->images) != MagickFalse)
2624 (void) ThrowMagickException(exception,GetMagickModule(),
2625 ResourceLimitFatalError,
"TimeLimitExceeded",
"`%s'",
2626 fx_info->images->filename);
2627 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
2629 if (fabs(gamma) < MagickEpsilon)
2631 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2636 if (LocaleCompare(expression,
"w") == 0)
2637 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2643 if (LocaleCompare(expression,
"y") == 0)
2644 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2650 if (LocaleCompare(expression,
"z") == 0)
2651 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2657 q=(
char *) expression;
2658 alpha=InterpretSiPrefixValue(expression,&q);
2659 if (q == expression)
2660 alpha=FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception);
2662 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2663 "UnbalancedParenthesis",
"`%s'",expression);
2667MagickExport MagickBooleanType FxEvaluateExpression(
FxInfo *fx_info,
2673 status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
2677MagickExport MagickBooleanType FxPreprocessExpression(
FxInfo *fx_info,
2687 fx_info->file=(FILE *) NULL;
2688 status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
2693MagickExport MagickBooleanType FxEvaluateChannelExpression(
FxInfo *fx_info,
2694 const ChannelType channel,
const ssize_t x,
const ssize_t y,
double *alpha,
2701 *alpha=FxEvaluateSubexpression(fx_info,channel,x,y,fx_info->expression,0,
2703 return(exception->severity == OptionError ? MagickFalse : MagickTrue);
2743 assert(fx_info != (
FxInfo **) NULL);
2744 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
2745 if (fx_info[i] != (
FxInfo *) NULL)
2746 fx_info[i]=DestroyFxInfo(fx_info[i]);
2747 fx_info=(
FxInfo **) RelinquishMagickMemory(fx_info);
2751static FxInfo **AcquireFxTLS(
const Image *image,
const char *expression,
2769 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
2770 fx_info=(
FxInfo **) AcquireQuantumMemory(number_threads,
sizeof(*fx_info));
2771 if (fx_info == (
FxInfo **) NULL)
2773 (void) ThrowMagickException(exception,GetMagickModule(),
2774 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
2775 return((
FxInfo **) NULL);
2777 (void) memset(fx_info,0,number_threads*
sizeof(*fx_info));
2778 if (*expression !=
'@')
2779 fx_expression=ConstantString(expression);
2781 fx_expression=FileToString(expression,~0UL,exception);
2782 for (i=0; i < (ssize_t) number_threads; i++)
2787 fx_info[i]=AcquireFxInfo(image,fx_expression);
2788 if (fx_info[i] == (
FxInfo *) NULL)
2790 status=FxPreprocessExpression(fx_info[i],&alpha,exception);
2791 if (status == MagickFalse)
2794 fx_expression=DestroyString(fx_expression);
2795 if (i < (ssize_t) number_threads)
2796 fx_info=DestroyFxTLS(fx_info);
2800MagickExport
Image *FxImage(
const Image *image,
const char *expression,
2806 fx_image=FxImageChannel(image,GrayChannel,expression,exception);
2810MagickExport
Image *FxImageChannel(
const Image *image,
const ChannelType channel,
2813#define FxImageTag "Fx/Image"
2819 **magick_restrict fx_info;
2833 assert(image != (
Image *) NULL);
2834 assert(image->signature == MagickCoreSignature);
2835 if (IsEventLogging() != MagickFalse)
2836 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2837 if (expression == (
const char *) NULL)
2838 return(CloneImage(image,0,0,MagickTrue,exception));
2839 fx_info=AcquireFxTLS(image,expression,exception);
2840 if (fx_info == (
FxInfo **) NULL)
2841 return((
Image *) NULL);
2842 fx_image=CloneImage(image,0,0,MagickTrue,exception);
2843 if (fx_image == (
Image *) NULL)
2845 fx_info=DestroyFxTLS(fx_info);
2846 return((
Image *) NULL);
2848 if (SetImageStorageClass(fx_image,DirectClass) == MagickFalse)
2850 InheritException(exception,&fx_image->exception);
2851 fx_info=DestroyFxTLS(fx_info);
2852 fx_image=DestroyImage(fx_image);
2853 return((
Image *) NULL);
2860 fx_view=AcquireAuthenticCacheView(fx_image,exception);
2861#if defined(MAGICKCORE_OPENMP_SUPPORT)
2862 #pragma omp parallel for schedule(dynamic) shared(progress,status) \
2863 magick_number_threads(image,fx_image,fx_image->rows, \
2864 GlobExpression(fx_info[0]->expression,"*debug(*",MagickTrue) == 0 ? 1 : 0)
2866 for (y=0; y < (ssize_t) fx_image->rows; y++)
2869 id = GetOpenMPThreadId();
2875 *magick_restrict fx_indexes;
2883 if (status == MagickFalse)
2885 q=GetCacheViewAuthenticPixels(fx_view,0,y,fx_image->columns,1,exception);
2891 fx_indexes=GetCacheViewAuthenticIndexQueue(fx_view);
2893 for (x=0; x < (ssize_t) fx_image->columns; x++)
2895 if ((channel & RedChannel) != 0)
2897 (void) FxEvaluateChannelExpression(fx_info[
id],RedChannel,x,y,
2899 SetPixelRed(q,ClampToQuantum((MagickRealType) QuantumRange*alpha));
2901 if ((channel & GreenChannel) != 0)
2903 (void) FxEvaluateChannelExpression(fx_info[
id],GreenChannel,x,y,
2905 SetPixelGreen(q,ClampToQuantum((MagickRealType) QuantumRange*alpha));
2907 if ((channel & BlueChannel) != 0)
2909 (void) FxEvaluateChannelExpression(fx_info[
id],BlueChannel,x,y,
2911 SetPixelBlue(q,ClampToQuantum((MagickRealType) QuantumRange*alpha));
2913 if ((channel & OpacityChannel) != 0)
2915 (void) FxEvaluateChannelExpression(fx_info[
id],OpacityChannel,x,y,
2917 if (image->matte == MagickFalse)
2918 SetPixelOpacity(q,ClampToQuantum((MagickRealType) QuantumRange*
2921 SetPixelOpacity(q,ClampToQuantum((MagickRealType) QuantumRange-
2922 (MagickRealType) QuantumRange*alpha));
2924 if (((channel & IndexChannel) != 0) &&
2925 (fx_image->colorspace == CMYKColorspace))
2927 (void) FxEvaluateChannelExpression(fx_info[
id],IndexChannel,x,y,
2929 SetPixelIndex(fx_indexes+x,ClampToQuantum((MagickRealType)
2930 QuantumRange*alpha));
2934 if (SyncCacheViewAuthenticPixels(fx_view,exception) == MagickFalse)
2936 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2941#if defined(MAGICKCORE_OPENMP_SUPPORT)
2945 proceed=SetImageProgress(image,FxImageTag,progress,image->rows);
2946 if (proceed == MagickFalse)
2950 fx_view=DestroyCacheView(fx_view);
2951 fx_info=DestroyFxTLS(fx_info);
2952 if (status == MagickFalse)
2953 fx_image=DestroyImage(fx_image);