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,
182MagickExport
FxInfo *AcquireFxInfo(
const Image *images,
const char *expression)
196 fx_info=(
FxInfo *) AcquireCriticalMemory(
sizeof(*fx_info));
197 (void) memset(fx_info,0,
sizeof(*fx_info));
198 fx_info->exception=AcquireExceptionInfo();
199 fx_info->images=images;
200 fx_info->colors=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
201 RelinquishMagickMemory);
202 fx_info->symbols=NewSplayTree(CompareSplayTreeString,RelinquishMagickMemory,
203 RelinquishMagickMemory);
204 fx_info->view=(
CacheView **) AcquireQuantumMemory(GetImageListLength(
205 fx_info->images),
sizeof(*fx_info->view));
206 if (fx_info->view == (
CacheView **) NULL)
207 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
209 next=GetFirstImageInList(fx_info->images);
210 for ( ; next != (
Image *) NULL; next=next->next)
212 fx_info->view[i]=AcquireVirtualCacheView(next,fx_info->exception);
215 fx_info->random_info=AcquireRandomInfo();
216 fx_info->expression=ConstantString(expression);
217 fx_info->file=stderr;
222 *fx_op=(
unsigned char) BitwiseAndAssignmentOperator;
223 (void) SubstituteString(&fx_info->expression,
"&=",(
char *) fx_op);
224 *fx_op=(
unsigned char) BitwiseOrAssignmentOperator;
225 (void) SubstituteString(&fx_info->expression,
"|=",(
char *) fx_op);
226 *fx_op=(
unsigned char) LeftShiftAssignmentOperator;
227 (void) SubstituteString(&fx_info->expression,
"<<=",(
char *) fx_op);
228 *fx_op=(
unsigned char) RightShiftAssignmentOperator;
229 (void) SubstituteString(&fx_info->expression,
">>=",(
char *) fx_op);
230 *fx_op=(
unsigned char) PowerAssignmentOperator;
231 (void) SubstituteString(&fx_info->expression,
"^=",(
char *) fx_op);
232 *fx_op=(
unsigned char) ModuloAssignmentOperator;
233 (void) SubstituteString(&fx_info->expression,
"%=",(
char *) fx_op);
234 *fx_op=(
unsigned char) PlusAssignmentOperator;
235 (void) SubstituteString(&fx_info->expression,
"+=",(
char *) fx_op);
236 *fx_op=(
unsigned char) SubtractAssignmentOperator;
237 (void) SubstituteString(&fx_info->expression,
"-=",(
char *) fx_op);
238 *fx_op=(
unsigned char) MultiplyAssignmentOperator;
239 (void) SubstituteString(&fx_info->expression,
"*=",(
char *) fx_op);
240 *fx_op=(
unsigned char) DivideAssignmentOperator;
241 (void) SubstituteString(&fx_info->expression,
"/=",(
char *) fx_op);
242 *fx_op=(
unsigned char) IncrementAssignmentOperator;
243 (void) SubstituteString(&fx_info->expression,
"++",(
char *) fx_op);
244 *fx_op=(
unsigned char) DecrementAssignmentOperator;
245 (void) SubstituteString(&fx_info->expression,
"--",(
char *) fx_op);
246 *fx_op=(
unsigned char) LeftShiftOperator;
247 (void) SubstituteString(&fx_info->expression,
"<<",(
char *) fx_op);
248 *fx_op=(
unsigned char) RightShiftOperator;
249 (void) SubstituteString(&fx_info->expression,
">>",(
char *) fx_op);
250 *fx_op=(
unsigned char) LessThanEqualOperator;
251 (void) SubstituteString(&fx_info->expression,
"<=",(
char *) fx_op);
252 *fx_op=(
unsigned char) GreaterThanEqualOperator;
253 (void) SubstituteString(&fx_info->expression,
">=",(
char *) fx_op);
254 *fx_op=(
unsigned char) EqualOperator;
255 (void) SubstituteString(&fx_info->expression,
"==",(
char *) fx_op);
256 *fx_op=(
unsigned char) NotEqualOperator;
257 (void) SubstituteString(&fx_info->expression,
"!=",(
char *) fx_op);
258 *fx_op=(
unsigned char) LogicalAndOperator;
259 (void) SubstituteString(&fx_info->expression,
"&&",(
char *) fx_op);
260 *fx_op=(
unsigned char) LogicalOrOperator;
261 (void) SubstituteString(&fx_info->expression,
"||",(
char *) fx_op);
262 *fx_op=(
unsigned char) ExponentialNotation;
263 (void) SubstituteString(&fx_info->expression,
"**",(
char *) fx_op);
267 (void) SubstituteString(&fx_info->expression,
"-",
"-1.0*");
268 (void) SubstituteString(&fx_info->expression,
"^-1.0*",
"^-");
269 (void) SubstituteString(&fx_info->expression,
"E-1.0*",
"E-");
270 (void) SubstituteString(&fx_info->expression,
"e-1.0*",
"e-");
271 (void) SubstituteString(&fx_info->expression,
" ",
"");
302 fx_info->exception=DestroyExceptionInfo(fx_info->exception);
303 fx_info->expression=DestroyString(fx_info->expression);
304 fx_info->symbols=DestroySplayTree(fx_info->symbols);
305 fx_info->colors=DestroySplayTree(fx_info->colors);
306 for (i=(ssize_t) GetImageListLength(fx_info->images)-1; i >= 0; i--)
307 fx_info->view[i]=DestroyCacheView(fx_info->view[i]);
308 fx_info->view=(
CacheView **) RelinquishMagickMemory(fx_info->view);
309 fx_info->random_info=DestroyRandomInfo(fx_info->random_info);
310 fx_info=(
FxInfo *) RelinquishMagickMemory(fx_info);
350static inline const double *GetFxSymbolValue(
FxInfo *fx_info,
const char *symbol)
352 return((
const double *) GetValueFromSplayTree(fx_info->symbols,symbol));
355static inline MagickBooleanType SetFxSymbolValue(
356 FxInfo *magick_restrict fx_info,
const char *magick_restrict symbol,
362 object=(
double *) GetValueFromSplayTree(fx_info->symbols,symbol);
363 if (
object != (
double *) NULL)
368 object=(
double *) AcquireMagickMemory(
sizeof(*
object));
369 if (
object == (
double *) NULL)
371 (void) ThrowMagickException(fx_info->exception,GetMagickModule(),
372 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
373 fx_info->images->filename);
377 return(AddValueToSplayTree(fx_info->symbols,ConstantString(symbol),object));
380static double FxChannelStatistics(
FxInfo *fx_info,
const Image *image,
381 ChannelType channel,
const char *symbol,
ExceptionInfo *exception)
384 channel_symbol[MaxTextExtent],
396 for (p=symbol; (*p !=
'.') && (*p !=
'\0'); p++) ;
397 *channel_symbol=
'\0';
403 (void) CopyMagickString(channel_symbol,p+1,MaxTextExtent);
404 option=ParseCommandOption(MagickChannelOptions,MagickTrue,channel_symbol);
406 channel=(ChannelType) option;
408 (void) FormatLocaleString(key,MaxTextExtent,
"%p.%.20g.%s",(
void *) image,
409 (double) channel,symbol);
410 value=GetFxSymbolValue(fx_info,key);
411 if (value != (
const double *) NULL)
412 return(QuantumScale*(*value));
414 if (LocaleNCompare(symbol,
"depth",5) == 0)
419 depth=GetImageChannelDepth(image,channel,exception);
420 statistic=(double) depth;
422 if (LocaleNCompare(symbol,
"kurtosis",8) == 0)
428 (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
432 if (LocaleNCompare(symbol,
"maxima",6) == 0)
438 (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
441 if (LocaleNCompare(symbol,
"mean",4) == 0)
447 (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
451 if (LocaleNCompare(symbol,
"minima",6) == 0)
457 (void) GetImageChannelRange(image,channel,&minima,&maxima,exception);
460 if (LocaleNCompare(symbol,
"skewness",8) == 0)
466 (void) GetImageChannelKurtosis(image,channel,&kurtosis,&skewness,
470 if (LocaleNCompare(symbol,
"standard_deviation",18) == 0)
476 (void) GetImageChannelMean(image,channel,&mean,&standard_deviation,
478 statistic=standard_deviation;
480 if (SetFxSymbolValue(fx_info,key,statistic) == MagickFalse)
482 return(QuantumScale*statistic);
486 FxEvaluateSubexpression(
FxInfo *,
const ChannelType,
const ssize_t,
487 const ssize_t,
const char *,
const size_t,
double *,
ExceptionInfo *);
489static inline MagickBooleanType IsFxFunction(
const char *expression,
490 const char *name,
const size_t length)
498 for (i=0; i <= length; i++)
499 if (expression[i] ==
'\0')
501 c=expression[length];
502 if ((LocaleNCompare(expression,name,length) == 0) &&
503 ((isspace((
int) ((
unsigned char) c)) == 0) || (c ==
'(')))
508static inline double FxGCD(
const double alpha,
const double beta,
511#define FxMaxFunctionDepth 200
514 return(FxGCD(beta,alpha,depth+1));
515 if ((fabs(beta) < 0.001) || (depth >= FxMaxFunctionDepth))
517 return(FxGCD(beta,alpha-beta*floor(alpha/beta),depth+1));
520static inline const char *FxSubexpression(
const char *expression,
530 subexpression=expression;
531 while ((*subexpression !=
'\0') &&
532 ((level != 1) || (strchr(
")",(
int) *subexpression) == (
char *) NULL)))
534 if (strchr(
"(",(
int) *subexpression) != (
char *) NULL)
537 if (strchr(
")",(
int) *subexpression) != (
char *) NULL)
541 if (*subexpression ==
'\0')
542 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
543 "UnbalancedParenthesis",
"`%s'",expression);
544 return(subexpression);
547static double FxGetSymbol(
FxInfo *fx_info,
const ChannelType channel,
548 const ssize_t x,
const ssize_t y,
const char *expression,
const size_t depth,
553 symbol[MaxTextExtent];
585 i=GetImageIndexInList(fx_info->images);
589 if (isalpha((
int) ((
unsigned char) *(p+1))) == 0)
594 subexpression=AcquireString(expression);
595 if (strchr(
"suv",(
int) *p) != (
char *) NULL)
602 i=GetImageIndexInList(fx_info->images);
605 case 'u': i=0;
break;
606 case 'v': i=1;
break;
613 for (p++; *p !=
'\0'; )
627 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
628 depth,&beta,exception);
636 if ((*p ==
'p') && (isalpha((
int) ((
unsigned char) *(p+1))) == 0))
643 for (p++; *p !=
'\0'; )
657 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
658 depth,&beta,exception);
669 for (p++; *p !=
'\0'; )
683 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,
684 depth,&beta,exception);
693 subexpression=DestroyString(subexpression);
695 image=GetImageFromList(fx_info->images,i);
696 if (image == (
Image *) NULL)
698 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
699 "NoSuchImage",
"`%s'",expression);
702 i=GetImageIndexInList(image);
703 GetMagickPixelPacket(image,&pixel);
704 status=InterpolateMagickPixelPacket(image,fx_info->view[i],image->interpolate,
705 point.x,point.y,&pixel,exception);
707 if ((*p !=
'\0') && (*(p+1) !=
'\0') && (*(p+2) !=
'\0') &&
708 (LocaleCompare(p,
"intensity") != 0) && (LocaleCompare(p,
"luma") != 0) &&
709 (LocaleCompare(p,
"luminance") != 0) && (LocaleCompare(p,
"hue") != 0) &&
710 (LocaleCompare(p,
"saturation") != 0) &&
711 (LocaleCompare(p,
"lightness") != 0))
719 (void) CopyMagickString(name,p,MaxTextExtent);
721 for (q=name+length-1; q > name; q--)
732 if ((*q !=
'\0') && (*(q+1) !=
'\0') && (*(q+2) !=
'\0') &&
733 (GetFxSymbolValue(fx_info,name) == (
const double *) NULL))
746 if (QueryMagickColor(name,&pixel,fx_info->exception) != MagickFalse)
748 (void) AddValueToSplayTree(fx_info->colors,ConstantString(name),
749 CloneMagickPixelPacket(&pixel));
754 (void) CopyMagickString(symbol,p,MaxTextExtent);
760 case RedChannel:
return(QuantumScale*pixel.red);
761 case GreenChannel:
return(QuantumScale*pixel.green);
762 case BlueChannel:
return(QuantumScale*pixel.blue);
768 if (pixel.matte == MagickFalse)
770 alpha=(double) (QuantumScale*GetPixelAlpha(&pixel));
775 if (image->colorspace != CMYKColorspace)
777 (void) ThrowMagickException(exception,GetMagickModule(),
778 ImageError,
"ColorSeparatedImageRequired",
"`%s'",
782 return(QuantumScale*pixel.index);
784 case DefaultChannels:
785 return(QuantumScale*GetMagickPixelIntensity(image,&pixel));
789 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
790 "UnableToParseExpression",
"`%s'",p);
798 if (LocaleCompare(symbol,
"a") == 0)
799 return((
double) (QuantumScale*GetPixelAlpha(&pixel)));
805 if (LocaleCompare(symbol,
"b") == 0)
806 return(QuantumScale*pixel.blue);
812 if (IsFxFunction(symbol,
"channel",7) != MagickFalse)
820 flags=ParseGeometry(symbol+7,&channel_info);
821 if (image->colorspace == CMYKColorspace)
826 if ((flags & RhoValue) == 0)
828 return(channel_info.rho);
832 if ((flags & SigmaValue) == 0)
834 return(channel_info.sigma);
838 if ((flags & XiValue) == 0)
840 return(channel_info.xi);
844 if ((flags & PsiValue) == 0)
846 return(channel_info.psi);
850 if ((flags & ChiValue) == 0)
852 return(channel_info.chi);
861 if ((flags & RhoValue) == 0)
863 return(channel_info.rho);
867 if ((flags & SigmaValue) == 0)
869 return(channel_info.sigma);
873 if ((flags & XiValue) == 0)
875 return(channel_info.xi);
879 if ((flags & PsiValue) == 0)
881 return(channel_info.psi);
885 if ((flags & ChiValue) == 0)
887 return(channel_info.chi);
893 if (LocaleCompare(symbol,
"c") == 0)
894 return(QuantumScale*pixel.red);
900 if (LocaleNCompare(symbol,
"depth",5) == 0)
901 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
907 if (LocaleCompare(symbol,
"extent") == 0)
909 if (image->extent != 0)
910 return((
double) image->extent);
911 return((
double) GetBlobSize(image));
918 if (LocaleCompare(symbol,
"g") == 0)
919 return(QuantumScale*pixel.green);
925 if (LocaleNCompare(symbol,
"kurtosis",8) == 0)
926 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
927 if (LocaleCompare(symbol,
"k") == 0)
929 if (image->colorspace != CMYKColorspace)
931 (void) ThrowMagickException(exception,GetMagickModule(),
932 OptionError,
"ColorSeparatedImageRequired",
"`%s'",
936 return(QuantumScale*pixel.index);
943 if (LocaleCompare(symbol,
"h") == 0)
944 return((
double) image->rows);
945 if (LocaleCompare(symbol,
"hue") == 0)
952 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
953 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
961 if ((LocaleCompare(symbol,
"image.depth") == 0) ||
962 (LocaleCompare(symbol,
"image.minima") == 0) ||
963 (LocaleCompare(symbol,
"image.maxima") == 0) ||
964 (LocaleCompare(symbol,
"image.mean") == 0) ||
965 (LocaleCompare(symbol,
"image.kurtosis") == 0) ||
966 (LocaleCompare(symbol,
"image.skewness") == 0) ||
967 (LocaleCompare(symbol,
"image.standard_deviation") == 0))
968 return(FxChannelStatistics(fx_info,image,channel,symbol+6,exception));
969 if (LocaleCompare(symbol,
"image.resolution.x") == 0)
970 return(image->x_resolution);
971 if (LocaleCompare(symbol,
"image.resolution.y") == 0)
972 return(image->y_resolution);
973 if (LocaleCompare(symbol,
"intensity") == 0)
974 return(QuantumScale*GetMagickPixelIntensity(image,&pixel));
975 if (LocaleCompare(symbol,
"i") == 0)
982 if (LocaleCompare(symbol,
"j") == 0)
989 if (LocaleCompare(symbol,
"lightness") == 0)
996 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
997 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
1000 if (LocaleCompare(symbol,
"luma") == 0)
1005 luma=0.212656*pixel.red+0.715158*pixel.green+0.072186*pixel.blue;
1006 return(QuantumScale*luma);
1008 if (LocaleCompare(symbol,
"luminance") == 0)
1013 luminance=0.212656*pixel.red+0.715158*pixel.green+0.072186*pixel.blue;
1014 return(QuantumScale*luminance);
1021 if (LocaleNCompare(symbol,
"maxima",6) == 0)
1022 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1023 if (LocaleNCompare(symbol,
"mean",4) == 0)
1024 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1025 if (LocaleNCompare(symbol,
"minima",6) == 0)
1026 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1027 if (LocaleCompare(symbol,
"m") == 0)
1028 return(QuantumScale*pixel.green);
1034 if (LocaleCompare(symbol,
"n") == 0)
1035 return((
double) GetImageListLength(fx_info->images));
1041 if (LocaleCompare(symbol,
"o") == 0)
1042 return(QuantumScale*pixel.opacity);
1048 if (LocaleCompare(symbol,
"page.height") == 0)
1049 return((
double) image->page.height);
1050 if (LocaleCompare(symbol,
"page.width") == 0)
1051 return((
double) image->page.width);
1052 if (LocaleCompare(symbol,
"page.x") == 0)
1053 return((
double) image->page.x);
1054 if (LocaleCompare(symbol,
"page.y") == 0)
1055 return((
double) image->page.y);
1056 if (LocaleCompare(symbol,
"printsize.x") == 0)
1057 return(PerceptibleReciprocal(image->x_resolution)*image->columns);
1058 if (LocaleCompare(symbol,
"printsize.y") == 0)
1059 return(PerceptibleReciprocal(image->y_resolution)*image->rows);
1065 if (LocaleCompare(symbol,
"quality") == 0)
1066 return((
double) image->quality);
1072 if (LocaleCompare(symbol,
"resolution.x") == 0)
1073 return(image->x_resolution);
1074 if (LocaleCompare(symbol,
"resolution.y") == 0)
1075 return(image->y_resolution);
1076 if (LocaleCompare(symbol,
"r") == 0)
1077 return(QuantumScale*pixel.red);
1083 if (LocaleCompare(symbol,
"saturation") == 0)
1090 ConvertRGBToHSL(ClampToQuantum(pixel.red),ClampToQuantum(pixel.green),
1091 ClampToQuantum(pixel.blue),&hue,&saturation,&lightness);
1094 if (LocaleNCompare(symbol,
"skewness",8) == 0)
1095 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1096 if (LocaleNCompare(symbol,
"standard_deviation",18) == 0)
1097 return(FxChannelStatistics(fx_info,image,channel,symbol,exception));
1103 if (LocaleCompare(symbol,
"t") == 0)
1104 return((
double) GetImageIndexInList(fx_info->images));
1110 if (LocaleCompare(symbol,
"w") == 0)
1111 return((
double) image->columns);
1117 if (LocaleCompare(symbol,
"y") == 0)
1118 return(QuantumScale*pixel.blue);
1124 if (LocaleCompare(symbol,
"z") == 0)
1129 depth=(double) GetImageChannelDepth(image,channel,fx_info->exception);
1137 value=GetFxSymbolValue(fx_info,symbol);
1138 if (value != (
const double *) NULL)
1140 artifact=GetImageArtifact(image,symbol);
1141 if (artifact != (
const char *) NULL)
1142 return(StringToDouble(artifact,(
char **) NULL));
1143 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1144 "UndefinedVariable",
"`%s'",symbol);
1145 (void) SetFxSymbolValue(fx_info,symbol,0.0);
1149static const char *FxOperatorPrecedence(
const char *expression,
1154 UndefinedPrecedence,
1156 BitwiseComplementPrecedence,
1158 ExponentialNotationPrecedence,
1162 RelationalPrecedence,
1163 EquivalencyPrecedence,
1164 BitwiseAndPrecedence,
1165 BitwiseOrPrecedence,
1166 LogicalAndPrecedence,
1167 LogicalOrPrecedence,
1169 AssignmentPrecedence,
1189 subexpression=(
const char *) NULL;
1190 target=NullPrecedence;
1191 while ((c !=
'\0') && (*expression !=
'\0'))
1193 precedence=UndefinedPrecedence;
1194 if ((isspace((
int) ((
unsigned char) *expression)) != 0) || (c == (int)
'@'))
1199 switch (*expression)
1204#if defined(MAGICKCORE_HAVE_ACOSH)
1205 if (IsFxFunction(expression,
"acosh",5) != MagickFalse)
1211#if defined(MAGICKCORE_HAVE_ASINH)
1212 if (IsFxFunction(expression,
"asinh",5) != MagickFalse)
1218#if defined(MAGICKCORE_HAVE_ATANH)
1219 if (IsFxFunction(expression,
"atanh",5) != MagickFalse)
1225 if (IsFxFunction(expression,
"atan2",5) != MagickFalse)
1235 if ((isdigit((
int) ((
unsigned char) c)) != 0) &&
1236 ((LocaleNCompare(expression,
"E+",2) == 0) ||
1237 (LocaleNCompare(expression,
"E-",2) == 0)))
1247 if ((IsFxFunction(expression,
"j0",2) != MagickFalse) ||
1248 (IsFxFunction(expression,
"j1",2) != MagickFalse))
1257 while (isxdigit((
int) ((
unsigned char) *(expression+1))) != 0)
1264 if ((c == (
int)
'{') || (c == (
int)
'['))
1267 if ((c == (
int)
'}') || (c == (
int)
']'))
1270 switch ((
unsigned char) *expression)
1275 precedence=BitwiseComplementPrecedence;
1281 precedence=ExponentPrecedence;
1286 if (((c != 0) && ((isdigit((
int) ((
unsigned char) c)) != 0) ||
1287 (strchr(
")",c) != (
char *) NULL))) &&
1288 (((islower((
int) ((
unsigned char) *expression)) != 0) ||
1289 (strchr(
"(",(
int) ((
unsigned char) *expression)) != (
char *) NULL)) ||
1290 ((isdigit((
int) ((
unsigned char) c)) == 0) &&
1291 (isdigit((
int) ((
unsigned char) *expression)) != 0))) &&
1292 (strchr(
"xy",(
int) ((
unsigned char) *expression)) == (
char *) NULL))
1293 precedence=MultiplyPrecedence;
1300 precedence=MultiplyPrecedence;
1306 if ((strchr(
"(+-/*%:&^|<>~,",c) == (
char *) NULL) ||
1307 (isalpha((
int) ((
unsigned char) c)) != 0))
1308 precedence=AdditionPrecedence;
1311 case BitwiseAndAssignmentOperator:
1312 case BitwiseOrAssignmentOperator:
1313 case LeftShiftAssignmentOperator:
1314 case RightShiftAssignmentOperator:
1315 case PowerAssignmentOperator:
1316 case ModuloAssignmentOperator:
1317 case PlusAssignmentOperator:
1318 case SubtractAssignmentOperator:
1319 case MultiplyAssignmentOperator:
1320 case DivideAssignmentOperator:
1321 case IncrementAssignmentOperator:
1322 case DecrementAssignmentOperator:
1324 precedence=AssignmentPrecedence;
1327 case LeftShiftOperator:
1328 case RightShiftOperator:
1330 precedence=ShiftPrecedence;
1334 case LessThanEqualOperator:
1335 case GreaterThanEqualOperator:
1338 precedence=RelationalPrecedence;
1342 case NotEqualOperator:
1344 precedence=EquivalencyPrecedence;
1349 precedence=BitwiseAndPrecedence;
1354 precedence=BitwiseOrPrecedence;
1357 case LogicalAndOperator:
1359 precedence=LogicalAndPrecedence;
1362 case LogicalOrOperator:
1364 precedence=LogicalOrPrecedence;
1367 case ExponentialNotation:
1369 precedence=ExponentialNotationPrecedence;
1375 precedence=TernaryPrecedence;
1380 precedence=AssignmentPrecedence;
1385 precedence=CommaPrecedence;
1390 precedence=SeparatorPrecedence;
1394 if ((precedence == BitwiseComplementPrecedence) ||
1395 (precedence == TernaryPrecedence) ||
1396 (precedence == AssignmentPrecedence))
1398 if (precedence > target)
1404 subexpression=expression;
1408 if (precedence >= target)
1414 subexpression=expression;
1416 if (strchr(
"(",(
int) *expression) != (
char *) NULL)
1417 expression=FxSubexpression(expression,exception);
1418 c=(int) (*expression++);
1420 return(subexpression);
1423static double FxEvaluateSubexpression(
FxInfo *fx_info,
const ChannelType channel,
1424 const ssize_t x,
const ssize_t y,
const char *expression,
const size_t depth,
1427#define FxMaxParenthesisDepth 58
1428#define FxMaxSubexpressionDepth 200
1429#define FxReturn(value) \
1431 subexpression=DestroyString(subexpression); \
1434#define FxParseConditional(subexpression,sentinal,p,q) \
1437 for (q=(char *) p; (*q != (sentinal)) && (*q != '\0'); q++) \
1440 for (q++; (*q != ')') && (*q != '\0'); q++); \
1446 (void) ThrowMagickException(exception,GetMagickModule(), \
1447 OptionError,"UnableToParseExpression","`%s'",subexpression); \
1450 if (strlen(q) == 1) \
1470 subexpression=AcquireString(expression);
1471 *subexpression=
'\0';
1472 if (depth > FxMaxSubexpressionDepth)
1474 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1475 "UnableToParseExpression",
"`%s'",expression);
1478 if (exception->severity >= ErrorException)
1480 while (isspace((
int) ((
unsigned char) *expression)) != 0)
1482 if (*expression ==
'\0')
1484 p=FxOperatorPrecedence(expression,exception);
1485 if (p != (
const char *) NULL)
1487 (void) CopyMagickString(subexpression,expression,(
size_t)
1489 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,depth+1,
1491 switch ((
unsigned char) *p)
1495 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1497 *beta=(double) (~(
size_t) *beta);
1502 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1504 FxReturn(*beta == 0.0 ? 1.0 : 0.0);
1508 *beta=pow(alpha,FxEvaluateSubexpression(fx_info,channel,x,y,++p,
1509 depth+1,beta,exception));
1513 case ExponentialNotation:
1515 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1517 FxReturn(alpha*(*beta));
1521 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1523 FxReturn(PerceptibleReciprocal(*beta)*alpha);
1527 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1529 FxReturn(fmod(alpha,*beta));
1533 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1535 FxReturn(alpha+(*beta));
1539 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1541 FxReturn(alpha-(*beta));
1543 case BitwiseAndAssignmentOperator:
1546 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1550 (void) ThrowMagickException(exception,GetMagickModule(),
1551 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1554 ClearMagickException(exception);
1555 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1557 value=(double) ((
size_t) (alpha+0.5) & (
size_t) (*beta+0.5));
1558 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1562 case BitwiseOrAssignmentOperator:
1565 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1569 (void) ThrowMagickException(exception,GetMagickModule(),
1570 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1573 ClearMagickException(exception);
1574 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1576 value=(double) ((
size_t) (alpha+0.5) | (
size_t) (*beta+0.5));
1577 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1581 case LeftShiftAssignmentOperator:
1584 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1588 (void) ThrowMagickException(exception,GetMagickModule(),
1589 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1592 ClearMagickException(exception);
1593 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1595 if ((
size_t) (*beta+0.5) >= (8*
sizeof(
size_t)))
1597 (void) ThrowMagickException(exception,GetMagickModule(),
1598 OptionError,
"ShiftCountOverflow",
"`%s'",subexpression);
1601 value=(double) ((
size_t) (alpha+0.5) << (
size_t) (*beta+0.5));
1602 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1606 case RightShiftAssignmentOperator:
1609 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1613 (void) ThrowMagickException(exception,GetMagickModule(),
1614 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1617 ClearMagickException(exception);
1618 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1620 if ((
size_t) (*beta+0.5) >= (8*
sizeof(
size_t)))
1622 (void) ThrowMagickException(exception,GetMagickModule(),
1623 OptionError,
"ShiftCountOverflow",
"`%s'",subexpression);
1626 value=(double) ((
size_t) (alpha+0.5) >> (
size_t) (*beta+0.5));
1627 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1631 case PowerAssignmentOperator:
1634 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1638 (void) ThrowMagickException(exception,GetMagickModule(),
1639 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1642 ClearMagickException(exception);
1643 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1645 value=pow(alpha,*beta);
1646 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1650 case ModuloAssignmentOperator:
1653 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1657 (void) ThrowMagickException(exception,GetMagickModule(),
1658 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1661 ClearMagickException(exception);
1662 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1664 value=fmod(alpha,*beta);
1665 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1669 case PlusAssignmentOperator:
1672 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1676 (void) ThrowMagickException(exception,GetMagickModule(),
1677 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1680 ClearMagickException(exception);
1681 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1683 value=alpha+(*beta);
1684 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1688 case SubtractAssignmentOperator:
1691 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1695 (void) ThrowMagickException(exception,GetMagickModule(),
1696 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1699 ClearMagickException(exception);
1700 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1702 value=alpha-(*beta);
1703 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1707 case MultiplyAssignmentOperator:
1710 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1714 (void) ThrowMagickException(exception,GetMagickModule(),
1715 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1718 ClearMagickException(exception);
1719 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1721 value=alpha*(*beta);
1722 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1726 case DivideAssignmentOperator:
1729 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1733 (void) ThrowMagickException(exception,GetMagickModule(),
1734 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1737 ClearMagickException(exception);
1738 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1740 value=alpha*PerceptibleReciprocal(*beta);
1741 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1745 case IncrementAssignmentOperator:
1747 if (*subexpression ==
'\0')
1748 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1751 if (*subexpression ==
'\0')
1753 if (SetFxSymbolValue(fx_info,p,value) == MagickFalse)
1757 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1761 case DecrementAssignmentOperator:
1763 if (*subexpression ==
'\0')
1764 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1767 if (*subexpression ==
'\0')
1769 if (SetFxSymbolValue(fx_info,p,value) == MagickFalse)
1773 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1777 case LeftShiftOperator:
1779 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1781 if ((
size_t) (gamma+0.5) >= (8*
sizeof(
size_t)))
1783 (void) ThrowMagickException(exception,GetMagickModule(),
1784 OptionError,
"ShiftCountOverflow",
"`%s'",subexpression);
1787 *beta=(double) ((
size_t) (alpha+0.5) << (
size_t) (gamma+0.5));
1790 case RightShiftOperator:
1792 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1794 if ((
size_t) (gamma+0.5) >= (8*
sizeof(
size_t)))
1796 (void) ThrowMagickException(exception,GetMagickModule(),
1797 OptionError,
"ShiftCountOverflow",
"`%s'",subexpression);
1800 *beta=(double) ((
size_t) (alpha+0.5) >> (
size_t) (gamma+0.5));
1805 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1807 FxReturn(alpha < *beta ? 1.0 : 0.0);
1809 case LessThanEqualOperator:
1811 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1813 FxReturn(alpha <= *beta ? 1.0 : 0.0);
1817 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1819 FxReturn(alpha > *beta ? 1.0 : 0.0);
1821 case GreaterThanEqualOperator:
1823 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1825 FxReturn(alpha >= *beta ? 1.0 : 0.0);
1829 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1831 FxReturn(fabs(alpha-(*beta)) < MagickEpsilon ? 1.0 : 0.0);
1833 case NotEqualOperator:
1835 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1837 FxReturn(fabs(alpha-(*beta)) >= MagickEpsilon ? 1.0 : 0.0);
1841 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1843 *beta=(double) ((
size_t) (alpha+0.5) & (
size_t) (gamma+0.5));
1848 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1850 *beta=(double) ((
size_t) (alpha+0.5) | (
size_t) (gamma+0.5));
1853 case LogicalAndOperator:
1861 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1863 *beta=(gamma > 0.0) ? 1.0 : 0.0;
1866 case LogicalOrOperator:
1874 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1876 *beta=(gamma > 0.0) ? 1.0 : 0.0;
1884 (void) CopyMagickString(subexpression,++p,MaxTextExtent-1);
1885 FxParseConditional(subexpression,
':',p,q);
1886 if (fabs(alpha) >= MagickEpsilon)
1887 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
1890 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
1897 while (isalpha((
int) ((
unsigned char) *q)) != 0)
1901 (void) ThrowMagickException(exception,GetMagickModule(),
1902 OptionError,
"UnableToParseExpression",
"`%s'",subexpression);
1905 ClearMagickException(exception);
1906 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1909 if (SetFxSymbolValue(fx_info,subexpression,value) == MagickFalse)
1915 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1921 *beta=FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,beta,
1929 gamma=alpha*FxEvaluateSubexpression(fx_info,channel,x,y,++p,depth+1,
1935 if (strchr(
"(",(
int) *expression) != (
char *) NULL)
1940 if (depth >= FxMaxParenthesisDepth)
1941 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1942 "ParenthesisNestedTooDeeply",
"`%s'",expression);
1943 length=CopyMagickString(subexpression,expression+1,MaxTextExtent);
1945 subexpression[length-1]=
'\0';
1946 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,subexpression,depth+1,
1950 switch (*expression)
1954 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1956 FxReturn(1.0*gamma);
1960 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1962 FxReturn(-1.0*gamma);
1966 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,expression+1,depth+1,
1968 FxReturn((
double) (~(
size_t) (gamma+0.5)));
1973 if (IsFxFunction(expression,
"abs",3) != MagickFalse)
1975 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
1976 depth+1,beta,exception);
1977 FxReturn(fabs(alpha));
1979#if defined(MAGICKCORE_HAVE_ACOSH)
1980 if (IsFxFunction(expression,
"acosh",5) != MagickFalse)
1982 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
1983 depth+1,beta,exception);
1984 FxReturn(acosh(alpha));
1987 if (IsFxFunction(expression,
"acos",4) != MagickFalse)
1989 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
1990 depth+1,beta,exception);
1991 FxReturn(acos(alpha));
1993#if defined(MAGICKCORE_HAVE_J1)
1994 if (IsFxFunction(expression,
"airy",4) != MagickFalse)
1996 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
1997 depth+1,beta,exception);
2000 gamma=2.0*j1((MagickPI*alpha))/(MagickPI*alpha);
2001 FxReturn(gamma*gamma);
2004#if defined(MAGICKCORE_HAVE_ASINH)
2005 if (IsFxFunction(expression,
"asinh",5) != MagickFalse)
2007 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2008 depth+1,beta,exception);
2009 FxReturn(asinh(alpha));
2012 if (IsFxFunction(expression,
"asin",4) != MagickFalse)
2014 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2015 depth+1,beta,exception);
2016 FxReturn(asin(alpha));
2018 if (IsFxFunction(expression,
"alt",3) != MagickFalse)
2020 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2021 depth+1,beta,exception);
2022 FxReturn(((ssize_t) alpha) & 0x01 ? -1.0 : 1.0);
2024 if (IsFxFunction(expression,
"atan2",5) != MagickFalse)
2026 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2027 depth+1,beta,exception);
2028 FxReturn(atan2(alpha,*beta));
2030#if defined(MAGICKCORE_HAVE_ATANH)
2031 if (IsFxFunction(expression,
"atanh",5) != MagickFalse)
2033 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2034 depth+1,beta,exception);
2035 FxReturn(atanh(alpha));
2038 if (IsFxFunction(expression,
"atan",4) != MagickFalse)
2040 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2041 depth+1,beta,exception);
2042 FxReturn(atan(alpha));
2044 if (LocaleCompare(expression,
"a") == 0)
2045 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2051 if (LocaleCompare(expression,
"b") == 0)
2052 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2058 if (IsFxFunction(expression,
"ceil",4) != MagickFalse)
2060 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2061 depth+1,beta,exception);
2062 FxReturn(ceil(alpha));
2064 if (IsFxFunction(expression,
"clamp",5) != MagickFalse)
2066 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2067 depth+1,beta,exception);
2074 if (IsFxFunction(expression,
"cosh",4) != MagickFalse)
2076 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2077 depth+1,beta,exception);
2078 FxReturn(cosh(alpha));
2080 if (IsFxFunction(expression,
"cos",3) != MagickFalse)
2082 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2083 depth+1,beta,exception);
2084 FxReturn(cos(alpha));
2086 if (LocaleCompare(expression,
"c") == 0)
2087 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2093 if (IsFxFunction(expression,
"debug",5) != MagickFalse)
2101 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2102 depth+1,beta,exception);
2103 switch (fx_info->images->colorspace)
2105 case CMYKColorspace:
2109 case CyanChannel: type=
"cyan";
break;
2110 case MagentaChannel: type=
"magenta";
break;
2111 case YellowChannel: type=
"yellow";
break;
2112 case AlphaChannel: type=
"alpha";
break;
2113 case BlackChannel: type=
"black";
break;
2114 default: type=
"unknown";
break;
2118 case GRAYColorspace:
2122 case RedChannel: type=
"gray";
break;
2123 case AlphaChannel: type=
"alpha";
break;
2124 default: type=
"unknown";
break;
2132 case RedChannel: type=
"red";
break;
2133 case GreenChannel: type=
"green";
break;
2134 case BlueChannel: type=
"blue";
break;
2135 case AlphaChannel: type=
"alpha";
break;
2136 default: type=
"unknown";
break;
2141 *subexpression=
'\0';
2143 if (strlen(expression) > 6)
2144 length=CopyMagickString(subexpression,expression+6,MaxTextExtent);
2146 subexpression[length-1]=
'\0';
2147 if (fx_info->file != (FILE *) NULL)
2148 (void) FormatLocaleFile(fx_info->file,
2149 "%s[%.20g,%.20g].%s: %s=%.*g\n",fx_info->images->filename,
2150 (
double) x,(double) y,type,subexpression,GetMagickPrecision(),
2154 if (IsFxFunction(expression,
"do",2) != MagickFalse)
2162 length=CopyMagickString(subexpression,expression+6,
2163 MagickPathExtent-1);
2165 subexpression[length-1]=
'\0';
2166 FxParseConditional(subexpression,
',',p,q);
2169 if (((fx_info->cycles++ % 8192) == 0) && (GetMagickTTL() <= 0))
2170 (void) ThrowMagickException(exception,GetMagickModule(),
2171 ResourceLimitFatalError,
"TimeLimitExceeded",
"`%s'",
2172 fx_info->images->filename);
2173 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2175 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2177 if (fabs(gamma) < MagickEpsilon)
2182 if (IsFxFunction(expression,
"drc",3) != MagickFalse)
2184 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2185 depth+1,beta,exception);
2186 FxReturn(alpha*PerceptibleReciprocal(*beta*(alpha-1.0)+1.0));
2193 if (LocaleCompare(expression,
"epsilon") == 0)
2194 FxReturn(MagickEpsilon);
2195#if defined(MAGICKCORE_HAVE_ERF)
2196 if (IsFxFunction(expression,
"erf",3) != MagickFalse)
2198 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2199 depth+1,beta,exception);
2200 FxReturn(erf(alpha));
2203 if (IsFxFunction(expression,
"exp",3) != MagickFalse)
2205 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2206 depth+1,beta,exception);
2207 FxReturn(exp(alpha));
2209 if (LocaleCompare(expression,
"e") == 0)
2210 FxReturn(2.7182818284590452354);
2216 if (IsFxFunction(expression,
"floor",5) != MagickFalse)
2218 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2219 depth+1,beta,exception);
2220 FxReturn(floor(alpha));
2222 if (IsFxFunction(expression,
"for",3) != MagickFalse)
2233 length=CopyMagickString(subexpression,expression+4,
2234 MagickPathExtent-1);
2236 subexpression[length-1]=
'\0';
2237 FxParseConditional(subexpression,
',',p,q);
2238 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2240 (void) CopyMagickString(subexpression,q+1,MagickPathExtent-1);
2241 FxParseConditional(subexpression,
',',p,q);
2244 if (((fx_info->cycles++ % 8192) == 0) && (GetMagickTTL() <= 0))
2245 (void) ThrowMagickException(exception,GetMagickModule(),
2246 ResourceLimitFatalError,
"TimeLimitExceeded",
"`%s'",
2247 fx_info->images->filename);
2248 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2250 if (fabs(gamma) < MagickEpsilon)
2252 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2262 if (IsFxFunction(expression,
"gauss",5) != MagickFalse)
2264 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2265 depth+1,beta,exception);
2266 FxReturn(exp((-alpha*alpha/2.0))/sqrt(2.0*MagickPI));
2268 if (IsFxFunction(expression,
"gcd",3) != MagickFalse)
2273 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2274 depth+1,beta,exception);
2277 gcd=FxGCD(alpha,*beta,0);
2280 if (LocaleCompare(expression,
"g") == 0)
2281 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2287 if (LocaleCompare(expression,
"h") == 0)
2288 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2289 if (LocaleCompare(expression,
"hue") == 0)
2290 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2291 if (IsFxFunction(expression,
"hypot",5) != MagickFalse)
2293 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2294 depth+1,beta,exception);
2295 FxReturn(hypot(alpha,*beta));
2302 if (LocaleCompare(expression,
"k") == 0)
2303 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2309 if (IsFxFunction(expression,
"if",2) != MagickFalse)
2320 length=CopyMagickString(subexpression,expression+3,
2321 MagickPathExtent-1);
2323 subexpression[length-1]=
'\0';
2324 FxParseConditional(subexpression,
',',p,q);
2325 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,&sans,
2327 (void) CopyMagickString(subexpression,q+1,MagickPathExtent-1);
2328 FxParseConditional(subexpression,
',',p,q);
2329 if (fabs(alpha) >= MagickEpsilon)
2330 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
2333 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2337 if (LocaleCompare(expression,
"intensity") == 0)
2338 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2339 if (IsFxFunction(expression,
"int",3) != MagickFalse)
2341 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2342 depth+1,beta,exception);
2343 FxReturn(floor(alpha));
2345 if (IsFxFunction(expression,
"isnan",5) != MagickFalse)
2347 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2348 depth+1,beta,exception);
2349 FxReturn((
double) !!IsNaN(alpha));
2351 if (LocaleCompare(expression,
"i") == 0)
2352 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2358 if (LocaleCompare(expression,
"j") == 0)
2359 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2360#if defined(MAGICKCORE_HAVE_J0)
2361 if (IsFxFunction(expression,
"j0",2) != MagickFalse)
2363 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2364 depth+1,beta,exception);
2365 FxReturn(j0(alpha));
2368#if defined(MAGICKCORE_HAVE_J1)
2369 if (IsFxFunction(expression,
"j1",2) != MagickFalse)
2371 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2372 depth+1,beta,exception);
2373 FxReturn(j1(alpha));
2376#if defined(MAGICKCORE_HAVE_J1)
2377 if (IsFxFunction(expression,
"jinc",4) != MagickFalse)
2379 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2380 depth+1,beta,exception);
2383 FxReturn((2.0*j1((MagickPI*alpha))/(MagickPI*alpha)));
2391 if (IsFxFunction(expression,
"ln",2) != MagickFalse)
2393 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+2,
2394 depth+1,beta,exception);
2395 FxReturn(log(alpha));
2397 if (IsFxFunction(expression,
"logtwo",6) != MagickFalse)
2399 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,
2400 depth+1,beta,exception);
2401 FxReturn(MagickLog10(alpha)/log10(2.0));
2403 if (IsFxFunction(expression,
"log",3) != MagickFalse)
2405 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2406 depth+1,beta,exception);
2407 FxReturn(MagickLog10(alpha));
2409 if (LocaleCompare(expression,
"lightness") == 0)
2410 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2416 if (LocaleCompare(expression,
"MaxRGB") == 0)
2417 FxReturn((
double) QuantumRange);
2418 if (LocaleNCompare(expression,
"maxima",6) == 0)
2420 if (IsFxFunction(expression,
"max",3) != MagickFalse)
2422 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2423 depth+1,beta,exception);
2424 FxReturn(alpha > *beta ? alpha : *beta);
2426 if (LocaleNCompare(expression,
"minima",6) == 0)
2428 if (IsFxFunction(expression,
"min",3) != MagickFalse)
2430 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2431 depth+1,beta,exception);
2432 FxReturn(alpha < *beta ? alpha : *beta);
2434 if (IsFxFunction(expression,
"mod",3) != MagickFalse)
2436 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2437 depth+1,beta,exception);
2438 FxReturn(alpha-floor((alpha*PerceptibleReciprocal(*beta)))*(*beta));
2440 if (LocaleCompare(expression,
"m") == 0)
2441 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2447 if (IsFxFunction(expression,
"not",3) != MagickFalse)
2449 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2450 depth+1,beta,exception);
2451 FxReturn((
double) (alpha < MagickEpsilon));
2453 if (LocaleCompare(expression,
"n") == 0)
2454 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2460 if (LocaleCompare(expression,
"Opaque") == 0)
2462 if (LocaleCompare(expression,
"o") == 0)
2463 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2469 if (LocaleCompare(expression,
"phi") == 0)
2470 FxReturn(MagickPHI);
2471 if (LocaleCompare(expression,
"pi") == 0)
2473 if (IsFxFunction(expression,
"pow",3) != MagickFalse)
2475 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2476 depth+1,beta,exception);
2477 FxReturn(pow(alpha,*beta));
2479 if (LocaleCompare(expression,
"p") == 0)
2480 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2486 if (LocaleCompare(expression,
"QuantumRange") == 0)
2487 FxReturn((
double) QuantumRange);
2488 if (LocaleCompare(expression,
"QuantumScale") == 0)
2489 FxReturn(QuantumScale);
2495 if (IsFxFunction(expression,
"rand",4) != MagickFalse)
2500#if defined(MAGICKCORE_OPENMP_SUPPORT)
2501 #pragma omp critical (MagickCore_FxEvaluateSubexpression)
2503 alpha=GetPseudoRandomValue(fx_info->random_info);
2506 if (IsFxFunction(expression,
"round",5) != MagickFalse)
2508 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2509 depth+1,beta,exception);
2510 if ((alpha-floor(alpha)) < (ceil(alpha)-alpha))
2511 FxReturn(floor(alpha));
2512 FxReturn(ceil(alpha));
2514 if (LocaleCompare(expression,
"r") == 0)
2515 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2521 if (LocaleCompare(expression,
"saturation") == 0)
2522 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2523 if (IsFxFunction(expression,
"sign",4) != MagickFalse)
2525 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2526 depth+1,beta,exception);
2527 FxReturn(alpha < 0.0 ? -1.0 : 1.0);
2529 if (IsFxFunction(expression,
"sinc",4) != MagickFalse)
2531 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2532 depth+1,beta,exception);
2535 FxReturn(sin((MagickPI*alpha))/(MagickPI*alpha));
2537 if (IsFxFunction(expression,
"sinh",4) != MagickFalse)
2539 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2540 depth+1,beta,exception);
2541 FxReturn(sinh(alpha));
2543 if (IsFxFunction(expression,
"sin",3) != MagickFalse)
2545 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2546 depth+1,beta,exception);
2547 FxReturn(sin(alpha));
2549 if (IsFxFunction(expression,
"sqrt",4) != MagickFalse)
2551 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2552 depth+1,beta,exception);
2553 FxReturn(sqrt(alpha));
2555 if (IsFxFunction(expression,
"squish",6) != MagickFalse)
2557 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+6,
2558 depth+1,beta,exception);
2559 FxReturn((1.0/(1.0+exp(-alpha))));
2561 if (LocaleCompare(expression,
"s") == 0)
2562 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2568 if (IsFxFunction(expression,
"tanh",4) != MagickFalse)
2570 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+4,
2571 depth+1,beta,exception);
2572 FxReturn(tanh(alpha));
2574 if (IsFxFunction(expression,
"tan",3) != MagickFalse)
2576 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+3,
2577 depth+1,beta,exception);
2578 FxReturn(tan(alpha));
2580 if (LocaleCompare(expression,
"Transparent") == 0)
2582 if (IsFxFunction(expression,
"trunc",5) != MagickFalse)
2584 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,expression+5,
2585 depth+1,beta,exception);
2587 FxReturn(floor(alpha));
2588 FxReturn(ceil(alpha));
2590 if (LocaleCompare(expression,
"t") == 0)
2591 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2597 if (LocaleCompare(expression,
"u") == 0)
2598 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2604 if (LocaleCompare(expression,
"v") == 0)
2605 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2611 if (IsFxFunction(expression,
"while",5) != MagickFalse)
2619 length=CopyMagickString(subexpression,expression+6,
2620 MagickPathExtent-1);
2622 subexpression[length-1]=
'\0';
2623 FxParseConditional(subexpression,
',',p,q);
2626 if (((fx_info->cycles++ % 8192) == 0) && (GetMagickTTL() <= 0))
2627 (void) ThrowMagickException(exception,GetMagickModule(),
2628 ResourceLimitFatalError,
"TimeLimitExceeded",
"`%s'",
2629 fx_info->images->filename);
2630 gamma=FxEvaluateSubexpression(fx_info,channel,x,y,p,depth+1,beta,
2632 if (fabs(gamma) < MagickEpsilon)
2634 alpha=FxEvaluateSubexpression(fx_info,channel,x,y,q+1,depth+1,beta,
2639 if (LocaleCompare(expression,
"w") == 0)
2640 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2646 if (LocaleCompare(expression,
"y") == 0)
2647 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2653 if (LocaleCompare(expression,
"z") == 0)
2654 FxReturn(FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception));
2660 q=(
char *) expression;
2661 alpha=InterpretSiPrefixValue(expression,&q);
2662 if (q == expression)
2663 alpha=FxGetSymbol(fx_info,channel,x,y,expression,depth+1,exception);
2665 (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2666 "UnbalancedParenthesis",
"`%s'",expression);
2670MagickExport MagickBooleanType FxEvaluateExpression(
FxInfo *fx_info,
2676 status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
2680MagickExport MagickBooleanType FxPreprocessExpression(
FxInfo *fx_info,
2690 fx_info->file=(FILE *) NULL;
2691 status=FxEvaluateChannelExpression(fx_info,GrayChannel,0,0,alpha,exception);
2696MagickExport MagickBooleanType FxEvaluateChannelExpression(
FxInfo *fx_info,
2697 const ChannelType channel,
const ssize_t x,
const ssize_t y,
double *alpha,
2704 *alpha=FxEvaluateSubexpression(fx_info,channel,x,y,fx_info->expression,0,
2706 return(exception->severity == OptionError ? MagickFalse : MagickTrue);
2746 assert(fx_info != (
FxInfo **) NULL);
2747 for (i=0; i < (ssize_t) GetMagickResourceLimit(ThreadResource); i++)
2748 if (fx_info[i] != (
FxInfo *) NULL)
2749 fx_info[i]=DestroyFxInfo(fx_info[i]);
2750 fx_info=(
FxInfo **) RelinquishMagickMemory(fx_info);
2754static FxInfo **AcquireFxTLS(
const Image *image,
const char *expression,
2772 number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
2773 fx_info=(
FxInfo **) AcquireQuantumMemory(number_threads,
sizeof(*fx_info));
2774 if (fx_info == (
FxInfo **) NULL)
2776 (void) ThrowMagickException(exception,GetMagickModule(),
2777 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",image->filename);
2778 return((
FxInfo **) NULL);
2780 (void) memset(fx_info,0,number_threads*
sizeof(*fx_info));
2781 if (*expression !=
'@')
2782 fx_expression=ConstantString(expression);
2784 fx_expression=FileToString(expression,~0UL,exception);
2785 for (i=0; i < (ssize_t) number_threads; i++)
2790 fx_info[i]=AcquireFxInfo(image,fx_expression);
2791 if (fx_info[i] == (
FxInfo *) NULL)
2793 status=FxPreprocessExpression(fx_info[i],&alpha,exception);
2794 if (status == MagickFalse)
2797 fx_expression=DestroyString(fx_expression);
2798 if (i < (ssize_t) number_threads)
2799 fx_info=DestroyFxTLS(fx_info);
2803MagickExport
Image *FxImage(
const Image *image,
const char *expression,
2809 fx_image=FxImageChannel(image,GrayChannel,expression,exception);
2813MagickExport
Image *FxImageChannel(
const Image *image,
const ChannelType channel,
2816#define FxImageTag "Fx/Image"
2822 **magick_restrict fx_info;
2836 assert(image != (
Image *) NULL);
2837 assert(image->signature == MagickCoreSignature);
2838 if (IsEventLogging() != MagickFalse)
2839 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2840 if (expression == (
const char *) NULL)
2841 return(CloneImage(image,0,0,MagickTrue,exception));
2842 fx_info=AcquireFxTLS(image,expression,exception);
2843 if (fx_info == (
FxInfo **) NULL)
2844 return((
Image *) NULL);
2845 fx_image=CloneImage(image,0,0,MagickTrue,exception);
2846 if (fx_image == (
Image *) NULL)
2848 fx_info=DestroyFxTLS(fx_info);
2849 return((
Image *) NULL);
2851 if (SetImageStorageClass(fx_image,DirectClass) == MagickFalse)
2853 InheritException(exception,&fx_image->exception);
2854 fx_info=DestroyFxTLS(fx_info);
2855 fx_image=DestroyImage(fx_image);
2856 return((
Image *) NULL);
2863 fx_view=AcquireAuthenticCacheView(fx_image,exception);
2864#if defined(MAGICKCORE_OPENMP_SUPPORT)
2865 #pragma omp parallel for schedule(dynamic) shared(progress,status) \
2866 magick_number_threads(image,fx_image,fx_image->rows, \
2867 GlobExpression(fx_info[0]->expression,"*debug(*",MagickTrue) == 0 ? 1 : 0)
2869 for (y=0; y < (ssize_t) fx_image->rows; y++)
2872 id = GetOpenMPThreadId();
2878 *magick_restrict fx_indexes;
2886 if (status == MagickFalse)
2888 q=GetCacheViewAuthenticPixels(fx_view,0,y,fx_image->columns,1,exception);
2894 fx_indexes=GetCacheViewAuthenticIndexQueue(fx_view);
2896 for (x=0; x < (ssize_t) fx_image->columns; x++)
2898 if ((channel & RedChannel) != 0)
2900 (void) FxEvaluateChannelExpression(fx_info[
id],RedChannel,x,y,
2902 SetPixelRed(q,ClampToQuantum((MagickRealType) QuantumRange*alpha));
2904 if ((channel & GreenChannel) != 0)
2906 (void) FxEvaluateChannelExpression(fx_info[
id],GreenChannel,x,y,
2908 SetPixelGreen(q,ClampToQuantum((MagickRealType) QuantumRange*alpha));
2910 if ((channel & BlueChannel) != 0)
2912 (void) FxEvaluateChannelExpression(fx_info[
id],BlueChannel,x,y,
2914 SetPixelBlue(q,ClampToQuantum((MagickRealType) QuantumRange*alpha));
2916 if ((channel & OpacityChannel) != 0)
2918 (void) FxEvaluateChannelExpression(fx_info[
id],OpacityChannel,x,y,
2920 if (image->matte == MagickFalse)
2921 SetPixelOpacity(q,ClampToQuantum((MagickRealType) QuantumRange*
2924 SetPixelOpacity(q,ClampToQuantum((MagickRealType) QuantumRange-
2925 (MagickRealType) QuantumRange*alpha));
2927 if (((channel & IndexChannel) != 0) &&
2928 (fx_image->colorspace == CMYKColorspace))
2930 (void) FxEvaluateChannelExpression(fx_info[
id],IndexChannel,x,y,
2932 SetPixelIndex(fx_indexes+x,ClampToQuantum((MagickRealType)
2933 QuantumRange*alpha));
2937 if (SyncCacheViewAuthenticPixels(fx_view,exception) == MagickFalse)
2939 if (image->progress_monitor != (MagickProgressMonitor) NULL)
2944#if defined(MAGICKCORE_OPENMP_SUPPORT)
2948 proceed=SetImageProgress(image,FxImageTag,progress,image->rows);
2949 if (proceed == MagickFalse)
2953 fx_view=DestroyCacheView(fx_view);
2954 fx_info=DestroyFxTLS(fx_info);
2955 if (status == MagickFalse)
2956 fx_image=DestroyImage(fx_image);