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/statistic-private.h"
94#include "MagickCore/string_.h"
95#include "MagickCore/thread-private.h"
96#include "MagickCore/threshold.h"
97#include "MagickCore/timer-private.h"
98#include "MagickCore/token.h"
99#include "MagickCore/transform.h"
100#include "MagickCore/transform-private.h"
101#include "MagickCore/utility.h"
104#define MaxTokenLen 100
106#define TableExtend 0.1
107#define InitNumOprStack 50
108#define MinValStackSize 100
109#define InitNumUserSymbols 50
111#define SECONDS_ERR -FLT_MAX
113typedef long double fxFltType;
169 {oAddEq,
"+=", 12, 1},
170 {oSubtractEq,
"-=", 12, 1},
171 {oMultiplyEq,
"*=", 13, 1},
172 {oDivideEq,
"/=", 13, 1},
173 {oPlusPlus,
"++", 12, 0},
174 {oSubSub,
"--", 12, 0},
176 {oSubtract,
"-", 12, 2},
177 {oMultiply,
"*", 13, 2},
178 {oDivide,
"/", 13, 2},
179 {oModulus,
"%", 13, 2},
180 {oUnaryPlus,
"+", 14, 1},
181 {oUnaryMinus,
"-", 14, 1},
182 {oLshift,
"<<", 11, 2},
183 {oRshift,
">>", 11, 2},
185 {oNotEq,
"!=", 9, 2},
186 {oLtEq,
"<=", 10, 2},
187 {oGtEq,
">=", 10, 2},
190 {oLogAnd,
"&&", 6, 2},
191 {oLogOr,
"||", 5, 2},
192 {oLogNot,
"!", 16, 1},
193 {oBitAnd,
"&", 8, 2},
195 {oBitNot,
"~", 16, 1},
199 {oOpenParen,
"(", 0, 0},
200 {oCloseParen,
")", 0, 0},
201 {oOpenBracket,
"[", 0, 0},
202 {oCloseBracket,
"]", 0, 0},
203 {oOpenBrace,
"{", 0, 0},
204 {oCloseBrace,
"}", 0, 0},
205 {oAssign,
"=", 3, 1},
206 {oNull,
"onull", 17, 0}
234 {cEpsilon, MagickEpsilon,
"epsilon"},
235 {cE, 2.7182818284590452354,
"e"},
236 {cOpaque, 1.0,
"opaque"},
237 {cPhi, MagickPHI,
"phi"},
238 {cPi, MagickPI,
"pi"},
239 {cQuantumRange, QuantumRange,
"quantumrange"},
240 {cQuantumScale, QuantumScale,
"quantumscale"},
241 {cTransparent, 0.0,
"transparent"},
242 {cMaxRgb, QuantumRange,
"MaxRGB"},
243 {cNull, 0.0,
"cnull"}
246#define FirstFunc ((FunctionE) (oNull+1))
250#if defined(MAGICKCORE_HAVE_ACOSH)
254#if defined(MAGICKCORE_HAVE_J1)
258#if defined(MAGICKCORE_HAVE_ASINH)
262#if defined(MAGICKCORE_HAVE_ATANH)
274#if defined(MAGICKCORE_HAVE_ERF)
285#if defined(MAGICKCORE_HAVE_J0)
288#if defined(MAGICKCORE_HAVE_J1)
291#if defined(MAGICKCORE_HAVE_J1)
343#if defined(MAGICKCORE_HAVE_ACOSH)
344 {fAcosh,
"acosh" , 1},
347#if defined(MAGICKCORE_HAVE_J1)
351#if defined(MAGICKCORE_HAVE_ASINH)
352 {fAsinh,
"asinh" , 1},
355#if defined(MAGICKCORE_HAVE_ATANH)
356 {fAtanh,
"atanh" , 1},
358 {fAtan2,
"atan2" , 2},
361 {fChannel,
"channel", 5},
362 {fClamp,
"clamp" , 1},
365 {fDebug,
"debug" , 1},
367#if defined(MAGICKCORE_HAVE_ERF)
370 {fEpoch,
"epoch" , 1},
372 {fFloor,
"floor" , 1},
373 {fGauss,
"gauss" , 1},
375 {fHypot,
"hypot" , 2},
377 {fIsnan,
"isnan" , 1},
378#if defined(MAGICKCORE_HAVE_J0)
381#if defined(MAGICKCORE_HAVE_J1)
384#if defined(MAGICKCORE_HAVE_J1)
388 {fLogtwo,
"logtwo", 1},
390 {fMagickTime,
"magicktime", 0},
397 {fRound,
"round" , 1},
403 {fSquish,
"squish", 1},
406 {fTrunc,
"trunc" , 1},
410 {fWhile,
"while", 2},
423#define FirstImgAttr ((ImgAttrE) (fNull+1))
467 {aDepth,
"depth", MagickTrue},
468 {aExtent,
"extent", MagickFalse},
469 {aKurtosis,
"kurtosis", MagickTrue},
470 {aMaxima,
"maxima", MagickTrue},
471 {aMean,
"mean", MagickTrue},
472 {aMedian,
"median", MagickTrue},
473 {aMinima,
"minima", MagickTrue},
474 {aPage,
"page", MagickFalse},
475 {aPageX,
"page.x", MagickFalse},
476 {aPageY,
"page.y", MagickFalse},
477 {aPageWid,
"page.width", MagickFalse},
478 {aPageHt,
"page.height", MagickFalse},
479 {aPrintsize,
"printsize", MagickFalse},
480 {aPrintsizeX,
"printsize.x", MagickFalse},
481 {aPrintsizeY,
"printsize.y", MagickFalse},
482 {aQuality,
"quality", MagickFalse},
483 {aRes,
"resolution", MagickFalse},
484 {aResX,
"resolution.x", MagickFalse},
485 {aResY,
"resolution.y", MagickFalse},
486 {aSkewness,
"skewness", MagickTrue},
487 {aStdDev,
"standard_deviation", MagickTrue},
488 {aH,
"h", MagickFalse},
489 {aN,
"n", MagickFalse},
490 {aT,
"t", MagickFalse},
491 {aW,
"w", MagickFalse},
492 {aZ,
"z", MagickFalse},
493 {aNull,
"anull", MagickFalse},
494 {aNull,
"anull", MagickFalse},
495 {aNull,
"anull", MagickFalse},
496 {aNull,
"anull", MagickFalse}
499#define FirstSym ((SymbolE) (aNull+1))
530static const SymbolT Symbols[] = {
532 {sIntensity,
"intensity"},
533 {sLightness,
"lightness"},
535 {sLuminance,
"luminance"},
536 {sSaturation,
"saturation"},
557#define FirstCont (sNull+1)
584 {rGotoChk,
"gotochk", 0},
585 {rIfZeroGoto,
"ifzerogoto", 1},
586 {rIfNotZeroGoto,
"ifnotzerogoto", 1},
587 {rCopyFrom,
"copyfrom", 0},
588 {rCopyTo,
"copyto", 1},
589 {rZerStk,
"zerstk", 0},
593#define NULL_ADDRESS -2
609#define NO_CHAN_QUAL ((PixelChannel) (-1))
610#define THIS_CHANNEL ((PixelChannel) (-2))
611#define HUE_CHANNEL ((PixelChannel) (-3))
612#define SAT_CHANNEL ((PixelChannel) (-4))
613#define LIGHT_CHANNEL ((PixelChannel) (-5))
614#define INTENSITY_CHANNEL ((PixelChannel) (-6))
617 {
"r", RedPixelChannel},
618 {
"g", GreenPixelChannel},
619 {
"b", BluePixelChannel},
620 {
"c", CyanPixelChannel},
621 {
"m", MagentaPixelChannel},
622 {
"y", YellowPixelChannel},
623 {
"k", BlackPixelChannel},
624 {
"a", AlphaPixelChannel},
625 {
"o", AlphaPixelChannel},
626 {
"hue", HUE_CHANNEL},
627 {
"saturation", SAT_CHANNEL},
628 {
"lightness", LIGHT_CHANNEL},
629 {
"intensity", INTENSITY_CHANNEL},
630 {
"all", CompositePixelChannel},
631 {
"this", THIS_CHANNEL},
655static const char * sElementTypes[] = {
712 fxFltType * ValStack;
713 fxFltType * UserSymVals;
721 MagickBooleanType NeedStats;
722 MagickBooleanType GotStats;
723 MagickBooleanType NeedHsl;
724 MagickBooleanType DebugOpt;
725 MagickBooleanType ContainsDebug;
728 char ShortExp[MagickPathExtent];
730 char token[MagickPathExtent];
741 OperatorE * OperatorStack;
747 **magick_restrict random_infos;
759static MagickBooleanType TranslateStatementList
760 (
FxInfo * pfx,
const char * strLimit,
char * chLimit);
762static MagickBooleanType TranslateExpression
763 (
FxInfo * pfx,
const char * strLimit,
char * chLimit, MagickBooleanType * needPopAll);
765static MagickBooleanType GetFunction (
FxInfo * pfx, FunctionE fe);
767static inline MagickBooleanType ChanIsVirtual (PixelChannel pc)
769 if (pc==HUE_CHANNEL || pc==SAT_CHANNEL || pc==LIGHT_CHANNEL || pc==INTENSITY_CHANNEL)
775static MagickBooleanType InitFx (
FxInfo * pfx,
const Image * img,
781 pfx->ImgListLen = GetImageListLength (img);
782 pfx->ImgNum = GetImageIndexInList (img);
783 pfx->image = (
Image *)img;
785 pfx->NeedStats = MagickFalse;
786 pfx->GotStats = MagickFalse;
787 pfx->NeedHsl = MagickFalse;
788 pfx->DebugOpt = IsStringTrue (GetImageArtifact (img,
"fx:debug"));
789 pfx->statistics = NULL;
792 pfx->exception = exception;
793 pfx->precision = GetMagickPrecision ();
794 pfx->random_infos = AcquireRandomInfoTLS ();
795 pfx->ContainsDebug = MagickFalse;
796 pfx->runType = (CalcAllStats) ? rtEntireImage : rtCornerOnly;
797 pfx->Imgs = (
ImgT *)AcquireQuantumMemory (pfx->ImgListLen, sizeof (
ImgT));
799 (void) ThrowMagickException (
800 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
802 (
unsigned long) pfx->ImgListLen);
806 next = GetFirstImageInList (img);
807 for ( ; next != (
Image *) NULL; next=next->next)
809 ImgT * pimg = &pfx->Imgs[i];
810 pimg->View = AcquireVirtualCacheView (next, pfx->exception);
812 (void) ThrowMagickException (
813 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
817 for ( ; i > 0; i--) {
818 pimg = &pfx->Imgs[i-1];
819 pimg->View = DestroyCacheView (pimg->View);
821 pfx->Imgs=(
ImgT *) RelinquishMagickMemory (pfx->Imgs);
827 pfx->Images = ImageListToArray (img, pfx->exception);
832static MagickBooleanType DeInitFx (
FxInfo * pfx)
836 if (pfx->Images) pfx->Images = (
Image**) RelinquishMagickMemory (pfx->Images);
839 for (i = (ssize_t)GetImageListLength(pfx->image); i > 0; i--) {
840 ImgT * pimg = &pfx->Imgs[i-1];
841 pimg->View = DestroyCacheView (pimg->View);
843 pfx->Imgs=(
ImgT *) RelinquishMagickMemory (pfx->Imgs);
845 pfx->random_infos = DestroyRandomInfoTLS (pfx->random_infos);
847 if (pfx->statistics) {
848 for (i = (ssize_t)GetImageListLength(pfx->image); i > 0; i--) {
849 pfx->statistics[i-1]=(
ChannelStatistics *) RelinquishMagickMemory (pfx->statistics[i-1]);
858static ElementTypeE TypeOfOpr (
int op)
860 if (op < oNull)
return etOperator;
861 if (op == oNull)
return etConstant;
862 if (op <= fNull)
return etFunction;
863 if (op <= aNull)
return etImgAttr;
864 if (op <= sNull)
return etSymbol;
865 if (op <= rNull)
return etControl;
867 return (ElementTypeE) 0;
870static char * SetPtrShortExp (
FxInfo * pfx,
char * pExp,
size_t len)
877 *pfx->ShortExp =
'\0';
880 slen = CopyMagickString (pfx->ShortExp, pExp, len);
882 (void) CopyMagickString (pfx->ShortExp+MaxLen,
"...", 4);
884 p = strchr (pfx->ShortExp,
'\n');
885 if (p) (void) CopyMagickString (p,
"...", 4);
886 p = strchr (pfx->ShortExp,
'\r');
887 if (p) (void) CopyMagickString (p,
"...", 4);
889 return pfx->ShortExp;
892static char * SetShortExp (
FxInfo * pfx)
894 return SetPtrShortExp (pfx, pfx->pex, MaxTokenLen-1);
897static int FindUserSymbol (
FxInfo * pfx,
char * name)
904 lenName = strlen (name);
905 for (i=0; i < pfx->usedUserSymbols; i++) {
907 if (lenName == pus->len && LocaleNCompare (name, pus->pex, lenName)==0)
break;
909 if (i == pfx->usedUserSymbols)
return NULL_ADDRESS;
913static MagickBooleanType ExtendUserSymbols (
FxInfo * pfx)
915 pfx->numUserSymbols = (int) ceil (pfx->numUserSymbols * (1 + TableExtend));
916 pfx->UserSymbols = (
UserSymbolT*) ResizeMagickMemory (pfx->UserSymbols, (
size_t) pfx->numUserSymbols *
sizeof(
UserSymbolT));
917 if (!pfx->UserSymbols) {
918 (void) ThrowMagickException (
919 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
921 pfx->numUserSymbols);
928static int AddUserSymbol (
FxInfo * pfx,
char * pex,
size_t len)
931 if (++pfx->usedUserSymbols >= pfx->numUserSymbols) {
932 if (!ExtendUserSymbols (pfx))
return -1;
934 pus = &pfx->UserSymbols[pfx->usedUserSymbols-1];
938 return pfx->usedUserSymbols-1;
941static void DumpTables (FILE * fh)
945 for (i=0; i <= rNull; i++) {
946 const char * str =
"";
947 if ( i < oNull) str = Operators[i].str;
948 if (i >= (
int) FirstFunc && i < fNull) str = Functions[i-(int) FirstFunc].str;
949 if (i >= (
int) FirstImgAttr && i < aNull) str = ImgAttrs[i-(int) FirstImgAttr].str;
950 if (i >= (
int) FirstSym && i < sNull) str = Symbols[i-(int) FirstSym].str;
951 if (i >= (
int) FirstCont && i < rNull) str = Controls[i-(int) FirstCont].str;
952 if (i==0 ) fprintf (stderr,
"Operators:\n ");
953 else if (i==oNull) fprintf (stderr,
"\nFunctions:\n ");
954 else if (i==fNull) fprintf (stderr,
"\nImage attributes:\n ");
955 else if (i==aNull) fprintf (stderr,
"\nSymbols:\n ");
956 else if (i==sNull) fprintf (stderr,
"\nControls:\n ");
957 fprintf (fh,
" %s", str);
962static char * NameOfUserSym (
FxInfo * pfx,
int ndx,
char * buf)
965 assert (ndx >= 0 && ndx < pfx->usedUserSymbols);
966 pus = &pfx->UserSymbols[ndx];
967 (void) CopyMagickString (buf, pus->pex, pus->len+1);
971static void DumpUserSymbols (
FxInfo * pfx, FILE * fh)
973 char UserSym[MagickPathExtent];
975 fprintf (fh,
"UserSymbols (%i)\n", pfx->usedUserSymbols);
976 for (i=0; i < pfx->usedUserSymbols; i++) {
977 fprintf (fh,
" %i: '%s'\n", i, NameOfUserSym (pfx, i, UserSym));
981static MagickBooleanType BuildRPN (
FxInfo * pfx)
983 pfx->numUserSymbols = InitNumUserSymbols;
984 pfx->usedUserSymbols = 0;
985 pfx->UserSymbols = (
UserSymbolT*) AcquireMagickMemory ((
size_t) pfx->numUserSymbols *
sizeof(
UserSymbolT));
986 if (!pfx->UserSymbols) {
987 (void) ThrowMagickException (
988 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
990 pfx->numUserSymbols);
994 pfx->numElements = RpnInit;
995 pfx->usedElements = 0;
996 pfx->Elements = NULL;
998 pfx->Elements = (
ElementT*) AcquireMagickMemory ((
size_t) pfx->numElements *
sizeof(
ElementT));
1000 if (!pfx->Elements) {
1001 (void) ThrowMagickException (
1002 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1008 pfx->usedOprStack = 0;
1009 pfx->maxUsedOprStack = 0;
1010 pfx->numOprStack = InitNumOprStack;
1011 pfx->OperatorStack = (OperatorE*) AcquireMagickMemory ((
size_t) pfx->numOprStack *
sizeof(OperatorE));
1012 if (!pfx->OperatorStack) {
1013 (void) ThrowMagickException (
1014 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1015 "OperatorStack",
"%i",
1023static MagickBooleanType AllocFxRt (
FxInfo * pfx,
fxRtT * pfxrt)
1027 pfxrt->random_info = AcquireRandomInfo ();
1028 pfxrt->thisPixel = NULL;
1030 nRnd = 20 + 10 * (int) GetPseudoRandomValue (pfxrt->random_info);
1031 for (i=0; i < nRnd; i++) (
void) GetPseudoRandomValue (pfxrt->random_info);;
1033 pfxrt->usedValStack = 0;
1034 pfxrt->numValStack = 2 * pfx->maxUsedOprStack;
1035 if (pfxrt->numValStack < MinValStackSize) pfxrt->numValStack = MinValStackSize;
1036 pfxrt->ValStack = (fxFltType*) AcquireMagickMemory ((
size_t) pfxrt->numValStack *
sizeof(fxFltType));
1037 if (!pfxrt->ValStack) {
1038 (void) ThrowMagickException (
1039 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1041 pfxrt->numValStack);
1045 pfxrt->UserSymVals = NULL;
1047 if (pfx->usedUserSymbols) {
1048 pfxrt->UserSymVals = (fxFltType*) AcquireMagickMemory ((
size_t) pfx->usedUserSymbols *
sizeof(fxFltType));
1049 if (!pfxrt->UserSymVals) {
1050 (void) ThrowMagickException (
1051 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1052 "UserSymVals",
"%i",
1053 pfx->usedUserSymbols);
1056 for (i = 0; i < pfx->usedUserSymbols; i++) pfxrt->UserSymVals[i] = (fxFltType) 0;
1062static MagickBooleanType ExtendRPN (
FxInfo * pfx)
1064 pfx->numElements = (int) ceil (pfx->numElements * (1 + TableExtend));
1065 pfx->Elements = (
ElementT*) ResizeMagickMemory (pfx->Elements, (
size_t) pfx->numElements *
sizeof(
ElementT));
1066 if (!pfx->Elements) {
1067 (void) ThrowMagickException (
1068 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1076static inline MagickBooleanType OprInPlace (
int op)
1078 return (op >= oAddEq && op <= oSubSub ? MagickTrue : MagickFalse);
1081static const char * OprStr (
int oprNum)
1084 if (oprNum < 0) str =
"bad OprStr";
1085 else if (oprNum <= oNull) str = Operators[oprNum].str;
1086 else if (oprNum <= fNull) str = Functions[oprNum-(int) FirstFunc].str;
1087 else if (oprNum <= aNull) str = ImgAttrs[oprNum-(int) FirstImgAttr].str;
1088 else if (oprNum <= sNull) str = Symbols[oprNum-(int) FirstSym].str;
1089 else if (oprNum <= rNull) str = Controls[oprNum-(int) FirstCont].str;
1096static MagickBooleanType DumpRPN (
FxInfo * pfx, FILE * fh)
1100 fprintf (fh,
"DumpRPN:");
1101 fprintf (fh,
" numElements=%i", pfx->numElements);
1102 fprintf (fh,
" usedElements=%i", pfx->usedElements);
1103 fprintf (fh,
" maxUsedOprStack=%i", pfx->maxUsedOprStack);
1104 fprintf (fh,
" ImgListLen=%g", (
double) pfx->ImgListLen);
1105 fprintf (fh,
" NeedStats=%s", pfx->NeedStats ?
"yes" :
"no");
1106 fprintf (fh,
" GotStats=%s", pfx->GotStats ?
"yes" :
"no");
1107 fprintf (fh,
" NeedHsl=%s\n", pfx->NeedHsl ?
"yes" :
"no");
1108 if (pfx->runType==rtEntireImage) fprintf (stderr,
"EntireImage");
1109 else if (pfx->runType==rtCornerOnly) fprintf (stderr,
"CornerOnly");
1113 for (i=0; i < pfx->usedElements; i++) {
1114 ElementT * pel = &pfx->Elements[i];
1115 pel->number_dest = 0;
1117 for (i=0; i < pfx->usedElements; i++) {
1118 ElementT * pel = &pfx->Elements[i];
1119 if (pel->operator_index == rGoto || pel->operator_index == rGotoChk || pel->operator_index == rIfZeroGoto || pel->operator_index == rIfNotZeroGoto) {
1120 if (pel->element_index >= 0 && pel->element_index < pfx->numElements) {
1121 ElementT * pelDest = &pfx->Elements[pel->element_index];
1122 pelDest->number_dest++;
1126 for (i=0; i < pfx->usedElements; i++) {
1127 char UserSym[MagickPathExtent];
1129 ElementT * pel = &pfx->Elements[i];
1130 const char * str = OprStr (pel->operator_index);
1131 const char *sRelAbs =
"";
1133 if (pel->operator_index == fP || pel->operator_index == fUP || pel->operator_index == fVP || pel->operator_index == fSP)
1134 sRelAbs = pel->is_relative ?
"[]" :
"{}";
1136 if (pel->type == etColourConstant)
1137 fprintf (fh,
" %i: %s vals=%.*Lg,%.*Lg,%.*Lg '%s%s' nArgs=%i ndx=%i %s",
1138 i, sElementTypes[pel->type],
1139 pfx->precision, pel->val, pfx->precision, pel->val1, pfx->precision, pel->val2,
1140 str, sRelAbs, pel->number_args, pel->element_index,
1141 pel->do_push ?
"push" :
"NO push");
1143 fprintf (fh,
" %i: %s val=%.*Lg '%s%s' nArgs=%i ndx=%i %s",
1144 i, sElementTypes[pel->type], pfx->precision, pel->val, str, sRelAbs,
1145 pel->number_args, pel->element_index,
1146 pel->do_push ?
"push" :
"NO push");
1148 if (pel->img_attr_qual != aNull)
1149 fprintf (fh,
" ia=%s", OprStr((
int) pel->img_attr_qual));
1151 if (pel->channel_qual != NO_CHAN_QUAL) {
1152 if (pel->channel_qual == THIS_CHANNEL) fprintf (stderr,
" ch=this");
1153 else fprintf (stderr,
" ch=%i", pel->channel_qual);
1156 if (pel->operator_index == rCopyTo) {
1157 fprintf (fh,
" CopyTo ==> %s", NameOfUserSym (pfx, pel->element_index, UserSym));
1158 }
else if (pel->operator_index == rCopyFrom) {
1159 fprintf (fh,
" CopyFrom <== %s", NameOfUserSym (pfx, pel->element_index, UserSym));
1160 }
else if (OprInPlace (pel->operator_index)) {
1161 fprintf (fh,
" <==> %s", NameOfUserSym (pfx, pel->element_index, UserSym));
1163 if (pel->number_dest > 0) fprintf (fh,
" <==dest(%i)", pel->number_dest);
1169static void DestroyRPN (
FxInfo * pfx)
1171 pfx->numOprStack = 0;
1172 pfx->usedOprStack = 0;
1173 if (pfx->OperatorStack) pfx->OperatorStack = (OperatorE*) RelinquishMagickMemory (pfx->OperatorStack);
1175 pfx->numElements = 0;
1176 pfx->usedElements = 0;
1177 if (pfx->Elements) pfx->Elements = (
ElementT*) RelinquishMagickMemory (pfx->Elements);
1179 pfx->usedUserSymbols = 0;
1180 if (pfx->UserSymbols) pfx->UserSymbols = (
UserSymbolT*) RelinquishMagickMemory (pfx->UserSymbols);
1183static void DestroyFxRt (
fxRtT * pfxrt)
1185 pfxrt->usedValStack = 0;
1186 if (pfxrt->ValStack) pfxrt->ValStack = (fxFltType*) RelinquishMagickMemory (pfxrt->ValStack);
1187 if (pfxrt->UserSymVals) pfxrt->UserSymVals = (fxFltType*) RelinquishMagickMemory (pfxrt->UserSymVals);
1189 pfxrt->random_info = DestroyRandomInfo (pfxrt->random_info);
1192static size_t GetToken (
FxInfo * pfx)
1203 char * p = pfx->pex;
1207 if (!isalpha((
int)*p))
return 0;
1214 if (LocaleNCompare (p,
"icc-", 4) == 0) {
1217 while (isalpha ((
int)*p)) { len++; p++; }
1218 }
else if (LocaleNCompare (p,
"device-", 7) == 0) {
1221 while (isalpha ((
int)*p)) { len++; p++; }
1223 while (isalpha ((
int)*p)) { len++; p++; }
1224 if (*p ==
'_') { len++; p++; }
1225 while (isalpha ((
int)*p)) { len++; p++; }
1226 while (isdigit ((
int)*p)) { len++; p++; }
1228 if (len >= MaxTokenLen) {
1229 (void) ThrowMagickException (
1230 pfx->exception, GetMagickModule(), OptionError,
1231 "GetToken: too long",
"%g at '%s'",
1232 (
double) len, SetShortExp(pfx));
1236 (void) CopyMagickString (pfx->token, pfx->pex, (len+1<MaxTokenLen)?len+1:MaxTokenLen);
1239 pfx->lenToken = strlen (pfx->token);
1243static MagickBooleanType TokenMaybeUserSymbol (
FxInfo * pfx)
1245 char * p = pfx->token;
1248 if (!isalpha ((
int)*p++))
return MagickFalse;
1251 if (i < 2)
return MagickFalse;
1255static MagickBooleanType AddElement (
FxInfo * pfx, fxFltType val,
int oprNum)
1259 assert (oprNum <= rNull);
1261 if (++pfx->usedElements >= pfx->numElements) {
1262 if (!ExtendRPN (pfx))
return MagickFalse;
1265 pel = &pfx->Elements[pfx->usedElements-1];
1266 pel->type = TypeOfOpr (oprNum);
1268 pel->val1 = (fxFltType) 0;
1269 pel->val2 = (fxFltType) 0;
1270 pel->operator_index = oprNum;
1271 pel->do_push = MagickTrue;
1272 pel->element_index = 0;
1273 pel->channel_qual = NO_CHAN_QUAL;
1274 pel->img_attr_qual = aNull;
1275 pel->number_dest = 0;
1276 pel->exp_start = NULL;
1279 if (oprNum <= oNull) pel->number_args = Operators[oprNum].number_args;
1280 else if (oprNum <= fNull) pel->number_args = Functions[oprNum-(int) FirstFunc].number_args;
1281 else if (oprNum <= aNull) pel->number_args = 0;
1282 else if (oprNum <= sNull) pel->number_args = 0;
1283 else pel->number_args = Controls[oprNum-(int) FirstCont].number_args;
1288static MagickBooleanType AddAddressingElement (
FxInfo * pfx,
int oprNum,
int EleNdx)
1291 if (!AddElement (pfx, (fxFltType) 0, oprNum))
return MagickFalse;
1292 pel = &pfx->Elements[pfx->usedElements-1];
1293 pel->element_index = EleNdx;
1294 if (oprNum == rGoto || oprNum == rGotoChk || oprNum == rIfZeroGoto || oprNum == rIfNotZeroGoto
1295 || oprNum == rZerStk)
1297 pel->do_push = MagickFalse;
1307static MagickBooleanType AddColourElement (
FxInfo * pfx, fxFltType val0, fxFltType val1, fxFltType val2)
1310 if (!AddElement (pfx, val0, oNull))
return MagickFalse;
1311 pel = &pfx->Elements[pfx->usedElements-1];
1314 pel->type = etColourConstant;
1318static inline void SkipSpaces (
FxInfo * pfx)
1320 while (isspace ((
int)*pfx->pex)) pfx->pex++;
1323static inline char PeekChar (
FxInfo * pfx)
1329static inline MagickBooleanType PeekStr (
FxInfo * pfx,
const char * str)
1333 return (LocaleNCompare (pfx->pex, str, strlen(str))==0 ? MagickTrue : MagickFalse);
1336static MagickBooleanType ExpectChar (
FxInfo * pfx,
char c)
1338 if (PeekChar (pfx) != c) {
1339 (void) ThrowMagickException (
1340 pfx->exception, GetMagickModule(), OptionError,
1341 "Expected char",
"'%c' at '%s'", c, SetShortExp (pfx));
1348static int MaybeXYWH (
FxInfo * pfx, ImgAttrE * pop)
1355 if (*pop != aPage && *pop != aPrintsize && *pop != aRes)
return 0;
1357 if (PeekChar (pfx) !=
'.')
return 0;
1359 if (!ExpectChar (pfx,
'.'))
return 0;
1361 (void) GetToken (pfx);
1362 if (LocaleCompare (
"x", pfx->token)==0) ret=1;
1363 else if (LocaleCompare (
"y", pfx->token)==0) ret=2;
1364 else if (LocaleCompare (
"width", pfx->token)==0) ret=3;
1365 else if (LocaleCompare (
"height", pfx->token)==0) ret=4;
1368 (void) ThrowMagickException (
1369 pfx->exception, GetMagickModule(), OptionError,
1370 "Invalid 'x' or 'y' or 'width' or 'height' token=",
"'%s' at '%s'",
1371 pfx->token, SetShortExp(pfx));
1373 if (*pop == aPage) (*pop) = (ImgAttrE) ((
int) *pop + ret);
1376 (void) ThrowMagickException (
1377 pfx->exception, GetMagickModule(), OptionError,
1378 "Invalid 'width' or 'height' token=",
"'%s' at '%s'",
1379 pfx->token, SetShortExp(pfx));
1381 (*pop) = (ImgAttrE) ((
int) *pop + ret);
1384 pfx->pex+=pfx->lenToken;
1389static MagickBooleanType ExtendOperatorStack (
FxInfo * pfx)
1391 pfx->numOprStack = (int) ceil (pfx->numOprStack * (1 + TableExtend));
1392 pfx->OperatorStack = (OperatorE*) ResizeMagickMemory (pfx->OperatorStack, (
size_t) pfx->numOprStack *
sizeof(OperatorE));
1393 if (!pfx->OperatorStack) {
1394 (void) ThrowMagickException (
1395 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1403static MagickBooleanType PushOperatorStack (
FxInfo * pfx,
int op)
1405 if (++pfx->usedOprStack >= pfx->numOprStack) {
1406 if (!ExtendOperatorStack (pfx))
1409 pfx->OperatorStack[pfx->usedOprStack-1] = (OperatorE) op;
1411 if (pfx->maxUsedOprStack < pfx->usedOprStack)
1412 pfx->maxUsedOprStack = pfx->usedOprStack;
1416static OperatorE GetLeadingOp (
FxInfo * pfx)
1418 OperatorE op = oNull;
1420 if (*pfx->pex ==
'-') op = oUnaryMinus;
1421 else if (*pfx->pex ==
'+') op = oUnaryPlus;
1422 else if (*pfx->pex ==
'~') op = oBitNot;
1423 else if (*pfx->pex ==
'!') op = oLogNot;
1424 else if (*pfx->pex ==
'(') op = oOpenParen;
1429static inline MagickBooleanType OprIsUnaryPrefix (OperatorE op)
1431 return (op == oUnaryMinus || op == oUnaryPlus || op == oBitNot || op == oLogNot ? MagickTrue : MagickFalse);
1434static MagickBooleanType TopOprIsUnaryPrefix (
FxInfo * pfx)
1436 if (!pfx->usedOprStack)
return MagickFalse;
1438 return OprIsUnaryPrefix (pfx->OperatorStack[pfx->usedOprStack-1]);
1441static MagickBooleanType PopOprOpenParen (
FxInfo * pfx, OperatorE op)
1444 if (!pfx->usedOprStack)
return MagickFalse;
1446 if (pfx->OperatorStack[pfx->usedOprStack-1] != op)
return MagickFalse;
1448 pfx->usedOprStack--;
1453static int GetCoordQualifier (
FxInfo * pfx,
int op)
1457 if (op != fU && op != fV && op != fS)
return -1;
1459 (void) GetToken (pfx);
1461 if (pfx->lenToken != 1) {
1464 if (*pfx->token !=
'p' && *pfx->token !=
'P')
return -1;
1465 if (!GetFunction (pfx, fP))
return -1;
1470static PixelChannel GetChannelQualifier (
FxInfo * pfx,
int op)
1472 if (op == fU || op == fV || op == fP ||
1473 op == fUP || op == fVP ||
1474 op == fS || (op >= (
int) FirstImgAttr && op <= aNull)
1477 const ChannelT * pch = &Channels[0];
1478 (void) GetToken (pfx);
1481 if (LocaleCompare (pch->str, pfx->token)==0) {
1483 if (op >= (
int) FirstImgAttr && op <= (
int) ((OperatorE)aNull) &&
1484 ChanIsVirtual (pch->pixel_channel)
1487 (void) ThrowMagickException (
1488 pfx->exception, GetMagickModule(), OptionError,
1489 "Can't have image attribute with channel qualifier at",
"'%s' at '%s'",
1490 pfx->token, SetShortExp(pfx));
1491 return NO_CHAN_QUAL;
1494 pfx->pex += pfx->lenToken;
1495 return pch->pixel_channel;
1500 return NO_CHAN_QUAL;
1503static ImgAttrE GetImgAttrToken (
FxInfo * pfx)
1505 ImgAttrE ia = aNull;
1507 for (ia = FirstImgAttr; ia < aNull; ia=(ImgAttrE) (ia+1)) {
1508 iaStr = ImgAttrs[ia-(int) FirstImgAttr].str;
1509 if (LocaleCompare (iaStr, pfx->token)==0) {
1510 pfx->pex += strlen(pfx->token);
1511 if (ImgAttrs[ia-(
int) FirstImgAttr].need_stats != MagickFalse) pfx->NeedStats = MagickTrue;
1512 MaybeXYWH (pfx, &ia);
1517 if (ia == aPage || ia == aPrintsize || ia == aRes) {
1518 (void) ThrowMagickException (
1519 pfx->exception, GetMagickModule(), OptionError,
1520 "Attribute",
"'%s' needs qualifier at '%s'",
1521 iaStr, SetShortExp(pfx));
1527static ImgAttrE GetImgAttrQualifier (
FxInfo * pfx,
int op)
1529 ImgAttrE ia = aNull;
1530 if (op == (OperatorE)fU || op == (OperatorE)fV || op == (OperatorE)fP || op == (OperatorE)fS) {
1531 (void) GetToken (pfx);
1532 if (pfx->lenToken == 0) {
1535 ia = GetImgAttrToken (pfx);
1540static MagickBooleanType IsQualifier (
FxInfo * pfx)
1542 if (PeekChar (pfx) ==
'.') {
1549static MagickBooleanType ParseISO860(
const char* text,
struct tm* tp)
1559 memset(tp,0,
sizeof(
struct tm));
1560 if (sscanf(text,
"%d-%d-%dT%d:%d:%d",&year,&month,&day,&hour,&min,&sec) != 6)
1561 return(MagickFalse);
1562 tp->tm_year=year-1900;
1572static ssize_t GetProperty (
FxInfo * pfx, fxFltType *val, fxFltType *seconds)
1579 if (seconds != NULL) *seconds = SECONDS_ERR;
1581 if (PeekStr (pfx,
"%[")) {
1584 char sProperty [MagickPathExtent];
1585 char * p = pfx->pex + 2;
1589 if (*p ==
'[') level++;
1590 else if (*p ==
']') {
1591 if (level == 0)
break;
1596 if (!*p || level != 0) {
1597 (void) ThrowMagickException (
1598 pfx->exception, GetMagickModule(), OptionError,
1599 "After '%[' expected ']' at",
"'%s'",
1604 len = (size_t) (p - pfx->pex + 1);
1605 if (len > MaxTokenLen) {
1606 (void) ThrowMagickException (
1607 pfx->exception, GetMagickModule(), OptionError,
1608 "Too much text between '%[' and ']' at",
"'%s'",
1613 (void) CopyMagickString (sProperty, pfx->pex, len+1);
1614 sProperty[len] =
'\0';
1618 text = InterpretImageProperties (pfx->image->image_info, pfx->image,
1619 sProperty, pfx->exception);
1620 if (!text || !*text) {
1621 text = DestroyString(text);
1622 (void) ThrowMagickException (
1623 pfx->exception, GetMagickModule(), OptionError,
1624 "Unknown property",
"'%s' at '%s'",
1625 sProperty, SetShortExp(pfx));
1629 if (seconds != NULL) {
1631 if (ParseISO860(text,&tp) == MagickFalse) {
1632 (void) ThrowMagickException (
1633 pfx->exception, GetMagickModule(), OptionError,
1634 "Function 'epoch' expected date property, found ",
"'%s' at '%s'",
1635 text, SetShortExp(pfx));
1636 text = DestroyString(text);
1637 *seconds = SECONDS_ERR;
1640 *seconds = (fxFltType)mktime (&tp);
1643 *val = strtold (text, &tailptr);
1644 if (text == tailptr) {
1645 text = DestroyString(text);
1646 (void) ThrowMagickException (
1647 pfx->exception, GetMagickModule(), OptionError,
1648 "Property",
"'%s' text '%s' is not a number at '%s'",
1649 sProperty, text, SetShortExp(pfx));
1650 text = DestroyString(text);
1654 text = DestroyString(text);
1656 return ((ssize_t) len);
1662static inline ssize_t GetConstantColour (
FxInfo * pfx, fxFltType *v0, fxFltType *v1, fxFltType *v2)
1673 *dummy_exception = AcquireExceptionInfo ();
1683 char ColSp[MagickPathExtent];
1684 (void) CopyMagickString (ColSp, pfx->token, MaxTokenLen);
1685 p = ColSp + pfx->lenToken - 1;
1686 if (*p ==
'a' || *p ==
'A') *p =
'\0';
1688 (void) GetPixelInfo (pfx->image, &colour);
1692 IsGray = (LocaleCompare (ColSp,
"gray") == 0) ? MagickTrue : MagickFalse;
1693 IsIcc = (LocaleCompare (ColSp,
"icc-color") == 0) ? MagickTrue : MagickFalse;
1694 IsDev = (LocaleNCompare (ColSp,
"device-", 7) == 0) ? MagickTrue : MagickFalse;
1698 if (!QueryColorCompliance (pfx->token, AllCompliance, &colour, dummy_exception) || IsGray) {
1699 ssize_t type = ParseCommandOption (MagickColorspaceOptions, MagickFalse, ColSp);
1700 if (type >= 0 || IsIcc || IsDev) {
1701 char * q = pfx->pex + pfx->lenToken;
1702 while (isspace((
int) ((
unsigned char) *q))) q++;
1705 char sFunc[MagickPathExtent];
1706 while (*q && *q !=
')') q++;
1708 (void) ThrowMagickException (
1709 pfx->exception, GetMagickModule(), OptionError,
1710 "constant color missing ')'",
"at '%s'",
1712 dummy_exception = DestroyExceptionInfo (dummy_exception);
1715 lenfun = (size_t) (q - pfx->pex + 1);
1716 if (lenfun > MaxTokenLen) {
1717 (void) ThrowMagickException (
1718 pfx->exception, GetMagickModule(), OptionError,
1719 "lenfun too long",
"'%lu' at '%s'",
1720 (
unsigned long) lenfun, SetShortExp(pfx));
1721 dummy_exception = DestroyExceptionInfo (dummy_exception);
1724 (void) CopyMagickString (sFunc, pfx->pex, lenfun+1);
1725 if (QueryColorCompliance (sFunc, AllCompliance, &colour, dummy_exception)) {
1726 *v0 = QuantumScale*colour.red;
1727 *v1 = QuantumScale*colour.green;
1728 *v2 = QuantumScale*colour.blue;
1729 dummy_exception = DestroyExceptionInfo (dummy_exception);
1730 return (ssize_t)lenfun;
1733 (void) ThrowMagickException (
1734 pfx->exception, GetMagickModule(), OptionError,
1735 "colorspace but not a valid color with '(...)' at",
"'%s'",
1737 dummy_exception = DestroyExceptionInfo (dummy_exception);
1742 dummy_exception = DestroyExceptionInfo (dummy_exception);
1747 *v0 = QuantumScale*colour.red;
1748 *v1 = QuantumScale*colour.green;
1749 *v2 = QuantumScale*colour.blue;
1751 dummy_exception = DestroyExceptionInfo (dummy_exception);
1752 return (ssize_t)strlen (pfx->token);
1755static inline ssize_t GetHexColour (
FxInfo * pfx, fxFltType *v0, fxFltType *v1, fxFltType *v2)
1764 if (*pfx->pex !=
'#')
return 0;
1768 while (isxdigit ((
int)*p)) p++;
1769 if (isalpha ((
int)*p)) {
1770 (void) ThrowMagickException (
1771 pfx->exception, GetMagickModule(), OptionError,
1772 "Bad hex number at",
"'%s'",
1777 len = (size_t) (p - pfx->pex);
1778 if (len < 1)
return 0;
1779 if (len >= MaxTokenLen) {
1780 (void) ThrowMagickException (
1781 pfx->exception, GetMagickModule(), OptionError,
1782 "Hex colour too long at",
"'%s'",
1786 (void) CopyMagickString (pfx->token, pfx->pex, len+1);
1788 (void) GetPixelInfo (pfx->image, &colour);
1790 if (!QueryColorCompliance (pfx->token, AllCompliance, &colour, pfx->exception)) {
1791 (void) ThrowMagickException (
1792 pfx->exception, GetMagickModule(), OptionError,
1793 "QueryColorCompliance rejected",
"'%s' at '%s'",
1794 pfx->token, SetShortExp(pfx));
1798 *v0 = QuantumScale*colour.red;
1799 *v1 = QuantumScale*colour.green;
1800 *v2 = QuantumScale*colour.blue;
1802 return (ssize_t) len;
1805static MagickBooleanType GetFunction (
FxInfo * pfx, FunctionE fe)
1809 const char * funStr = Functions[fe-(int) FirstFunc].str;
1810 int nArgs = Functions[fe-(int) FirstFunc].number_args;
1812 char expChLimit =
')';
1813 const char *strLimit =
",)";
1814 OperatorE pushOp = oOpenParen;
1821 int ndx0 = NULL_ADDRESS, ndx1 = NULL_ADDRESS, ndx2 = NULL_ADDRESS, ndx3 = NULL_ADDRESS;
1823 MagickBooleanType coordQual = MagickFalse;
1824 PixelChannel chQual = NO_CHAN_QUAL;
1825 ImgAttrE iaQual = aNull;
1827 pfx->pex += pfx->lenToken;
1830 char p = PeekChar (pfx);
1832 (void) ExpectChar (pfx,
'{');
1833 pushOp = oOpenBrace;
1837 }
else if (p==
'[') {
1838 (void) ExpectChar (pfx,
'[');
1839 pushOp = oOpenBracket;
1848 }
else if (fe == fU) {
1849 char p = PeekChar (pfx);
1851 (void) ExpectChar (pfx,
'[');
1852 pushOp = oOpenBracket;
1861 }
else if (fe == fV || fe == fS) {
1863 pushOp = oOpenBracket;
1867 if (!ExpectChar (pfx,
'('))
return MagickFalse;
1869 if (!PushOperatorStack (pfx, (
int) pushOp))
return MagickFalse;
1871 pExpStart = pfx->pex;
1872 ndx0 = pfx->usedElements;
1874 (void) AddAddressingElement (pfx, rGoto, NULL_ADDRESS);
1881 lenOptArt = GetProperty (pfx, &val, &seconds);
1882 if (seconds == SECONDS_ERR) {
1884 (void) ThrowMagickException (
1885 pfx->exception, GetMagickModule(), OptionError,
1886 "Function 'epoch' expected date property",
"at '%s'",
1890 if (lenOptArt < 0)
return MagickFalse;
1891 if (lenOptArt > 0) {
1892 (void) AddElement (pfx, seconds, oNull);
1893 pfx->pex += lenOptArt;
1894 if (!ExpectChar (pfx,
')'))
return MagickFalse;
1895 if (!PopOprOpenParen (pfx, pushOp))
return MagickFalse;
1902 if (TranslateStatementList (pfx, strLimit, &chLimit)) {
1906 (void) ThrowMagickException (
1907 pfx->exception, GetMagickModule(), OptionError,
1908 "For function",
"'%s' expected ')' at '%s'",
1909 funStr, SetShortExp(pfx));
1913 if (!chLimit)
break;
1914 if (fe == fP || fe == fS|| fe == fIf) {
1915 (void) AddElement (pfx, (fxFltType) 0, oNull);
1920 if (strchr (strLimit, chLimit)==NULL) {
1921 (void) ThrowMagickException (
1922 pfx->exception, GetMagickModule(), OptionError,
1923 "For function",
"'%s' expected one of '%s' after expression but found '%c' at '%s'",
1924 funStr, strLimit, chLimit ? chLimit :
' ', SetShortExp(pfx));
1933 if (ndx1 != NULL_ADDRESS) {
1934 (void) ThrowMagickException (
1935 pfx->exception, GetMagickModule(), OptionError,
1936 "For function",
"'%s' required argument is missing at '%s'",
1937 funStr, SetShortExp(pfx));
1940 ndx1 = pfx->usedElements;
1941 if (fe==fWhile || fe==fIf) {
1942 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
1943 }
else if (fe==fDo) {
1944 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
1945 }
else if (fe==fFor) {
1946 pfx->Elements[pfx->usedElements-1].do_push = MagickFalse;
1950 if (ndx2 != NULL_ADDRESS) {
1951 (void) ThrowMagickException (
1952 pfx->exception, GetMagickModule(), OptionError,
1953 "For function",
"'%s' required argument is missing at '%s'",
1954 funStr, SetShortExp(pfx));
1957 ndx2 = pfx->usedElements;
1959 pfx->Elements[pfx->usedElements-1].do_push = MagickFalse;
1960 (void) AddAddressingElement (pfx, rGotoChk, ndx0);
1961 }
else if (fe==fDo) {
1962 pfx->Elements[pfx->usedElements-1].do_push = MagickFalse;
1963 (void) AddAddressingElement (pfx, rGotoChk, ndx0 + 1);
1964 }
else if (fe==fFor) {
1965 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
1966 pfx->Elements[pfx->usedElements-1].do_push = MagickTrue;
1967 (void) AddAddressingElement (pfx, rZerStk, NULL_ADDRESS);
1968 }
else if (fe==fIf) {
1969 (void) AddAddressingElement (pfx, rGoto, NULL_ADDRESS);
1973 if (ndx3 != NULL_ADDRESS) {
1974 (void) ThrowMagickException (
1975 pfx->exception, GetMagickModule(), OptionError,
1976 "For function",
"'%s' required argument is missing at '%s'",
1977 funStr, SetShortExp(pfx));
1981 pfx->Elements[pfx->usedElements-1].do_push = MagickFalse;
1982 (void) AddAddressingElement (pfx, rGotoChk, ndx1);
1984 ndx3 = pfx->usedElements;
1989 if (chLimit == expChLimit) {
1990 lenExp = (size_t) (pfx->pex - pExpStart - 1);
1994 if (chLimit && chLimit != expChLimit && chLimit !=
',' ) {
1995 (void) ThrowMagickException (
1996 pfx->exception, GetMagickModule(), OptionError,
1997 "For function",
"'%s' expected '%c', found '%c' at '%s'",
1998 funStr, expChLimit, chLimit ? chLimit :
' ', SetShortExp(pfx));
2002 if (fe == fP || fe == fS || fe == fU || fe == fChannel) {
2003 while (FndArgs < Functions[fe-(
int) FirstFunc].number_args) {
2004 (void) AddElement (pfx, (fxFltType) 0, oNull);
2009 if (FndArgs > Functions[fe-(
int) FirstFunc].number_args)
2012 (void) ThrowMagickException (
2013 pfx->exception, GetMagickModule(), OptionError,
2014 "For function",
"'%s' expected up to %i arguments, found '%i' at '%s'",
2015 funStr, Functions[fe-(
int) FirstFunc].number_args, FndArgs, SetShortExp(pfx));
2017 (void) ThrowMagickException (
2018 pfx->exception, GetMagickModule(), OptionError,
2019 "For function",
"'%s' expected %i arguments, found '%i' at '%s'",
2020 funStr, Functions[fe-(
int) FirstFunc].number_args, FndArgs, SetShortExp(pfx));
2024 if (FndArgs < Functions[fe-(
int) FirstFunc].number_args) {
2025 (void) ThrowMagickException (
2026 pfx->exception, GetMagickModule(), OptionError,
2027 "For function",
"'%s' expected %i arguments, found too few (%i) at '%s'",
2028 funStr, Functions[fe-(
int) FirstFunc].number_args, FndArgs, SetShortExp(pfx));
2031 if (fe != fS && fe != fV && FndArgs == 0 && Functions[fe-(
int) FirstFunc].number_args == 0) {
2033 chLimit = expChLimit;
2034 if (!ExpectChar (pfx,
')'))
return MagickFalse;
2037 if (chLimit != expChLimit) {
2038 (void) ThrowMagickException (
2039 pfx->exception, GetMagickModule(), OptionError,
2040 "For function",
"'%s', arguments don't end with '%c' at '%s'",
2041 funStr, expChLimit, SetShortExp(pfx));
2044 if (!PopOprOpenParen (pfx, pushOp)) {
2045 (void) ThrowMagickException (
2046 pfx->exception, GetMagickModule(), OptionError,
2047 "Bug: For function",
"'%s' tos not '%s' at '%s'",
2048 funStr, Operators[pushOp].str, SetShortExp(pfx));
2052 if (IsQualifier (pfx)) {
2054 if (fe == fU || fe == fV || fe == fS) {
2056 coordQual = (GetCoordQualifier (pfx, (
int) fe) == 1) ? MagickTrue : MagickFalse;
2061 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2062 if (pel->operator_index != fP) {
2063 (void) ThrowMagickException (
2064 pfx->exception, GetMagickModule(), OptionError,
2065 "Bug: For function",
"'%s' last element not 'p' at '%s'",
2066 funStr, SetShortExp(pfx));
2069 chQual = pel->channel_qual;
2070 expChLimit = (pel->is_relative) ?
']' :
'}';
2071 pfx->usedElements--;
2072 if (fe == fU) fe = fUP;
2073 else if (fe == fV) fe = fVP;
2074 else if (fe == fS) fe = fSP;
2075 funStr = Functions[fe-(int) FirstFunc].str;
2079 if ( chQual == NO_CHAN_QUAL &&
2080 (fe == fP || fe == fS || fe == fSP || fe == fU || fe == fUP || fe == fV || fe == fVP)
2083 chQual = GetChannelQualifier (pfx, (
int) fe);
2086 if (chQual == NO_CHAN_QUAL && (fe == fU || fe == fV || fe == fS)) {
2088 iaQual = GetImgAttrQualifier (pfx, (
int) fe);
2090 if (IsQualifier (pfx) && chQual == NO_CHAN_QUAL && iaQual != aNull) {
2091 chQual = GetChannelQualifier (pfx, (
int) fe);
2093 if (coordQual && iaQual != aNull) {
2094 (void) ThrowMagickException (
2095 pfx->exception, GetMagickModule(), OptionError,
2096 "For function",
"'%s', can't have qualifiers 'p' and image attribute '%s' at '%s'",
2097 funStr, pfx->token, SetShortExp(pfx));
2100 if (!coordQual && chQual == NO_CHAN_QUAL && iaQual == aNull) {
2101 (void) ThrowMagickException (
2102 pfx->exception, GetMagickModule(), OptionError,
2103 "For function",
"'%s', bad qualifier '%s' at '%s'",
2104 funStr, pfx->token, SetShortExp(pfx));
2107 if (!coordQual && chQual == CompositePixelChannel && iaQual == aNull) {
2108 (void) ThrowMagickException (
2109 pfx->exception, GetMagickModule(), OptionError,
2110 "For function",
"'%s', bad composite qualifier '%s' at '%s'",
2111 funStr, pfx->token, SetShortExp(pfx));
2115 if (chQual == HUE_CHANNEL || chQual == SAT_CHANNEL || chQual == LIGHT_CHANNEL) {
2116 pfx->NeedHsl = MagickTrue;
2118 if (iaQual >= FirstImgAttr && iaQual < aNull) {
2119 (void) ThrowMagickException (
2120 pfx->exception, GetMagickModule(), OptionError,
2121 "Can't have image attribute with HLS qualifier at",
"'%s'",
2128 if (iaQual != aNull && chQual != NO_CHAN_QUAL) {
2129 if (ImgAttrs[iaQual-(
int) FirstImgAttr].need_stats == MagickFalse) {
2130 (void) ThrowMagickException (
2131 pfx->exception, GetMagickModule(), OptionError,
2132 "Can't have image attribute ",
"'%s' with channel qualifier '%s' at '%s'",
2133 ImgAttrs[iaQual-(
int) FirstImgAttr].str,
2134 pfx->token, SetShortExp(pfx));
2137 if (ChanIsVirtual (chQual)) {
2138 (void) ThrowMagickException (
2139 pfx->exception, GetMagickModule(), OptionError,
2140 "Can't have statistical image attribute ",
"'%s' with virtual channel qualifier '%s' at '%s'",
2141 ImgAttrs[iaQual-(
int) FirstImgAttr].str,
2142 pfx->token, SetShortExp(pfx));
2149 pfx->Elements[ndx1].element_index = ndx2+1;
2150 }
else if (fe==fDo) {
2151 pfx->Elements[ndx0].element_index = ndx1+1;
2152 pfx->Elements[ndx1].element_index = ndx2+1;
2153 }
else if (fe==fFor) {
2154 pfx->Elements[ndx2].element_index = ndx3;
2155 }
else if (fe==fIf) {
2156 pfx->Elements[ndx1].element_index = ndx2 + 1;
2157 pfx->Elements[ndx2].element_index = ndx3;
2159 if (fe == fU && iaQual == aNull) {
2160 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2161 if (pel->type == etConstant && pel->val == 0.0) {
2162 pfx->usedElements--;
2166 (void) AddElement (pfx, (fxFltType) 0, (
int) fe);
2167 if (fe == fP || fe == fU || fe == fU0 || fe == fUP ||
2168 fe == fV || fe == fVP || fe == fS || fe == fSP)
2170 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2171 pel->is_relative = (expChLimit ==
']' ? MagickTrue : MagickFalse);
2172 if (chQual >= 0) pel->channel_qual = chQual;
2173 if (iaQual != aNull && (fe == fU || fe == fV || fe == fS)) {
2175 pel->img_attr_qual = iaQual;
2180 if (pExpStart && lenExp) {
2181 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2182 pel->exp_start = pExpStart;
2183 pel->exp_len = lenExp;
2187 pfx->ContainsDebug = MagickTrue;
2192static MagickBooleanType IsStealth (
int op)
2194 return (op == fU0 || op == fUP || op == fSP || op == fVP ||
2195 (op >= FirstCont && op <= rNull) ? MagickTrue : MagickFalse
2199static MagickBooleanType GetOperand (
2200 FxInfo * pfx, MagickBooleanType * UserSymbol, MagickBooleanType * NewUserSymbol,
int * UserSymNdx,
2201 MagickBooleanType * needPopAll)
2204 *NewUserSymbol = *UserSymbol = MagickFalse;
2205 *UserSymNdx = NULL_ADDRESS;
2208 if (!*pfx->pex)
return MagickFalse;
2209 (void) GetToken (pfx);
2211 if (pfx->lenToken==0) {
2215 OperatorE op = GetLeadingOp (pfx);
2216 if (op==oOpenParen) {
2217 char chLimit =
'\0';
2218 if (!PushOperatorStack (pfx, (
int) op))
return MagickFalse;
2220 if (!TranslateExpression (pfx,
")", &chLimit, needPopAll)) {
2221 (void) ThrowMagickException (
2222 pfx->exception, GetMagickModule(), OptionError,
2223 "Empty expression in parentheses at",
"'%s'",
2227 if (chLimit !=
')') {
2228 (void) ThrowMagickException (
2229 pfx->exception, GetMagickModule(), OptionError,
2230 "'(' but no ')' at",
"'%s'",
2235 if (!PopOprOpenParen (pfx, oOpenParen)) {
2236 (void) ThrowMagickException (
2237 pfx->exception, GetMagickModule(), OptionError,
2238 "Bug: tos not '(' at",
"'%s'",
2243 }
else if (OprIsUnaryPrefix (op)) {
2244 if (!PushOperatorStack (pfx, (
int) op))
return MagickFalse;
2247 if (!*pfx->pex)
return MagickFalse;
2249 if (!GetOperand (pfx, UserSymbol, NewUserSymbol, UserSymNdx, needPopAll)) {
2250 (void) ThrowMagickException (
2251 pfx->exception, GetMagickModule(), OptionError,
2252 "After unary, bad operand at",
"'%s'",
2257 if (*NewUserSymbol) {
2258 (void) ThrowMagickException (
2259 pfx->exception, GetMagickModule(), OptionError,
2260 "After unary, NewUserSymbol at",
"'%s'",
2266 (void) AddAddressingElement (pfx, rCopyFrom, *UserSymNdx);
2267 *UserSymNdx = NULL_ADDRESS;
2269 *UserSymbol = MagickFalse;
2270 *NewUserSymbol = MagickFalse;
2273 (void) GetToken (pfx);
2275 }
else if (*pfx->pex ==
'#') {
2276 fxFltType v0=0, v1=0, v2=0;
2277 ssize_t lenToken = GetHexColour (pfx, &v0, &v1, &v2);
2279 (void) ThrowMagickException (
2280 pfx->exception, GetMagickModule(), OptionError,
2281 "Bad hex number at",
"'%s'",
2284 }
else if (lenToken > 0) {
2285 (void) AddColourElement (pfx, v0, v1, v2);
2296 fxFltType val = strtold (pfx->pex, &tailptr);
2297 if (pfx->pex != tailptr) {
2305 const char Prefixes[] =
"yzafpnum.kMGTPEZY";
2306 const char * pSi = strchr (Prefixes, *tailptr);
2307 if (pSi && *pSi !=
'.') Pow = (double) ((pSi - Prefixes) * 3 - 24);
2308 else if (*tailptr ==
'c') Pow = -2;
2309 else if (*tailptr ==
'h') Pow = 2;
2310 else if (*tailptr ==
'k') Pow = 3;
2312 if (*(++pfx->pex) ==
'i') {
2313 val *= pow (2.0, Pow/0.3);
2316 val *= pow (10.0, Pow);
2320 (void) AddElement (pfx, val, oNull);
2324 val = (fxFltType) 0;
2325 lenOptArt = GetProperty (pfx, &val, NULL);
2326 if (lenOptArt < 0)
return MagickFalse;
2327 if (lenOptArt > 0) {
2328 (void) AddElement (pfx, val, oNull);
2329 pfx->pex += lenOptArt;
2336 if (pfx->lenToken > 0) {
2341 for (ce = (ConstantE)0; ce < cNull; ce=(ConstantE) (ce+1)) {
2342 const char * ceStr = Constants[ce].str;
2343 if (LocaleCompare (ceStr, pfx->token)==0) {
2349 (void) AddElement (pfx, Constants[ce].val, oNull);
2350 pfx->pex += pfx->lenToken;
2359 for (fe = FirstFunc; fe < fNull; fe=(FunctionE) (fe+1)) {
2360 const char * feStr = Functions[fe-(int) FirstFunc].str;
2361 if (LocaleCompare (feStr, pfx->token)==0) {
2366 if (fe == fV && pfx->ImgListLen < 2) {
2367 (void) ThrowMagickException (
2368 pfx->exception, GetMagickModule(), OptionError,
2369 "Symbol 'v' but fewer than two images at",
"'%s'",
2374 if (IsStealth ((
int) fe)) {
2375 (void) ThrowMagickException (
2376 pfx->exception, GetMagickModule(), OptionError,
2377 "Function",
"'%s' not permitted at '%s'",
2378 pfx->token, SetShortExp(pfx));
2381 if (fe == fDo || fe == fFor || fe == fIf || fe == fWhile) {
2382 *needPopAll = MagickTrue;
2385 if (fe != fNull)
return (GetFunction (pfx, fe));
2391 ImgAttrE ia = GetImgAttrToken (pfx);
2394 (void) AddElement (pfx, val, (
int) ia);
2396 if (ImgAttrs[ia-(
int) FirstImgAttr].need_stats != MagickFalse) {
2397 if (IsQualifier (pfx)) {
2398 PixelChannel chQual = GetChannelQualifier (pfx, (
int) ia);
2400 if (chQual == NO_CHAN_QUAL) {
2401 (void) ThrowMagickException (
2402 pfx->exception, GetMagickModule(), OptionError,
2403 "Bad channel qualifier at",
"'%s'",
2408 pel = &pfx->Elements[pfx->usedElements-1];
2409 pel->channel_qual = chQual;
2420 for (se = FirstSym; se < sNull; se=(SymbolE) (se+1)) {
2421 const char * seStr = Symbols[se-(int) FirstSym].str;
2422 if (LocaleCompare (seStr, pfx->token)==0) {
2428 (void) AddElement (pfx, val, (
int) se);
2429 pfx->pex += pfx->lenToken;
2431 if (se==sHue || se==sSaturation || se==sLightness) pfx->NeedHsl = MagickTrue;
2439 fxFltType v0, v1, v2;
2440 ssize_t ColLen = GetConstantColour (pfx, &v0, &v1, &v2);
2441 if (ColLen < 0)
return MagickFalse;
2443 (void) AddColourElement (pfx, v0, v1, v2);
2452 const char *artifact;
2453 artifact = GetImageArtifact (pfx->image, pfx->token);
2454 if (artifact != (
const char *) NULL) {
2456 fxFltType val = strtold (artifact, &tailptr);
2457 if (pfx->token == tailptr) {
2458 (void) ThrowMagickException (
2459 pfx->exception, GetMagickModule(), OptionError,
2460 "Artifact",
"'%s' has value '%s', not a number, at '%s'",
2461 pfx->token, artifact, SetShortExp(pfx));
2464 (void) AddElement (pfx, val, oNull);
2465 pfx->pex+=pfx->lenToken;
2472 if (TokenMaybeUserSymbol (pfx)) {
2473 *UserSymbol = MagickTrue;
2474 *UserSymNdx = FindUserSymbol (pfx, pfx->token);
2475 if (*UserSymNdx == NULL_ADDRESS) {
2476 *UserSymNdx = AddUserSymbol (pfx, pfx->pex, pfx->lenToken);
2477 *NewUserSymbol = MagickTrue;
2480 pfx->pex += pfx->lenToken;
2486 (void) ThrowMagickException (
2487 pfx->exception, GetMagickModule(), OptionError,
2488 "Expected operand at",
"'%s'",
2494static inline MagickBooleanType IsRealOperator (OperatorE op)
2496 return (op < oOpenParen || op > oCloseBrace) ? MagickTrue : MagickFalse;
2499static inline MagickBooleanType ProcessTernaryOpr (
FxInfo * pfx,
TernaryT * ptern)
2504 if (pfx->usedOprStack == 0)
2506 if (pfx->OperatorStack[pfx->usedOprStack-1] == oQuery) {
2507 if (ptern->addr_query != NULL_ADDRESS) {
2508 (void) ThrowMagickException (
2509 pfx->exception, GetMagickModule(), OptionError,
2510 "Already have '?' in sub-expression at",
"'%s'",
2514 if (ptern->addr_colon != NULL_ADDRESS) {
2515 (void) ThrowMagickException (
2516 pfx->exception, GetMagickModule(), OptionError,
2517 "Already have ':' in sub-expression at",
"'%s'",
2521 pfx->usedOprStack--;
2522 ptern->addr_query = pfx->usedElements;
2523 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
2526 else if (pfx->OperatorStack[pfx->usedOprStack-1] == oColon) {
2527 if (ptern->addr_query == NULL_ADDRESS) {
2528 (void) ThrowMagickException (
2529 pfx->exception, GetMagickModule(), OptionError,
2530 "Need '?' in sub-expression at",
"'%s'",
2534 if (ptern->addr_colon != NULL_ADDRESS) {
2535 (void) ThrowMagickException (
2536 pfx->exception, GetMagickModule(), OptionError,
2537 "Already have ':' in sub-expression at",
"'%s'",
2541 pfx->usedOprStack--;
2542 ptern->addr_colon = pfx->usedElements;
2543 pfx->Elements[pfx->usedElements-1].do_push = MagickTrue;
2544 (void) AddAddressingElement (pfx, rGoto, NULL_ADDRESS);
2550static MagickBooleanType GetOperator (
2552 MagickBooleanType * Assign, MagickBooleanType * Update, MagickBooleanType * IncrDecr)
2556 MagickBooleanType DoneIt = MagickFalse;
2558 for (op = (OperatorE)0; op != oNull; op=(OperatorE) (op+1)) {
2559 const char * opStr = Operators[op].str;
2560 len = strlen(opStr);
2561 if (LocaleNCompare (opStr, pfx->pex, len)==0) {
2566 if (!IsRealOperator (op)) {
2567 (void) ThrowMagickException (
2568 pfx->exception, GetMagickModule(), OptionError,
2569 "Not a real operator at",
"'%s'",
2575 (void) ThrowMagickException (
2576 pfx->exception, GetMagickModule(), OptionError,
2577 "Expected operator at",
"'%s'",
2582 *Assign = (op==oAssign) ? MagickTrue : MagickFalse;
2583 *Update = OprInPlace ((
int) op);
2584 *IncrDecr = (op == oPlusPlus || op == oSubSub) ? MagickTrue : MagickFalse;
2591 while (pfx->usedOprStack > 0) {
2592 OperatorE top = pfx->OperatorStack[pfx->usedOprStack-1];
2593 int precTop, precNew;
2594 if (top == oOpenParen || top == oAssign || OprInPlace ((
int) top))
break;
2595 precTop = Operators[top].precedence;
2596 precNew = Operators[op].precedence;
2600 if (precTop < precNew)
break;
2601 (void) AddElement (pfx, (fxFltType) 0, (
int) top);
2602 pfx->usedOprStack--;
2608 if (op==oCloseParen) {
2609 if (pfx->usedOprStack == 0) {
2610 (void) ThrowMagickException (
2611 pfx->exception, GetMagickModule(), OptionError,
2612 "Found ')' but nothing on stack at",
"'%s'",
2617 if (pfx->OperatorStack[pfx->usedOprStack-1] != oOpenParen) {
2618 (void) ThrowMagickException (
2619 pfx->exception, GetMagickModule(), OptionError,
2620 "Found ')' but no '(' on stack at",
"'%s'",
2624 pfx->usedOprStack--;
2625 DoneIt = MagickTrue;
2629 if (!PushOperatorStack (pfx, (
int) op))
return MagickFalse;
2637static MagickBooleanType ResolveTernaryAddresses (
FxInfo * pfx,
TernaryT * ptern)
2639 if (ptern->addr_query == NULL_ADDRESS && ptern->addr_colon == NULL_ADDRESS)
2642 if (ptern->addr_query != NULL_ADDRESS && ptern->addr_colon != NULL_ADDRESS) {
2643 pfx->Elements[ptern->addr_query].element_index = ptern->addr_colon + 1;
2644 pfx->Elements[ptern->addr_colon].element_index = pfx->usedElements;
2645 ptern->addr_query = NULL_ADDRESS;
2646 ptern->addr_colon = NULL_ADDRESS;
2647 }
else if (ptern->addr_query != NULL_ADDRESS) {
2648 (void) ThrowMagickException (
2649 pfx->exception, GetMagickModule(), OptionError,
2650 "'?' with no corresponding ':'",
"'%s' at '%s'",
2651 pfx->token, SetShortExp(pfx));
2653 }
else if (ptern->addr_colon != NULL_ADDRESS) {
2654 (void) ThrowMagickException (
2655 pfx->exception, GetMagickModule(), OptionError,
2656 "':' with no corresponding '?'",
"'%s' at '%s'",
2657 pfx->token, SetShortExp(pfx));
2663static MagickBooleanType TranslateExpression (
2664 FxInfo * pfx,
const char * strLimit,
char * chLimit, MagickBooleanType * needPopAll)
2668 MagickBooleanType UserSymbol, NewUserSymbol;
2669 int UserSymNdx0, UserSymNdx1;
2672 Assign = MagickFalse,
2673 Update = MagickFalse,
2674 IncrDecr = MagickFalse;
2679 ternary.addr_query = NULL_ADDRESS;
2680 ternary.addr_colon = NULL_ADDRESS;
2686 StartEleNdx = pfx->usedElements-1;
2687 if (StartEleNdx < 0) StartEleNdx = 0;
2696 if (strchr(strLimit,*pfx->pex)!=NULL) {
2697 *chLimit = *pfx->pex;
2704 if (!GetOperand (pfx, &UserSymbol, &NewUserSymbol, &UserSymNdx0, needPopAll))
return MagickFalse;
2709 while (*pfx->pex && (!*strLimit || (strchr(strLimit,*pfx->pex)==NULL))) {
2710 if (!GetOperator (pfx, &Assign, &Update, &IncrDecr))
return MagickFalse;
2712 if (NewUserSymbol && !Assign) {
2713 (void) ThrowMagickException (
2714 pfx->exception, GetMagickModule(), OptionError,
2715 "Expected assignment after new UserSymbol",
"'%s' at '%s'",
2716 pfx->token, SetShortExp(pfx));
2719 if (!UserSymbol && Assign) {
2720 (void) ThrowMagickException (
2721 pfx->exception, GetMagickModule(), OptionError,
2722 "Attempted assignment to non-UserSymbol",
"'%s' at '%s'",
2723 pfx->token, SetShortExp(pfx));
2726 if (!UserSymbol && Update) {
2727 (void) ThrowMagickException (
2728 pfx->exception, GetMagickModule(), OptionError,
2729 "Attempted update to non-UserSymbol",
"'%s' at '%s'",
2730 pfx->token, SetShortExp(pfx));
2733 if (UserSymbol && (Assign || Update) && !IncrDecr) {
2735 if (!TranslateExpression (pfx, strLimit, chLimit, needPopAll))
return MagickFalse;
2736 if (!*pfx->pex)
break;
2737 if (!*strLimit)
break;
2738 if (strchr(strLimit,*chLimit)!=NULL)
break;
2740 if (UserSymbol && !Assign && !Update && UserSymNdx0 != NULL_ADDRESS) {
2742 (void) AddAddressingElement (pfx, rCopyFrom, UserSymNdx0);
2743 UserSymNdx0 = NULL_ADDRESS;
2744 pel = &pfx->Elements[pfx->usedElements-1];
2745 pel->do_push = MagickTrue;
2749 while (TopOprIsUnaryPrefix (pfx)) {
2750 OperatorE op = pfx->OperatorStack[pfx->usedOprStack-1];
2751 (void) AddElement (pfx, (fxFltType) 0, (
int) op);
2752 pfx->usedOprStack--;
2756 if (!ProcessTernaryOpr (pfx, &ternary))
return MagickFalse;
2758 if (ternary.addr_colon != NULL_ADDRESS) {
2759 if (!TranslateExpression (pfx,
",);", chLimit, needPopAll))
return MagickFalse;
2763 UserSymbol = NewUserSymbol = MagickFalse;
2765 if ( (!*pfx->pex) || (*strLimit && (strchr(strLimit,*pfx->pex)!=NULL) ) )
2767 if (IncrDecr)
break;
2769 (void) ThrowMagickException (
2770 pfx->exception, GetMagickModule(), OptionError,
2771 "Expected operand after operator",
"at '%s'",
2777 (void) ThrowMagickException (
2778 pfx->exception, GetMagickModule(), OptionError,
2779 "'++' and '--' must be the final operators in an expression at",
"'%s'",
2784 if (!GetOperand (pfx, &UserSymbol, &NewUserSymbol, &UserSymNdx1, needPopAll)) {
2785 (void) ThrowMagickException (
2786 pfx->exception, GetMagickModule(), OptionError,
2787 "Expected operand at",
"'%s'",
2792 if (NewUserSymbol && !Assign) {
2793 (void) ThrowMagickException (
2794 pfx->exception, GetMagickModule(), OptionError,
2795 "NewUserSymbol",
"'%s' after non-assignment operator at '%s'",
2796 pfx->token, SetShortExp(pfx));
2799 if (UserSymbol && !NewUserSymbol) {
2800 (void) AddAddressingElement (pfx, rCopyFrom, UserSymNdx1);
2801 UserSymNdx1 = NULL_ADDRESS;
2803 UserSymNdx0 = UserSymNdx1;
2806 if (UserSymbol && !Assign && !Update && UserSymNdx0 != NULL_ADDRESS) {
2808 if (NewUserSymbol) {
2809 (void) ThrowMagickException (
2810 pfx->exception, GetMagickModule(), OptionError,
2811 "NewUserSymbol",
"'%s' needs assignment operator at '%s'",
2812 pfx->token, SetShortExp(pfx));
2815 (void) AddAddressingElement (pfx, rCopyFrom, UserSymNdx0);
2816 pel = &pfx->Elements[pfx->usedElements-1];
2817 pel->do_push = MagickTrue;
2820 if (*pfx->pex && !*chLimit && (strchr(strLimit,*pfx->pex)!=NULL)) {
2821 *chLimit = *pfx->pex;
2824 while (pfx->usedOprStack) {
2825 OperatorE op = pfx->OperatorStack[pfx->usedOprStack-1];
2826 if (op == oOpenParen || op == oOpenBracket || op == oOpenBrace) {
2829 if ( (op==oAssign && !Assign) || (OprInPlace((
int) op) && !Update) ) {
2832 pfx->usedOprStack--;
2833 (void) AddElement (pfx, (fxFltType) 0, (
int) op);
2834 if (op == oAssign) {
2835 if (UserSymNdx0 < 0) {
2836 (void) ThrowMagickException (
2837 pfx->exception, GetMagickModule(), OptionError,
2838 "Assignment to unknown user symbol at",
"'%s'",
2844 pfx->usedElements--;
2845 (void) AddAddressingElement (pfx, rCopyTo, UserSymNdx0);
2847 }
else if (OprInPlace ((
int) op)) {
2848 if (UserSymNdx0 < 0) {
2849 (void) ThrowMagickException (
2850 pfx->exception, GetMagickModule(), OptionError,
2851 "Operator-in-place to unknown user symbol at",
"'%s'",
2857 pfx->Elements[pfx->usedElements-1].element_index = UserSymNdx0;
2862 if (ternary.addr_query != NULL_ADDRESS) *needPopAll = MagickTrue;
2864 (void) ResolveTernaryAddresses (pfx, &ternary);
2868 if (!pfx->teDepth && *needPopAll) {
2869 (void) AddAddressingElement (pfx, rZerStk, NULL_ADDRESS);
2870 *needPopAll = MagickFalse;
2873 if (pfx->exception->severity >= ErrorException)
2880static MagickBooleanType TranslateStatement (
FxInfo * pfx,
char * strLimit,
char * chLimit)
2882 MagickBooleanType NeedPopAll = MagickFalse;
2886 if (!*pfx->pex)
return MagickFalse;
2888 if (!TranslateExpression (pfx, strLimit, chLimit, &NeedPopAll)) {
2891 if (pfx->usedElements && *chLimit==
';') {
2896 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2897 if (pel->do_push) pel->do_push = MagickFalse;
2903static MagickBooleanType TranslateStatementList (
FxInfo * pfx,
const char * strLimit,
char * chLimit)
2905#define MAX_SLIMIT 10
2906 char sLimits[MAX_SLIMIT];
2909 if (!*pfx->pex)
return MagickFalse;
2910 (void) CopyMagickString (sLimits, strLimit, MAX_SLIMIT-1);
2912 if (strchr(strLimit,
';')==NULL)
2913 (void) ConcatenateMagickString (sLimits,
";", MAX_SLIMIT);
2916 if (!TranslateStatement (pfx, sLimits, chLimit))
return MagickFalse;
2918 if (!*pfx->pex)
break;
2920 if (*chLimit !=
';') {
2925 if (pfx->exception->severity >= ErrorException)
2944 for (ch=0; ch <= (int) MaxPixelChannels; ch++) {
2945 cs[ch].mean *= QuantumScale;
2946 cs[ch].median *= QuantumScale;
2947 cs[ch].maxima *= QuantumScale;
2948 cs[ch].minima *= QuantumScale;
2949 cs[ch].standard_deviation *= QuantumScale;
2955static MagickBooleanType CollectStatistics (
FxInfo * pfx)
2957 Image * img = GetFirstImageInList (pfx->image);
2962 if (!pfx->statistics) {
2963 (void) ThrowMagickException (
2964 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
2965 "Statistics",
"%lu",
2966 (
unsigned long) pfx->ImgListLen);
2971 pfx->statistics[imgNum] = CollectOneImgStats (pfx, img);
2973 if (++imgNum == pfx->ImgListLen)
break;
2974 img = GetNextImageInList (img);
2975 assert (img != (
Image *) NULL);
2977 pfx->GotStats = MagickTrue;
2982static inline MagickBooleanType PushVal (
FxInfo * pfx,
fxRtT * pfxrt, fxFltType val,
int addr)
2984 if (pfxrt->usedValStack >=pfxrt->numValStack) {
2985 (void) ThrowMagickException (
2986 pfx->exception, GetMagickModule(), OptionError,
2987 "ValStack overflow at addr=",
"%i",
2992 pfxrt->ValStack[pfxrt->usedValStack++] = val;
2996static inline fxFltType PopVal (
FxInfo * pfx,
fxRtT * pfxrt,
int addr)
2998 if (pfxrt->usedValStack <= 0) {
2999 (void) ThrowMagickException (
3000 pfx->exception, GetMagickModule(), OptionError,
3001 "ValStack underflow at addr=",
"%i",
3003 return (fxFltType) 0;
3006 return pfxrt->ValStack[--pfxrt->usedValStack];
3009static inline fxFltType ImageStat (
3010 FxInfo * pfx, ssize_t ImgNum, PixelChannel channel, ImgAttrE ia)
3014 MagickBooleanType NeedRelinq = MagickFalse;
3018 (void) ThrowMagickException(pfx->exception,GetMagickModule(),
3019 OptionError,
"NoSuchImage",
"%lu",(
unsigned long) ImgNum);
3023 if (pfx->GotStats) {
3024 if ((channel < 0) || (channel > MaxPixelChannels))
3026 (void) ThrowMagickException(pfx->exception,GetMagickModule(),
3027 OptionError,
"NoSuchImageChannel",
"%i",channel);
3028 channel=(PixelChannel) 0;
3030 cs = pfx->statistics[ImgNum];
3031 }
else if (pfx->NeedStats) {
3033 if ((channel < 0) || (channel > MaxPixelChannels))
3035 (void) ThrowMagickException(pfx->exception,GetMagickModule(),
3036 OptionError,
"NoSuchImageChannel",
"%i",channel);
3037 channel=(PixelChannel) 0;
3039 cs = CollectOneImgStats (pfx, pfx->Images[ImgNum]);
3040 NeedRelinq = MagickTrue;
3045 ret = (fxFltType) GetImageDepth (pfx->Images[ImgNum], pfx->exception);
3048 ret = (fxFltType) GetBlobSize (pfx->image);
3052 ret = cs[channel].kurtosis;
3056 ret = cs[channel].maxima;
3060 ret = cs[channel].mean;
3064 ret = cs[channel].median;
3068 ret = cs[channel].minima;
3074 ret = (fxFltType) pfx->Images[ImgNum]->page.x;
3077 ret = (fxFltType) pfx->Images[ImgNum]->page.y;
3080 ret = (fxFltType) pfx->Images[ImgNum]->page.width;
3083 ret = (fxFltType) pfx->Images[ImgNum]->page.height;
3089 ret = (fxFltType) PerceptibleReciprocal (pfx->Images[ImgNum]->resolution.x)
3090 * pfx->Images[ImgNum]->columns;
3093 ret = (fxFltType) PerceptibleReciprocal (pfx->Images[ImgNum]->resolution.y)
3094 * pfx->Images[ImgNum]->rows;
3097 ret = (fxFltType) pfx->Images[ImgNum]->quality;
3103 ret = pfx->Images[ImgNum]->resolution.x;
3106 ret = pfx->Images[ImgNum]->resolution.y;
3110 ret = cs[channel].skewness;
3114 ret = cs[channel].standard_deviation;
3117 ret = (fxFltType) pfx->Images[ImgNum]->rows;
3120 ret = (fxFltType) pfx->ImgListLen;
3123 ret = (fxFltType) ImgNum;
3126 ret = (fxFltType) pfx->Images[ImgNum]->columns;
3129 ret = (fxFltType) GetImageDepth (pfx->Images[ImgNum], pfx->exception);
3132 (void) ThrowMagickException (pfx->exception,GetMagickModule(),OptionError,
3133 "Unknown ia=",
"%i",ia);
3140static inline fxFltType FxGcd (fxFltType x, fxFltType y,
const size_t depth)
3142#define FxMaxFunctionDepth 200
3145 return (FxGcd (y, x, depth+1));
3146 if ((fabs((
double) y) < 0.001) || (depth >= FxMaxFunctionDepth))
3148 return (FxGcd (y, x-y*floor((
double) (x/y)), depth+1));
3151static inline ssize_t ChkImgNum (
FxInfo * pfx, fxFltType f)
3154 ssize_t i = (ssize_t) floor ((
double) f + 0.5);
3155 if (i < 0) i += (ssize_t) pfx->ImgListLen;
3156 if (i < 0 || i >= (ssize_t) pfx->ImgListLen) {
3157 (void) ThrowMagickException (
3158 pfx->exception, GetMagickModule(), OptionError,
3159 "ImgNum",
"%lu bad for ImgListLen %lu",
3160 (
unsigned long) i, (
unsigned long) pfx->ImgListLen);
3166#define WHICH_ATTR_CHAN \
3167 (pel->channel_qual == NO_CHAN_QUAL) ? CompositePixelChannel : \
3168 (pel->channel_qual == THIS_CHANNEL) ? channel : pel->channel_qual
3170#define WHICH_NON_ATTR_CHAN \
3171 (pel->channel_qual == NO_CHAN_QUAL || \
3172 pel->channel_qual == THIS_CHANNEL || \
3173 pel->channel_qual == CompositePixelChannel \
3174 ) ? (channel == CompositePixelChannel ? RedPixelChannel: channel) \
3177static fxFltType GetHslFlt (
FxInfo * pfx, ssize_t ImgNum,
const fxFltType fx,
const fxFltType fy,
3178 PixelChannel channel)
3180 Image * img = pfx->Images[ImgNum];
3182 double red, green, blue;
3183 double hue=0, saturation=0, lightness=0;
3185 MagickBooleanType okay = MagickTrue;
3186 if(!InterpolatePixelChannel (img, pfx->Imgs[ImgNum].View, RedPixelChannel, img->interpolate,
3187 (
double) fx, (
double) fy, &red, pfx->exception)) okay = MagickFalse;
3188 if(!InterpolatePixelChannel (img, pfx->Imgs[ImgNum].View, GreenPixelChannel, img->interpolate,
3189 (
double) fx, (
double) fy, &green, pfx->exception)) okay = MagickFalse;
3190 if(!InterpolatePixelChannel (img, pfx->Imgs[ImgNum].View, BluePixelChannel, img->interpolate,
3191 (
double) fx, (
double) fy, &blue, pfx->exception)) okay = MagickFalse;
3194 (void) ThrowMagickException (
3195 pfx->exception, GetMagickModule(), OptionError,
3196 "GetHslFlt failure",
"%lu %g,%g %i", (
unsigned long) ImgNum,
3197 (
double) fx, (
double) fy, channel);
3201 &hue, &saturation, &lightness);
3203 if (channel == HUE_CHANNEL)
return hue;
3204 if (channel == SAT_CHANNEL)
return saturation;
3205 if (channel == LIGHT_CHANNEL)
return lightness;
3210static fxFltType GetHslInt (
FxInfo * pfx, ssize_t ImgNum,
const ssize_t imgx,
const ssize_t imgy, PixelChannel channel)
3212 Image * img = pfx->Images[ImgNum];
3214 double hue=0, saturation=0, lightness=0;
3216 const Quantum * p = GetCacheViewVirtualPixels (pfx->Imgs[ImgNum].View, imgx, imgy, 1, 1, pfx->exception);
3217 if (p == (
const Quantum *) NULL)
3219 (void) ThrowMagickException (pfx->exception,GetMagickModule(),
3220 OptionError,
"GetHslInt failure",
"%lu %li,%li %i",(
unsigned long) ImgNum,
3221 (
long) imgx,(
long) imgy,channel);
3226 GetPixelRed (img, p), GetPixelGreen (img, p), GetPixelBlue (img, p),
3227 &hue, &saturation, &lightness);
3229 if (channel == HUE_CHANNEL)
return hue;
3230 if (channel == SAT_CHANNEL)
return saturation;
3231 if (channel == LIGHT_CHANNEL)
return lightness;
3236static inline fxFltType GetIntensity (
FxInfo * pfx, ssize_t ImgNum,
const fxFltType fx,
const fxFltType fy)
3239 quantum_pixel[MaxPixelChannels];
3244 Image * img = pfx->Images[ImgNum];
3246 (void) GetPixelInfo (img, &pixelinf);
3248 if (!InterpolatePixelInfo (img, pfx->Imgs[pfx->ImgNum].View, img->interpolate,
3249 (
double) fx, (
double) fy, &pixelinf, pfx->exception))
3251 (void) ThrowMagickException (
3252 pfx->exception, GetMagickModule(), OptionError,
3253 "GetIntensity failure",
"%lu %g,%g", (
unsigned long) ImgNum,
3254 (
double) fx, (
double) fy);
3257 SetPixelViaPixelInfo (img, &pixelinf, quantum_pixel);
3258 return QuantumScale * GetPixelIntensity (img, quantum_pixel);
3261static MagickBooleanType ExecuteRPN (
FxInfo * pfx,
fxRtT * pfxrt, fxFltType *result,
3262 const PixelChannel channel,
const ssize_t imgx,
const ssize_t imgy)
3264 const Quantum * p = pfxrt->thisPixel;
3265 fxFltType regA=0, regB=0, regC=0, regD=0, regE=0;
3266 Image * img = pfx->image;
3268 MagickBooleanType NeedRelinq = MagickFalse;
3269 double hue=0, saturation=0, lightness=0;
3276 if (!p) p = GetCacheViewVirtualPixels (
3277 pfx->Imgs[pfx->ImgNum].View, imgx, imgy, 1, 1, pfx->exception);
3279 if (p == (
const Quantum *) NULL)
3281 (void) ThrowMagickException (pfx->exception,GetMagickModule(),
3282 OptionError,
"Can't get virtual pixels",
"%lu %li,%li",(
unsigned long)
3283 pfx->ImgNum,(
long) imgx,(
long) imgy);
3284 return(MagickFalse);
3287 if (pfx->GotStats) {
3288 cs = pfx->statistics[pfx->ImgNum];
3289 }
else if (pfx->NeedStats) {
3290 cs = CollectOneImgStats (pfx, pfx->Images[pfx->ImgNum]);
3291 NeedRelinq = MagickTrue;
3298 GetPixelRed (img, p), GetPixelGreen (img, p), GetPixelBlue (img, p),
3299 &hue, &saturation, &lightness);
3302 for (i=0; i < pfx->usedElements; i++) {
3307 (void) ThrowMagickException (
3308 pfx->exception, GetMagickModule(), OptionError,
3309 "Bad run-time address",
"%i", i);
3311 pel=&pfx->Elements[i];
3312 switch (pel->number_args) {
3316 regA = PopVal (pfx, pfxrt, i);
3319 regB = PopVal (pfx, pfxrt, i);
3320 regA = PopVal (pfx, pfxrt, i);
3323 regC = PopVal (pfx, pfxrt, i);
3324 regB = PopVal (pfx, pfxrt, i);
3325 regA = PopVal (pfx, pfxrt, i);
3328 regD = PopVal (pfx, pfxrt, i);
3329 regC = PopVal (pfx, pfxrt, i);
3330 regB = PopVal (pfx, pfxrt, i);
3331 regA = PopVal (pfx, pfxrt, i);
3334 regE = PopVal (pfx, pfxrt, i);
3335 regD = PopVal (pfx, pfxrt, i);
3336 regC = PopVal (pfx, pfxrt, i);
3337 regB = PopVal (pfx, pfxrt, i);
3338 regA = PopVal (pfx, pfxrt, i);
3341 (void) ThrowMagickException (
3342 pfx->exception, GetMagickModule(), OptionError,
3343 "Too many args:",
"%i", pel->number_args);
3347 switch (pel->operator_index) {
3349 regA = (pfxrt->UserSymVals[pel->element_index] += regA);
3352 regA = (pfxrt->UserSymVals[pel->element_index] -= regA);
3355 regA = (pfxrt->UserSymVals[pel->element_index] *= regA);
3358 regA = (pfxrt->UserSymVals[pel->element_index] *= PerceptibleReciprocal((
double)regA));
3361 regA = pfxrt->UserSymVals[pel->element_index]++;
3364 regA = pfxrt->UserSymVals[pel->element_index]--;
3376 regA *= PerceptibleReciprocal((
double)regB);
3379 regA = fmod ((
double) regA, fabs(floor((
double) regB+0.5)));
3388 if ((
size_t) (regB+0.5) >= (8*
sizeof(
size_t)))
3390 (void) ThrowMagickException ( pfx->exception, GetMagickModule(),
3391 OptionError,
"undefined shift",
"%g", (
double) regB);
3392 regA = (fxFltType) 0.0;
3395 regA = (fxFltType) ((
size_t)(regA+0.5) << (
size_t)(regB+0.5));
3398 if ((
size_t) (regB+0.5) >= (8*
sizeof(
size_t)))
3400 (void) ThrowMagickException ( pfx->exception, GetMagickModule(),
3401 OptionError,
"undefined shift",
"%g", (
double) regB);
3402 regA = (fxFltType) 0.0;
3405 regA = (fxFltType) ((
size_t)(regA+0.5) >> (
size_t)(regB+0.5));
3408 regA = fabs((
double) (regA-regB)) < MagickEpsilon ? 1.0 : 0.0;
3411 regA = fabs((
double) (regA-regB)) >= MagickEpsilon ? 1.0 : 0.0;
3414 regA = (regA <= regB) ? 1.0 : 0.0;
3417 regA = (regA >= regB) ? 1.0 : 0.0;
3420 regA = (regA < regB) ? 1.0 : 0.0;
3423 regA = (regA > regB) ? 1.0 : 0.0;
3426 regA = (regA<=0) ? 0.0 : (regB > 0) ? 1.0 : 0.0;
3429 regA = (regA>0) ? 1.0 : (regB > 0.0) ? 1.0 : 0.0;
3432 regA = (regA==0) ? 1.0 : 0.0;
3435 regA = (fxFltType) ((size_t)(regA+0.5) & (size_t)(regB+0.5));
3438 regA = (fxFltType) ((size_t)(regA+0.5) | (size_t)(regB+0.5));
3442 regA = (fxFltType) (~(size_t)(regA+0.5));
3445 regA = pow ((
double) regA, (
double) regB);
3461 if (pel->type == etColourConstant) {
3462 switch (channel) {
default:
3463 case (PixelChannel) 0:
3466 case (PixelChannel) 1:
3469 case (PixelChannel) 2:
3479 regA = fabs ((
double) regA);
3481#if defined(MAGICKCORE_HAVE_ACOSH)
3483 regA = acosh ((
double) regA);
3487 regA = acos ((
double) regA);
3489#if defined(MAGICKCORE_HAVE_J1)
3491 if (regA==0) regA = 1.0;
3493 fxFltType gamma = 2.0 * j1 ((MagickPI*regA)) / (MagickPI*regA);
3494 regA = gamma * gamma;
3499 regA = (fxFltType) (((ssize_t) regA) & 0x01 ? -1.0 : 1.0);
3501#if defined(MAGICKCORE_HAVE_ASINH)
3503 regA = asinh ((
double) regA);
3507 regA = asin ((
double) regA);
3509#if defined(MAGICKCORE_HAVE_ATANH)
3511 regA = atanh ((
double) regA);
3515 regA = atan2 ((
double) regA, (
double) regB);
3518 regA = atan ((
double) regA);
3521 regA = ceil ((
double) regA);
3525 case (PixelChannel) 0:
break;
3526 case (PixelChannel) 1: regA = regB;
break;
3527 case (PixelChannel) 2: regA = regC;
break;
3528 case (PixelChannel) 3: regA = regD;
break;
3529 case (PixelChannel) 4: regA = regE;
break;
3530 default: regA = 0.0;
3534 if (regA < 0) regA = 0.0;
3535 else if (regA > 1.0) regA = 1.0;
3538 regA = cosh ((
double) regA);
3541 regA = cos ((
double) regA);
3546 (void) fprintf (stderr,
"%s[%g,%g].[%i]: %s=%.*g\n",
3547 img->filename, (
double) imgx, (
double) imgy,
3548 channel, SetPtrShortExp (pfx, pel->exp_start, (
size_t) (pel->exp_len+1)),
3549 pfx->precision, (
double) regA);
3552 regA = regA / (regB*(regA-1.0) + 1.0);
3554#if defined(MAGICKCORE_HAVE_ERF)
3556 regA = erf ((
double) regA);
3563 regA = exp ((
double) regA);
3566 regA = floor ((
double) regA);
3569 regA = exp((
double) (-regA*regA/2.0))/sqrt(2.0*MagickPI);
3573 regA = FxGcd (regA, regB, 0);
3576 regA = hypot ((
double) regA, (
double) regB);
3579 regA = floor ((
double) regA);
3582 regA = (fxFltType) (!!IsNaN (regA));
3584#if defined(MAGICKCORE_HAVE_J0)
3586 regA = j0 ((
double) regA);
3589#if defined(MAGICKCORE_HAVE_J1)
3591 regA = j1 ((
double) regA);
3594#if defined(MAGICKCORE_HAVE_J1)
3596 if (regA==0) regA = 1.0;
3597 else regA = 2.0 * j1 ((MagickPI*regA))/(MagickPI*regA);
3601 regA = log ((
double) regA);
3604 regA = MagickLog10((
double) regA) / log10(2.0);
3607 regA = MagickLog10 ((
double) regA);
3610 regA = GetMagickTime ();
3613 regA = (regA > regB) ? regA : regB;
3616 regA = (regA < regB) ? regA : regB;
3619 regA = regA - floor((
double) (regA*PerceptibleReciprocal((
double) regB)))*regB;
3622 regA = (fxFltType) (regA < MagickEpsilon);
3625 regA = pow ((
double) regA, (
double) regB);
3628#if defined(MAGICKCORE_OPENMP_SUPPORT)
3629 #pragma omp critical (MagickCore_ExecuteRPN)
3631 regA = GetPseudoRandomValue (pfxrt->random_info);
3635 regA = floor ((
double) regA + 0.5);
3638 regA = (regA < 0) ? -1.0 : 1.0;
3641 regA = sin ((
double) (MagickPI*regA)) / (MagickPI*regA);
3644 regA = sinh ((
double) regA);
3647 regA = sin ((
double) regA);
3650 regA = sqrt ((
double) regA);
3653 regA = 1.0 / (1.0 + exp ((
double) -regA));
3656 regA = tanh ((
double) regA);
3659 regA = tan ((
double) regA);
3662 if (regA >= 0) regA = floor ((
double) regA);
3663 else regA = ceil ((
double) regA);
3675 ssize_t ImgNum = ChkImgNum (pfx, regA);
3676 if (ImgNum < 0)
break;
3677 regA = (fxFltType) 0;
3679 Image * pimg = pfx->Images[0];
3680 if (pel->img_attr_qual == aNull) {
3681 if ((
int) pel->channel_qual < 0) {
3682 if (pel->channel_qual == NO_CHAN_QUAL || pel->channel_qual == THIS_CHANNEL) {
3683 if (pfx->ImgNum==0) {
3684 regA = QuantumScale * (double) p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3686 const Quantum * pv = GetCacheViewVirtualPixels (
3687 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3689 (void) ThrowMagickException (
3690 pfx->exception, GetMagickModule(), OptionError,
3691 "fU can't get cache",
"%lu", (
unsigned long) ImgNum);
3694 regA = QuantumScale * (double) pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3696 }
else if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL ||
3697 pel->channel_qual == LIGHT_CHANNEL) {
3698 regA = GetHslInt (pfx, ImgNum, imgx, imgy, pel->channel_qual);
3700 }
else if (pel->channel_qual == INTENSITY_CHANNEL) {
3701 regA = GetIntensity (pfx, 0, (
double) imgx, (
double) imgy);
3705 if (pfx->ImgNum==0) {
3706 regA = QuantumScale * (double) p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3708 const Quantum * pv = GetCacheViewVirtualPixels (
3709 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3711 (void) ThrowMagickException (
3712 pfx->exception, GetMagickModule(), OptionError,
3713 "fU can't get cache",
"%lu", (
unsigned long) ImgNum);
3716 regA = QuantumScale * (double) pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3721 regA = ImageStat (pfx, 0, WHICH_ATTR_CHAN, pel->img_attr_qual);
3725 if (pel->img_attr_qual == aNull) {
3727 if ((
int) pel->channel_qual < 0) {
3728 if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL ||
3729 pel->channel_qual == LIGHT_CHANNEL)
3731 regA = GetHslInt (pfx, ImgNum, imgx, imgy, pel->channel_qual);
3733 }
else if (pel->channel_qual == INTENSITY_CHANNEL)
3735 regA = GetIntensity (pfx, ImgNum, (fxFltType) imgx, (fxFltType) imgy);
3740 pv = GetCacheViewVirtualPixels (
3741 pfx->Imgs[ImgNum].View, imgx, imgy, 1,1, pfx->exception);
3743 (void) ThrowMagickException (
3744 pfx->exception, GetMagickModule(), OptionError,
3745 "fU can't get cache",
"%lu", (
unsigned long) ImgNum);
3748 regA = QuantumScale * (double)
3749 pv[pfx->Images[ImgNum]->channel_map[WHICH_NON_ATTR_CHAN].offset];
3751 regA = ImageStat (pfx, ImgNum, WHICH_ATTR_CHAN, pel->img_attr_qual);
3760 Image * pimg = pfx->Images[0];
3761 if ((
int) pel->channel_qual < 0) {
3762 if (pel->channel_qual == NO_CHAN_QUAL || pel->channel_qual == THIS_CHANNEL) {
3764 if (pfx->ImgNum==0) {
3765 regA = QuantumScale * (double) p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3767 const Quantum * pv = GetCacheViewVirtualPixels (
3768 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3770 (void) ThrowMagickException (
3771 pfx->exception, GetMagickModule(), OptionError,
3772 "fU0 can't get cache",
"%i", 0);
3775 regA = QuantumScale * (double) pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3778 }
else if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL ||
3779 pel->channel_qual == LIGHT_CHANNEL) {
3780 regA = GetHslInt (pfx, 0, imgx, imgy, pel->channel_qual);
3782 }
else if (pel->channel_qual == INTENSITY_CHANNEL) {
3783 regA = GetIntensity (pfx, 0, (fxFltType) imgx, (fxFltType) imgy);
3786 if (pfx->ImgNum==0) {
3787 regA = QuantumScale * (double) p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3789 const Quantum * pv = GetCacheViewVirtualPixels (
3790 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3792 (void) ThrowMagickException (
3793 pfx->exception, GetMagickModule(), OptionError,
3794 "fU0 can't get cache",
"%i", 0);
3797 regA = QuantumScale * (double) pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3804 ssize_t ImgNum = ChkImgNum (pfx, regA);
3807 if (ImgNum < 0)
break;
3809 if (pel->is_relative) {
3817 if ((
int) pel->channel_qual < 0) {
3818 if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL
3819 || pel->channel_qual == LIGHT_CHANNEL) {
3820 regA = GetHslFlt (pfx, ImgNum, fx, fy, pel->channel_qual);
3822 }
else if (pel->channel_qual == INTENSITY_CHANNEL) {
3823 regA = GetIntensity (pfx, ImgNum, fx, fy);
3830 Image * imUP = pfx->Images[ImgNum];
3831 if (! InterpolatePixelChannel (imUP, pfx->Imgs[ImgNum].View, WHICH_NON_ATTR_CHAN,
3832 imUP->interpolate, (
double) fx, (
double) fy, &v, pfx->exception))
3834 (void) ThrowMagickException (
3835 pfx->exception, GetMagickModule(), OptionError,
3836 "fUP can't get interpolate",
"%lu", (
unsigned long) ImgNum);
3839 regA = v * QuantumScale;
3848 if (pel->operator_index == fS) ImgNum = pfx->ImgNum;
3850 if (pel->img_attr_qual == aNull) {
3851 const Quantum * pv = GetCacheViewVirtualPixels (
3852 pfx->Imgs[ImgNum].View, imgx, imgy, 1,1, pfx->exception);
3854 (void) ThrowMagickException (
3855 pfx->exception, GetMagickModule(), OptionError,
3856 "fV can't get cache",
"%lu", (
unsigned long) ImgNum);
3860 if ((
int) pel->channel_qual < 0) {
3861 if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL ||
3862 pel->channel_qual == LIGHT_CHANNEL) {
3863 regA = GetHslInt (pfx, ImgNum, imgx, imgy, pel->channel_qual);
3865 }
else if (pel->channel_qual == INTENSITY_CHANNEL) {
3866 regA = GetIntensity (pfx, ImgNum, (
double) imgx, (
double) imgy);
3871 regA = QuantumScale * (double)
3872 pv[pfx->Images[ImgNum]->channel_map[WHICH_NON_ATTR_CHAN].offset];
3874 regA = ImageStat (pfx, ImgNum, WHICH_ATTR_CHAN, pel->img_attr_qual);
3884 ssize_t ImgNum = pfx->ImgNum;
3885 if (pel->operator_index == fVP) ImgNum = 1;
3886 if (pel->is_relative) {
3893 if ((
int) pel->channel_qual < 0) {
3894 if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL ||
3895 pel->channel_qual == LIGHT_CHANNEL) {
3896 regA = GetHslFlt (pfx, ImgNum, fx, fy, pel->channel_qual);
3898 }
else if (pel->channel_qual == INTENSITY_CHANNEL) {
3899 regA = GetIntensity (pfx, ImgNum, fx, fy);
3907 if (! InterpolatePixelChannel (pfx->Images[ImgNum], pfx->Imgs[ImgNum].View,
3908 WHICH_NON_ATTR_CHAN, pfx->Images[ImgNum]->interpolate,
3909 (
double) fx, (
double) fy, &v, pfx->exception)
3912 (void) ThrowMagickException (
3913 pfx->exception, GetMagickModule(), OptionError,
3914 "fSP or fVP can't get interp",
"%lu", (
unsigned long) ImgNum);
3917 regA = v * (fxFltType)QuantumScale;
3925 regA = (fxFltType) GetImageDepth (img, pfx->exception);
3928 regA = (fxFltType) img->extent;
3932 regA = cs[WHICH_ATTR_CHAN].kurtosis;
3936 regA = cs[WHICH_ATTR_CHAN].maxima;
3940 regA = cs[WHICH_ATTR_CHAN].mean;
3944 regA = cs[WHICH_ATTR_CHAN].median;
3948 regA = cs[WHICH_ATTR_CHAN].minima;
3953 regA = (fxFltType) img->page.x;
3956 regA = (fxFltType) img->page.y;
3959 regA = (fxFltType) img->page.width;
3962 regA = (fxFltType) img->page.height;
3967 regA = (fxFltType) PerceptibleReciprocal (img->resolution.x) * img->columns;
3970 regA = (fxFltType) PerceptibleReciprocal (img->resolution.y) * img->rows;
3973 regA = (fxFltType) img->quality;
3978 regA = (fxFltType) img->resolution.x;
3981 regA = (fxFltType) img->resolution.y;
3985 regA = cs[WHICH_ATTR_CHAN].skewness;
3989 regA = cs[WHICH_ATTR_CHAN].standard_deviation;
3992 regA = (fxFltType) img->rows;
3995 regA = (fxFltType) pfx->ImgListLen;
3998 regA = (fxFltType) pfx->ImgNum;
4001 regA = (fxFltType) img->columns;
4004 regA = (fxFltType) GetImageDepth (img, pfx->exception);
4012 regA = GetIntensity (pfx, pfx->ImgNum, (
double) imgx, (
double) imgy);
4019 regA = QuantumScale * (0.212656 * (double) GetPixelRed (img,p) +
4020 0.715158 * (double) GetPixelGreen (img,p) +
4021 0.072186 * (double) GetPixelBlue (img,p));
4027 regA = QuantumScale * (double) GetPixelAlpha (img, p);
4030 regA = QuantumScale * (double) GetPixelBlue (img, p);
4033 regA = QuantumScale * (double) GetPixelCyan (img, p);
4036 regA = QuantumScale * (double) GetPixelGreen (img, p);
4039 regA = (fxFltType) imgx;
4042 regA = (fxFltType) imgy;
4045 regA = QuantumScale * (double) GetPixelBlack (img, p);
4048 regA = QuantumScale * (double) GetPixelGreen (img, p);
4051 regA = QuantumScale * (double) GetPixelAlpha (img, p);
4054 regA = QuantumScale * (double) GetPixelRed (img, p);
4057 regA = QuantumScale * (double) GetPixelYellow (img, p);
4063 assert (pel->element_index >= 0);
4064 i = pel->element_index-1;
4067 assert (pel->element_index >= 0);
4068 i = pel->element_index-1;
4069 if (IsImageTTLExpired(img) != MagickFalse) {
4070 i = pfx->usedElements-1;
4071 (void) ThrowMagickException (pfx->exception, GetMagickModule(),
4072 ResourceLimitFatalError,
"TimeLimitExceeded",
"`%s'", img->filename);
4076 assert (pel->element_index >= 0);
4077 if (fabs((
double) regA) < MagickEpsilon) i = pel->element_index-1;
4079 case rIfNotZeroGoto:
4080 assert (pel->element_index >= 0);
4081 if (fabs((
double) regA) > MagickEpsilon) i = pel->element_index-1;
4084 assert (pel->element_index >= 0);
4085 regA = pfxrt->UserSymVals[pel->element_index];
4088 assert (pel->element_index >= 0);
4089 pfxrt->UserSymVals[pel->element_index] = regA;
4092 pfxrt->usedValStack = 0;
4098 (void) ThrowMagickException (
4099 pfx->exception, GetMagickModule(), OptionError,
4100 "pel->oprNum",
"%i '%s' not yet implemented",
4101 (
int)pel->operator_index, OprStr(pel->operator_index));
4105 if (!PushVal (pfx, pfxrt, regA, i))
break;
4108 if (pfxrt->usedValStack > 0) regA = PopVal (pfx, pfxrt, 9999);
4114 if (pfx->exception->severity >= ErrorException)
4117 if (pfxrt->usedValStack != 0) {
4118 (void) ThrowMagickException (
4119 pfx->exception, GetMagickModule(), OptionError,
4120 "ValStack not empty",
"(%i)", pfxrt->usedValStack);
4129MagickPrivate MagickBooleanType FxEvaluateChannelExpression (
4131 const PixelChannel channel,
const ssize_t x,
const ssize_t y,
4135 id = GetOpenMPThreadId();
4139 assert (pfx != NULL);
4140 assert (pfx->image != NULL);
4141 assert (pfx->Images != NULL);
4142 assert (pfx->Imgs != NULL);
4143 assert (pfx->fxrts != NULL);
4145 pfx->fxrts[id].thisPixel = NULL;
4147 if (!ExecuteRPN (pfx, &pfx->fxrts[
id], &ret, channel, x, y)) {
4148 (void) ThrowMagickException (
4149 exception, GetMagickModule(), OptionError,
4150 "ExecuteRPN failed",
" ");
4154 *result = (double) ret;
4159static FxInfo *AcquireFxInfoPrivate (
const Image * images,
const char * expression,
4164 FxInfo * pfx = (
FxInfo*) AcquireCriticalMemory (
sizeof (*pfx));
4166 memset (pfx, 0,
sizeof (*pfx));
4168 if (!InitFx (pfx, images, CalcAllStats, exception)) {
4169 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4173 if (!BuildRPN (pfx)) {
4174 (void) DeInitFx (pfx);
4175 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4179 if ((*expression ==
'@') && (strlen(expression) > 1))
4180 pfx->expression=FileToString(expression,~0UL,exception);
4181 if (pfx->expression == (
char *) NULL)
4182 pfx->expression=ConstantString(expression);
4183 pfx->pex = (
char *) pfx->expression;
4186 if (!TranslateStatementList (pfx,
";", &chLimit)) {
4187 (void) DestroyRPN (pfx);
4188 pfx->expression = DestroyString (pfx->expression);
4190 (void) DeInitFx (pfx);
4191 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4196 (void) ThrowMagickException (
4197 pfx->exception, GetMagickModule(), OptionError,
4198 "Translate expression depth",
"(%i) not 0",
4201 (void) DestroyRPN (pfx);
4202 pfx->expression = DestroyString (pfx->expression);
4204 (void) DeInitFx (pfx);
4205 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4209 if (chLimit !=
'\0' && chLimit !=
';') {
4210 (void) ThrowMagickException (
4211 pfx->exception, GetMagickModule(), OptionError,
4212 "AcquireFxInfo: TranslateExpression did not exhaust input",
"(chLimit=%i) at'%s'",
4213 (
int)chLimit, pfx->pex);
4215 (void) DestroyRPN (pfx);
4216 pfx->expression = DestroyString (pfx->expression);
4218 (void) DeInitFx (pfx);
4219 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4223 if (pfx->NeedStats && pfx->runType == rtEntireImage && !pfx->statistics) {
4224 if (!CollectStatistics (pfx)) {
4225 (void) DestroyRPN (pfx);
4226 pfx->expression = DestroyString (pfx->expression);
4228 (void) DeInitFx (pfx);
4229 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4234 if (pfx->DebugOpt) {
4235 DumpTables (stderr);
4236 DumpUserSymbols (pfx, stderr);
4237 (void) DumpRPN (pfx, stderr);
4241 size_t number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
4244 pfx->fxrts = (
fxRtT *)AcquireQuantumMemory (number_threads,
sizeof(
fxRtT));
4246 (void) ThrowMagickException (
4247 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
4249 (
unsigned long) number_threads);
4250 (void) DestroyRPN (pfx);
4251 pfx->expression = DestroyString (pfx->expression);
4253 (void) DeInitFx (pfx);
4254 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4257 for (t=0; t < (ssize_t) number_threads; t++) {
4258 if (!AllocFxRt (pfx, &pfx->fxrts[t])) {
4259 (void) ThrowMagickException (
4260 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
4261 "AllocFxRt t=",
"%g",
4265 for (t2 = t-1; t2 >= 0; t2--) {
4266 DestroyFxRt (&pfx->fxrts[t]);
4269 pfx->fxrts = (
fxRtT *) RelinquishMagickMemory (pfx->fxrts);
4270 (void) DestroyRPN (pfx);
4271 pfx->expression = DestroyString (pfx->expression);
4273 (void) DeInitFx (pfx);
4274 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4284 return AcquireFxInfoPrivate (images, expression, MagickFalse, exception);
4291 assert (pfx != NULL);
4292 assert (pfx->image != NULL);
4293 assert (pfx->Images != NULL);
4294 assert (pfx->Imgs != NULL);
4295 assert (pfx->fxrts != NULL);
4297 for (t=0; t < (ssize_t) GetMagickResourceLimit(ThreadResource); t++) {
4298 DestroyFxRt (&pfx->fxrts[t]);
4300 pfx->fxrts = (
fxRtT *) RelinquishMagickMemory (pfx->fxrts);
4304 pfx->expression = DestroyString (pfx->expression);
4307 (void) DeInitFx (pfx);
4309 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4316MagickExport
Image *FxImage(
const Image *image,
const char *expression,
4319#define FxImageTag "FxNew/Image"
4340 assert(image != (
Image *) NULL);
4341 assert(image->signature == MagickCoreSignature);
4342 if (IsEventLogging() != MagickFalse)
4343 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4344 if (expression == (
const char *) NULL)
4345 return(CloneImage(image,0,0,MagickTrue,exception));
4346 fx_image=CloneImage(image,0,0,MagickTrue,exception);
4347 if (!fx_image)
return NULL;
4348 if (SetImageStorageClass(fx_image,DirectClass,exception) == MagickFalse) {
4349 fx_image=DestroyImage(fx_image);
4353 pfx = AcquireFxInfoPrivate (image, expression, MagickTrue, exception);
4356 fx_image=DestroyImage(fx_image);
4360 assert (pfx->image != NULL);
4361 assert (pfx->Images != NULL);
4362 assert (pfx->Imgs != NULL);
4363 assert (pfx->fxrts != NULL);
4367 image_view = AcquireVirtualCacheView (image, pfx->exception);
4368 fx_view = AcquireAuthenticCacheView (fx_image, pfx->exception);
4369#if defined(MAGICKCORE_OPENMP_SUPPORT)
4370 #pragma omp parallel for schedule(dynamic) shared(progress,status) \
4371 magick_number_threads(image,fx_image,fx_image->rows, \
4372 pfx->ContainsDebug ? 0 : 1)
4374 for (y=0; y < (ssize_t) fx_image->rows; y++)
4377 id = GetOpenMPThreadId();
4391 if (status == MagickFalse)
4393 p = GetCacheViewVirtualPixels (image_view, 0, y, image->columns, 1, pfx->exception);
4394 q = QueueCacheViewAuthenticPixels (fx_view, 0, y, fx_image->columns, 1, pfx->exception);
4395 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL)) {
4399 for (x=0; x < (ssize_t) fx_image->columns; x++) {
4402 pfx->fxrts[id].thisPixel = (Quantum *)p;
4404 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4406 PixelChannel channel = GetPixelChannelChannel (image, i);
4407 PixelTrait traits = GetPixelChannelTraits (image, channel);
4408 PixelTrait fx_traits = GetPixelChannelTraits (fx_image, channel);
4409 if ((traits == UndefinedPixelTrait) ||
4410 (fx_traits == UndefinedPixelTrait))
4412 if ((fx_traits & CopyPixelTrait) != 0) {
4413 SetPixelChannel (fx_image, channel, p[i], q);
4417 if (!ExecuteRPN (pfx, &pfx->fxrts[
id], &result, channel, x, y)) {
4422 q[i] = ClampToQuantum ((MagickRealType) (QuantumRange*result));
4424 p+=(ptrdiff_t) GetPixelChannels (image);
4425 q+=(ptrdiff_t) GetPixelChannels (fx_image);
4427 if (SyncCacheViewAuthenticPixels(fx_view, pfx->exception) == MagickFalse)
4429 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4434#if defined(MAGICKCORE_OPENMP_SUPPORT)
4438 proceed = SetImageProgress (image, FxImageTag, progress, image->rows);
4439 if (proceed == MagickFalse)
4444 fx_view = DestroyCacheView (fx_view);
4445 image_view = DestroyCacheView (image_view);
4449 if (pfx->DebugOpt && pfx->usedUserSymbols) {
4451 char UserSym[MagickPathExtent];
4452 fprintf (stderr,
"User symbols (%i):\n", pfx->usedUserSymbols);
4453 for (t=0; t < (int) GetMagickResourceLimit(ThreadResource); t++) {
4454 for (i = 0; i < (int) pfx->usedUserSymbols; i++) {
4455 fprintf (stderr,
"th=%i us=%i '%s': %.*Lg\n",
4456 t, i, NameOfUserSym (pfx, i, UserSym), pfx->precision, pfx->fxrts[t].UserSymVals[i]);
4461 if ((status == MagickFalse) || (pfx->exception->severity >= ErrorException))
4462 fx_image=DestroyImage(fx_image);
4464 pfx=DestroyFxInfo(pfx);