44 #include "MagickCore/studio.h"
45 #include "MagickCore/accelerate-private.h"
46 #include "MagickCore/annotate.h"
47 #include "MagickCore/artifact.h"
48 #include "MagickCore/attribute.h"
49 #include "MagickCore/cache.h"
50 #include "MagickCore/cache-view.h"
51 #include "MagickCore/channel.h"
52 #include "MagickCore/color.h"
53 #include "MagickCore/color-private.h"
54 #include "MagickCore/colorspace-private.h"
55 #include "MagickCore/composite.h"
56 #include "MagickCore/decorate.h"
57 #include "MagickCore/distort.h"
58 #include "MagickCore/draw.h"
59 #include "MagickCore/effect.h"
60 #include "MagickCore/enhance.h"
61 #include "MagickCore/exception.h"
62 #include "MagickCore/exception-private.h"
63 #include "MagickCore/fx.h"
64 #include "MagickCore/fx-private.h"
65 #include "MagickCore/gem.h"
66 #include "MagickCore/gem-private.h"
67 #include "MagickCore/geometry.h"
68 #include "MagickCore/layer.h"
69 #include "MagickCore/list.h"
70 #include "MagickCore/log.h"
71 #include "MagickCore/image.h"
72 #include "MagickCore/image-private.h"
73 #include "MagickCore/magick.h"
74 #include "MagickCore/memory_.h"
75 #include "MagickCore/memory-private.h"
76 #include "MagickCore/monitor.h"
77 #include "MagickCore/monitor-private.h"
78 #include "MagickCore/option.h"
79 #include "MagickCore/pixel.h"
80 #include "MagickCore/pixel-accessor.h"
81 #include "MagickCore/policy.h"
82 #include "MagickCore/property.h"
83 #include "MagickCore/quantum.h"
84 #include "MagickCore/quantum-private.h"
85 #include "MagickCore/random_.h"
86 #include "MagickCore/random-private.h"
87 #include "MagickCore/resample.h"
88 #include "MagickCore/resample-private.h"
89 #include "MagickCore/resize.h"
90 #include "MagickCore/resource_.h"
91 #include "MagickCore/splay-tree.h"
92 #include "MagickCore/statistic.h"
93 #include "MagickCore/string_.h"
94 #include "MagickCore/thread-private.h"
95 #include "MagickCore/threshold.h"
96 #include "MagickCore/token.h"
97 #include "MagickCore/transform.h"
98 #include "MagickCore/transform-private.h"
99 #include "MagickCore/utility.h"
102 #define MaxTokenLen 100
104 #define TableExtend 0.1
105 #define InitNumOprStack 50
106 #define MinValStackSize 100
107 #define InitNumUserSymbols 50
109 typedef long double fxFltType;
160 {oAddEq,
"+=", 12, 1},
161 {oSubtractEq,
"-=", 12, 1},
162 {oMultiplyEq,
"*=", 13, 1},
163 {oDivideEq,
"/=", 13, 1},
164 {oPlusPlus,
"++", 12, 0},
165 {oSubSub,
"--", 12, 0},
167 {oSubtract,
"-", 12, 2},
168 {oMultiply,
"*", 13, 2},
169 {oDivide,
"/", 13, 2},
170 {oModulus,
"%", 13, 2},
171 {oUnaryPlus,
"+", 14, 1},
172 {oUnaryMinus,
"-", 14, 1},
173 {oLshift,
"<<", 11, 2},
174 {oRshift,
">>", 11, 2},
176 {oNotEq,
"!=", 9, 2},
177 {oLtEq,
"<=", 10, 2},
178 {oGtEq,
">=", 10, 2},
181 {oLogAnd,
"&&", 6, 2},
182 {oLogOr,
"||", 5, 2},
183 {oLogNot,
"!", 16, 1},
184 {oBitAnd,
"&", 8, 2},
186 {oBitNot,
"~", 16, 1},
190 {oOpenParen,
"(", 0, 0},
191 {oCloseParen,
")", 0, 0},
192 {oOpenBracket,
"[", 0, 0},
193 {oCloseBracket,
"]", 0, 0},
194 {oOpenBrace,
"{", 0, 0},
195 {oCloseBrace,
"}", 0, 0},
196 {oAssign,
"=", 3, 1},
197 {oNull,
"onull", 17, 0}
220 {cEpsilon, MagickEpsilon,
"epsilon"},
221 {cE, 2.7182818284590452354,
"e"},
222 {cOpaque, 1.0,
"opaque"},
223 {cPhi, MagickPHI,
"phi"},
224 {cPi, MagickPI,
"pi"},
225 {cQuantumRange, QuantumRange,
"quantumrange"},
226 {cQuantumScale, QuantumScale,
"quantumscale"},
227 {cTransparent, 0.0,
"transparent"},
228 {cMaxRgb, QuantumRange,
"MaxRGB"},
229 {cNull, 0.0,
"cnull"}
232 #define FirstFunc ((FunctionE) (oNull+1))
236 #if defined(MAGICKCORE_HAVE_ACOSH)
240 #if defined(MAGICKCORE_HAVE_J1)
244 #if defined(MAGICKCORE_HAVE_ASINH)
248 #if defined(MAGICKCORE_HAVE_ATANH)
260 #if defined(MAGICKCORE_HAVE_ERF)
270 #if defined(MAGICKCORE_HAVE_J0)
273 #if defined(MAGICKCORE_HAVE_J1)
276 #if defined(MAGICKCORE_HAVE_J1)
322 #if defined(MAGICKCORE_HAVE_ACOSH)
323 {fAcosh,
"acosh" , 1},
326 #if defined(MAGICKCORE_HAVE_J1)
330 #if defined(MAGICKCORE_HAVE_ASINH)
331 {fAsinh,
"asinh" , 1},
334 #if defined(MAGICKCORE_HAVE_ATANH)
335 {fAtanh,
"atanh" , 1},
337 {fAtan2,
"atan2" , 2},
340 {fChannel,
"channel", 5},
341 {fClamp,
"clamp" , 1},
344 {fDebug,
"debug" , 1},
346 #if defined(MAGICKCORE_HAVE_ERF)
350 {fFloor,
"floor" , 1},
351 {fGauss,
"gauss" , 2},
353 {fHypot,
"hypot" , 2},
355 {fIsnan,
"isnan" , 1},
356 #if defined(MAGICKCORE_HAVE_J0)
359 #if defined(MAGICKCORE_HAVE_J1)
362 #if defined(MAGICKCORE_HAVE_J1)
366 {fLogtwo,
"logtwo", 1},
374 {fRound,
"round" , 1},
380 {fSquish,
"squish", 1},
383 {fTrunc,
"trunc" , 1},
387 {fWhile,
"while", 2},
400 #define FirstImgAttr ((ImgAttrE) (fNull+1))
438 static const ImgAttrT ImgAttrs[] = {
439 {aDepth,
"depth", 1},
440 {aExtent,
"extent", 0},
441 {aKurtosis,
"kurtosis", 1},
442 {aMaxima,
"maxima", 1},
444 {aMedian,
"median", 1},
445 {aMinima,
"minima", 1},
447 {aPageX,
"page.x", 0},
448 {aPageY,
"page.y", 0},
449 {aPageWid,
"page.width", 0},
450 {aPageHt,
"page.height", 0},
451 {aPrintsize,
"printsize", 0},
452 {aPrintsizeX,
"printsize.x", 0},
453 {aPrintsizeY,
"printsize.y", 0},
454 {aQuality,
"quality", 0},
455 {aRes,
"resolution", 0},
456 {aResX,
"resolution.x", 0},
457 {aResY,
"resolution.y", 0},
458 {aSkewness,
"skewness", 1},
459 {aStdDev,
"standard_deviation", 1},
471 #define FirstSym ((SymbolE) (aNull+1))
499 static const SymbolT Symbols[] = {
501 {sIntensity,
"intensity"},
502 {sLightness,
"lightness"},
504 {sLuminance,
"luminance"},
505 {sSaturation,
"saturation"},
526 #define FirstCont (sNull+1)
545 static const ControlT Controls[] = {
547 {rIfZeroGoto,
"ifzerogoto", 1},
548 {rIfNotZeroGoto,
"ifnotzerogoto", 1},
549 {rCopyFrom,
"copyfrom", 0},
550 {rCopyTo,
"copyto", 1},
551 {rZerStk,
"zerstk", 0},
555 #define NULL_ADDRESS -2
564 PixelChannel pixChan;
567 #define NO_CHAN_QUAL ((PixelChannel) (-1))
568 #define THIS_CHANNEL ((PixelChannel) (-2))
569 #define HUE_CHANNEL ((PixelChannel) (-3))
570 #define SAT_CHANNEL ((PixelChannel) (-4))
571 #define LIGHT_CHANNEL ((PixelChannel) (-5))
572 #define INTENSITY_CHANNEL ((PixelChannel) (-6))
574 static const ChannelT Channels[] = {
575 {
"r", RedPixelChannel},
576 {
"g", GreenPixelChannel},
577 {
"b", BluePixelChannel},
578 {
"c", CyanPixelChannel},
579 {
"m", MagentaPixelChannel},
580 {
"y", YellowPixelChannel},
581 {
"k", BlackPixelChannel},
582 {
"a", AlphaPixelChannel},
583 {
"o", AlphaPixelChannel},
584 {
"hue", HUE_CHANNEL},
585 {
"saturation", SAT_CHANNEL},
586 {
"lightness", LIGHT_CHANNEL},
587 {
"intensity", INTENSITY_CHANNEL},
588 {
"all", CompositePixelChannel},
589 {
"this", THIS_CHANNEL},
610 static const char * sElementTypes[] = {
626 MagickBooleanType IsRelative;
627 MagickBooleanType DoPush;
630 PixelChannel ChannelQual;
631 ImgAttrE ImgAttrQual;
651 fxFltType * ValStack;
652 fxFltType * UserSymVals;
660 MagickBooleanType NeedStats;
661 MagickBooleanType GotStats;
662 MagickBooleanType NeedHsl;
663 MagickBooleanType DebugOpt;
664 MagickBooleanType ContainsDebug;
667 char ShortExp[MagickPathExtent];
669 char token[MagickPathExtent];
680 OperatorE * OperatorStack;
686 **magick_restrict random_infos;
698 static MagickBooleanType TranslateStatementList
699 (
FxInfo * pfx,
const char * strLimit,
char * chLimit);
701 static MagickBooleanType TranslateExpression
702 (
FxInfo * pfx,
const char * strLimit,
char * chLimit, MagickBooleanType * needPopAll);
704 static MagickBooleanType GetFunction (
FxInfo * pfx, FunctionE fe);
706 static MagickBooleanType InitFx (
FxInfo * pfx,
const Image * img,
712 pfx->ImgListLen = GetImageListLength (img);
713 pfx->ImgNum = GetImageIndexInList (img);
714 pfx->image = (
Image *)img;
716 pfx->NeedStats = MagickFalse;
717 pfx->GotStats = MagickFalse;
718 pfx->NeedHsl = MagickFalse;
719 pfx->DebugOpt = IsStringTrue (GetImageArtifact (img,
"fx:debug"));
720 pfx->statistics = NULL;
723 pfx->exception = exception;
724 pfx->precision = GetMagickPrecision ();
725 pfx->random_infos = AcquireRandomInfoTLS ();
726 pfx->ContainsDebug = MagickFalse;
727 pfx->runType = (CalcAllStats) ? rtEntireImage : rtCornerOnly;
728 pfx->Imgs = (
ImgT *)AcquireQuantumMemory (pfx->ImgListLen, sizeof (
ImgT));
730 (void) ThrowMagickException (
731 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
733 (
unsigned long) pfx->ImgListLen);
737 next = GetFirstImageInList (img);
738 for ( ; next != (
Image *) NULL; next=next->next)
740 ImgT * pimg = &pfx->Imgs[i];
741 pimg->View = AcquireVirtualCacheView (next, pfx->exception);
743 (void) ThrowMagickException (
744 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
748 for ( ; i > 0; i--) {
749 pimg = &pfx->Imgs[i-1];
750 pimg->View = DestroyCacheView (pimg->View);
752 pfx->Imgs=(
ImgT *) RelinquishMagickMemory (pfx->Imgs);
758 pfx->Images = ImageListToArray (img, pfx->exception);
763 static MagickBooleanType DeInitFx (
FxInfo * pfx)
767 if (pfx->Images) pfx->Images = (
Image**) RelinquishMagickMemory (pfx->Images);
770 for (i = (ssize_t)GetImageListLength(pfx->image); i > 0; i--) {
771 ImgT * pimg = &pfx->Imgs[i-1];
772 pimg->View = DestroyCacheView (pimg->View);
774 pfx->Imgs=(
ImgT *) RelinquishMagickMemory (pfx->Imgs);
776 pfx->random_infos = DestroyRandomInfoTLS (pfx->random_infos);
778 if (pfx->statistics) {
779 for (i = (ssize_t)GetImageListLength(pfx->image); i > 0; i--) {
780 pfx->statistics[i-1]=(
ChannelStatistics *) RelinquishMagickMemory (pfx->statistics[i-1]);
789 static ElementTypeE TypeOfOpr (
int op)
791 if (op < oNull)
return etOperator;
792 if (op == oNull)
return etConstant;
793 if (op <= fNull)
return etFunction;
794 if (op <= aNull)
return etImgAttr;
795 if (op <= sNull)
return etSymbol;
796 if (op <= rNull)
return etControl;
798 return (ElementTypeE) 0;
801 static char * SetPtrShortExp (
FxInfo * pfx,
char * pExp,
size_t len)
808 *pfx->ShortExp =
'\0';
811 slen = CopyMagickString (pfx->ShortExp, pExp, len);
813 (void) CopyMagickString (pfx->ShortExp+MaxLen,
"...", 4);
815 p = strchr (pfx->ShortExp,
'\n');
816 if (p) (void) CopyMagickString (p,
"...", 4);
817 p = strchr (pfx->ShortExp,
'\r');
818 if (p) (void) CopyMagickString (p,
"...", 4);
820 return pfx->ShortExp;
823 static char * SetShortExp (
FxInfo * pfx)
825 return SetPtrShortExp (pfx, pfx->pex, MaxTokenLen-1);
828 static int FindUserSymbol (
FxInfo * pfx,
char * name)
835 lenName = strlen (name);
836 for (i=0; i < pfx->usedUserSymbols; i++) {
838 if (lenName == pus->len && LocaleNCompare (name, pus->pex, lenName)==0)
break;
840 if (i == pfx->usedUserSymbols)
return NULL_ADDRESS;
844 static MagickBooleanType ExtendUserSymbols (
FxInfo * pfx)
846 pfx->numUserSymbols = (int) ceil (pfx->numUserSymbols * (1 + TableExtend));
847 pfx->UserSymbols = (
UserSymbolT*) ResizeMagickMemory (pfx->UserSymbols, pfx->numUserSymbols *
sizeof(
UserSymbolT));
848 if (!pfx->UserSymbols) {
849 (void) ThrowMagickException (
850 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
852 pfx->numUserSymbols);
859 static int AddUserSymbol (
FxInfo * pfx,
char * pex,
size_t len)
862 if (++pfx->usedUserSymbols >= pfx->numUserSymbols) {
863 if (!ExtendUserSymbols (pfx))
return -1;
865 pus = &pfx->UserSymbols[pfx->usedUserSymbols-1];
869 return pfx->usedUserSymbols-1;
872 static void DumpTables (FILE * fh)
876 for (i=0; i <= rNull; i++) {
877 const char * str =
"";
878 if ( i < oNull) str = Operators[i].str;
879 if (i >= FirstFunc && i < fNull) str = Functions[i-FirstFunc].str;
880 if (i >= FirstImgAttr && i < aNull) str = ImgAttrs[i-FirstImgAttr].str;
881 if (i >= FirstSym && i < sNull) str = Symbols[i-FirstSym].str;
882 if (i >= FirstCont && i < rNull) str = Controls[i-FirstCont].str;
883 if (i==0 ) fprintf (stderr,
"Operators:\n ");
884 else if (i==oNull) fprintf (stderr,
"\nFunctions:\n ");
885 else if (i==fNull) fprintf (stderr,
"\nImage attributes:\n ");
886 else if (i==aNull) fprintf (stderr,
"\nSymbols:\n ");
887 else if (i==sNull) fprintf (stderr,
"\nControls:\n ");
888 fprintf (fh,
" %s", str);
893 static char * NameOfUserSym (
FxInfo * pfx,
int ndx,
char * buf)
896 assert (ndx >= 0 && ndx < pfx->usedUserSymbols);
897 pus = &pfx->UserSymbols[ndx];
898 (void) CopyMagickString (buf, pus->pex, pus->len+1);
902 static void DumpUserSymbols (
FxInfo * pfx, FILE * fh)
904 char UserSym[MagickPathExtent];
906 fprintf (fh,
"UserSymbols (%i)\n", pfx->usedUserSymbols);
907 for (i=0; i < pfx->usedUserSymbols; i++) {
908 fprintf (fh,
" %i: '%s'\n", i, NameOfUserSym (pfx, i, UserSym));
912 static MagickBooleanType BuildRPN (
FxInfo * pfx)
914 pfx->numUserSymbols = InitNumUserSymbols;
915 pfx->usedUserSymbols = 0;
917 if (!pfx->UserSymbols) {
918 (void) ThrowMagickException (
919 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
921 pfx->numUserSymbols);
925 pfx->numElements = RpnInit;
926 pfx->usedElements = 0;
927 pfx->Elements = NULL;
929 pfx->Elements = (
ElementT*) AcquireMagickMemory (pfx->numElements *
sizeof(
ElementT));
931 if (!pfx->Elements) {
932 (void) ThrowMagickException (
933 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
939 pfx->usedOprStack = 0;
940 pfx->maxUsedOprStack = 0;
941 pfx->numOprStack = InitNumOprStack;
942 pfx->OperatorStack = (OperatorE*) AcquireMagickMemory (pfx->numOprStack *
sizeof(OperatorE));
943 if (!pfx->OperatorStack) {
944 (void) ThrowMagickException (
945 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
946 "OperatorStack",
"%i",
954 static MagickBooleanType AllocFxRt (
FxInfo * pfx,
fxRtT * pfxrt)
958 pfxrt->random_info = AcquireRandomInfo ();
959 pfxrt->thisPixel = NULL;
961 nRnd = 20 + 10 * (int) GetPseudoRandomValue (pfxrt->random_info);
962 for (i=0; i < nRnd; i++) (
void) GetPseudoRandomValue (pfxrt->random_info);;
964 pfxrt->usedValStack = 0;
965 pfxrt->numValStack = 2 * pfx->maxUsedOprStack;
966 if (pfxrt->numValStack < MinValStackSize) pfxrt->numValStack = MinValStackSize;
967 pfxrt->ValStack = (fxFltType*) AcquireMagickMemory (pfxrt->numValStack *
sizeof(fxFltType));
968 if (!pfxrt->ValStack) {
969 (void) ThrowMagickException (
970 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
976 pfxrt->UserSymVals = NULL;
978 if (pfx->usedUserSymbols) {
979 pfxrt->UserSymVals = (fxFltType*) AcquireMagickMemory (pfx->usedUserSymbols *
sizeof(fxFltType));
980 if (!pfxrt->UserSymVals) {
981 (void) ThrowMagickException (
982 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
984 pfx->usedUserSymbols);
987 for (i = 0; i < pfx->usedUserSymbols; i++) pfxrt->UserSymVals[i] = (fxFltType) 0;
992 static MagickBooleanType ExtendRPN (
FxInfo * pfx)
994 pfx->numElements = (int) ceil (pfx->numElements * (1 + TableExtend));
995 pfx->Elements = (
ElementT*) ResizeMagickMemory (pfx->Elements, pfx->numElements *
sizeof(
ElementT));
996 if (!pfx->Elements) {
997 (void) ThrowMagickException (
998 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1006 static MagickBooleanType
inline OprInPlace (
int op)
1008 return (op >= oAddEq && op <= oSubSub ? MagickTrue : MagickFalse);
1011 static const char * OprStr (
int oprNum)
1014 if (oprNum < 0) str =
"bad OprStr";
1015 else if (oprNum <= oNull) str = Operators[oprNum].str;
1016 else if (oprNum <= fNull) str = Functions[oprNum-FirstFunc].str;
1017 else if (oprNum <= aNull) str = ImgAttrs[oprNum-FirstImgAttr].str;
1018 else if (oprNum <= sNull) str = Symbols[oprNum-FirstSym].str;
1019 else if (oprNum <= rNull) str = Controls[oprNum-FirstCont].str;
1026 static MagickBooleanType DumpRPN (
FxInfo * pfx, FILE * fh)
1030 fprintf (fh,
"DumpRPN:");
1031 fprintf (fh,
" numElements=%i", pfx->numElements);
1032 fprintf (fh,
" usedElements=%i", pfx->usedElements);
1033 fprintf (fh,
" maxUsedOprStack=%i", pfx->maxUsedOprStack);
1034 fprintf (fh,
" ImgListLen=%g", (
double) pfx->ImgListLen);
1035 fprintf (fh,
" NeedStats=%s", pfx->NeedStats ?
"yes" :
"no");
1036 fprintf (fh,
" GotStats=%s", pfx->GotStats ?
"yes" :
"no");
1037 fprintf (fh,
" NeedHsl=%s\n", pfx->NeedHsl ?
"yes" :
"no");
1038 if (pfx->runType==rtEntireImage) fprintf (stderr,
"EntireImage");
1039 else if (pfx->runType==rtCornerOnly) fprintf (stderr,
"CornerOnly");
1043 for (i=0; i < pfx->usedElements; i++) {
1044 ElementT * pel = &pfx->Elements[i];
1047 for (i=0; i < pfx->usedElements; i++) {
1048 ElementT * pel = &pfx->Elements[i];
1049 if (pel->oprNum == rGoto || pel->oprNum == rIfZeroGoto || pel->oprNum == rIfNotZeroGoto) {
1050 if (pel->EleNdx >= 0 && pel->EleNdx < pfx->numElements) {
1051 ElementT * pelDest = &pfx->Elements[pel->EleNdx];
1056 for (i=0; i < pfx->usedElements; i++) {
1057 char UserSym[MagickPathExtent];
1059 ElementT * pel = &pfx->Elements[i];
1060 const char * str = OprStr (pel->oprNum);
1061 const char *sRelAbs =
"";
1063 if (pel->oprNum == fP || pel->oprNum == fUP || pel->oprNum == fVP || pel->oprNum == fSP)
1064 sRelAbs = pel->IsRelative ?
"[]" :
"{}";
1066 if (pel->type == etColourConstant)
1067 fprintf (fh,
" %i: %s vals=%.*Lg,%.*Lg,%.*Lg '%s%s' nArgs=%i ndx=%i %s",
1068 i, sElementTypes[pel->type],
1069 pfx->precision, pel->val, pfx->precision, pel->val1, pfx->precision, pel->val2,
1070 str, sRelAbs, pel->nArgs, pel->EleNdx,
1071 pel->DoPush ?
"push" :
"NO push");
1073 fprintf (fh,
" %i: %s val=%.*Lg '%s%s' nArgs=%i ndx=%i %s",
1074 i, sElementTypes[pel->type], pfx->precision, pel->val, str, sRelAbs,
1075 pel->nArgs, pel->EleNdx,
1076 pel->DoPush ?
"push" :
"NO push");
1078 if (pel->ImgAttrQual != aNull)
1079 fprintf (fh,
" ia=%s", OprStr(pel->ImgAttrQual));
1081 if (pel->ChannelQual != NO_CHAN_QUAL) {
1082 if (pel->ChannelQual == THIS_CHANNEL) fprintf (stderr,
" ch=this");
1083 else fprintf (stderr,
" ch=%i", pel->ChannelQual);
1086 if (pel->oprNum == rCopyTo) {
1087 fprintf (fh,
" CopyTo ==> %s", NameOfUserSym (pfx, pel->EleNdx, UserSym));
1088 }
else if (pel->oprNum == rCopyFrom) {
1089 fprintf (fh,
" CopyFrom <== %s", NameOfUserSym (pfx, pel->EleNdx, UserSym));
1090 }
else if (OprInPlace (pel->oprNum)) {
1091 fprintf (fh,
" <==> %s", NameOfUserSym (pfx, pel->EleNdx, UserSym));
1093 if (pel->nDest > 0) fprintf (fh,
" <==dest(%i)", pel->nDest);
1099 static void DestroyRPN (
FxInfo * pfx)
1101 pfx->numOprStack = 0;
1102 pfx->usedOprStack = 0;
1103 if (pfx->OperatorStack) pfx->OperatorStack = (OperatorE*) RelinquishMagickMemory (pfx->OperatorStack);
1105 pfx->numElements = 0;
1106 pfx->usedElements = 0;
1107 if (pfx->Elements) pfx->Elements = (
ElementT*) RelinquishMagickMemory (pfx->Elements);
1109 pfx->usedUserSymbols = 0;
1110 if (pfx->UserSymbols) pfx->UserSymbols = (
UserSymbolT*) RelinquishMagickMemory (pfx->UserSymbols);
1113 static void DestroyFxRt (
fxRtT * pfxrt)
1115 pfxrt->usedValStack = 0;
1116 if (pfxrt->ValStack) pfxrt->ValStack = (fxFltType*) RelinquishMagickMemory (pfxrt->ValStack);
1117 if (pfxrt->UserSymVals) pfxrt->UserSymVals = (fxFltType*) RelinquishMagickMemory (pfxrt->UserSymVals);
1119 pfxrt->random_info = DestroyRandomInfo (pfxrt->random_info);
1122 static size_t GetToken (
FxInfo * pfx)
1133 char * p = pfx->pex;
1137 if (!isalpha((
int)*p))
return 0;
1144 if (LocaleNCompare (p,
"icc-", 4) == 0) {
1147 while (isalpha ((
int)*p)) { len++; p++; }
1148 }
else if (LocaleNCompare (p,
"device-", 7) == 0) {
1151 while (isalpha ((
int)*p)) { len++; p++; }
1153 while (isalpha ((
int)*p)) { len++; p++; }
1154 if (*p ==
'_') { len++; p++; }
1155 while (isalpha ((
int)*p)) { len++; p++; }
1156 while (isdigit ((
int)*p)) { len++; p++; }
1158 if (len >= MaxTokenLen) {
1159 (void) ThrowMagickException (
1160 pfx->exception, GetMagickModule(), OptionError,
1161 "GetToken: too long",
"%g at '%s'",
1162 (double) len, SetShortExp(pfx));
1166 (void) CopyMagickString (pfx->token, pfx->pex, (len+1<MaxTokenLen)?len+1:MaxTokenLen);
1169 pfx->lenToken = strlen (pfx->token);
1173 static MagickBooleanType TokenMaybeUserSymbol (
FxInfo * pfx)
1175 char * p = pfx->token;
1178 if (!isalpha ((
int)*p++))
return MagickFalse;
1181 if (i < 2)
return MagickFalse;
1185 static MagickBooleanType AddElement (
FxInfo * pfx, fxFltType val,
int oprNum)
1189 assert (oprNum <= rNull);
1191 if (++pfx->usedElements >= pfx->numElements) {
1192 if (!ExtendRPN (pfx))
return MagickFalse;
1195 pel = &pfx->Elements[pfx->usedElements-1];
1196 pel->type = TypeOfOpr (oprNum);
1198 pel->val1 = (fxFltType) 0;
1199 pel->val2 = (fxFltType) 0;
1200 pel->oprNum = oprNum;
1201 pel->DoPush = MagickTrue;
1203 pel->ChannelQual = NO_CHAN_QUAL;
1204 pel->ImgAttrQual = aNull;
1206 pel->pExpStart = NULL;
1209 if (oprNum <= oNull) pel->nArgs = Operators[oprNum].nArgs;
1210 else if (oprNum <= fNull) pel->nArgs = Functions[oprNum-FirstFunc].nArgs;
1211 else if (oprNum <= aNull) pel->nArgs = 0;
1212 else if (oprNum <= sNull) pel->nArgs = 0;
1213 else pel->nArgs = Controls[oprNum-FirstCont].nArgs;
1218 static MagickBooleanType AddAddressingElement (
FxInfo * pfx,
int oprNum,
int EleNdx)
1221 if (!AddElement (pfx, (fxFltType) 0, oprNum))
return MagickFalse;
1222 pel = &pfx->Elements[pfx->usedElements-1];
1223 pel->EleNdx = EleNdx;
1224 if (oprNum == rGoto || oprNum == rIfZeroGoto || oprNum == rIfNotZeroGoto
1225 || oprNum == rZerStk)
1227 pel->DoPush = MagickFalse;
1237 static MagickBooleanType AddColourElement (
FxInfo * pfx, fxFltType val0, fxFltType val1, fxFltType val2)
1240 if (!AddElement (pfx, val0, oNull))
return MagickFalse;
1241 pel = &pfx->Elements[pfx->usedElements-1];
1244 pel->type = etColourConstant;
1248 static void inline SkipSpaces (
FxInfo * pfx)
1250 while (isspace ((
int)*pfx->pex)) pfx->pex++;
1253 static char inline PeekChar (
FxInfo * pfx)
1259 static MagickBooleanType
inline PeekStr (
FxInfo * pfx,
const char * str)
1263 return (LocaleNCompare (pfx->pex, str, strlen(str))==0 ? MagickTrue : MagickFalse);
1266 static MagickBooleanType ExpectChar (
FxInfo * pfx,
char c)
1268 if (PeekChar (pfx) != c) {
1269 (void) ThrowMagickException (
1270 pfx->exception, GetMagickModule(), OptionError,
1271 "Expected char",
"'%c' at '%s'", c, SetShortExp (pfx));
1278 static int MaybeXYWH (
FxInfo * pfx, ImgAttrE * pop)
1285 if (*pop != aPage && *pop != aPrintsize && *pop != aRes)
return 0;
1287 if (PeekChar (pfx) !=
'.')
return 0;
1289 if (!ExpectChar (pfx,
'.'))
return 0;
1291 (void) GetToken (pfx);
1292 if (LocaleCompare (
"x", pfx->token)==0) ret=1;
1293 else if (LocaleCompare (
"y", pfx->token)==0) ret=2;
1294 else if (LocaleCompare (
"width", pfx->token)==0) ret=3;
1295 else if (LocaleCompare (
"height", pfx->token)==0) ret=4;
1298 (void) ThrowMagickException (
1299 pfx->exception, GetMagickModule(), OptionError,
1300 "Invalid 'x' or 'y' or 'width' or 'height' token=",
"'%s' at '%s'",
1301 pfx->token, SetShortExp(pfx));
1303 if (*pop == aPage) (*pop) = (ImgAttrE) (*pop + ret);
1306 (void) ThrowMagickException (
1307 pfx->exception, GetMagickModule(), OptionError,
1308 "Invalid 'width' or 'height' token=",
"'%s' at '%s'",
1309 pfx->token, SetShortExp(pfx));
1311 (*pop) = (ImgAttrE) (*pop + ret);
1314 pfx->pex+=pfx->lenToken;
1319 static MagickBooleanType ExtendOperatorStack (
FxInfo * pfx)
1321 pfx->numOprStack = (int) ceil (pfx->numOprStack * (1 + TableExtend));
1322 pfx->OperatorStack = (OperatorE*) ResizeMagickMemory (pfx->OperatorStack, pfx->numOprStack *
sizeof(OperatorE));
1323 if (!pfx->OperatorStack) {
1324 (void) ThrowMagickException (
1325 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1333 static MagickBooleanType PushOperatorStack (
FxInfo * pfx,
int op)
1335 if (++pfx->usedOprStack >= pfx->numOprStack) {
1336 if (!ExtendOperatorStack (pfx))
1339 pfx->OperatorStack[pfx->usedOprStack-1] = (OperatorE) op;
1341 if (pfx->maxUsedOprStack < pfx->usedOprStack)
1342 pfx->maxUsedOprStack = pfx->usedOprStack;
1346 static OperatorE GetLeadingOp (
FxInfo * pfx)
1348 OperatorE op = oNull;
1350 if (*pfx->pex ==
'-') op = oUnaryMinus;
1351 else if (*pfx->pex ==
'+') op = oUnaryPlus;
1352 else if (*pfx->pex ==
'~') op = oBitNot;
1353 else if (*pfx->pex ==
'!') op = oLogNot;
1354 else if (*pfx->pex ==
'(') op = oOpenParen;
1359 static MagickBooleanType
inline OprIsUnaryPrefix (OperatorE op)
1361 return (op == oUnaryMinus || op == oUnaryPlus || op == oBitNot || op == oLogNot ? MagickTrue : MagickFalse);
1364 static MagickBooleanType TopOprIsUnaryPrefix (
FxInfo * pfx)
1366 if (!pfx->usedOprStack)
return MagickFalse;
1368 return OprIsUnaryPrefix (pfx->OperatorStack[pfx->usedOprStack-1]);
1371 static MagickBooleanType PopOprOpenParen (
FxInfo * pfx, OperatorE op)
1374 if (!pfx->usedOprStack)
return MagickFalse;
1376 if (pfx->OperatorStack[pfx->usedOprStack-1] != op)
return MagickFalse;
1378 pfx->usedOprStack--;
1383 static int GetCoordQualifier (
FxInfo * pfx,
int op)
1387 if (op != fU && op != fV && op != fS)
return -1;
1389 (void) GetToken (pfx);
1391 if (pfx->lenToken != 1) {
1394 if (*pfx->token !=
'p' && *pfx->token !=
'P')
return -1;
1395 if (!GetFunction (pfx, fP))
return -1;
1400 static PixelChannel GetChannelQualifier (
FxInfo * pfx,
int op)
1402 if (op == fU || op == fV || op == fP ||
1403 op == fUP || op == fVP ||
1404 op == fS || (op >= FirstImgAttr && op <= aNull)
1407 const ChannelT * pch = &Channels[0];
1408 (void) GetToken (pfx);
1411 if (LocaleCompare (pch->str, pfx->token)==0) {
1413 if (op >= FirstImgAttr && op <= (OperatorE)aNull &&
1414 (pch->pixChan == HUE_CHANNEL ||
1415 pch->pixChan == SAT_CHANNEL ||
1416 pch->pixChan == LIGHT_CHANNEL)
1419 (void) ThrowMagickException (
1420 pfx->exception, GetMagickModule(), OptionError,
1421 "Can't have image attribute with HLS qualifier at",
"'%s'",
1423 return NO_CHAN_QUAL;
1426 pfx->pex += pfx->lenToken;
1427 return pch->pixChan;
1432 return NO_CHAN_QUAL;
1435 static ImgAttrE GetImgAttrToken (
FxInfo * pfx)
1437 ImgAttrE ia = aNull;
1439 for (ia = FirstImgAttr; ia < aNull; ia=(ImgAttrE) (ia+1)) {
1440 iaStr = ImgAttrs[ia-FirstImgAttr].str;
1441 if (LocaleCompare (iaStr, pfx->token)==0) {
1442 pfx->pex += strlen(pfx->token);
1443 if (ImgAttrs[ia-FirstImgAttr].NeedStats == 1) pfx->NeedStats = MagickTrue;
1444 MaybeXYWH (pfx, &ia);
1449 if (ia == aPage || ia == aPrintsize || ia == aRes) {
1450 (void) ThrowMagickException (
1451 pfx->exception, GetMagickModule(), OptionError,
1452 "Attribute",
"'%s' needs qualifier at '%s'",
1453 iaStr, SetShortExp(pfx));
1459 static ImgAttrE GetImgAttrQualifier (
FxInfo * pfx,
int op)
1461 ImgAttrE ia = aNull;
1462 if (op == (OperatorE)fU || op == (OperatorE)fV || op == (OperatorE)fP || op == (OperatorE)fS) {
1463 (void) GetToken (pfx);
1464 if (pfx->lenToken == 0) {
1467 ia = GetImgAttrToken (pfx);
1472 static MagickBooleanType IsQualifier (
FxInfo * pfx)
1474 if (PeekChar (pfx) ==
'.') {
1481 static ssize_t GetProperty (
FxInfo * pfx, fxFltType *val)
1487 if (PeekStr (pfx,
"%[")) {
1490 char sProperty [MagickPathExtent];
1491 char * p = pfx->pex + 2;
1495 if (*p ==
'[') level++;
1496 else if (*p ==
']') {
1497 if (level == 0)
break;
1502 if (!*p || level != 0) {
1503 (void) ThrowMagickException (
1504 pfx->exception, GetMagickModule(), OptionError,
1505 "After '%[' expected ']' at",
"'%s'",
1510 len = (size_t) (p - pfx->pex + 1);
1511 if (len > MaxTokenLen) {
1512 (void) ThrowMagickException (
1513 pfx->exception, GetMagickModule(), OptionError,
1514 "Too much text between '%[' and ']' at",
"'%s'",
1519 (void) CopyMagickString (sProperty, pfx->pex, len+1);
1520 sProperty[len] =
'\0';
1524 text = InterpretImageProperties (pfx->image->image_info, pfx->image,
1525 sProperty, pfx->exception);
1526 if (!text || !*text) {
1527 text = DestroyString(text);
1528 (void) ThrowMagickException (
1529 pfx->exception, GetMagickModule(), OptionError,
1530 "Unknown property",
"'%s' at '%s'",
1531 sProperty, SetShortExp(pfx));
1535 *val = strtold (text, &tailptr);
1536 if (text == tailptr) {
1537 text = DestroyString(text);
1538 (void) ThrowMagickException (
1539 pfx->exception, GetMagickModule(), OptionError,
1540 "Property",
"'%s' text '%s' is not a number at '%s'",
1541 sProperty, text, SetShortExp(pfx));
1545 text = DestroyString(text);
1547 return ((ssize_t) len);
1553 static ssize_t
inline GetConstantColour (
FxInfo * pfx, fxFltType *v0, fxFltType *v1, fxFltType *v2)
1564 *dummy_exception = AcquireExceptionInfo ();
1574 char ColSp[MagickPathExtent];
1575 (void) CopyMagickString (ColSp, pfx->token, MaxTokenLen);
1576 p = ColSp + pfx->lenToken - 1;
1577 if (*p ==
'a' || *p ==
'A') *p =
'\0';
1579 (void) GetPixelInfo (pfx->image, &colour);
1583 IsGray = (LocaleCompare (ColSp,
"gray") == 0) ? MagickTrue : MagickFalse;
1584 IsIcc = (LocaleCompare (ColSp,
"icc-color") == 0) ? MagickTrue : MagickFalse;
1585 IsDev = (LocaleNCompare (ColSp,
"device-", 7) == 0) ? MagickTrue : MagickFalse;
1589 if (!QueryColorCompliance (pfx->token, AllCompliance, &colour, dummy_exception) || IsGray) {
1590 ssize_t type = ParseCommandOption (MagickColorspaceOptions, MagickFalse, ColSp);
1591 if (type >= 0 || IsIcc || IsDev) {
1592 char * q = pfx->pex + pfx->lenToken;
1593 while (isspace((
int) ((
unsigned char) *q))) q++;
1596 char sFunc[MagickPathExtent];
1597 while (*q && *q !=
')') q++;
1599 (void) ThrowMagickException (
1600 pfx->exception, GetMagickModule(), OptionError,
1601 "constant color missing ')'",
"at '%s'",
1603 dummy_exception = DestroyExceptionInfo (dummy_exception);
1606 lenfun = (size_t) (q - pfx->pex + 1);
1607 if (lenfun > MaxTokenLen) {
1608 (void) ThrowMagickException (
1609 pfx->exception, GetMagickModule(), OptionError,
1610 "lenfun too long",
"'%lu' at '%s'",
1611 (
unsigned long) lenfun, SetShortExp(pfx));
1612 dummy_exception = DestroyExceptionInfo (dummy_exception);
1615 (void) CopyMagickString (sFunc, pfx->pex, lenfun+1);
1616 if (QueryColorCompliance (sFunc, AllCompliance, &colour, dummy_exception)) {
1617 *v0 = colour.red / QuantumRange;
1618 *v1 = colour.green / QuantumRange;
1619 *v2 = colour.blue / QuantumRange;
1620 dummy_exception = DestroyExceptionInfo (dummy_exception);
1621 return (ssize_t)lenfun;
1624 (void) ThrowMagickException (
1625 pfx->exception, GetMagickModule(), OptionError,
1626 "colorspace but not a valid color with '(...)' at",
"'%s'",
1628 dummy_exception = DestroyExceptionInfo (dummy_exception);
1633 dummy_exception = DestroyExceptionInfo (dummy_exception);
1638 *v0 = colour.red / QuantumRange;
1639 *v1 = colour.green / QuantumRange;
1640 *v2 = colour.blue / QuantumRange;
1642 dummy_exception = DestroyExceptionInfo (dummy_exception);
1643 return (ssize_t)strlen (pfx->token);
1646 static ssize_t
inline GetHexColour (
FxInfo * pfx, fxFltType *v0, fxFltType *v1, fxFltType *v2)
1655 if (*pfx->pex !=
'#')
return 0;
1659 while (isxdigit ((
int)*p)) p++;
1660 if (isalpha ((
int)*p)) {
1661 (void) ThrowMagickException (
1662 pfx->exception, GetMagickModule(), OptionError,
1663 "Bad hex number at",
"'%s'",
1668 len = (size_t) (p - pfx->pex);
1669 if (len < 1)
return 0;
1670 if (len >= MaxTokenLen) {
1671 (void) ThrowMagickException (
1672 pfx->exception, GetMagickModule(), OptionError,
1673 "Hex colour too long at",
"'%s'",
1677 (void) CopyMagickString (pfx->token, pfx->pex, len+1);
1679 (void) GetPixelInfo (pfx->image, &colour);
1681 if (!QueryColorCompliance (pfx->token, AllCompliance, &colour, pfx->exception)) {
1682 (void) ThrowMagickException (
1683 pfx->exception, GetMagickModule(), OptionError,
1684 "QueryColorCompliance rejected",
"'%s' at '%s'",
1685 pfx->token, SetShortExp(pfx));
1689 *v0 = colour.red / QuantumRange;
1690 *v1 = colour.green / QuantumRange;
1691 *v2 = colour.blue / QuantumRange;
1693 return (ssize_t) len;
1696 static MagickBooleanType GetFunction (
FxInfo * pfx, FunctionE fe)
1700 const char * funStr = Functions[fe-FirstFunc].str;
1701 int nArgs = Functions[fe-FirstFunc].nArgs;
1703 char expChLimit =
')';
1704 const char *strLimit =
",)";
1705 OperatorE pushOp = oOpenParen;
1712 int ndx0 = NULL_ADDRESS, ndx1 = NULL_ADDRESS, ndx2 = NULL_ADDRESS, ndx3 = NULL_ADDRESS;
1714 MagickBooleanType coordQual = MagickFalse;
1715 PixelChannel chQual = NO_CHAN_QUAL;
1716 ImgAttrE iaQual = aNull;
1718 pfx->pex += pfx->lenToken;
1721 char p = PeekChar (pfx);
1723 (void) ExpectChar (pfx,
'{');
1724 pushOp = oOpenBrace;
1728 }
else if (p==
'[') {
1729 (void) ExpectChar (pfx,
'[');
1730 pushOp = oOpenBracket;
1739 }
else if (fe == fU) {
1740 char p = PeekChar (pfx);
1742 (void) ExpectChar (pfx,
'[');
1743 pushOp = oOpenBracket;
1752 }
else if (fe == fV || fe == fS) {
1754 pushOp = oOpenBracket;
1758 if (!ExpectChar (pfx,
'('))
return MagickFalse;
1760 if (!PushOperatorStack (pfx, pushOp))
return MagickFalse;
1762 pExpStart = pfx->pex;
1763 ndx0 = pfx->usedElements;
1765 (void) AddAddressingElement (pfx, rGoto, NULL_ADDRESS);
1769 if (TranslateStatementList (pfx, strLimit, &chLimit)) {
1773 if (!chLimit)
break;
1774 if (fe == fP || fe == fS|| fe == fIf) {
1775 (void) AddElement (pfx, (fxFltType) 0, oNull);
1780 if (strchr (strLimit, chLimit)==NULL) {
1781 (void) ThrowMagickException (
1782 pfx->exception, GetMagickModule(), OptionError,
1783 "For function",
"'%s' expected one of '%s' after expression but found '%c' at '%s'",
1784 funStr, strLimit, chLimit ? chLimit :
' ', SetShortExp(pfx));
1793 if (ndx1 != NULL_ADDRESS) {
1794 (void) ThrowMagickException (
1795 pfx->exception, GetMagickModule(), OptionError,
1796 "For function",
"'%s' required argument is missing at '%s'",
1797 funStr, SetShortExp(pfx));
1800 ndx1 = pfx->usedElements;
1802 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
1803 }
else if (fe==fDo) {
1804 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
1805 }
else if (fe==fFor) {
1806 pfx->Elements[pfx->usedElements-1].DoPush = MagickFalse;
1807 }
else if (fe==fIf) {
1808 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
1809 pfx->Elements[pfx->usedElements-1].DoPush = MagickTrue;
1813 if (ndx2 != NULL_ADDRESS) {
1814 (void) ThrowMagickException (
1815 pfx->exception, GetMagickModule(), OptionError,
1816 "For function",
"'%s' required argument is missing at '%s'",
1817 funStr, SetShortExp(pfx));
1820 ndx2 = pfx->usedElements;
1822 pfx->Elements[pfx->usedElements-1].DoPush = MagickFalse;
1823 (void) AddAddressingElement (pfx, rGoto, ndx0);
1824 }
else if (fe==fDo) {
1825 pfx->Elements[pfx->usedElements-1].DoPush = MagickFalse;
1826 (void) AddAddressingElement (pfx, rGoto, ndx0 + 1);
1827 }
else if (fe==fFor) {
1828 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
1829 pfx->Elements[pfx->usedElements-1].DoPush = MagickTrue;
1830 (void) AddAddressingElement (pfx, rZerStk, NULL_ADDRESS);
1831 }
else if (fe==fIf) {
1832 (void) AddAddressingElement (pfx, rGoto, NULL_ADDRESS);
1836 if (ndx3 != NULL_ADDRESS) {
1837 (void) ThrowMagickException (
1838 pfx->exception, GetMagickModule(), OptionError,
1839 "For function",
"'%s' required argument is missing at '%s'",
1840 funStr, SetShortExp(pfx));
1844 pfx->Elements[pfx->usedElements-1].DoPush = MagickFalse;
1845 (void) AddAddressingElement (pfx, rGoto, ndx1);
1847 ndx3 = pfx->usedElements;
1852 if (chLimit == expChLimit) {
1853 lenExp = pfx->pex - pExpStart - 1;
1857 if (chLimit && chLimit != expChLimit && chLimit !=
',' ) {
1858 (void) ThrowMagickException (
1859 pfx->exception, GetMagickModule(), OptionError,
1860 "For function",
"'%s' expected '%c', found '%c' at '%s'",
1861 funStr, expChLimit, chLimit ? chLimit :
' ', SetShortExp(pfx));
1865 if (fe == fP || fe == fS || fe == fU || fe == fChannel) {
1866 while (FndArgs < Functions[fe-FirstFunc].nArgs) {
1867 (void) AddElement (pfx, (fxFltType) 0, oNull);
1872 if (FndArgs > Functions[fe-FirstFunc].nArgs)
1875 (void) ThrowMagickException (
1876 pfx->exception, GetMagickModule(), OptionError,
1877 "For function",
"'%s' expected up to %i arguments, found '%i' at '%s'",
1878 funStr, Functions[fe-FirstFunc].nArgs, FndArgs, SetShortExp(pfx));
1880 (void) ThrowMagickException (
1881 pfx->exception, GetMagickModule(), OptionError,
1882 "For function",
"'%s' expected %i arguments, found '%i' at '%s'",
1883 funStr, Functions[fe-FirstFunc].nArgs, FndArgs, SetShortExp(pfx));
1887 if (FndArgs < Functions[fe-FirstFunc].nArgs) {
1888 (void) ThrowMagickException (
1889 pfx->exception, GetMagickModule(), OptionError,
1890 "For function",
"'%s' expected %i arguments, found too few (%i) at '%s'",
1891 funStr, Functions[fe-FirstFunc].nArgs, FndArgs, SetShortExp(pfx));
1894 if (fe != fS && fe != fV && FndArgs == 0 && Functions[fe-FirstFunc].nArgs == 0) {
1896 chLimit = expChLimit;
1897 if (!ExpectChar (pfx,
')'))
return MagickFalse;
1900 if (chLimit != expChLimit) {
1901 (void) ThrowMagickException (
1902 pfx->exception, GetMagickModule(), OptionError,
1903 "For function",
"'%s', arguments don't end with '%c' at '%s'",
1904 funStr, expChLimit, SetShortExp(pfx));
1907 if (!PopOprOpenParen (pfx, pushOp)) {
1908 (void) ThrowMagickException (
1909 pfx->exception, GetMagickModule(), OptionError,
1910 "Bug: For function",
"'%s' tos not '%s' at '%s'",
1911 funStr, Operators[pushOp].str, SetShortExp(pfx));
1915 if (IsQualifier (pfx)) {
1917 if (fe == fU || fe == fV || fe == fS) {
1919 coordQual = (GetCoordQualifier (pfx, fe) == 1) ? MagickTrue : MagickFalse;
1924 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
1925 if (pel->oprNum != fP) {
1926 (void) ThrowMagickException (
1927 pfx->exception, GetMagickModule(), OptionError,
1928 "Bug: For function",
"'%s' last element not 'p' at '%s'",
1929 funStr, SetShortExp(pfx));
1932 chQual = pel->ChannelQual;
1933 expChLimit = (pel->IsRelative) ?
']' :
'}';
1934 pfx->usedElements--;
1935 if (fe == fU) fe = fUP;
1936 else if (fe == fV) fe = fVP;
1937 else if (fe == fS) fe = fSP;
1938 funStr = Functions[fe-FirstFunc].str;
1942 if ( chQual == NO_CHAN_QUAL &&
1943 (fe == fP || fe == fS || fe == fSP || fe == fU || fe == fUP || fe == fV || fe == fVP)
1946 chQual = GetChannelQualifier (pfx, fe);
1949 if (chQual == NO_CHAN_QUAL && (fe == fU || fe == fV || fe == fS)) {
1951 iaQual = GetImgAttrQualifier (pfx, fe);
1953 if (IsQualifier (pfx) && chQual == NO_CHAN_QUAL && iaQual != aNull) {
1954 chQual = GetChannelQualifier (pfx, fe);
1956 if (coordQual && iaQual != aNull) {
1957 (void) ThrowMagickException (
1958 pfx->exception, GetMagickModule(), OptionError,
1959 "For function",
"'%s', can't have qualifiers 'p' and image attribute '%s' at '%s'",
1960 funStr, pfx->token, SetShortExp(pfx));
1963 if (!coordQual && chQual == NO_CHAN_QUAL && iaQual == aNull) {
1964 (void) ThrowMagickException (
1965 pfx->exception, GetMagickModule(), OptionError,
1966 "For function",
"'%s', bad qualifier '%s' at '%s'",
1967 funStr, pfx->token, SetShortExp(pfx));
1970 if (!coordQual && chQual == CompositePixelChannel && iaQual == aNull) {
1971 (void) ThrowMagickException (
1972 pfx->exception, GetMagickModule(), OptionError,
1973 "For function",
"'%s', bad composite qualifier '%s' at '%s'",
1974 funStr, pfx->token, SetShortExp(pfx));
1978 if (chQual == HUE_CHANNEL || chQual == SAT_CHANNEL || chQual == LIGHT_CHANNEL) {
1979 pfx->NeedHsl = MagickTrue;
1981 if (iaQual >= FirstImgAttr && iaQual < aNull) {
1982 (void) ThrowMagickException (
1983 pfx->exception, GetMagickModule(), OptionError,
1984 "Can't have image attribute with HLS qualifier at",
"'%s'",
1992 pfx->Elements[ndx1].EleNdx = ndx2+1;
1993 }
else if (fe==fDo) {
1994 pfx->Elements[ndx0].EleNdx = ndx1+1;
1995 pfx->Elements[ndx1].EleNdx = ndx2+1;
1996 }
else if (fe==fFor) {
1997 pfx->Elements[ndx2].EleNdx = ndx3;
1998 }
else if (fe==fIf) {
1999 pfx->Elements[ndx1].EleNdx = ndx2 + 1;
2000 pfx->Elements[ndx2].EleNdx = ndx3;
2002 if (fe == fU && iaQual == aNull) {
2003 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2004 if (pel->type == etConstant && pel->val == 0.0) {
2005 pfx->usedElements--;
2009 (void) AddElement (pfx, (fxFltType) 0, fe);
2010 if (fe == fP || fe == fU || fe == fU0 || fe == fUP ||
2011 fe == fV || fe == fVP || fe == fS || fe == fSP)
2013 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2014 pel->IsRelative = (expChLimit ==
']' ? MagickTrue : MagickFalse);
2015 if (chQual >= 0) pel->ChannelQual = chQual;
2016 if (iaQual != aNull && (fe == fU || fe == fV || fe == fS)) {
2018 pel->ImgAttrQual = iaQual;
2023 if (pExpStart && lenExp) {
2024 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2025 pel->pExpStart = pExpStart;
2026 pel->lenExp = lenExp;
2030 pfx->ContainsDebug = MagickTrue;
2035 static MagickBooleanType IsStealth (
int op)
2037 return (op == fU0 || op == fUP || op == fSP || op == fVP ||
2038 (op >= FirstCont && op <= rNull) ? MagickTrue : MagickFalse
2042 static MagickBooleanType GetOperand (
2043 FxInfo * pfx, MagickBooleanType * UserSymbol, MagickBooleanType * NewUserSymbol,
int * UserSymNdx,
2044 MagickBooleanType * needPopAll)
2047 *NewUserSymbol = *UserSymbol = MagickFalse;
2048 *UserSymNdx = NULL_ADDRESS;
2051 if (!*pfx->pex)
return MagickFalse;
2052 (void) GetToken (pfx);
2054 if (pfx->lenToken==0) {
2058 OperatorE op = GetLeadingOp (pfx);
2059 if (op==oOpenParen) {
2060 char chLimit =
'\0';
2061 if (!PushOperatorStack (pfx, op))
return MagickFalse;
2063 if (!TranslateExpression (pfx,
")", &chLimit, needPopAll)) {
2064 (void) ThrowMagickException (
2065 pfx->exception, GetMagickModule(), OptionError,
2066 "Empty expression in parentheses at",
"'%s'",
2070 if (chLimit !=
')') {
2071 (void) ThrowMagickException (
2072 pfx->exception, GetMagickModule(), OptionError,
2073 "'(' but no ')' at",
"'%s'",
2078 if (!PopOprOpenParen (pfx, oOpenParen)) {
2079 (void) ThrowMagickException (
2080 pfx->exception, GetMagickModule(), OptionError,
2081 "Bug: tos not '(' at",
"'%s'",
2086 }
else if (OprIsUnaryPrefix (op)) {
2087 if (!PushOperatorStack (pfx, op))
return MagickFalse;
2090 if (!*pfx->pex)
return MagickFalse;
2092 if (!GetOperand (pfx, UserSymbol, NewUserSymbol, UserSymNdx, needPopAll)) {
2093 (void) ThrowMagickException (
2094 pfx->exception, GetMagickModule(), OptionError,
2095 "After unary, bad operand at",
"'%s'",
2100 if (*NewUserSymbol) {
2101 (void) ThrowMagickException (
2102 pfx->exception, GetMagickModule(), OptionError,
2103 "After unary, NewUserSymbol at",
"'%s'",
2109 (void) AddAddressingElement (pfx, rCopyFrom, *UserSymNdx);
2110 *UserSymNdx = NULL_ADDRESS;
2112 *UserSymbol = MagickFalse;
2113 *NewUserSymbol = MagickFalse;
2116 (void) GetToken (pfx);
2118 }
else if (*pfx->pex ==
'#') {
2119 fxFltType v0=0, v1=0, v2=0;
2120 ssize_t lenToken = GetHexColour (pfx, &v0, &v1, &v2);
2122 (void) ThrowMagickException (
2123 pfx->exception, GetMagickModule(), OptionError,
2124 "Bad hex number at",
"'%s'",
2127 }
else if (lenToken > 0) {
2128 (void) AddColourElement (pfx, v0, v1, v2);
2139 fxFltType val = strtold (pfx->pex, &tailptr);
2140 if (pfx->pex != tailptr) {
2148 const char Prefices[] =
"yzafpnum.kMGTPEZY";
2149 const char * pSi = strchr (Prefices, *tailptr);
2150 if (pSi && *pSi !=
'.') Pow = (pSi - Prefices) * 3 - 24;
2151 else if (*tailptr ==
'c') Pow = -2;
2152 else if (*tailptr ==
'h') Pow = 2;
2153 else if (*tailptr ==
'k') Pow = 3;
2155 if (*(++pfx->pex) ==
'i') {
2156 val *= pow (2.0, Pow/0.3);
2159 val *= pow (10.0, Pow);
2163 (void) AddElement (pfx, val, oNull);
2167 val = (fxFltType) 0;
2168 lenOptArt = GetProperty (pfx, &val);
2169 if (lenOptArt < 0)
return MagickFalse;
2170 if (lenOptArt > 0) {
2171 (void) AddElement (pfx, val, oNull);
2172 pfx->pex += lenOptArt;
2179 if (pfx->lenToken > 0) {
2184 for (ce = (ConstantE)0; ce < cNull; ce=(ConstantE) (ce+1)) {
2185 const char * ceStr = Constants[ce].str;
2186 if (LocaleCompare (ceStr, pfx->token)==0) {
2192 (void) AddElement (pfx, Constants[ce].val, oNull);
2193 pfx->pex += pfx->lenToken;
2202 for (fe = FirstFunc; fe < fNull; fe=(FunctionE) (fe+1)) {
2203 const char * feStr = Functions[fe-FirstFunc].str;
2204 if (LocaleCompare (feStr, pfx->token)==0) {
2209 if (fe == fV && pfx->ImgListLen < 2) {
2210 (void) ThrowMagickException (
2211 pfx->exception, GetMagickModule(), OptionError,
2212 "Symbol 'v' but fewer than two images at",
"'%s'",
2217 if (IsStealth (fe)) {
2218 (void) ThrowMagickException (
2219 pfx->exception, GetMagickModule(), OptionError,
2220 "Function",
"'%s' not permitted at '%s'",
2221 pfx->token, SetShortExp(pfx));
2224 if (fe == fDo || fe == fFor || fe == fIf || fe == fWhile) {
2225 *needPopAll = MagickTrue;
2228 if (fe != fNull)
return (GetFunction (pfx, fe));
2234 ImgAttrE ia = GetImgAttrToken (pfx);
2237 (void) AddElement (pfx, val, ia);
2239 if (ImgAttrs[ia-FirstImgAttr].NeedStats==1) {
2240 if (IsQualifier (pfx)) {
2241 PixelChannel chQual = GetChannelQualifier (pfx, ia);
2243 if (chQual == NO_CHAN_QUAL) {
2244 (void) ThrowMagickException (
2245 pfx->exception, GetMagickModule(), OptionError,
2246 "Bad channel qualifier at",
"'%s'",
2251 pel = &pfx->Elements[pfx->usedElements-1];
2252 pel->ChannelQual = chQual;
2263 for (se = FirstSym; se < sNull; se=(SymbolE) (se+1)) {
2264 const char * seStr = Symbols[se-FirstSym].str;
2265 if (LocaleCompare (seStr, pfx->token)==0) {
2271 (void) AddElement (pfx, val, se);
2272 pfx->pex += pfx->lenToken;
2274 if (se==sHue || se==sSaturation || se==sLightness) pfx->NeedHsl = MagickTrue;
2282 fxFltType v0, v1, v2;
2283 ssize_t ColLen = GetConstantColour (pfx, &v0, &v1, &v2);
2284 if (ColLen < 0)
return MagickFalse;
2286 (void) AddColourElement (pfx, v0, v1, v2);
2295 const char *artifact;
2296 artifact = GetImageArtifact (pfx->image, pfx->token);
2297 if (artifact != (
const char *) NULL) {
2299 fxFltType val = strtold (artifact, &tailptr);
2300 if (pfx->token == tailptr) {
2301 (void) ThrowMagickException (
2302 pfx->exception, GetMagickModule(), OptionError,
2303 "Artifact",
"'%s' has value '%s', not a number, at '%s'",
2304 pfx->token, artifact, SetShortExp(pfx));
2307 (void) AddElement (pfx, val, oNull);
2308 pfx->pex+=pfx->lenToken;
2315 if (TokenMaybeUserSymbol (pfx)) {
2316 *UserSymbol = MagickTrue;
2317 *UserSymNdx = FindUserSymbol (pfx, pfx->token);
2318 if (*UserSymNdx == NULL_ADDRESS) {
2319 *UserSymNdx = AddUserSymbol (pfx, pfx->pex, pfx->lenToken);
2320 *NewUserSymbol = MagickTrue;
2323 pfx->pex += pfx->lenToken;
2329 (void) ThrowMagickException (
2330 pfx->exception, GetMagickModule(), OptionError,
2331 "Expected operand at",
"'%s'",
2337 static MagickBooleanType
inline IsRealOperator (OperatorE op)
2339 return (op < oOpenParen || op > oCloseBrace) ? MagickTrue : MagickFalse;
2342 static MagickBooleanType
inline ProcessTernaryOpr (
FxInfo * pfx,
TernaryT * ptern)
2347 if (pfx->usedOprStack == 0)
2349 if (pfx->OperatorStack[pfx->usedOprStack-1] == oQuery) {
2350 if (ptern->addrQuery != NULL_ADDRESS) {
2351 (void) ThrowMagickException (
2352 pfx->exception, GetMagickModule(), OptionError,
2353 "Already have '?' in sub-expression at",
"'%s'",
2357 if (ptern->addrColon != NULL_ADDRESS) {
2358 (void) ThrowMagickException (
2359 pfx->exception, GetMagickModule(), OptionError,
2360 "Already have ':' in sub-expression at",
"'%s'",
2364 pfx->usedOprStack--;
2365 ptern->addrQuery = pfx->usedElements;
2366 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
2369 else if (pfx->OperatorStack[pfx->usedOprStack-1] == oColon) {
2370 if (ptern->addrQuery == NULL_ADDRESS) {
2371 (void) ThrowMagickException (
2372 pfx->exception, GetMagickModule(), OptionError,
2373 "Need '?' in sub-expression at",
"'%s'",
2377 if (ptern->addrColon != NULL_ADDRESS) {
2378 (void) ThrowMagickException (
2379 pfx->exception, GetMagickModule(), OptionError,
2380 "Already have ':' in sub-expression at",
"'%s'",
2384 pfx->usedOprStack--;
2385 ptern->addrColon = pfx->usedElements;
2386 pfx->Elements[pfx->usedElements-1].DoPush = MagickTrue;
2387 (void) AddAddressingElement (pfx, rGoto, NULL_ADDRESS);
2393 static MagickBooleanType GetOperator (
2395 MagickBooleanType * Assign, MagickBooleanType * Update, MagickBooleanType * IncrDecr)
2399 MagickBooleanType DoneIt = MagickFalse;
2401 for (op = (OperatorE)0; op != oNull; op=(OperatorE) (op+1)) {
2402 const char * opStr = Operators[op].str;
2403 len = strlen(opStr);
2404 if (LocaleNCompare (opStr, pfx->pex, len)==0) {
2409 if (!IsRealOperator (op)) {
2410 (void) ThrowMagickException (
2411 pfx->exception, GetMagickModule(), OptionError,
2412 "Not a real operator at",
"'%s'",
2418 (void) ThrowMagickException (
2419 pfx->exception, GetMagickModule(), OptionError,
2420 "Expected operator at",
"'%s'",
2425 *Assign = (op==oAssign) ? MagickTrue : MagickFalse;
2426 *Update = OprInPlace (op);
2427 *IncrDecr = (op == oPlusPlus || op == oSubSub) ? MagickTrue : MagickFalse;
2434 while (pfx->usedOprStack > 0) {
2435 OperatorE top = pfx->OperatorStack[pfx->usedOprStack-1];
2436 int precTop, precNew;
2437 if (top == oOpenParen || top == oAssign || OprInPlace (top))
break;
2438 precTop = Operators[top].precedence;
2439 precNew = Operators[op].precedence;
2443 if (precTop < precNew)
break;
2444 (void) AddElement (pfx, (fxFltType) 0, top);
2445 pfx->usedOprStack--;
2451 if (op==oCloseParen) {
2452 if (pfx->usedOprStack == 0) {
2453 (void) ThrowMagickException (
2454 pfx->exception, GetMagickModule(), OptionError,
2455 "Found ')' but nothing on stack at",
"'%s'",
2460 if (pfx->OperatorStack[pfx->usedOprStack-1] != oOpenParen) {
2461 (void) ThrowMagickException (
2462 pfx->exception, GetMagickModule(), OptionError,
2463 "Found ')' but no '(' on stack at",
"'%s'",
2467 pfx->usedOprStack--;
2468 DoneIt = MagickTrue;
2472 if (!PushOperatorStack (pfx, op))
return MagickFalse;
2480 static MagickBooleanType ResolveTernaryAddresses (
FxInfo * pfx,
TernaryT * ptern)
2482 if (ptern->addrQuery == NULL_ADDRESS && ptern->addrColon == NULL_ADDRESS)
2485 if (ptern->addrQuery != NULL_ADDRESS && ptern->addrColon != NULL_ADDRESS) {
2486 pfx->Elements[ptern->addrQuery].EleNdx = ptern->addrColon + 1;
2487 pfx->Elements[ptern->addrColon].EleNdx = pfx->usedElements;
2488 ptern->addrQuery = NULL_ADDRESS;
2489 ptern->addrColon = NULL_ADDRESS;
2490 }
else if (ptern->addrQuery != NULL_ADDRESS) {
2491 (void) ThrowMagickException (
2492 pfx->exception, GetMagickModule(), OptionError,
2493 "'?' with no corresponding ':'",
"'%s' at '%s'",
2494 pfx->token, SetShortExp(pfx));
2496 }
else if (ptern->addrColon != NULL_ADDRESS) {
2497 (void) ThrowMagickException (
2498 pfx->exception, GetMagickModule(), OptionError,
2499 "':' with no corresponding '?'",
"'%s' at '%s'",
2500 pfx->token, SetShortExp(pfx));
2506 static MagickBooleanType TranslateExpression (
2507 FxInfo * pfx,
const char * strLimit,
char * chLimit, MagickBooleanType * needPopAll)
2511 MagickBooleanType UserSymbol, NewUserSymbol;
2512 int UserSymNdx0, UserSymNdx1;
2515 Assign = MagickFalse,
2516 Update = MagickFalse,
2517 IncrDecr = MagickFalse;
2522 ternary.addrQuery = NULL_ADDRESS;
2523 ternary.addrColon = NULL_ADDRESS;
2529 StartEleNdx = pfx->usedElements-1;
2530 if (StartEleNdx < 0) StartEleNdx = 0;
2539 if (strchr(strLimit,*pfx->pex)!=NULL) {
2540 *chLimit = *pfx->pex;
2547 if (!GetOperand (pfx, &UserSymbol, &NewUserSymbol, &UserSymNdx0, needPopAll))
return MagickFalse;
2552 while (*pfx->pex && (!*strLimit || (strchr(strLimit,*pfx->pex)==NULL))) {
2553 if (!GetOperator (pfx, &Assign, &Update, &IncrDecr))
return MagickFalse;
2555 if (NewUserSymbol && !Assign) {
2556 (void) ThrowMagickException (
2557 pfx->exception, GetMagickModule(), OptionError,
2558 "Expected assignment after new UserSymbol",
"'%s' at '%s'",
2559 pfx->token, SetShortExp(pfx));
2562 if (!UserSymbol && Assign) {
2563 (void) ThrowMagickException (
2564 pfx->exception, GetMagickModule(), OptionError,
2565 "Attempted assignment to non-UserSymbol",
"'%s' at '%s'",
2566 pfx->token, SetShortExp(pfx));
2569 if (!UserSymbol && Update) {
2570 (void) ThrowMagickException (
2571 pfx->exception, GetMagickModule(), OptionError,
2572 "Attempted update to non-UserSymbol",
"'%s' at '%s'",
2573 pfx->token, SetShortExp(pfx));
2576 if (UserSymbol && (Assign || Update) && !IncrDecr) {
2578 if (!TranslateExpression (pfx, strLimit, chLimit, needPopAll))
return MagickFalse;
2579 if (!*pfx->pex)
break;
2580 if (!*strLimit)
break;
2581 if (strchr(strLimit,*chLimit)!=NULL)
break;
2583 if (UserSymbol && !Assign && !Update && UserSymNdx0 != NULL_ADDRESS) {
2585 (void) AddAddressingElement (pfx, rCopyFrom, UserSymNdx0);
2586 UserSymNdx0 = NULL_ADDRESS;
2587 pel = &pfx->Elements[pfx->usedElements-1];
2588 pel->DoPush = MagickTrue;
2592 while (TopOprIsUnaryPrefix (pfx)) {
2593 OperatorE op = pfx->OperatorStack[pfx->usedOprStack-1];
2594 (void) AddElement (pfx, (fxFltType) 0, op);
2595 pfx->usedOprStack--;
2599 if (!ProcessTernaryOpr (pfx, &ternary))
return MagickFalse;
2601 if (ternary.addrColon != NULL_ADDRESS) {
2602 if (!TranslateExpression (pfx,
",);", chLimit, needPopAll))
return MagickFalse;
2606 UserSymbol = NewUserSymbol = MagickFalse;
2608 if ( (!*pfx->pex) || (*strLimit && (strchr(strLimit,*pfx->pex)!=NULL) ) )
2610 if (IncrDecr)
break;
2612 (void) ThrowMagickException (
2613 pfx->exception, GetMagickModule(), OptionError,
2614 "Expected operand after operator",
"at '%s'",
2620 (void) ThrowMagickException (
2621 pfx->exception, GetMagickModule(), OptionError,
2622 "'++' and '--' must be the final operators in an expression at",
"'%s'",
2627 if (!GetOperand (pfx, &UserSymbol, &NewUserSymbol, &UserSymNdx1, needPopAll)) {
2628 (void) ThrowMagickException (
2629 pfx->exception, GetMagickModule(), OptionError,
2630 "Expected operand at",
"'%s'",
2635 if (NewUserSymbol && !Assign) {
2636 (void) ThrowMagickException (
2637 pfx->exception, GetMagickModule(), OptionError,
2638 "NewUserSymbol",
"'%s' after non-assignment operator at '%s'",
2639 pfx->token, SetShortExp(pfx));
2642 if (UserSymbol && !NewUserSymbol) {
2643 (void) AddAddressingElement (pfx, rCopyFrom, UserSymNdx1);
2644 UserSymNdx1 = NULL_ADDRESS;
2646 UserSymNdx0 = UserSymNdx1;
2649 if (UserSymbol && !Assign && !Update && UserSymNdx0 != NULL_ADDRESS) {
2651 if (NewUserSymbol) {
2652 (void) ThrowMagickException (
2653 pfx->exception, GetMagickModule(), OptionError,
2654 "NewUserSymbol",
"'%s' needs assignment operator at '%s'",
2655 pfx->token, SetShortExp(pfx));
2658 (void) AddAddressingElement (pfx, rCopyFrom, UserSymNdx0);
2659 pel = &pfx->Elements[pfx->usedElements-1];
2660 pel->DoPush = MagickTrue;
2663 if (*pfx->pex && !*chLimit && (strchr(strLimit,*pfx->pex)!=NULL)) {
2664 *chLimit = *pfx->pex;
2667 while (pfx->usedOprStack) {
2668 OperatorE op = pfx->OperatorStack[pfx->usedOprStack-1];
2669 if (op == oOpenParen || op == oOpenBracket || op == oOpenBrace) {
2672 if ( (op==oAssign && !Assign) || (OprInPlace(op) && !Update) ) {
2675 pfx->usedOprStack--;
2676 (void) AddElement (pfx, (fxFltType) 0, op);
2677 if (op == oAssign) {
2678 if (UserSymNdx0 < 0) {
2679 (void) ThrowMagickException (
2680 pfx->exception, GetMagickModule(), OptionError,
2681 "Assignment to unknown user symbol at",
"'%s'",
2687 pfx->usedElements--;
2688 (void) AddAddressingElement (pfx, rCopyTo, UserSymNdx0);
2690 }
else if (OprInPlace (op)) {
2691 if (UserSymNdx0 < 0) {
2692 (void) ThrowMagickException (
2693 pfx->exception, GetMagickModule(), OptionError,
2694 "Operator-in-place to unknown user symbol at",
"'%s'",
2700 pfx->Elements[pfx->usedElements-1].EleNdx = UserSymNdx0;
2705 if (ternary.addrQuery != NULL_ADDRESS) *needPopAll = MagickTrue;
2707 (void) ResolveTernaryAddresses (pfx, &ternary);
2711 if (!pfx->teDepth && *needPopAll) {
2712 (void) AddAddressingElement (pfx, rZerStk, NULL_ADDRESS);
2713 *needPopAll = MagickFalse;
2716 if (pfx->exception->severity != UndefinedException)
2723 static MagickBooleanType TranslateStatement (
FxInfo * pfx,
char * strLimit,
char * chLimit)
2725 MagickBooleanType NeedPopAll = MagickFalse;
2729 if (!*pfx->pex)
return MagickFalse;
2731 if (!TranslateExpression (pfx, strLimit, chLimit, &NeedPopAll)) {
2734 if (pfx->usedElements && *chLimit==
';') {
2739 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2740 if (pel->DoPush) pel->DoPush = MagickFalse;
2746 static MagickBooleanType TranslateStatementList (
FxInfo * pfx,
const char * strLimit,
char * chLimit)
2748 #define MAX_SLIMIT 10
2749 char sLimits[MAX_SLIMIT];
2752 if (!*pfx->pex)
return MagickFalse;
2753 (void) CopyMagickString (sLimits, strLimit, MAX_SLIMIT-1);
2755 if (strchr(strLimit,
';')==NULL)
2756 (
void) ConcatenateMagickString (sLimits,
";", MAX_SLIMIT);
2759 if (!TranslateStatement (pfx, sLimits, chLimit))
return MagickFalse;
2761 if (!*pfx->pex)
break;
2763 if (*chLimit !=
';') {
2768 if (pfx->exception->severity != UndefinedException)
2787 for (ch=0; ch <= (int) MaxPixelChannels; ch++) {
2788 cs[ch].mean *= QuantumScale;
2789 cs[ch].median *= QuantumScale;
2790 cs[ch].maxima *= QuantumScale;
2791 cs[ch].minima *= QuantumScale;
2792 cs[ch].standard_deviation *= QuantumScale;
2793 cs[ch].kurtosis *= QuantumScale;
2794 cs[ch].skewness *= QuantumScale;
2795 cs[ch].entropy *= QuantumScale;
2801 static MagickBooleanType CollectStatistics (
FxInfo * pfx)
2803 Image * img = GetFirstImageInList (pfx->image);
2808 if (!pfx->statistics) {
2809 (void) ThrowMagickException (
2810 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
2811 "Statistics",
"%lu",
2812 (
unsigned long) pfx->ImgListLen);
2817 pfx->statistics[imgNum] = CollectOneImgStats (pfx, img);
2819 if (++imgNum == pfx->ImgListLen)
break;
2820 img = GetNextImageInList (img);
2821 assert (img != (
Image *) NULL);
2823 pfx->GotStats = MagickTrue;
2828 static MagickBooleanType
inline PushVal (
FxInfo * pfx,
fxRtT * pfxrt, fxFltType val,
int addr)
2830 if (pfxrt->usedValStack >=pfxrt->numValStack) {
2831 (void) ThrowMagickException (
2832 pfx->exception, GetMagickModule(), OptionError,
2833 "ValStack overflow at addr=",
"%i",
2838 pfxrt->ValStack[pfxrt->usedValStack++] = val;
2842 static inline fxFltType PopVal (
FxInfo * pfx,
fxRtT * pfxrt,
int addr)
2844 if (pfxrt->usedValStack <= 0) {
2845 (void) ThrowMagickException (
2846 pfx->exception, GetMagickModule(), OptionError,
2847 "ValStack underflow at addr=",
"%i",
2849 return (fxFltType) 0;
2852 return pfxrt->ValStack[--pfxrt->usedValStack];
2855 static inline fxFltType ImageStat (
2856 FxInfo * pfx, ssize_t ImgNum, PixelChannel channel, ImgAttrE ia)
2860 MagickBooleanType NeedRelinq = MagickFalse;
2862 assert (channel >= 0 && channel <= MaxPixelChannels);
2864 if (pfx->GotStats) {
2865 cs = pfx->statistics[ImgNum];
2866 }
else if (pfx->NeedStats) {
2868 cs = CollectOneImgStats (pfx, pfx->Images[ImgNum]);
2869 NeedRelinq = MagickTrue;
2874 ret = (fxFltType) GetImageDepth (pfx->Images[ImgNum], pfx->exception);
2877 ret = (fxFltType) GetBlobSize (pfx->image);
2881 ret = cs[channel].kurtosis;
2885 ret = cs[channel].maxima;
2889 ret = cs[channel].mean;
2893 ret = cs[channel].median;
2897 ret = cs[channel].minima;
2903 ret = (fxFltType) pfx->Images[ImgNum]->page.x;
2906 ret = (fxFltType) pfx->Images[ImgNum]->page.y;
2909 ret = (fxFltType) pfx->Images[ImgNum]->page.width;
2912 ret = (fxFltType) pfx->Images[ImgNum]->page.height;
2918 ret = (fxFltType) PerceptibleReciprocal (pfx->Images[ImgNum]->resolution.x)
2919 * pfx->Images[ImgNum]->columns;
2922 ret = (fxFltType) PerceptibleReciprocal (pfx->Images[ImgNum]->resolution.y)
2923 * pfx->Images[ImgNum]->rows;
2926 ret = (fxFltType) pfx->Images[ImgNum]->quality;
2932 ret = pfx->Images[ImgNum]->resolution.x;
2935 ret = pfx->Images[ImgNum]->resolution.y;
2939 ret = cs[channel].skewness;
2943 ret = cs[channel].standard_deviation;
2946 ret = (fxFltType) pfx->Images[ImgNum]->rows;
2949 ret = (fxFltType) pfx->ImgListLen;
2952 ret = (fxFltType) ImgNum;
2955 ret = (fxFltType) pfx->Images[ImgNum]->columns;
2958 ret = (fxFltType) GetImageDepth (pfx->Images[ImgNum], pfx->exception);
2961 (void) ThrowMagickException (pfx->exception,GetMagickModule(),OptionError,
2962 "Unknown ia=",
"%i",ia);
2969 static fxFltType
inline FxGcd (fxFltType x, fxFltType y,
const size_t depth)
2971 #define FxMaxFunctionDepth 200
2974 return (FxGcd (y, x, depth+1));
2975 if ((fabs((
double) y) < 0.001) || (depth >= FxMaxFunctionDepth))
2977 return (FxGcd (y, x-y*floor((
double) (x/y)), depth+1));
2980 static ssize_t
inline ChkImgNum (
FxInfo * pfx, fxFltType f)
2983 ssize_t i = (ssize_t) floor ((
double) f + 0.5);
2984 if (i < 0) i += pfx->ImgListLen;
2985 if (i < 0 || i >= (ssize_t)pfx->ImgListLen) {
2986 (void) ThrowMagickException (
2987 pfx->exception, GetMagickModule(), OptionError,
2988 "ImgNum",
"%lu bad for ImgListLen %lu",
2989 (
unsigned long) i, (
unsigned long) pfx->ImgListLen);
2995 #define WHICH_ATTR_CHAN \
2996 (pel->ChannelQual == NO_CHAN_QUAL) ? CompositePixelChannel : \
2997 (pel->ChannelQual == THIS_CHANNEL) ? channel : pel->ChannelQual
2999 #define WHICH_NON_ATTR_CHAN \
3000 (pel->ChannelQual == NO_CHAN_QUAL || \
3001 pel->ChannelQual == THIS_CHANNEL || \
3002 pel->ChannelQual == CompositePixelChannel \
3003 ) ? (channel == CompositePixelChannel ? RedPixelChannel: channel) \
3006 static fxFltType GetHslFlt (
FxInfo * pfx, ssize_t ImgNum,
const fxFltType fx,
const fxFltType fy,
3009 Image * img = pfx->Images[ImgNum];
3011 double red, green, blue;
3012 double hue=0, saturation=0, lightness=0;
3014 MagickBooleanType okay = MagickTrue;
3015 if(!InterpolatePixelChannel (img, pfx->Imgs[ImgNum].View, RedPixelChannel, img->interpolate,
3016 (
double) fx, (
double) fy, &red, pfx->exception)) okay = MagickFalse;
3017 if(!InterpolatePixelChannel (img, pfx->Imgs[ImgNum].View, GreenPixelChannel, img->interpolate,
3018 (
double) fx, (
double) fy, &green, pfx->exception)) okay = MagickFalse;
3019 if(!InterpolatePixelChannel (img, pfx->Imgs[ImgNum].View, BluePixelChannel, img->interpolate,
3020 (
double) fx, (
double) fy, &blue, pfx->exception)) okay = MagickFalse;
3023 (void) ThrowMagickException (
3024 pfx->exception, GetMagickModule(), OptionError,
3025 "GetHslFlt failure",
"%lu %g,%g %i", (
unsigned long) ImgNum,
3026 (
double) fx, (double) fy, channel);
3030 &hue, &saturation, &lightness);
3032 if (channel == HUE_CHANNEL)
return hue;
3033 if (channel == SAT_CHANNEL)
return saturation;
3034 if (channel == LIGHT_CHANNEL)
return lightness;
3039 static fxFltType GetHslInt (
FxInfo * pfx, ssize_t ImgNum,
const ssize_t imgx,
const ssize_t imgy,
int channel)
3041 Image * img = pfx->Images[ImgNum];
3043 double hue=0, saturation=0, lightness=0;
3045 const Quantum * p = GetCacheViewVirtualPixels (pfx->Imgs[ImgNum].View, imgx, imgy, 1, 1, pfx->exception);
3046 if (p == (
const Quantum *) NULL)
3048 (void) ThrowMagickException (pfx->exception,GetMagickModule(),
3049 OptionError,
"GetHslInt failure",
"%lu %li,%li %i",(
unsigned long) ImgNum,
3050 (
long) imgx,(long) imgy,channel);
3055 GetPixelRed (img, p), GetPixelGreen (img, p), GetPixelBlue (img, p),
3056 &hue, &saturation, &lightness);
3058 if (channel == HUE_CHANNEL)
return hue;
3059 if (channel == SAT_CHANNEL)
return saturation;
3060 if (channel == LIGHT_CHANNEL)
return lightness;
3065 static fxFltType
inline GetIntensity (
FxInfo * pfx, ssize_t ImgNum,
const fxFltType fx,
const fxFltType fy)
3068 quantum_pixel[MaxPixelChannels];
3073 Image * img = pfx->Images[ImgNum];
3075 (void) GetPixelInfo (img, &pixelinf);
3077 if (!InterpolatePixelInfo (img, pfx->Imgs[pfx->ImgNum].View, img->interpolate,
3078 (
double) fx, (
double) fy, &pixelinf, pfx->exception))
3080 (void) ThrowMagickException (
3081 pfx->exception, GetMagickModule(), OptionError,
3082 "GetIntensity failure",
"%lu %g,%g", (
unsigned long) ImgNum,
3083 (
double) fx, (double) fy);
3086 SetPixelViaPixelInfo (img, &pixelinf, quantum_pixel);
3087 return QuantumScale * GetPixelIntensity (img, quantum_pixel);
3090 static MagickBooleanType ExecuteRPN (
FxInfo * pfx,
fxRtT * pfxrt, fxFltType *result,
3091 const PixelChannel channel,
const ssize_t imgx,
const ssize_t imgy)
3093 const Quantum * p = pfxrt->thisPixel;
3094 fxFltType regA=0, regB=0, regC=0, regD=0, regE=0;
3095 Image * img = pfx->image;
3097 MagickBooleanType NeedRelinq = MagickFalse;
3098 double hue=0, saturation=0, lightness=0;
3105 if (!p) p = GetCacheViewVirtualPixels (
3106 pfx->Imgs[pfx->ImgNum].View, imgx, imgy, 1, 1, pfx->exception);
3108 if (p == (
const Quantum *) NULL)
3110 (void) ThrowMagickException (pfx->exception,GetMagickModule(),
3111 OptionError,
"GetHslInt failure",
"%lu %li,%li",(
unsigned long)
3112 pfx->ImgNum,(
long) imgx,(long) imgy);
3113 return(MagickFalse);
3116 if (pfx->GotStats) {
3117 cs = pfx->statistics[pfx->ImgNum];
3118 }
else if (pfx->NeedStats) {
3119 cs = CollectOneImgStats (pfx, pfx->Images[pfx->ImgNum]);
3120 NeedRelinq = MagickTrue;
3127 GetPixelRed (img, p), GetPixelGreen (img, p), GetPixelBlue (img, p),
3128 &hue, &saturation, &lightness);
3131 for (i=0; i < pfx->usedElements; i++) {
3133 switch (pel->nArgs) {
3137 regA = PopVal (pfx, pfxrt, i);
3140 regB = PopVal (pfx, pfxrt, i);
3141 regA = PopVal (pfx, pfxrt, i);
3144 regC = PopVal (pfx, pfxrt, i);
3145 regB = PopVal (pfx, pfxrt, i);
3146 regA = PopVal (pfx, pfxrt, i);
3149 regD = PopVal (pfx, pfxrt, i);
3150 regC = PopVal (pfx, pfxrt, i);
3151 regB = PopVal (pfx, pfxrt, i);
3152 regA = PopVal (pfx, pfxrt, i);
3155 regE = PopVal (pfx, pfxrt, i);
3156 regD = PopVal (pfx, pfxrt, i);
3157 regC = PopVal (pfx, pfxrt, i);
3158 regB = PopVal (pfx, pfxrt, i);
3159 regA = PopVal (pfx, pfxrt, i);
3162 (void) ThrowMagickException (
3163 pfx->exception, GetMagickModule(), OptionError,
3164 "Too many args:",
"%i", pel->nArgs);
3168 switch (pel->oprNum) {
3170 regA = (pfxrt->UserSymVals[pel->EleNdx] += regA);
3173 regA = (pfxrt->UserSymVals[pel->EleNdx] -= regA);
3176 regA = (pfxrt->UserSymVals[pel->EleNdx] *= regA);
3179 regA = (pfxrt->UserSymVals[pel->EleNdx] *= PerceptibleReciprocal((
double)regA));
3182 regA = pfxrt->UserSymVals[pel->EleNdx]++;
3185 regA = pfxrt->UserSymVals[pel->EleNdx]--;
3197 regA *= PerceptibleReciprocal((
double)regB);
3200 regA = fmod ((
double) regA, fabs(floor((
double) regB+0.5)));
3209 if ((
size_t) (regB+0.5) >= (8*
sizeof(
size_t)))
3211 (void) ThrowMagickException ( pfx->exception, GetMagickModule(),
3212 OptionError,
"undefined shift",
"%g", (double) regB);
3213 regA = (fxFltType) 0.0;
3216 regA = (fxFltType) ((
size_t)(regA+0.5) << (
size_t)(regB+0.5));
3219 if ((
size_t) (regB+0.5) >= (8*
sizeof(
size_t)))
3221 (void) ThrowMagickException ( pfx->exception, GetMagickModule(),
3222 OptionError,
"undefined shift",
"%g", (double) regB);
3223 regA = (fxFltType) 0.0;
3226 regA = (fxFltType) ((
size_t)(regA+0.5) >> (
size_t)(regB+0.5));
3229 regA = fabs((
double) (regA-regB)) < MagickEpsilon ? 1.0 : 0.0;
3232 regA = fabs((
double) (regA-regB)) >= MagickEpsilon ? 1.0 : 0.0;
3235 regA = (regA <= regB) ? 1.0 : 0.0;
3238 regA = (regA >= regB) ? 1.0 : 0.0;
3241 regA = (regA < regB) ? 1.0 : 0.0;
3244 regA = (regA > regB) ? 1.0 : 0.0;
3247 regA = (regA<=0) ? 0.0 : (regB > 0) ? 1.0 : 0.0;
3250 regA = (regA>0) ? 1.0 : (regB > 0.0) ? 1.0 : 0.0;
3253 regA = (regA==0) ? 1.0 : 0.0;
3256 regA = (fxFltType) ((
size_t)(regA+0.5) & (
size_t)(regB+0.5));
3259 regA = (fxFltType) ((
size_t)(regA+0.5) | (
size_t)(regB+0.5));
3263 regA = (fxFltType) (~(
size_t)(regA+0.5));
3266 regA = pow ((
double) regA, (
double) regB);
3282 if (pel->type == etColourConstant) {
3283 switch (channel) {
default:
3284 case (PixelChannel) 0:
3287 case (PixelChannel) 1:
3290 case (PixelChannel) 2:
3300 regA = fabs ((
double) regA);
3302 #if defined(MAGICKCORE_HAVE_ACOSH)
3304 regA = acosh ((
double) regA);
3308 regA = acos ((
double) regA);
3310 #if defined(MAGICKCORE_HAVE_J1)
3312 if (regA==0) regA = 1.0;
3314 fxFltType gamma = 2.0 * j1 ((MagickPI*regA)) / (MagickPI*regA);
3315 regA = gamma * gamma;
3320 regA = (fxFltType) (((ssize_t) regA) & 0x01 ? -1.0 : 1.0);
3322 #if defined(MAGICKCORE_HAVE_ASINH)
3324 regA = asinh ((
double) regA);
3328 regA = asin ((
double) regA);
3330 #if defined(MAGICKCORE_HAVE_ATANH)
3332 regA = atanh ((
double) regA);
3336 regA = atan2 ((
double) regA, (
double) regB);
3339 regA = atan ((
double) regA);
3342 regA = ceil ((
double) regA);
3346 case (PixelChannel) 0:
break;
3347 case (PixelChannel) 1: regA = regB;
break;
3348 case (PixelChannel) 2: regA = regC;
break;
3349 case (PixelChannel) 3: regA = regD;
break;
3350 case (PixelChannel) 4: regA = regE;
break;
3351 default: regA = 0.0;
3355 if (regA < 0) regA = 0.0;
3356 else if (regA > 1.0) regA = 1.0;
3359 regA = cosh ((
double) regA);
3362 regA = cos ((
double) regA);
3367 (void) fprintf (stderr,
"%s[%g,%g].[%i]: %s=%.*g\n",
3368 img->filename, (
double) imgx, (double) imgy,
3369 channel, SetPtrShortExp (pfx, pel->pExpStart, (
size_t) (pel->lenExp+1)),
3370 pfx->precision, (double) regA);
3373 regA = regA / (regB*(regA-1.0) + 1.0);
3375 #if defined(MAGICKCORE_HAVE_ERF)
3377 regA = erf ((
double) regA);
3381 regA = exp ((
double) regA);
3384 regA = floor ((
double) regA);
3387 regA = exp((
double) (-regA*regA/2.0))/sqrt(2.0*MagickPI);
3391 regA = FxGcd (regA, regB, 0);
3394 regA = hypot ((
double) regA, (
double) regB);
3397 regA = floor ((
double) regA);
3400 regA = (fxFltType) (!!IsNaN (regA));
3402 #if defined(MAGICKCORE_HAVE_J0)
3404 regA = j0 ((
double) regA);
3407 #if defined(MAGICKCORE_HAVE_J1)
3409 regA = j1 ((
double) regA);
3412 #if defined(MAGICKCORE_HAVE_J1)
3414 if (regA==0) regA = 1.0;
3415 else regA = 2.0 * j1 ((MagickPI*regA))/(MagickPI*regA);
3419 regA = log ((
double) regA);
3422 regA = log10((
double) regA) / log10(2.0);
3425 regA = log10 ((
double) regA);
3428 regA = (regA > regB) ? regA : regB;
3431 regA = (regA < regB) ? regA : regB;
3434 regA = regA - floor((
double) (regA*PerceptibleReciprocal((
double) regB)))*regB;
3437 regA = (fxFltType) (regA < MagickEpsilon);
3440 regA = pow ((
double) regA, (
double) regB);
3443 #if defined(MAGICKCORE_OPENMP_SUPPORT)
3444 #pragma omp critical (MagickCore_ExecuteRPN)
3446 regA = GetPseudoRandomValue (pfxrt->random_info);
3450 regA = floor ((
double) regA + 0.5);
3453 regA = (regA < 0) ? -1.0 : 1.0;
3456 regA = sin ((
double) (MagickPI*regA)) / (MagickPI*regA);
3459 regA = sinh ((
double) regA);
3462 regA = sin ((
double) regA);
3465 regA = sqrt ((
double) regA);
3468 regA = 1.0 / (1.0 + exp ((
double) -regA));
3471 regA = tanh ((
double) regA);
3474 regA = tan ((
double) regA);
3477 if (regA >= 0) regA = floor ((
double) regA);
3478 else regA = ceil ((
double) regA);
3490 ssize_t ImgNum = ChkImgNum (pfx, regA);
3491 if (ImgNum < 0)
break;
3492 regA = (fxFltType) 0;
3494 Image * pimg = pfx->Images[0];
3495 int pech = (int)pel->ChannelQual;
3496 if (pel->ImgAttrQual == aNull) {
3498 if (pech == NO_CHAN_QUAL || pech == THIS_CHANNEL) {
3499 if (pfx->ImgNum==0) {
3500 regA = QuantumScale * p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3502 const Quantum * pv = GetCacheViewVirtualPixels (
3503 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3505 (void) ThrowMagickException (
3506 pfx->exception, GetMagickModule(), OptionError,
3507 "fU can't get cache",
"%lu", (
unsigned long) ImgNum);
3510 regA = QuantumScale * pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3512 }
else if (pech == HUE_CHANNEL || pech == SAT_CHANNEL ||
3513 pech == LIGHT_CHANNEL) {
3514 regA = GetHslInt (pfx, ImgNum, imgx, imgy, pech);
3516 }
else if (pech == INTENSITY_CHANNEL) {
3517 regA = GetIntensity (pfx, 0, (
double) imgx, (
double) imgy);
3521 if (pfx->ImgNum==0) {
3522 regA = QuantumScale * p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3524 const Quantum * pv = GetCacheViewVirtualPixels (
3525 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3527 (void) ThrowMagickException (
3528 pfx->exception, GetMagickModule(), OptionError,
3529 "fU can't get cache",
"%lu", (
unsigned long) ImgNum);
3532 regA = QuantumScale * pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3537 regA = ImageStat (pfx, 0, WHICH_ATTR_CHAN, pel->ImgAttrQual);
3541 if (pel->ImgAttrQual == aNull) {
3543 if ((
int)pel->ChannelQual < 0) {
3544 if (pel->ChannelQual == HUE_CHANNEL || pel->ChannelQual == SAT_CHANNEL ||
3545 pel->ChannelQual == LIGHT_CHANNEL)
3547 regA = GetHslInt (pfx, ImgNum, imgx, imgy, pel->ChannelQual);
3549 }
else if (pel->ChannelQual == INTENSITY_CHANNEL)
3551 regA = GetIntensity (pfx, ImgNum, (fxFltType) imgx, (fxFltType) imgy);
3556 pv = GetCacheViewVirtualPixels (
3557 pfx->Imgs[ImgNum].View, imgx, imgy, 1,1, pfx->exception);
3559 (void) ThrowMagickException (
3560 pfx->exception, GetMagickModule(), OptionError,
3561 "fU can't get cache",
"%lu", (
unsigned long) ImgNum);
3564 regA = QuantumScale *
3565 pv[pfx->Images[ImgNum]->channel_map[WHICH_NON_ATTR_CHAN].offset];
3567 regA = ImageStat (pfx, ImgNum, WHICH_ATTR_CHAN, pel->ImgAttrQual);
3576 Image * pimg = pfx->Images[0];
3577 int pech = (int)pel->ChannelQual;
3579 if (pech == NO_CHAN_QUAL || pech == THIS_CHANNEL) {
3581 if (pfx->ImgNum==0) {
3582 regA = QuantumScale * p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3584 const Quantum * pv = GetCacheViewVirtualPixels (
3585 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3587 (void) ThrowMagickException (
3588 pfx->exception, GetMagickModule(), OptionError,
3589 "fU0 can't get cache",
"%i", 0);
3592 regA = QuantumScale * pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3595 }
else if (pel->ChannelQual == HUE_CHANNEL || pel->ChannelQual == SAT_CHANNEL ||
3596 pel->ChannelQual == LIGHT_CHANNEL) {
3597 regA = GetHslInt (pfx, 0, imgx, imgy, pel->ChannelQual);
3599 }
else if (pel->ChannelQual == INTENSITY_CHANNEL) {
3600 regA = GetIntensity (pfx, 0, (fxFltType) imgx, (fxFltType) imgy);
3603 if (pfx->ImgNum==0) {
3604 regA = QuantumScale * p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3606 const Quantum * pv = GetCacheViewVirtualPixels (
3607 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3609 (void) ThrowMagickException (
3610 pfx->exception, GetMagickModule(), OptionError,
3611 "fU0 can't get cache",
"%i", 0);
3614 regA = QuantumScale * pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3621 ssize_t ImgNum = ChkImgNum (pfx, regA);
3624 if (ImgNum < 0)
break;
3626 if (pel->IsRelative) {
3634 if ((
int)pel->ChannelQual < 0) {
3635 if (pel->ChannelQual == HUE_CHANNEL || pel->ChannelQual == SAT_CHANNEL
3636 || pel->ChannelQual == LIGHT_CHANNEL) {
3637 regA = GetHslFlt (pfx, ImgNum, fx, fy, pel->ChannelQual);
3639 }
else if (pel->ChannelQual == INTENSITY_CHANNEL) {
3640 regA = GetIntensity (pfx, ImgNum, fx, fy);
3647 Image * imUP = pfx->Images[ImgNum];
3648 if (! InterpolatePixelChannel (imUP, pfx->Imgs[ImgNum].View, WHICH_NON_ATTR_CHAN,
3649 imUP->interpolate, (
double) fx, (
double) fy, &v, pfx->exception))
3651 (void) ThrowMagickException (
3652 pfx->exception, GetMagickModule(), OptionError,
3653 "fUP can't get interpolate",
"%lu", (
unsigned long) ImgNum);
3656 regA = v * QuantumScale;
3665 if (pel->oprNum == fS) ImgNum = pfx->ImgNum;
3667 if (pel->ImgAttrQual == aNull) {
3668 const Quantum * pv = GetCacheViewVirtualPixels (
3669 pfx->Imgs[ImgNum].View, imgx, imgy, 1,1, pfx->exception);
3671 (void) ThrowMagickException (
3672 pfx->exception, GetMagickModule(), OptionError,
3673 "fV can't get cache",
"%lu", (
unsigned long) ImgNum);
3677 if ((
int)pel->ChannelQual < 0) {
3678 if (pel->ChannelQual == HUE_CHANNEL || pel->ChannelQual == SAT_CHANNEL ||
3679 pel->ChannelQual == LIGHT_CHANNEL) {
3680 regA = GetHslInt (pfx, ImgNum, imgx, imgy, pel->ChannelQual);
3682 }
else if (pel->ChannelQual == INTENSITY_CHANNEL) {
3683 regA = GetIntensity (pfx, ImgNum, (
double) imgx, (
double) imgy);
3688 regA = QuantumScale *
3689 pv[pfx->Images[ImgNum]->channel_map[WHICH_NON_ATTR_CHAN].offset];
3691 regA = ImageStat (pfx, ImgNum, WHICH_ATTR_CHAN, pel->ImgAttrQual);
3701 ssize_t ImgNum = pfx->ImgNum;
3702 if (pel->oprNum == fVP) ImgNum = 1;
3703 if (pel->IsRelative) {
3710 if ((
int)pel->ChannelQual < 0) {
3711 if (pel->ChannelQual == HUE_CHANNEL || pel->ChannelQual == SAT_CHANNEL ||
3712 pel->ChannelQual == LIGHT_CHANNEL) {
3713 regA = GetHslFlt (pfx, ImgNum, fx, fy, pel->ChannelQual);
3715 }
else if (pel->ChannelQual == INTENSITY_CHANNEL) {
3716 regA = GetIntensity (pfx, ImgNum, fx, fy);
3723 if (! InterpolatePixelChannel (pfx->Images[ImgNum], pfx->Imgs[ImgNum].View,
3724 WHICH_NON_ATTR_CHAN, pfx->Images[ImgNum]->interpolate,
3725 (
double) fx, (
double) fy, &v, pfx->exception)
3728 (void) ThrowMagickException (
3729 pfx->exception, GetMagickModule(), OptionError,
3730 "fSP or fVP can't get interp",
"%lu", (
unsigned long) ImgNum);
3733 regA = v * (fxFltType)QuantumScale;
3741 regA = (fxFltType) GetImageDepth (img, pfx->exception);
3744 regA = (fxFltType) img->extent;
3748 regA = cs[WHICH_ATTR_CHAN].kurtosis;
3752 regA = cs[WHICH_ATTR_CHAN].maxima;
3756 regA = cs[WHICH_ATTR_CHAN].mean;
3760 regA = cs[WHICH_ATTR_CHAN].median;
3764 regA = cs[WHICH_ATTR_CHAN].minima;
3769 regA = (fxFltType) img->page.x;
3772 regA = (fxFltType) img->page.y;
3775 regA = (fxFltType) img->page.width;
3778 regA = (fxFltType) img->page.height;
3783 regA = (fxFltType) PerceptibleReciprocal (img->resolution.x) * img->columns;
3786 regA = (fxFltType) PerceptibleReciprocal (img->resolution.y) * img->rows;
3789 regA = (fxFltType) img->quality;
3794 regA = (fxFltType) img->resolution.x;
3797 regA = (fxFltType) img->resolution.y;
3801 regA = cs[WHICH_ATTR_CHAN].skewness;
3805 regA = cs[WHICH_ATTR_CHAN].standard_deviation;
3808 regA = (fxFltType) img->rows;
3811 regA = (fxFltType) pfx->ImgListLen;
3814 regA = (fxFltType) pfx->ImgNum;
3817 regA = (fxFltType) img->columns;
3820 regA = (fxFltType) GetImageDepth (img, pfx->exception);
3828 regA = GetIntensity (pfx, pfx->ImgNum, (
double) imgx, (
double) imgy);
3835 regA = QuantumScale * (0.212656 * GetPixelRed (img,p) +
3836 0.715158 * GetPixelGreen (img,p) +
3837 0.072186 * GetPixelBlue (img,p));
3843 regA = QuantumScale * GetPixelAlpha (img, p);
3846 regA = QuantumScale * GetPixelBlue (img, p);
3849 regA = QuantumScale * GetPixelCyan (img, p);
3852 regA = QuantumScale * GetPixelGreen (img, p);
3855 regA = (fxFltType) imgx;
3858 regA = (fxFltType) imgy;
3861 regA = QuantumScale * GetPixelBlack (img, p);
3864 regA = QuantumScale * GetPixelGreen (img, p);
3867 regA = QuantumScale * GetPixelAlpha (img, p);
3870 regA = QuantumScale * GetPixelRed (img, p);
3873 regA = QuantumScale * GetPixelYellow (img, p);
3879 assert (pel->EleNdx >= 0);
3883 assert (pel->EleNdx >= 0);
3884 if (fabs((
double) regA) < MagickEpsilon) i = pel->EleNdx-1;
3886 case rIfNotZeroGoto:
3887 assert (pel->EleNdx >= 0);
3888 if (fabs((
double) regA) > MagickEpsilon) i = pel->EleNdx-1;
3891 assert (pel->EleNdx >= 0);
3892 regA = pfxrt->UserSymVals[pel->EleNdx];
3895 assert (pel->EleNdx >= 0);
3896 pfxrt->UserSymVals[pel->EleNdx] = regA;
3899 pfxrt->usedValStack = 0;
3905 (void) ThrowMagickException (
3906 pfx->exception, GetMagickModule(), OptionError,
3907 "pel->oprNum",
"%i '%s' not yet implemented",
3908 (int)pel->oprNum, OprStr(pel->oprNum));
3912 (void) ThrowMagickException (
3913 pfx->exception, GetMagickModule(), OptionError,
3914 "Bad run-time address",
"%i", i);
3917 if (!PushVal (pfx, pfxrt, regA, i))
break;
3920 if (pfxrt->usedValStack > 0) regA = PopVal (pfx, pfxrt, 9999);
3926 if (pfx->exception->severity != UndefinedException) {
3930 if (pfxrt->usedValStack != 0) {
3931 (void) ThrowMagickException (
3932 pfx->exception, GetMagickModule(), OptionError,
3933 "ValStack not empty",
"(%i)", pfxrt->usedValStack);
3942 MagickPrivate MagickBooleanType FxEvaluateChannelExpression (
3944 const PixelChannel channel,
const ssize_t x,
const ssize_t y,
3948 id = GetOpenMPThreadId();
3952 assert (pfx != NULL);
3953 assert (pfx->image != NULL);
3954 assert (pfx->Images != NULL);
3955 assert (pfx->Imgs != NULL);
3956 assert (pfx->fxrts != NULL);
3958 pfx->fxrts[id].thisPixel = NULL;
3960 if (!ExecuteRPN (pfx, &pfx->fxrts[
id], &ret, channel, x, y)) {
3961 (void) ThrowMagickException (
3962 exception, GetMagickModule(), OptionError,
3963 "ExcuteRPN failed",
" ");
3967 *result = (double) ret;
3972 static FxInfo *AcquireFxInfoPrivate (
const Image * images,
const char * expression,
3977 FxInfo * pfx = (
FxInfo*) AcquireCriticalMemory (
sizeof (*pfx));
3979 memset (pfx, 0,
sizeof (*pfx));
3981 if (!InitFx (pfx, images, CalcAllStats, exception)) {
3982 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
3986 if (!BuildRPN (pfx)) {
3987 (void) DeInitFx (pfx);
3988 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
3992 if ((*expression ==
'@') && (strlen(expression) > 1))
4000 status=IsRightsAuthorized(PathPolicyDomain,ReadPolicyRights,expression);
4001 if (status != MagickFalse)
4002 pfx->expression=FileToString(expression+1,~0UL,exception);
4006 (void) ThrowMagickException(exception,GetMagickModule(),PolicyError,
4007 "NotAuthorized",
"`%s'",expression);
4010 if (pfx->expression == (
char *) NULL)
4011 pfx->expression=ConstantString(expression);
4012 pfx->pex = (
char *) pfx->expression;
4015 if (!TranslateStatementList (pfx,
";", &chLimit)) {
4016 (void) DestroyRPN (pfx);
4017 pfx->expression = DestroyString (pfx->expression);
4019 (void) DeInitFx (pfx);
4020 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4025 (void) ThrowMagickException (
4026 pfx->exception, GetMagickModule(), OptionError,
4027 "Translate expression depth",
"(%i) not 0",
4030 (void) DestroyRPN (pfx);
4031 pfx->expression = DestroyString (pfx->expression);
4033 (void) DeInitFx (pfx);
4034 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4038 if (chLimit !=
'\0' && chLimit !=
';') {
4039 (void) ThrowMagickException (
4040 pfx->exception, GetMagickModule(), OptionError,
4041 "AcquireFxInfo: TranslateExpression did not exhaust input",
"(chLimit=%i) at'%s'",
4042 (int)chLimit, pfx->pex);
4044 (void) DestroyRPN (pfx);
4045 pfx->expression = DestroyString (pfx->expression);
4047 (void) DeInitFx (pfx);
4048 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4052 if (pfx->NeedStats && pfx->runType == rtEntireImage && !pfx->statistics) {
4053 if (!CollectStatistics (pfx)) {
4054 (void) DestroyRPN (pfx);
4055 pfx->expression = DestroyString (pfx->expression);
4057 (void) DeInitFx (pfx);
4058 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4063 if (pfx->DebugOpt) {
4064 DumpTables (stderr);
4065 DumpUserSymbols (pfx, stderr);
4066 (void) DumpRPN (pfx, stderr);
4070 size_t number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
4073 pfx->fxrts = (
fxRtT *)AcquireQuantumMemory (number_threads,
sizeof(
fxRtT));
4075 (void) ThrowMagickException (
4076 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
4078 (
unsigned long) number_threads);
4079 (void) DestroyRPN (pfx);
4080 pfx->expression = DestroyString (pfx->expression);
4082 (void) DeInitFx (pfx);
4083 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4086 for (t=0; t < (ssize_t) number_threads; t++) {
4087 if (!AllocFxRt (pfx, &pfx->fxrts[t])) {
4088 (void) ThrowMagickException (
4089 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
4090 "AllocFxRt t=",
"%g",
4094 for (t2 = t-1; t2 >= 0; t2--) {
4095 DestroyFxRt (&pfx->fxrts[t]);
4098 pfx->fxrts = (
fxRtT *) RelinquishMagickMemory (pfx->fxrts);
4099 (void) DestroyRPN (pfx);
4100 pfx->expression = DestroyString (pfx->expression);
4102 (void) DeInitFx (pfx);
4103 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4113 return AcquireFxInfoPrivate (images, expression, MagickFalse, exception);
4120 assert (pfx != NULL);
4121 assert (pfx->image != NULL);
4122 assert (pfx->Images != NULL);
4123 assert (pfx->Imgs != NULL);
4124 assert (pfx->fxrts != NULL);
4126 for (t=0; t < (ssize_t) GetMagickResourceLimit(ThreadResource); t++) {
4127 DestroyFxRt (&pfx->fxrts[t]);
4129 pfx->fxrts = (
fxRtT *) RelinquishMagickMemory (pfx->fxrts);
4133 pfx->expression = DestroyString (pfx->expression);
4136 (void) DeInitFx (pfx);
4138 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4145 MagickExport
Image *FxImage(
const Image *image,
const char *expression,
4148 #define FxImageTag "FxNew/Image"
4169 assert(image != (
Image *) NULL);
4170 assert(image->signature == MagickCoreSignature);
4171 if (IsEventLogging() != MagickFalse)
4172 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4173 if (expression == (
const char *) NULL)
4174 return(CloneImage(image,0,0,MagickTrue,exception));
4175 fx_image=CloneImage(image,0,0,MagickTrue,exception);
4176 if (!fx_image)
return NULL;
4177 if (SetImageStorageClass(fx_image,DirectClass,exception) == MagickFalse) {
4178 fx_image=DestroyImage(fx_image);
4182 pfx = AcquireFxInfoPrivate (image, expression, MagickTrue, exception);
4185 fx_image=DestroyImage(fx_image);
4189 assert (pfx->image != NULL);
4190 assert (pfx->Images != NULL);
4191 assert (pfx->Imgs != NULL);
4192 assert (pfx->fxrts != NULL);
4196 image_view = AcquireVirtualCacheView (image, pfx->exception);
4197 fx_view = AcquireAuthenticCacheView (fx_image, pfx->exception);
4198 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4199 #pragma omp parallel for schedule(dynamic) shared(progress,status) \
4200 magick_number_threads(image,fx_image,fx_image->rows, \
4201 pfx->ContainsDebug ? 0 : 1)
4203 for (y=0; y < (ssize_t) fx_image->rows; y++)
4206 id = GetOpenMPThreadId();
4220 if (status == MagickFalse)
4222 p = GetCacheViewVirtualPixels (image_view, 0, y, image->columns, 1, pfx->exception);
4223 q = QueueCacheViewAuthenticPixels (fx_view, 0, y, fx_image->columns, 1, pfx->exception);
4224 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL)) {
4228 for (x=0; x < (ssize_t) fx_image->columns; x++) {
4231 pfx->fxrts[id].thisPixel = (Quantum *)p;
4233 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4235 PixelChannel channel = GetPixelChannelChannel (image, i);
4236 PixelTrait traits = GetPixelChannelTraits (image, channel);
4237 PixelTrait fx_traits = GetPixelChannelTraits (fx_image, channel);
4238 if ((traits == UndefinedPixelTrait) ||
4239 (fx_traits == UndefinedPixelTrait))
4241 if ((fx_traits & CopyPixelTrait) != 0) {
4242 SetPixelChannel (fx_image, channel, p[i], q);
4246 if (!ExecuteRPN (pfx, &pfx->fxrts[
id], &result, channel, x, y)) {
4251 q[i] = ClampToQuantum ((MagickRealType) (QuantumRange*result));
4253 p+=GetPixelChannels (image);
4254 q+=GetPixelChannels (fx_image);
4256 if (SyncCacheViewAuthenticPixels(fx_view, pfx->exception) == MagickFalse)
4258 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4263 #if defined(MAGICKCORE_OPENMP_SUPPORT)
4267 proceed = SetImageProgress (image, FxImageTag, progress, image->rows);
4268 if (proceed == MagickFalse)
4273 fx_view = DestroyCacheView (fx_view);
4274 image_view = DestroyCacheView (image_view);
4278 if (pfx->DebugOpt && pfx->usedUserSymbols) {
4280 char UserSym[MagickPathExtent];
4281 fprintf (stderr,
"User symbols (%i):\n", pfx->usedUserSymbols);
4282 for (t=0; t < (int) GetMagickResourceLimit(ThreadResource); t++) {
4283 for (i = 0; i < (int) pfx->usedUserSymbols; i++) {
4284 fprintf (stderr,
"th=%i us=%i '%s': %.*Lg\n",
4285 t, i, NameOfUserSym (pfx, i, UserSym), pfx->precision, pfx->fxrts[t].UserSymVals[i]);
4290 if (pfx->exception->severity != UndefinedException) {
4291 status = MagickFalse;
4294 if (status == MagickFalse)
4295 fx_image = DestroyImage (fx_image);
4297 pfx = DestroyFxInfo (pfx);