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
111typedef long double fxFltType;
167 {oAddEq,
"+=", 12, 1},
168 {oSubtractEq,
"-=", 12, 1},
169 {oMultiplyEq,
"*=", 13, 1},
170 {oDivideEq,
"/=", 13, 1},
171 {oPlusPlus,
"++", 12, 0},
172 {oSubSub,
"--", 12, 0},
174 {oSubtract,
"-", 12, 2},
175 {oMultiply,
"*", 13, 2},
176 {oDivide,
"/", 13, 2},
177 {oModulus,
"%", 13, 2},
178 {oUnaryPlus,
"+", 14, 1},
179 {oUnaryMinus,
"-", 14, 1},
180 {oLshift,
"<<", 11, 2},
181 {oRshift,
">>", 11, 2},
183 {oNotEq,
"!=", 9, 2},
184 {oLtEq,
"<=", 10, 2},
185 {oGtEq,
">=", 10, 2},
188 {oLogAnd,
"&&", 6, 2},
189 {oLogOr,
"||", 5, 2},
190 {oLogNot,
"!", 16, 1},
191 {oBitAnd,
"&", 8, 2},
193 {oBitNot,
"~", 16, 1},
197 {oOpenParen,
"(", 0, 0},
198 {oCloseParen,
")", 0, 0},
199 {oOpenBracket,
"[", 0, 0},
200 {oCloseBracket,
"]", 0, 0},
201 {oOpenBrace,
"{", 0, 0},
202 {oCloseBrace,
"}", 0, 0},
203 {oAssign,
"=", 3, 1},
204 {oNull,
"onull", 17, 0}
232 {cEpsilon, MagickEpsilon,
"epsilon"},
233 {cE, 2.7182818284590452354,
"e"},
234 {cOpaque, 1.0,
"opaque"},
235 {cPhi, MagickPHI,
"phi"},
236 {cPi, MagickPI,
"pi"},
237 {cQuantumRange, QuantumRange,
"quantumrange"},
238 {cQuantumScale, QuantumScale,
"quantumscale"},
239 {cTransparent, 0.0,
"transparent"},
240 {cMaxRgb, QuantumRange,
"MaxRGB"},
241 {cNull, 0.0,
"cnull"}
244#define FirstFunc ((FunctionE) (oNull+1))
248#if defined(MAGICKCORE_HAVE_ACOSH)
252#if defined(MAGICKCORE_HAVE_J1)
256#if defined(MAGICKCORE_HAVE_ASINH)
260#if defined(MAGICKCORE_HAVE_ATANH)
272#if defined(MAGICKCORE_HAVE_ERF)
282#if defined(MAGICKCORE_HAVE_J0)
285#if defined(MAGICKCORE_HAVE_J1)
288#if defined(MAGICKCORE_HAVE_J1)
339#if defined(MAGICKCORE_HAVE_ACOSH)
340 {fAcosh,
"acosh" , 1},
343#if defined(MAGICKCORE_HAVE_J1)
347#if defined(MAGICKCORE_HAVE_ASINH)
348 {fAsinh,
"asinh" , 1},
351#if defined(MAGICKCORE_HAVE_ATANH)
352 {fAtanh,
"atanh" , 1},
354 {fAtan2,
"atan2" , 2},
357 {fChannel,
"channel", 5},
358 {fClamp,
"clamp" , 1},
361 {fDebug,
"debug" , 1},
363#if defined(MAGICKCORE_HAVE_ERF)
367 {fFloor,
"floor" , 1},
368 {fGauss,
"gauss" , 1},
370 {fHypot,
"hypot" , 2},
372 {fIsnan,
"isnan" , 1},
373#if defined(MAGICKCORE_HAVE_J0)
376#if defined(MAGICKCORE_HAVE_J1)
379#if defined(MAGICKCORE_HAVE_J1)
383 {fLogtwo,
"logtwo", 1},
391 {fRound,
"round" , 1},
397 {fSquish,
"squish", 1},
400 {fTrunc,
"trunc" , 1},
404 {fWhile,
"while", 2},
417#define FirstImgAttr ((ImgAttrE) (fNull+1))
461 {aDepth,
"depth", MagickTrue},
462 {aExtent,
"extent", MagickFalse},
463 {aKurtosis,
"kurtosis", MagickTrue},
464 {aMaxima,
"maxima", MagickTrue},
465 {aMean,
"mean", MagickTrue},
466 {aMedian,
"median", MagickTrue},
467 {aMinima,
"minima", MagickTrue},
468 {aPage,
"page", MagickFalse},
469 {aPageX,
"page.x", MagickFalse},
470 {aPageY,
"page.y", MagickFalse},
471 {aPageWid,
"page.width", MagickFalse},
472 {aPageHt,
"page.height", MagickFalse},
473 {aPrintsize,
"printsize", MagickFalse},
474 {aPrintsizeX,
"printsize.x", MagickFalse},
475 {aPrintsizeY,
"printsize.y", MagickFalse},
476 {aQuality,
"quality", MagickFalse},
477 {aRes,
"resolution", MagickFalse},
478 {aResX,
"resolution.x", MagickFalse},
479 {aResY,
"resolution.y", MagickFalse},
480 {aSkewness,
"skewness", MagickTrue},
481 {aStdDev,
"standard_deviation", MagickTrue},
482 {aH,
"h", MagickFalse},
483 {aN,
"n", MagickFalse},
484 {aT,
"t", MagickFalse},
485 {aW,
"w", MagickFalse},
486 {aZ,
"z", MagickFalse},
487 {aNull,
"anull", MagickFalse},
488 {aNull,
"anull", MagickFalse},
489 {aNull,
"anull", MagickFalse},
490 {aNull,
"anull", MagickFalse}
493#define FirstSym ((SymbolE) (aNull+1))
524static const SymbolT Symbols[] = {
526 {sIntensity,
"intensity"},
527 {sLightness,
"lightness"},
529 {sLuminance,
"luminance"},
530 {sSaturation,
"saturation"},
551#define FirstCont (sNull+1)
578 {rGotoChk,
"gotochk", 0},
579 {rIfZeroGoto,
"ifzerogoto", 1},
580 {rIfNotZeroGoto,
"ifnotzerogoto", 1},
581 {rCopyFrom,
"copyfrom", 0},
582 {rCopyTo,
"copyto", 1},
583 {rZerStk,
"zerstk", 0},
587#define NULL_ADDRESS -2
603#define NO_CHAN_QUAL ((PixelChannel) (-1))
604#define THIS_CHANNEL ((PixelChannel) (-2))
605#define HUE_CHANNEL ((PixelChannel) (-3))
606#define SAT_CHANNEL ((PixelChannel) (-4))
607#define LIGHT_CHANNEL ((PixelChannel) (-5))
608#define INTENSITY_CHANNEL ((PixelChannel) (-6))
611 {
"r", RedPixelChannel},
612 {
"g", GreenPixelChannel},
613 {
"b", BluePixelChannel},
614 {
"c", CyanPixelChannel},
615 {
"m", MagentaPixelChannel},
616 {
"y", YellowPixelChannel},
617 {
"k", BlackPixelChannel},
618 {
"a", AlphaPixelChannel},
619 {
"o", AlphaPixelChannel},
620 {
"hue", HUE_CHANNEL},
621 {
"saturation", SAT_CHANNEL},
622 {
"lightness", LIGHT_CHANNEL},
623 {
"intensity", INTENSITY_CHANNEL},
624 {
"all", CompositePixelChannel},
625 {
"this", THIS_CHANNEL},
649static const char * sElementTypes[] = {
706 fxFltType * ValStack;
707 fxFltType * UserSymVals;
715 MagickBooleanType NeedStats;
716 MagickBooleanType GotStats;
717 MagickBooleanType NeedHsl;
718 MagickBooleanType DebugOpt;
719 MagickBooleanType ContainsDebug;
722 char ShortExp[MagickPathExtent];
724 char token[MagickPathExtent];
735 OperatorE * OperatorStack;
741 **magick_restrict random_infos;
753static MagickBooleanType TranslateStatementList
754 (
FxInfo * pfx,
const char * strLimit,
char * chLimit);
756static MagickBooleanType TranslateExpression
757 (
FxInfo * pfx,
const char * strLimit,
char * chLimit, MagickBooleanType * needPopAll);
759static MagickBooleanType GetFunction (
FxInfo * pfx, FunctionE fe);
761static inline MagickBooleanType ChanIsVirtual (PixelChannel pc)
763 if (pc==HUE_CHANNEL || pc==SAT_CHANNEL || pc==LIGHT_CHANNEL || pc==INTENSITY_CHANNEL)
769static MagickBooleanType InitFx (
FxInfo * pfx,
const Image * img,
775 pfx->ImgListLen = GetImageListLength (img);
776 pfx->ImgNum = GetImageIndexInList (img);
777 pfx->image = (
Image *)img;
779 pfx->NeedStats = MagickFalse;
780 pfx->GotStats = MagickFalse;
781 pfx->NeedHsl = MagickFalse;
782 pfx->DebugOpt = IsStringTrue (GetImageArtifact (img,
"fx:debug"));
783 pfx->statistics = NULL;
786 pfx->exception = exception;
787 pfx->precision = GetMagickPrecision ();
788 pfx->random_infos = AcquireRandomInfoTLS ();
789 pfx->ContainsDebug = MagickFalse;
790 pfx->runType = (CalcAllStats) ? rtEntireImage : rtCornerOnly;
791 pfx->Imgs = (
ImgT *)AcquireQuantumMemory (pfx->ImgListLen, sizeof (
ImgT));
793 (void) ThrowMagickException (
794 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
796 (
unsigned long) pfx->ImgListLen);
800 next = GetFirstImageInList (img);
801 for ( ; next != (
Image *) NULL; next=next->next)
803 ImgT * pimg = &pfx->Imgs[i];
804 pimg->View = AcquireVirtualCacheView (next, pfx->exception);
806 (void) ThrowMagickException (
807 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
811 for ( ; i > 0; i--) {
812 pimg = &pfx->Imgs[i-1];
813 pimg->View = DestroyCacheView (pimg->View);
815 pfx->Imgs=(
ImgT *) RelinquishMagickMemory (pfx->Imgs);
821 pfx->Images = ImageListToArray (img, pfx->exception);
826static MagickBooleanType DeInitFx (
FxInfo * pfx)
830 if (pfx->Images) pfx->Images = (
Image**) RelinquishMagickMemory (pfx->Images);
833 for (i = (ssize_t)GetImageListLength(pfx->image); i > 0; i--) {
834 ImgT * pimg = &pfx->Imgs[i-1];
835 pimg->View = DestroyCacheView (pimg->View);
837 pfx->Imgs=(
ImgT *) RelinquishMagickMemory (pfx->Imgs);
839 pfx->random_infos = DestroyRandomInfoTLS (pfx->random_infos);
841 if (pfx->statistics) {
842 for (i = (ssize_t)GetImageListLength(pfx->image); i > 0; i--) {
843 pfx->statistics[i-1]=(
ChannelStatistics *) RelinquishMagickMemory (pfx->statistics[i-1]);
852static ElementTypeE TypeOfOpr (
int op)
854 if (op < oNull)
return etOperator;
855 if (op == oNull)
return etConstant;
856 if (op <= fNull)
return etFunction;
857 if (op <= aNull)
return etImgAttr;
858 if (op <= sNull)
return etSymbol;
859 if (op <= rNull)
return etControl;
861 return (ElementTypeE) 0;
864static char * SetPtrShortExp (
FxInfo *pfx,
char *pExp,
size_t len)
871 *pfx->ShortExp =
'\0';
874 slen = CopyMagickString(pfx->ShortExp, pExp, MagickPathExtent);
877 (void) CopyMagickString(pfx->ShortExp + MaxLen,
"...", 4);
880 p = strchr(pfx->ShortExp,
'\n');
881 if (p) (void) CopyMagickString(p,
"...", 4);
883 p = strchr(pfx->ShortExp,
'\r');
884 if (p) (void) CopyMagickString(p,
"...", 4);
887 return pfx->ShortExp;
890static char * SetShortExp (
FxInfo * pfx)
892 return SetPtrShortExp (pfx, pfx->pex, MaxTokenLen-1);
895static int FindUserSymbol (
FxInfo * pfx,
char * name)
902 lenName = strlen (name);
903 for (i=0; i < pfx->usedUserSymbols; i++) {
905 if (lenName == pus->len && LocaleNCompare (name, pus->pex, lenName)==0)
break;
907 if (i == pfx->usedUserSymbols)
return NULL_ADDRESS;
911static MagickBooleanType ExtendUserSymbols (
FxInfo * pfx)
913 pfx->numUserSymbols = (int) ceil (pfx->numUserSymbols * (1 + TableExtend));
914 pfx->UserSymbols = (
UserSymbolT*) ResizeMagickMemory (pfx->UserSymbols, (
size_t) pfx->numUserSymbols *
sizeof(
UserSymbolT));
915 if (!pfx->UserSymbols) {
916 (void) ThrowMagickException (
917 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
919 pfx->numUserSymbols);
926static int AddUserSymbol (
FxInfo * pfx,
char * pex,
size_t len)
929 if (++pfx->usedUserSymbols >= pfx->numUserSymbols) {
930 if (!ExtendUserSymbols (pfx))
return -1;
932 pus = &pfx->UserSymbols[pfx->usedUserSymbols-1];
936 return pfx->usedUserSymbols-1;
939static void DumpTables (FILE * fh)
943 for (i=0; i <= rNull; i++) {
944 const char * str =
"";
945 if ( i < oNull) str = Operators[i].str;
946 if (i >= (
int) FirstFunc && i < fNull) str = Functions[i-(int) FirstFunc].str;
947 if (i >= (
int) FirstImgAttr && i < aNull) str = ImgAttrs[i-(
int) FirstImgAttr].str;
948 if (i >= (
int) FirstSym && i < sNull) str = Symbols[i-(
int) FirstSym].str;
949 if (i >= (
int) FirstCont && i < rNull) str = Controls[i-(
int) FirstCont].str;
950 if (i==0 ) fprintf (stderr,
"Operators:\n ");
951 else if (i==oNull) fprintf (stderr,
"\nFunctions:\n ");
952 else if (i==fNull) fprintf (stderr,
"\nImage attributes:\n ");
953 else if (i==aNull) fprintf (stderr,
"\nSymbols:\n ");
954 else if (i==sNull) fprintf (stderr,
"\nControls:\n ");
955 fprintf (fh,
" %s", str);
960static char * NameOfUserSym (
FxInfo * pfx,
int ndx,
char * buf)
963 assert (ndx >= 0 && ndx < pfx->usedUserSymbols);
964 pus = &pfx->UserSymbols[ndx];
965 (void) CopyMagickString (buf, pus->pex, pus->len+1);
969static void DumpUserSymbols (
FxInfo * pfx, FILE * fh)
971 char UserSym[MagickPathExtent];
973 fprintf (fh,
"UserSymbols (%i)\n", pfx->usedUserSymbols);
974 for (i=0; i < pfx->usedUserSymbols; i++) {
975 fprintf (fh,
" %i: '%s'\n", i, NameOfUserSym (pfx, i, UserSym));
979static MagickBooleanType BuildRPN (
FxInfo * pfx)
981 pfx->numUserSymbols = InitNumUserSymbols;
982 pfx->usedUserSymbols = 0;
983 pfx->UserSymbols = (
UserSymbolT*) AcquireMagickMemory ((
size_t) pfx->numUserSymbols *
sizeof(
UserSymbolT));
984 if (!pfx->UserSymbols) {
985 (void) ThrowMagickException (
986 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
988 pfx->numUserSymbols);
992 pfx->numElements = RpnInit;
993 pfx->usedElements = 0;
994 pfx->Elements = NULL;
996 pfx->Elements = (
ElementT*) AcquireMagickMemory ((
size_t) pfx->numElements *
sizeof(
ElementT));
998 if (!pfx->Elements) {
999 (void) ThrowMagickException (
1000 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1006 pfx->usedOprStack = 0;
1007 pfx->maxUsedOprStack = 0;
1008 pfx->numOprStack = InitNumOprStack;
1009 pfx->OperatorStack = (OperatorE*) AcquireMagickMemory ((
size_t) pfx->numOprStack *
sizeof(OperatorE));
1010 if (!pfx->OperatorStack) {
1011 (void) ThrowMagickException (
1012 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1013 "OperatorStack",
"%i",
1021static MagickBooleanType AllocFxRt (
FxInfo * pfx,
fxRtT * pfxrt)
1025 pfxrt->random_info = AcquireRandomInfo ();
1026 pfxrt->thisPixel = NULL;
1028 nRnd = 20 + 10 * (int) GetPseudoRandomValue (pfxrt->random_info);
1029 for (i=0; i < nRnd; i++) (
void) GetPseudoRandomValue (pfxrt->random_info);;
1031 pfxrt->usedValStack = 0;
1032 pfxrt->numValStack = 2 * pfx->maxUsedOprStack;
1033 if (pfxrt->numValStack < MinValStackSize) pfxrt->numValStack = MinValStackSize;
1034 pfxrt->ValStack = (fxFltType*) AcquireMagickMemory ((
size_t) pfxrt->numValStack *
sizeof(fxFltType));
1035 if (!pfxrt->ValStack) {
1036 (void) ThrowMagickException (
1037 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1039 pfxrt->numValStack);
1043 pfxrt->UserSymVals = NULL;
1045 if (pfx->usedUserSymbols) {
1046 pfxrt->UserSymVals = (fxFltType*) AcquireMagickMemory ((
size_t) pfx->usedUserSymbols *
sizeof(fxFltType));
1047 if (!pfxrt->UserSymVals) {
1048 (void) ThrowMagickException (
1049 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1050 "UserSymVals",
"%i",
1051 pfx->usedUserSymbols);
1054 for (i = 0; i < pfx->usedUserSymbols; i++) pfxrt->UserSymVals[i] = (fxFltType) 0;
1060static MagickBooleanType ExtendRPN(
FxInfo * pfx)
1071 element_count=(int) ceil(pfx->numElements*(1+TableExtend));
1072 new_elements=(
ElementT *) AcquireQuantumMemory((
size_t) element_count,
1073 sizeof(*new_elements));
1074 if (new_elements == (
ElementT *) NULL)
1076 (void) ThrowMagickException(pfx->exception,GetMagickModule(),
1077 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
"RPN table");
1078 return(MagickFalse);
1080 (void) memcpy(new_elements,pfx->Elements,(
size_t) pfx->usedElements*
1081 sizeof(*new_elements));
1082 pfx->Elements=(
ElementT *) RelinquishMagickMemory(pfx->Elements);
1083 pfx->Elements=new_elements;
1084 pfx->numElements=element_count;
1087 (void) ThrowMagickException(pfx->exception,GetMagickModule(),
1088 ResourceLimitFatalError,
"Elements",
"%i",pfx->numElements);
1089 return(MagickFalse);
1094static inline MagickBooleanType OprInPlace(
int op)
1096 return(op >= oAddEq && op <= oSubSub ? MagickTrue : MagickFalse);
1099static const char * OprStr (
int oprNum)
1102 if (oprNum < 0) str =
"bad OprStr";
1103 else if (oprNum <= oNull) str = Operators[oprNum].str;
1104 else if (oprNum <= fNull) str = Functions[oprNum-(int) FirstFunc].str;
1105 else if (oprNum <= aNull) str = ImgAttrs[oprNum-(int) FirstImgAttr].str;
1106 else if (oprNum <= sNull) str = Symbols[oprNum-(int) FirstSym].str;
1107 else if (oprNum <= rNull) str = Controls[oprNum-(int) FirstCont].str;
1114static MagickBooleanType DumpRPN (
FxInfo * pfx, FILE * fh)
1118 fprintf (fh,
"DumpRPN:");
1119 fprintf (fh,
" numElements=%i", pfx->numElements);
1120 fprintf (fh,
" usedElements=%i", pfx->usedElements);
1121 fprintf (fh,
" maxUsedOprStack=%i", pfx->maxUsedOprStack);
1122 fprintf (fh,
" ImgListLen=%g", (
double) pfx->ImgListLen);
1123 fprintf (fh,
" NeedStats=%s", pfx->NeedStats ?
"yes" :
"no");
1124 fprintf (fh,
" GotStats=%s", pfx->GotStats ?
"yes" :
"no");
1125 fprintf (fh,
" NeedHsl=%s\n", pfx->NeedHsl ?
"yes" :
"no");
1126 if (pfx->runType==rtEntireImage) fprintf (stderr,
"EntireImage");
1127 else if (pfx->runType==rtCornerOnly) fprintf (stderr,
"CornerOnly");
1131 for (i=0; i < pfx->usedElements; i++) {
1132 ElementT * pel = &pfx->Elements[i];
1133 pel->number_dest = 0;
1135 for (i=0; i < pfx->usedElements; i++) {
1136 ElementT * pel = &pfx->Elements[i];
1137 if (pel->operator_index == rGoto || pel->operator_index == rGotoChk || pel->operator_index == rIfZeroGoto || pel->operator_index == rIfNotZeroGoto) {
1138 if (pel->element_index >= 0 && pel->element_index < pfx->numElements) {
1139 ElementT * pelDest = &pfx->Elements[pel->element_index];
1140 pelDest->number_dest++;
1144 for (i=0; i < pfx->usedElements; i++) {
1145 char UserSym[MagickPathExtent];
1147 ElementT * pel = &pfx->Elements[i];
1148 const char * str = OprStr (pel->operator_index);
1149 const char *sRelAbs =
"";
1151 if (pel->operator_index == fP || pel->operator_index == fUP || pel->operator_index == fVP || pel->operator_index == fSP)
1152 sRelAbs = pel->is_relative ?
"[]" :
"{}";
1154 if (pel->type == etColourConstant)
1155 fprintf (fh,
" %i: %s vals=%.*Lg,%.*Lg,%.*Lg '%s%s' nArgs=%i ndx=%i %s",
1156 i, sElementTypes[pel->type],
1157 pfx->precision, pel->val, pfx->precision, pel->val1, pfx->precision, pel->val2,
1158 str, sRelAbs, pel->number_args, pel->element_index,
1159 pel->do_push ?
"push" :
"NO push");
1161 fprintf (fh,
" %i: %s val=%.*Lg '%s%s' nArgs=%i ndx=%i %s",
1162 i, sElementTypes[pel->type], pfx->precision, pel->val, str, sRelAbs,
1163 pel->number_args, pel->element_index,
1164 pel->do_push ?
"push" :
"NO push");
1166 if (pel->img_attr_qual != aNull)
1167 fprintf (fh,
" ia=%s", OprStr((
int) pel->img_attr_qual));
1169 if (pel->channel_qual != NO_CHAN_QUAL) {
1170 if (pel->channel_qual == THIS_CHANNEL) fprintf (stderr,
" ch=this");
1171 else fprintf (stderr,
" ch=%i", pel->channel_qual);
1174 if (pel->operator_index == rCopyTo) {
1175 fprintf (fh,
" CopyTo ==> %s", NameOfUserSym (pfx, pel->element_index, UserSym));
1176 }
else if (pel->operator_index == rCopyFrom) {
1177 fprintf (fh,
" CopyFrom <== %s", NameOfUserSym (pfx, pel->element_index, UserSym));
1178 }
else if (OprInPlace (pel->operator_index)) {
1179 fprintf (fh,
" <==> %s", NameOfUserSym (pfx, pel->element_index, UserSym));
1181 if (pel->number_dest > 0) fprintf (fh,
" <==dest(%i)", pel->number_dest);
1187static void DestroyRPN (
FxInfo * pfx)
1189 pfx->numOprStack = 0;
1190 pfx->usedOprStack = 0;
1191 if (pfx->OperatorStack) pfx->OperatorStack = (OperatorE*) RelinquishMagickMemory (pfx->OperatorStack);
1193 pfx->numElements = 0;
1194 pfx->usedElements = 0;
1195 if (pfx->Elements) pfx->Elements = (
ElementT*) RelinquishMagickMemory (pfx->Elements);
1197 pfx->usedUserSymbols = 0;
1198 if (pfx->UserSymbols) pfx->UserSymbols = (
UserSymbolT*) RelinquishMagickMemory (pfx->UserSymbols);
1201static void DestroyFxRt (
fxRtT * pfxrt)
1203 pfxrt->usedValStack = 0;
1204 if (pfxrt->ValStack) pfxrt->ValStack = (fxFltType*) RelinquishMagickMemory (pfxrt->ValStack);
1205 if (pfxrt->UserSymVals) pfxrt->UserSymVals = (fxFltType*) RelinquishMagickMemory (pfxrt->UserSymVals);
1207 pfxrt->random_info = DestroyRandomInfo (pfxrt->random_info);
1210static size_t GetToken (
FxInfo * pfx)
1221 char * p = pfx->pex;
1225 if (!isalpha((
int)*p))
return 0;
1232 if (LocaleNCompare (p,
"icc-", 4) == 0) {
1235 while (isalpha ((
int)*p)) { len++; p++; }
1236 }
else if (LocaleNCompare (p,
"device-", 7) == 0) {
1239 while (isalpha ((
int)*p)) { len++; p++; }
1241 while (isalpha ((
int)*p)) { len++; p++; }
1242 if (*p ==
'_') { len++; p++; }
1243 while (isalpha ((
int)*p)) { len++; p++; }
1244 while (isdigit ((
int)*p)) { len++; p++; }
1246 if (len >= MaxTokenLen) {
1247 (void) ThrowMagickException (
1248 pfx->exception, GetMagickModule(), OptionError,
1249 "GetToken: too long",
"%g at '%s'",
1250 (double) len, SetShortExp(pfx));
1254 (void) CopyMagickString (pfx->token, pfx->pex, (len+1<MaxTokenLen)?len+1:MaxTokenLen);
1257 pfx->lenToken = strlen (pfx->token);
1261static MagickBooleanType TokenMaybeUserSymbol (
FxInfo * pfx)
1263 char * p = pfx->token;
1266 if (!isalpha ((
int)*p++))
return MagickFalse;
1269 if (i < 2)
return MagickFalse;
1273static MagickBooleanType AddElement(
FxInfo * pfx,fxFltType val,
int oprNum)
1277 assert (oprNum <= rNull);
1279 if (++pfx->usedElements >= pfx->numElements)
1281 if (ExtendRPN(pfx) == MagickFalse)
1283 pfx->usedElements--;
1284 return(MagickFalse);
1287 if (pfx->Elements == (
ElementT *) NULL)
1289 pfx->usedElements--;
1290 return(MagickFalse);
1292 pel = &pfx->Elements[pfx->usedElements-1];
1293 pel->type = TypeOfOpr (oprNum);
1295 pel->val1 = (fxFltType) 0;
1296 pel->val2 = (fxFltType) 0;
1297 pel->operator_index = oprNum;
1298 pel->do_push = MagickTrue;
1299 pel->element_index = 0;
1300 pel->channel_qual = NO_CHAN_QUAL;
1301 pel->img_attr_qual = aNull;
1302 pel->number_dest = 0;
1303 pel->exp_start = NULL;
1306 if (oprNum <= oNull) pel->number_args = Operators[oprNum].number_args;
1307 else if (oprNum <= fNull) pel->number_args = Functions[oprNum-(int) FirstFunc].number_args;
1308 else if (oprNum <= aNull) pel->number_args = 0;
1309 else if (oprNum <= sNull) pel->number_args = 0;
1310 else pel->number_args = Controls[oprNum-(int) FirstCont].number_args;
1315static MagickBooleanType AddAddressingElement (
FxInfo * pfx,
int oprNum,
int EleNdx)
1318 if (!AddElement (pfx, (fxFltType) 0, oprNum))
return MagickFalse;
1319 pel = &pfx->Elements[pfx->usedElements-1];
1320 pel->element_index = EleNdx;
1321 if (oprNum == rGoto || oprNum == rGotoChk || oprNum == rIfZeroGoto || oprNum == rIfNotZeroGoto
1322 || oprNum == rZerStk)
1324 pel->do_push = MagickFalse;
1334static MagickBooleanType AddColourElement (
FxInfo * pfx, fxFltType val0, fxFltType val1, fxFltType val2)
1337 if (!AddElement (pfx, val0, oNull))
return MagickFalse;
1338 pel = &pfx->Elements[pfx->usedElements-1];
1341 pel->type = etColourConstant;
1345static inline void SkipSpaces (
FxInfo * pfx)
1347 while (isspace ((
int)*pfx->pex)) pfx->pex++;
1350static inline char PeekChar (
FxInfo * pfx)
1356static inline MagickBooleanType PeekStr (
FxInfo * pfx,
const char * str)
1360 return (LocaleNCompare (pfx->pex, str, strlen(str))==0 ? MagickTrue : MagickFalse);
1363static MagickBooleanType ExpectChar (
FxInfo * pfx,
char c)
1365 if (PeekChar (pfx) != c) {
1366 (void) ThrowMagickException (
1367 pfx->exception, GetMagickModule(), OptionError,
1368 "Expected char",
"'%c' at '%s'", c, SetShortExp (pfx));
1375static int MaybeXYWH (
FxInfo * pfx, ImgAttrE * pop)
1382 if (*pop != aPage && *pop != aPrintsize && *pop != aRes)
return 0;
1384 if (PeekChar (pfx) !=
'.')
return 0;
1386 if (!ExpectChar (pfx,
'.'))
return 0;
1388 (void) GetToken (pfx);
1389 if (LocaleCompare (
"x", pfx->token)==0) ret=1;
1390 else if (LocaleCompare (
"y", pfx->token)==0) ret=2;
1391 else if (LocaleCompare (
"width", pfx->token)==0) ret=3;
1392 else if (LocaleCompare (
"height", pfx->token)==0) ret=4;
1395 (void) ThrowMagickException (
1396 pfx->exception, GetMagickModule(), OptionError,
1397 "Invalid 'x' or 'y' or 'width' or 'height' token=",
"'%s' at '%s'",
1398 pfx->token, SetShortExp(pfx));
1400 if (*pop == aPage) (*pop) = (ImgAttrE) ((
int) *pop + ret);
1403 (void) ThrowMagickException (
1404 pfx->exception, GetMagickModule(), OptionError,
1405 "Invalid 'width' or 'height' token=",
"'%s' at '%s'",
1406 pfx->token, SetShortExp(pfx));
1408 (*pop) = (ImgAttrE) ((
int) *pop + ret);
1411 pfx->pex+=pfx->lenToken;
1416static MagickBooleanType ExtendOperatorStack (
FxInfo * pfx)
1418 pfx->numOprStack = (int) ceil (pfx->numOprStack * (1 + TableExtend));
1419 pfx->OperatorStack = (OperatorE*) ResizeMagickMemory (pfx->OperatorStack, (
size_t) pfx->numOprStack *
sizeof(OperatorE));
1420 if (!pfx->OperatorStack) {
1421 (void) ThrowMagickException (
1422 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1430static MagickBooleanType PushOperatorStack (
FxInfo * pfx,
int op)
1432 if (++pfx->usedOprStack >= pfx->numOprStack) {
1433 if (!ExtendOperatorStack (pfx))
1436 pfx->OperatorStack[pfx->usedOprStack-1] = (OperatorE) op;
1438 if (pfx->maxUsedOprStack < pfx->usedOprStack)
1439 pfx->maxUsedOprStack = pfx->usedOprStack;
1443static OperatorE GetLeadingOp (
FxInfo * pfx)
1445 OperatorE op = oNull;
1447 if (*pfx->pex ==
'-') op = oUnaryMinus;
1448 else if (*pfx->pex ==
'+') op = oUnaryPlus;
1449 else if (*pfx->pex ==
'~') op = oBitNot;
1450 else if (*pfx->pex ==
'!') op = oLogNot;
1451 else if (*pfx->pex ==
'(') op = oOpenParen;
1456static inline MagickBooleanType OprIsUnaryPrefix (OperatorE op)
1458 return (op == oUnaryMinus || op == oUnaryPlus || op == oBitNot || op == oLogNot ? MagickTrue : MagickFalse);
1461static MagickBooleanType TopOprIsUnaryPrefix (
FxInfo * pfx)
1463 if (!pfx->usedOprStack)
return MagickFalse;
1465 return OprIsUnaryPrefix (pfx->OperatorStack[pfx->usedOprStack-1]);
1468static MagickBooleanType PopOprOpenParen (
FxInfo * pfx, OperatorE op)
1471 if (!pfx->usedOprStack)
return MagickFalse;
1473 if (pfx->OperatorStack[pfx->usedOprStack-1] != op)
return MagickFalse;
1475 pfx->usedOprStack--;
1480static int GetCoordQualifier (
FxInfo * pfx,
int op)
1484 if (op != fU && op != fV && op != fS)
return -1;
1486 (void) GetToken (pfx);
1488 if (pfx->lenToken != 1) {
1491 if (*pfx->token !=
'p' && *pfx->token !=
'P')
return -1;
1492 if (!GetFunction (pfx, fP))
return -1;
1497static PixelChannel GetChannelQualifier (
FxInfo * pfx,
int op)
1499 if (op == fU || op == fV || op == fP ||
1500 op == fUP || op == fVP ||
1501 op == fS || (op >= (
int) FirstImgAttr && op <= aNull)
1504 const ChannelT * pch = &Channels[0];
1505 (void) GetToken (pfx);
1508 if (LocaleCompare (pch->str, pfx->token)==0) {
1510 if (op >= (
int) FirstImgAttr && op <= (int) ((OperatorE)aNull) &&
1511 ChanIsVirtual (pch->pixel_channel)
1514 (void) ThrowMagickException (
1515 pfx->exception, GetMagickModule(), OptionError,
1516 "Can't have image attribute with channel qualifier at",
"'%s' at '%s'",
1517 pfx->token, SetShortExp(pfx));
1518 return NO_CHAN_QUAL;
1521 pfx->pex += pfx->lenToken;
1522 return pch->pixel_channel;
1527 return NO_CHAN_QUAL;
1530static ImgAttrE GetImgAttrToken (
FxInfo * pfx)
1532 ImgAttrE ia = aNull;
1534 for (ia = FirstImgAttr; ia < aNull; ia=(ImgAttrE) (ia+1)) {
1535 iaStr = ImgAttrs[ia-(int) FirstImgAttr].str;
1536 if (LocaleCompare (iaStr, pfx->token)==0) {
1537 pfx->pex += strlen(pfx->token);
1538 if (ImgAttrs[ia-(
int) FirstImgAttr].need_stats != MagickFalse) pfx->NeedStats = MagickTrue;
1539 MaybeXYWH (pfx, &ia);
1544 if (ia == aPage || ia == aPrintsize || ia == aRes) {
1545 (void) ThrowMagickException (
1546 pfx->exception, GetMagickModule(), OptionError,
1547 "Attribute",
"'%s' needs qualifier at '%s'",
1548 iaStr, SetShortExp(pfx));
1554static ImgAttrE GetImgAttrQualifier (
FxInfo * pfx,
int op)
1556 ImgAttrE ia = aNull;
1557 if (op == (OperatorE)fU || op == (OperatorE)fV || op == (OperatorE)fP || op == (OperatorE)fS) {
1558 (void) GetToken (pfx);
1559 if (pfx->lenToken == 0) {
1562 ia = GetImgAttrToken (pfx);
1567static MagickBooleanType IsQualifier (
FxInfo * pfx)
1569 if (PeekChar (pfx) ==
'.') {
1576static ssize_t GetProperty (
FxInfo * pfx, fxFltType *val)
1582 if (PeekStr (pfx,
"%[")) {
1585 char sProperty [MagickPathExtent];
1586 char * p = pfx->pex + 2;
1590 if (*p ==
'[') level++;
1591 else if (*p ==
']') {
1592 if (level == 0)
break;
1597 if (!*p || level != 0) {
1598 (void) ThrowMagickException (
1599 pfx->exception, GetMagickModule(), OptionError,
1600 "After '%[' expected ']' at",
"'%s'",
1605 len = (size_t) (p - pfx->pex + 1);
1606 if (len > MaxTokenLen) {
1607 (void) ThrowMagickException (
1608 pfx->exception, GetMagickModule(), OptionError,
1609 "Too much text between '%[' and ']' at",
"'%s'",
1614 (void) CopyMagickString (sProperty, pfx->pex, len+1);
1615 sProperty[len] =
'\0';
1619 text = InterpretImageProperties (pfx->image->image_info, pfx->image,
1620 sProperty, pfx->exception);
1621 if (!text || !*text) {
1622 text = DestroyString(text);
1623 (void) ThrowMagickException (
1624 pfx->exception, GetMagickModule(), OptionError,
1625 "Unknown property",
"'%s' at '%s'",
1626 sProperty, SetShortExp(pfx));
1630 *val = strtold (text, &tailptr);
1631 if (text == tailptr) {
1632 text = DestroyString(text);
1633 (void) ThrowMagickException (
1634 pfx->exception, GetMagickModule(), OptionError,
1635 "Property",
"'%s' text '%s' is not a number at '%s'",
1636 sProperty, text, SetShortExp(pfx));
1640 text = DestroyString(text);
1642 return ((ssize_t) len);
1648static inline ssize_t GetConstantColour (
FxInfo * pfx, fxFltType *v0, fxFltType *v1, fxFltType *v2)
1659 *dummy_exception = AcquireExceptionInfo ();
1669 char ColSp[MagickPathExtent];
1670 (void) CopyMagickString (ColSp, pfx->token, MaxTokenLen);
1671 p = ColSp + pfx->lenToken - 1;
1672 if (*p ==
'a' || *p ==
'A') *p =
'\0';
1674 (void) GetPixelInfo (pfx->image, &colour);
1678 IsGray = (LocaleCompare (ColSp,
"gray") == 0) ? MagickTrue : MagickFalse;
1679 IsIcc = (LocaleCompare (ColSp,
"icc-color") == 0) ? MagickTrue : MagickFalse;
1680 IsDev = (LocaleNCompare (ColSp,
"device-", 7) == 0) ? MagickTrue : MagickFalse;
1684 if (!QueryColorCompliance (pfx->token, AllCompliance, &colour, dummy_exception) || IsGray) {
1685 ssize_t type = ParseCommandOption (MagickColorspaceOptions, MagickFalse, ColSp);
1686 if (type >= 0 || IsIcc || IsDev) {
1687 char * q = pfx->pex + pfx->lenToken;
1688 while (isspace((
int) ((
unsigned char) *q))) q++;
1691 char sFunc[MagickPathExtent];
1692 while (*q && *q !=
')') q++;
1694 (void) ThrowMagickException (
1695 pfx->exception, GetMagickModule(), OptionError,
1696 "constant color missing ')'",
"at '%s'",
1698 dummy_exception = DestroyExceptionInfo (dummy_exception);
1701 lenfun = (size_t) (q - pfx->pex + 1);
1702 if (lenfun > MaxTokenLen) {
1703 (void) ThrowMagickException (
1704 pfx->exception, GetMagickModule(), OptionError,
1705 "lenfun too long",
"'%lu' at '%s'",
1706 (
unsigned long) lenfun, SetShortExp(pfx));
1707 dummy_exception = DestroyExceptionInfo (dummy_exception);
1710 (void) CopyMagickString (sFunc, pfx->pex, lenfun+1);
1711 if (QueryColorCompliance (sFunc, AllCompliance, &colour, dummy_exception)) {
1712 *v0 = QuantumScale*colour.red;
1713 *v1 = QuantumScale*colour.green;
1714 *v2 = QuantumScale*colour.blue;
1715 dummy_exception = DestroyExceptionInfo (dummy_exception);
1716 return (ssize_t)lenfun;
1719 (void) ThrowMagickException (
1720 pfx->exception, GetMagickModule(), OptionError,
1721 "colorspace but not a valid color with '(...)' at",
"'%s'",
1723 dummy_exception = DestroyExceptionInfo (dummy_exception);
1728 dummy_exception = DestroyExceptionInfo (dummy_exception);
1733 *v0 = QuantumScale*colour.red;
1734 *v1 = QuantumScale*colour.green;
1735 *v2 = QuantumScale*colour.blue;
1737 dummy_exception = DestroyExceptionInfo (dummy_exception);
1738 return (ssize_t)strlen (pfx->token);
1741static inline ssize_t GetHexColour (
FxInfo * pfx, fxFltType *v0, fxFltType *v1, fxFltType *v2)
1750 if (*pfx->pex !=
'#')
return 0;
1754 while (isxdigit ((
int)*p)) p++;
1755 if (isalpha ((
int)*p)) {
1756 (void) ThrowMagickException (
1757 pfx->exception, GetMagickModule(), OptionError,
1758 "Bad hex number at",
"'%s'",
1763 len = (size_t) (p - pfx->pex);
1764 if (len < 1)
return 0;
1765 if (len >= MaxTokenLen) {
1766 (void) ThrowMagickException (
1767 pfx->exception, GetMagickModule(), OptionError,
1768 "Hex colour too long at",
"'%s'",
1772 (void) CopyMagickString (pfx->token, pfx->pex, len+1);
1774 (void) GetPixelInfo (pfx->image, &colour);
1776 if (!QueryColorCompliance (pfx->token, AllCompliance, &colour, pfx->exception)) {
1777 (void) ThrowMagickException (
1778 pfx->exception, GetMagickModule(), OptionError,
1779 "QueryColorCompliance rejected",
"'%s' at '%s'",
1780 pfx->token, SetShortExp(pfx));
1784 *v0 = QuantumScale*colour.red;
1785 *v1 = QuantumScale*colour.green;
1786 *v2 = QuantumScale*colour.blue;
1788 return (ssize_t) len;
1791static MagickBooleanType GetFunction (
FxInfo * pfx, FunctionE fe)
1795 const char * funStr = Functions[fe-(int) FirstFunc].str;
1796 int nArgs = Functions[fe-(int) FirstFunc].number_args;
1798 char expChLimit =
')';
1799 const char *strLimit =
",)";
1800 OperatorE pushOp = oOpenParen;
1807 int ndx0 = NULL_ADDRESS, ndx1 = NULL_ADDRESS, ndx2 = NULL_ADDRESS, ndx3 = NULL_ADDRESS;
1809 MagickBooleanType coordQual = MagickFalse;
1810 PixelChannel chQual = NO_CHAN_QUAL;
1811 ImgAttrE iaQual = aNull;
1813 pfx->pex += pfx->lenToken;
1816 char p = PeekChar (pfx);
1818 (void) ExpectChar (pfx,
'{');
1819 pushOp = oOpenBrace;
1823 }
else if (p==
'[') {
1824 (void) ExpectChar (pfx,
'[');
1825 pushOp = oOpenBracket;
1834 }
else if (fe == fU) {
1835 char p = PeekChar (pfx);
1837 (void) ExpectChar (pfx,
'[');
1838 pushOp = oOpenBracket;
1847 }
else if (fe == fV || fe == fS) {
1849 pushOp = oOpenBracket;
1853 if (!ExpectChar (pfx,
'('))
return MagickFalse;
1855 if (!PushOperatorStack (pfx, (
int) pushOp))
return MagickFalse;
1857 pExpStart = pfx->pex;
1858 ndx0 = pfx->usedElements;
1860 (void) AddAddressingElement (pfx, rGoto, NULL_ADDRESS);
1864 if (TranslateStatementList (pfx, strLimit, &chLimit)) {
1868 (void) ThrowMagickException (
1869 pfx->exception, GetMagickModule(), OptionError,
1870 "For function",
"'%s' expected ')' at '%s'",
1871 funStr, SetShortExp(pfx));
1875 if (!chLimit)
break;
1876 if (fe == fP || fe == fS|| fe == fIf) {
1877 (void) AddElement (pfx, (fxFltType) 0, oNull);
1882 if (strchr (strLimit, chLimit)==NULL) {
1883 (void) ThrowMagickException (
1884 pfx->exception, GetMagickModule(), OptionError,
1885 "For function",
"'%s' expected one of '%s' after expression but found '%c' at '%s'",
1886 funStr, strLimit, chLimit ? chLimit :
' ', SetShortExp(pfx));
1895 if (ndx1 != NULL_ADDRESS) {
1896 (void) ThrowMagickException (
1897 pfx->exception, GetMagickModule(), OptionError,
1898 "For function",
"'%s' required argument is missing at '%s'",
1899 funStr, SetShortExp(pfx));
1902 ndx1 = pfx->usedElements;
1903 if (fe==fWhile || fe==fIf) {
1904 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
1905 }
else if (fe==fDo) {
1906 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
1907 }
else if (fe==fFor) {
1908 pfx->Elements[pfx->usedElements-1].do_push = MagickFalse;
1912 if (ndx2 != NULL_ADDRESS) {
1913 (void) ThrowMagickException (
1914 pfx->exception, GetMagickModule(), OptionError,
1915 "For function",
"'%s' required argument is missing at '%s'",
1916 funStr, SetShortExp(pfx));
1919 ndx2 = pfx->usedElements;
1921 pfx->Elements[pfx->usedElements-1].do_push = MagickFalse;
1922 (void) AddAddressingElement (pfx, rGotoChk, ndx0);
1923 }
else if (fe==fDo) {
1924 pfx->Elements[pfx->usedElements-1].do_push = MagickFalse;
1925 (void) AddAddressingElement (pfx, rGotoChk, ndx0 + 1);
1926 }
else if (fe==fFor) {
1927 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
1928 pfx->Elements[pfx->usedElements-1].do_push = MagickTrue;
1929 (void) AddAddressingElement (pfx, rZerStk, NULL_ADDRESS);
1930 }
else if (fe==fIf) {
1931 (void) AddAddressingElement (pfx, rGoto, NULL_ADDRESS);
1935 if (ndx3 != NULL_ADDRESS) {
1936 (void) ThrowMagickException (
1937 pfx->exception, GetMagickModule(), OptionError,
1938 "For function",
"'%s' required argument is missing at '%s'",
1939 funStr, SetShortExp(pfx));
1943 pfx->Elements[pfx->usedElements-1].do_push = MagickFalse;
1944 (void) AddAddressingElement (pfx, rGotoChk, ndx1);
1946 ndx3 = pfx->usedElements;
1951 if (chLimit == expChLimit) {
1952 lenExp = (size_t) (pfx->pex - pExpStart - 1);
1956 if (chLimit && chLimit != expChLimit && chLimit !=
',' ) {
1957 (void) ThrowMagickException (
1958 pfx->exception, GetMagickModule(), OptionError,
1959 "For function",
"'%s' expected '%c', found '%c' at '%s'",
1960 funStr, expChLimit, chLimit ? chLimit :
' ', SetShortExp(pfx));
1964 if (fe == fP || fe == fS || fe == fU || fe == fChannel) {
1965 while (FndArgs < Functions[fe-(
int) FirstFunc].number_args) {
1966 (void) AddElement (pfx, (fxFltType) 0, oNull);
1971 if (FndArgs > Functions[fe-(
int) FirstFunc].number_args)
1974 (void) ThrowMagickException (
1975 pfx->exception, GetMagickModule(), OptionError,
1976 "For function",
"'%s' expected up to %i arguments, found '%i' at '%s'",
1977 funStr, Functions[fe-(int) FirstFunc].number_args, FndArgs, SetShortExp(pfx));
1979 (void) ThrowMagickException (
1980 pfx->exception, GetMagickModule(), OptionError,
1981 "For function",
"'%s' expected %i arguments, found '%i' at '%s'",
1982 funStr, Functions[fe-(int) FirstFunc].number_args, FndArgs, SetShortExp(pfx));
1986 if (FndArgs < Functions[fe-(
int) FirstFunc].number_args) {
1987 (void) ThrowMagickException (
1988 pfx->exception, GetMagickModule(), OptionError,
1989 "For function",
"'%s' expected %i arguments, found too few (%i) at '%s'",
1990 funStr, Functions[fe-(int) FirstFunc].number_args, FndArgs, SetShortExp(pfx));
1993 if (fe != fS && fe != fV && FndArgs == 0 && Functions[fe-(
int) FirstFunc].number_args == 0) {
1995 chLimit = expChLimit;
1996 if (!ExpectChar (pfx,
')'))
return MagickFalse;
1999 if (chLimit != expChLimit) {
2000 (void) ThrowMagickException (
2001 pfx->exception, GetMagickModule(), OptionError,
2002 "For function",
"'%s', arguments don't end with '%c' at '%s'",
2003 funStr, expChLimit, SetShortExp(pfx));
2006 if (!PopOprOpenParen (pfx, pushOp)) {
2007 (void) ThrowMagickException (
2008 pfx->exception, GetMagickModule(), OptionError,
2009 "Bug: For function",
"'%s' tos not '%s' at '%s'",
2010 funStr, Operators[pushOp].str, SetShortExp(pfx));
2014 if (IsQualifier (pfx)) {
2016 if (fe == fU || fe == fV || fe == fS) {
2018 coordQual = (GetCoordQualifier (pfx, (
int) fe) == 1) ? MagickTrue : MagickFalse;
2023 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2024 if (pel->operator_index != fP) {
2025 (void) ThrowMagickException (
2026 pfx->exception, GetMagickModule(), OptionError,
2027 "Bug: For function",
"'%s' last element not 'p' at '%s'",
2028 funStr, SetShortExp(pfx));
2031 chQual = pel->channel_qual;
2032 expChLimit = (pel->is_relative) ?
']' :
'}';
2033 pfx->usedElements--;
2034 if (fe == fU) fe = fUP;
2035 else if (fe == fV) fe = fVP;
2036 else if (fe == fS) fe = fSP;
2037 funStr = Functions[fe-(int) FirstFunc].str;
2041 if ( chQual == NO_CHAN_QUAL &&
2042 (fe == fP || fe == fS || fe == fSP || fe == fU || fe == fUP || fe == fV || fe == fVP)
2045 chQual = GetChannelQualifier (pfx, (
int) fe);
2048 if (chQual == NO_CHAN_QUAL && (fe == fU || fe == fV || fe == fS)) {
2050 iaQual = GetImgAttrQualifier (pfx, (
int) fe);
2052 if (IsQualifier (pfx) && chQual == NO_CHAN_QUAL && iaQual != aNull) {
2053 chQual = GetChannelQualifier (pfx, (
int) fe);
2055 if (coordQual && iaQual != aNull) {
2056 (void) ThrowMagickException (
2057 pfx->exception, GetMagickModule(), OptionError,
2058 "For function",
"'%s', can't have qualifiers 'p' and image attribute '%s' at '%s'",
2059 funStr, pfx->token, SetShortExp(pfx));
2062 if (!coordQual && chQual == NO_CHAN_QUAL && iaQual == aNull) {
2063 (void) ThrowMagickException (
2064 pfx->exception, GetMagickModule(), OptionError,
2065 "For function",
"'%s', bad qualifier '%s' at '%s'",
2066 funStr, pfx->token, SetShortExp(pfx));
2069 if (!coordQual && chQual == CompositePixelChannel && iaQual == aNull) {
2070 (void) ThrowMagickException (
2071 pfx->exception, GetMagickModule(), OptionError,
2072 "For function",
"'%s', bad composite qualifier '%s' at '%s'",
2073 funStr, pfx->token, SetShortExp(pfx));
2077 if (chQual == HUE_CHANNEL || chQual == SAT_CHANNEL || chQual == LIGHT_CHANNEL) {
2078 pfx->NeedHsl = MagickTrue;
2080 if (iaQual >= FirstImgAttr && iaQual < aNull) {
2081 (void) ThrowMagickException (
2082 pfx->exception, GetMagickModule(), OptionError,
2083 "Can't have image attribute with HLS qualifier at",
"'%s'",
2090 if (iaQual != aNull && chQual != NO_CHAN_QUAL) {
2091 if (ImgAttrs[iaQual-(
int) FirstImgAttr].need_stats == MagickFalse) {
2092 (void) ThrowMagickException (
2093 pfx->exception, GetMagickModule(), OptionError,
2094 "Can't have image attribute ",
"'%s' with channel qualifier '%s' at '%s'",
2095 ImgAttrs[iaQual-(int) FirstImgAttr].str,
2096 pfx->token, SetShortExp(pfx));
2099 if (ChanIsVirtual (chQual)) {
2100 (void) ThrowMagickException (
2101 pfx->exception, GetMagickModule(), OptionError,
2102 "Can't have statistical image attribute ",
"'%s' with virtual channel qualifier '%s' at '%s'",
2103 ImgAttrs[iaQual-(int) FirstImgAttr].str,
2104 pfx->token, SetShortExp(pfx));
2111 pfx->Elements[ndx1].element_index = ndx2+1;
2112 }
else if (fe==fDo) {
2113 pfx->Elements[ndx0].element_index = ndx1+1;
2114 pfx->Elements[ndx1].element_index = ndx2+1;
2115 }
else if (fe==fFor) {
2116 pfx->Elements[ndx2].element_index = ndx3;
2117 }
else if (fe==fIf) {
2118 pfx->Elements[ndx1].element_index = ndx2 + 1;
2119 pfx->Elements[ndx2].element_index = ndx3;
2121 if (fe == fU && iaQual == aNull) {
2122 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2123 if (pel->type == etConstant && pel->val == 0.0) {
2124 pfx->usedElements--;
2128 (void) AddElement (pfx, (fxFltType) 0, (int) fe);
2129 if (fe == fP || fe == fU || fe == fU0 || fe == fUP ||
2130 fe == fV || fe == fVP || fe == fS || fe == fSP)
2132 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2133 pel->is_relative = (expChLimit ==
']' ? MagickTrue : MagickFalse);
2134 if (chQual >= 0) pel->channel_qual = chQual;
2135 if (iaQual != aNull && (fe == fU || fe == fV || fe == fS)) {
2137 pel->img_attr_qual = iaQual;
2142 if (pExpStart && lenExp) {
2143 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2144 pel->exp_start = pExpStart;
2145 pel->exp_len = lenExp;
2149 pfx->ContainsDebug = MagickTrue;
2154static MagickBooleanType IsStealth (
int op)
2156 return (op == fU0 || op == fUP || op == fSP || op == fVP ||
2157 (op >= FirstCont && op <= rNull) ? MagickTrue : MagickFalse
2161static MagickBooleanType GetOperand (
2162 FxInfo * pfx, MagickBooleanType * UserSymbol, MagickBooleanType * NewUserSymbol,
int * UserSymNdx,
2163 MagickBooleanType * needPopAll)
2166 *NewUserSymbol = *UserSymbol = MagickFalse;
2167 *UserSymNdx = NULL_ADDRESS;
2170 if (!*pfx->pex)
return MagickFalse;
2171 (void) GetToken (pfx);
2173 if (pfx->lenToken==0) {
2177 OperatorE op = GetLeadingOp (pfx);
2178 if (op==oOpenParen) {
2179 char chLimit =
'\0';
2180 if (!PushOperatorStack (pfx, (
int) op))
return MagickFalse;
2182 if (!TranslateExpression (pfx,
")", &chLimit, needPopAll)) {
2183 (void) ThrowMagickException (
2184 pfx->exception, GetMagickModule(), OptionError,
2185 "Empty expression in parentheses at",
"'%s'",
2189 if (chLimit !=
')') {
2190 (void) ThrowMagickException (
2191 pfx->exception, GetMagickModule(), OptionError,
2192 "'(' but no ')' at",
"'%s'",
2197 if (!PopOprOpenParen (pfx, oOpenParen)) {
2198 (void) ThrowMagickException (
2199 pfx->exception, GetMagickModule(), OptionError,
2200 "Bug: tos not '(' at",
"'%s'",
2205 }
else if (OprIsUnaryPrefix (op)) {
2206 MagickBooleanType operand_ok;
2207 if (!PushOperatorStack (pfx, (
int) op))
return MagickFalse;
2210 if (!*pfx->pex)
return MagickFalse;
2211 if (pfx->teDepth >= MagickMaxRecursionDepth) {
2212 (void) ThrowMagickException (
2213 pfx->exception, GetMagickModule(), OptionError,
2214 "Expression too deeply nested",
"(depth %i exceeds limit %i)",
2215 pfx->teDepth, MagickMaxRecursionDepth);
2219 operand_ok=GetOperand (pfx, UserSymbol, NewUserSymbol, UserSymNdx, needPopAll);
2222 (void) ThrowMagickException (
2223 pfx->exception, GetMagickModule(), OptionError,
2224 "After unary, bad operand at",
"'%s'",
2229 if (*NewUserSymbol) {
2230 (void) ThrowMagickException (
2231 pfx->exception, GetMagickModule(), OptionError,
2232 "After unary, NewUserSymbol at",
"'%s'",
2238 (void) AddAddressingElement (pfx, rCopyFrom, *UserSymNdx);
2239 *UserSymNdx = NULL_ADDRESS;
2241 *UserSymbol = MagickFalse;
2242 *NewUserSymbol = MagickFalse;
2245 (void) GetToken (pfx);
2247 }
else if (*pfx->pex ==
'#') {
2248 fxFltType v0=0, v1=0, v2=0;
2249 ssize_t lenToken = GetHexColour (pfx, &v0, &v1, &v2);
2251 (void) ThrowMagickException (
2252 pfx->exception, GetMagickModule(), OptionError,
2253 "Bad hex number at",
"'%s'",
2256 }
else if (lenToken > 0) {
2257 (void) AddColourElement (pfx, v0, v1, v2);
2268 fxFltType val = strtold (pfx->pex, &tailptr);
2269 if (pfx->pex != tailptr) {
2277 const char Prefixes[] =
"yzafpnum.kMGTPEZY";
2278 const char * pSi = strchr (Prefixes, *tailptr);
2279 if (pSi && *pSi !=
'.') Pow = (double) ((pSi - Prefixes) * 3 - 24);
2280 else if (*tailptr ==
'c') Pow = -2;
2281 else if (*tailptr ==
'h') Pow = 2;
2282 else if (*tailptr ==
'k') Pow = 3;
2284 if (*(++pfx->pex) ==
'i') {
2285 val *= pow (2.0, Pow/0.3);
2288 val *= pow (10.0, Pow);
2292 (void) AddElement (pfx, val, oNull);
2296 val = (fxFltType) 0;
2297 lenOptArt = GetProperty (pfx, &val);
2298 if (lenOptArt < 0)
return MagickFalse;
2299 if (lenOptArt > 0) {
2300 (void) AddElement (pfx, val, oNull);
2301 pfx->pex += lenOptArt;
2308 if (pfx->lenToken > 0) {
2313 for (ce = (ConstantE)0; ce < cNull; ce=(ConstantE) (ce+1)) {
2314 const char * ceStr = Constants[ce].str;
2315 if (LocaleCompare (ceStr, pfx->token)==0) {
2321 (void) AddElement (pfx, Constants[ce].val, oNull);
2322 pfx->pex += pfx->lenToken;
2331 for (fe = FirstFunc; fe < fNull; fe=(FunctionE) (fe+1)) {
2332 const char * feStr = Functions[fe-(int) FirstFunc].str;
2333 if (LocaleCompare (feStr, pfx->token)==0) {
2338 if (fe == fV && pfx->ImgListLen < 2) {
2339 (void) ThrowMagickException (
2340 pfx->exception, GetMagickModule(), OptionError,
2341 "Symbol 'v' but fewer than two images at",
"'%s'",
2346 if (IsStealth ((
int) fe)) {
2347 (void) ThrowMagickException (
2348 pfx->exception, GetMagickModule(), OptionError,
2349 "Function",
"'%s' not permitted at '%s'",
2350 pfx->token, SetShortExp(pfx));
2353 if (fe == fDo || fe == fFor || fe == fIf || fe == fWhile) {
2354 *needPopAll = MagickTrue;
2357 if (fe != fNull)
return (GetFunction (pfx, fe));
2363 ImgAttrE ia = GetImgAttrToken (pfx);
2366 (void) AddElement (pfx, val, (
int) ia);
2368 if (ImgAttrs[ia-(
int) FirstImgAttr].need_stats != MagickFalse) {
2369 if (IsQualifier (pfx)) {
2370 PixelChannel chQual = GetChannelQualifier (pfx, (
int) ia);
2372 if (chQual == NO_CHAN_QUAL) {
2373 (void) ThrowMagickException (
2374 pfx->exception, GetMagickModule(), OptionError,
2375 "Bad channel qualifier at",
"'%s'",
2380 pel = &pfx->Elements[pfx->usedElements-1];
2381 pel->channel_qual = chQual;
2392 for (se = FirstSym; se < sNull; se=(SymbolE) (se+1)) {
2393 const char * seStr = Symbols[se-(int) FirstSym].str;
2394 if (LocaleCompare (seStr, pfx->token)==0) {
2400 (void) AddElement (pfx, val, (
int) se);
2401 pfx->pex += pfx->lenToken;
2403 if (se==sHue || se==sSaturation || se==sLightness) pfx->NeedHsl = MagickTrue;
2411 fxFltType v0, v1, v2;
2412 ssize_t ColLen = GetConstantColour (pfx, &v0, &v1, &v2);
2413 if (ColLen < 0)
return MagickFalse;
2415 (void) AddColourElement (pfx, v0, v1, v2);
2424 const char *artifact;
2425 artifact = GetImageArtifact (pfx->image, pfx->token);
2426 if (artifact != (
const char *) NULL) {
2428 fxFltType val = strtold (artifact, &tailptr);
2429 if (pfx->token == tailptr) {
2430 (void) ThrowMagickException (
2431 pfx->exception, GetMagickModule(), OptionError,
2432 "Artifact",
"'%s' has value '%s', not a number, at '%s'",
2433 pfx->token, artifact, SetShortExp(pfx));
2436 (void) AddElement (pfx, val, oNull);
2437 pfx->pex+=pfx->lenToken;
2444 if (TokenMaybeUserSymbol (pfx)) {
2445 *UserSymbol = MagickTrue;
2446 *UserSymNdx = FindUserSymbol (pfx, pfx->token);
2447 if (*UserSymNdx == NULL_ADDRESS) {
2448 *UserSymNdx = AddUserSymbol (pfx, pfx->pex, pfx->lenToken);
2449 *NewUserSymbol = MagickTrue;
2452 pfx->pex += pfx->lenToken;
2458 (void) ThrowMagickException (
2459 pfx->exception, GetMagickModule(), OptionError,
2460 "Expected operand at",
"'%s'",
2466static inline MagickBooleanType IsRealOperator (OperatorE op)
2468 return (op < oOpenParen || op > oCloseBrace) ? MagickTrue : MagickFalse;
2471static inline MagickBooleanType ProcessTernaryOpr (
FxInfo * pfx,
TernaryT * ptern)
2476 if (pfx->usedOprStack == 0)
2478 if (pfx->OperatorStack[pfx->usedOprStack-1] == oQuery) {
2479 if (ptern->addr_query != NULL_ADDRESS) {
2480 (void) ThrowMagickException (
2481 pfx->exception, GetMagickModule(), OptionError,
2482 "Already have '?' in sub-expression at",
"'%s'",
2486 if (ptern->addr_colon != NULL_ADDRESS) {
2487 (void) ThrowMagickException (
2488 pfx->exception, GetMagickModule(), OptionError,
2489 "Already have ':' in sub-expression at",
"'%s'",
2493 pfx->usedOprStack--;
2494 ptern->addr_query = pfx->usedElements;
2495 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
2498 else if (pfx->OperatorStack[pfx->usedOprStack-1] == oColon) {
2499 if (ptern->addr_query == NULL_ADDRESS) {
2500 (void) ThrowMagickException (
2501 pfx->exception, GetMagickModule(), OptionError,
2502 "Need '?' in sub-expression at",
"'%s'",
2506 if (ptern->addr_colon != NULL_ADDRESS) {
2507 (void) ThrowMagickException (
2508 pfx->exception, GetMagickModule(), OptionError,
2509 "Already have ':' in sub-expression at",
"'%s'",
2513 pfx->usedOprStack--;
2514 ptern->addr_colon = pfx->usedElements;
2515 pfx->Elements[pfx->usedElements-1].do_push = MagickTrue;
2516 (void) AddAddressingElement (pfx, rGoto, NULL_ADDRESS);
2522static MagickBooleanType GetOperator (
2524 MagickBooleanType * Assign, MagickBooleanType * Update, MagickBooleanType * IncrDecr)
2528 MagickBooleanType DoneIt = MagickFalse;
2530 for (op = (OperatorE)0; op != oNull; op=(OperatorE) (op+1)) {
2531 const char * opStr = Operators[op].str;
2532 len = strlen(opStr);
2533 if (LocaleNCompare (opStr, pfx->pex, len)==0) {
2538 if (!IsRealOperator (op)) {
2539 (void) ThrowMagickException (
2540 pfx->exception, GetMagickModule(), OptionError,
2541 "Not a real operator at",
"'%s'",
2547 (void) ThrowMagickException (
2548 pfx->exception, GetMagickModule(), OptionError,
2549 "Expected operator at",
"'%s'",
2554 *Assign = (op==oAssign) ? MagickTrue : MagickFalse;
2555 *Update = OprInPlace ((
int) op);
2556 *IncrDecr = (op == oPlusPlus || op == oSubSub) ? MagickTrue : MagickFalse;
2563 while (pfx->usedOprStack > 0) {
2564 OperatorE top = pfx->OperatorStack[pfx->usedOprStack-1];
2565 int precTop, precNew;
2566 if (top == oOpenParen || top == oAssign || OprInPlace ((
int) top))
break;
2567 precTop = Operators[top].precedence;
2568 precNew = Operators[op].precedence;
2572 if (precTop < precNew)
break;
2573 (void) AddElement (pfx, (fxFltType) 0, (int) top);
2574 pfx->usedOprStack--;
2580 if (op==oCloseParen) {
2581 if (pfx->usedOprStack == 0) {
2582 (void) ThrowMagickException (
2583 pfx->exception, GetMagickModule(), OptionError,
2584 "Found ')' but nothing on stack at",
"'%s'",
2589 if (pfx->OperatorStack[pfx->usedOprStack-1] != oOpenParen) {
2590 (void) ThrowMagickException (
2591 pfx->exception, GetMagickModule(), OptionError,
2592 "Found ')' but no '(' on stack at",
"'%s'",
2596 pfx->usedOprStack--;
2597 DoneIt = MagickTrue;
2601 if (!PushOperatorStack (pfx, (
int) op))
return MagickFalse;
2609static MagickBooleanType ResolveTernaryAddresses (
FxInfo * pfx,
TernaryT * ptern)
2611 if (ptern->addr_query == NULL_ADDRESS && ptern->addr_colon == NULL_ADDRESS)
2614 if (ptern->addr_query != NULL_ADDRESS && ptern->addr_colon != NULL_ADDRESS) {
2615 pfx->Elements[ptern->addr_query].element_index = ptern->addr_colon + 1;
2616 pfx->Elements[ptern->addr_colon].element_index = pfx->usedElements;
2617 ptern->addr_query = NULL_ADDRESS;
2618 ptern->addr_colon = NULL_ADDRESS;
2619 }
else if (ptern->addr_query != NULL_ADDRESS) {
2620 (void) ThrowMagickException (
2621 pfx->exception, GetMagickModule(), OptionError,
2622 "'?' with no corresponding ':'",
"'%s' at '%s'",
2623 pfx->token, SetShortExp(pfx));
2625 }
else if (ptern->addr_colon != NULL_ADDRESS) {
2626 (void) ThrowMagickException (
2627 pfx->exception, GetMagickModule(), OptionError,
2628 "':' with no corresponding '?'",
"'%s' at '%s'",
2629 pfx->token, SetShortExp(pfx));
2635static MagickBooleanType TranslateExpression (
2636 FxInfo * pfx,
const char * strLimit,
char * chLimit, MagickBooleanType * needPopAll)
2640 MagickBooleanType UserSymbol, NewUserSymbol;
2641 int UserSymNdx0, UserSymNdx1;
2644 Assign = MagickFalse,
2645 Update = MagickFalse,
2646 IncrDecr = MagickFalse;
2651 ternary.addr_query = NULL_ADDRESS;
2652 ternary.addr_colon = NULL_ADDRESS;
2654 if (pfx->teDepth >= MagickMaxRecursionDepth) {
2655 (void) ThrowMagickException(pfx->exception, GetMagickModule(), OptionError,
2656 "Expression too deeply nested",
"(depth %i exceeds limit %i)",
2657 pfx->teDepth, MagickMaxRecursionDepth);
2665 StartEleNdx = pfx->usedElements-1;
2666 if (StartEleNdx < 0) StartEleNdx = 0;
2675 if (strchr(strLimit,*pfx->pex)!=NULL) {
2676 *chLimit = *pfx->pex;
2683 if (!GetOperand (pfx, &UserSymbol, &NewUserSymbol, &UserSymNdx0, needPopAll))
return MagickFalse;
2688 while (*pfx->pex && (!*strLimit || (strchr(strLimit,*pfx->pex)==NULL))) {
2689 if (!GetOperator (pfx, &Assign, &Update, &IncrDecr))
return MagickFalse;
2691 if (NewUserSymbol && !Assign) {
2692 (void) ThrowMagickException (
2693 pfx->exception, GetMagickModule(), OptionError,
2694 "Expected assignment after new UserSymbol",
"'%s' at '%s'",
2695 pfx->token, SetShortExp(pfx));
2698 if (!UserSymbol && Assign) {
2699 (void) ThrowMagickException (
2700 pfx->exception, GetMagickModule(), OptionError,
2701 "Attempted assignment to non-UserSymbol",
"'%s' at '%s'",
2702 pfx->token, SetShortExp(pfx));
2705 if (!UserSymbol && Update) {
2706 (void) ThrowMagickException (
2707 pfx->exception, GetMagickModule(), OptionError,
2708 "Attempted update to non-UserSymbol",
"'%s' at '%s'",
2709 pfx->token, SetShortExp(pfx));
2712 if (UserSymbol && (Assign || Update) && !IncrDecr) {
2714 if (!TranslateExpression (pfx, strLimit, chLimit, needPopAll))
return MagickFalse;
2715 if (!*pfx->pex)
break;
2716 if (!*strLimit)
break;
2717 if (strchr(strLimit,*chLimit)!=NULL)
break;
2719 if (UserSymbol && !Assign && !Update && UserSymNdx0 != NULL_ADDRESS) {
2721 (void) AddAddressingElement (pfx, rCopyFrom, UserSymNdx0);
2722 UserSymNdx0 = NULL_ADDRESS;
2723 pel = &pfx->Elements[pfx->usedElements-1];
2724 pel->do_push = MagickTrue;
2728 while (TopOprIsUnaryPrefix (pfx)) {
2729 OperatorE op = pfx->OperatorStack[pfx->usedOprStack-1];
2730 (void) AddElement (pfx, (fxFltType) 0, (int) op);
2731 pfx->usedOprStack--;
2735 if (!ProcessTernaryOpr (pfx, &ternary))
return MagickFalse;
2737 if (ternary.addr_colon != NULL_ADDRESS) {
2738 if (!TranslateExpression (pfx,
",);", chLimit, needPopAll))
return MagickFalse;
2742 UserSymbol = NewUserSymbol = MagickFalse;
2744 if ( (!*pfx->pex) || (*strLimit && (strchr(strLimit,*pfx->pex)!=NULL) ) )
2746 if (IncrDecr)
break;
2748 (void) ThrowMagickException (
2749 pfx->exception, GetMagickModule(), OptionError,
2750 "Expected operand after operator",
"at '%s'",
2756 (void) ThrowMagickException (
2757 pfx->exception, GetMagickModule(), OptionError,
2758 "'++' and '--' must be the final operators in an expression at",
"'%s'",
2763 if (!GetOperand (pfx, &UserSymbol, &NewUserSymbol, &UserSymNdx1, needPopAll)) {
2764 (void) ThrowMagickException (
2765 pfx->exception, GetMagickModule(), OptionError,
2766 "Expected operand at",
"'%s'",
2771 if (NewUserSymbol && !Assign) {
2772 (void) ThrowMagickException (
2773 pfx->exception, GetMagickModule(), OptionError,
2774 "NewUserSymbol",
"'%s' after non-assignment operator at '%s'",
2775 pfx->token, SetShortExp(pfx));
2778 if (UserSymbol && !NewUserSymbol) {
2779 (void) AddAddressingElement (pfx, rCopyFrom, UserSymNdx1);
2780 UserSymNdx1 = NULL_ADDRESS;
2782 UserSymNdx0 = UserSymNdx1;
2785 if (UserSymbol && !Assign && !Update && UserSymNdx0 != NULL_ADDRESS) {
2787 if (NewUserSymbol) {
2788 (void) ThrowMagickException (
2789 pfx->exception, GetMagickModule(), OptionError,
2790 "NewUserSymbol",
"'%s' needs assignment operator at '%s'",
2791 pfx->token, SetShortExp(pfx));
2794 (void) AddAddressingElement (pfx, rCopyFrom, UserSymNdx0);
2795 pel = &pfx->Elements[pfx->usedElements-1];
2796 pel->do_push = MagickTrue;
2799 if (*pfx->pex && !*chLimit && (strchr(strLimit,*pfx->pex)!=NULL)) {
2800 *chLimit = *pfx->pex;
2803 while (pfx->usedOprStack) {
2804 OperatorE op = pfx->OperatorStack[pfx->usedOprStack-1];
2805 if (op == oOpenParen || op == oOpenBracket || op == oOpenBrace) {
2808 if ( (op==oAssign && !Assign) || (OprInPlace((
int) op) && !Update) ) {
2811 pfx->usedOprStack--;
2812 (void) AddElement (pfx, (fxFltType) 0, (int) op);
2813 if (op == oAssign) {
2814 if (UserSymNdx0 < 0) {
2815 (void) ThrowMagickException (
2816 pfx->exception, GetMagickModule(), OptionError,
2817 "Assignment to unknown user symbol at",
"'%s'",
2823 pfx->usedElements--;
2824 (void) AddAddressingElement (pfx, rCopyTo, UserSymNdx0);
2826 }
else if (OprInPlace ((
int) op)) {
2827 if (UserSymNdx0 < 0) {
2828 (void) ThrowMagickException (
2829 pfx->exception, GetMagickModule(), OptionError,
2830 "Operator-in-place to unknown user symbol at",
"'%s'",
2836 pfx->Elements[pfx->usedElements-1].element_index = UserSymNdx0;
2841 if (ternary.addr_query != NULL_ADDRESS) *needPopAll = MagickTrue;
2843 (void) ResolveTernaryAddresses (pfx, &ternary);
2847 if (!pfx->teDepth && *needPopAll) {
2848 (void) AddAddressingElement (pfx, rZerStk, NULL_ADDRESS);
2849 *needPopAll = MagickFalse;
2852 if (pfx->exception->severity >= ErrorException)
2859static MagickBooleanType TranslateStatement (
FxInfo * pfx,
char * strLimit,
char * chLimit)
2861 MagickBooleanType NeedPopAll = MagickFalse;
2865 if (!*pfx->pex)
return MagickFalse;
2867 if (!TranslateExpression (pfx, strLimit, chLimit, &NeedPopAll)) {
2870 if (pfx->usedElements && *chLimit==
';') {
2875 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2876 if (pel->do_push) pel->do_push = MagickFalse;
2882static MagickBooleanType TranslateStatementList (
FxInfo * pfx,
const char * strLimit,
char * chLimit)
2884#define MAX_SLIMIT 10
2885 char sLimits[MAX_SLIMIT];
2888 if (!*pfx->pex)
return MagickFalse;
2889 (void) CopyMagickString (sLimits, strLimit, MAX_SLIMIT-1);
2891 if (strchr(strLimit,
';')==NULL)
2892 (
void) ConcatenateMagickString (sLimits,
";", MAX_SLIMIT);
2895 if (!TranslateStatement (pfx, sLimits, chLimit))
return MagickFalse;
2897 if (!*pfx->pex)
break;
2899 if (*chLimit !=
';') {
2904 if (pfx->exception->severity >= ErrorException)
2923 for (ch=0; ch <= (int) MaxPixelChannels; ch++) {
2924 cs[ch].mean *= QuantumScale;
2925 cs[ch].median *= QuantumScale;
2926 cs[ch].maxima *= QuantumScale;
2927 cs[ch].minima *= QuantumScale;
2928 cs[ch].standard_deviation *= QuantumScale;
2934static MagickBooleanType CollectStatistics (
FxInfo * pfx)
2936 Image * img = GetFirstImageInList (pfx->image);
2941 if (!pfx->statistics) {
2942 (void) ThrowMagickException (
2943 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
2944 "Statistics",
"%lu",
2945 (
unsigned long) pfx->ImgListLen);
2950 pfx->statistics[imgNum] = CollectOneImgStats (pfx, img);
2952 if (++imgNum == pfx->ImgListLen)
break;
2953 img = GetNextImageInList (img);
2954 assert (img != (
Image *) NULL);
2956 pfx->GotStats = MagickTrue;
2961static inline MagickBooleanType PushVal (
FxInfo * pfx,
fxRtT * pfxrt, fxFltType val,
int addr)
2963 if (pfxrt->usedValStack >=pfxrt->numValStack) {
2964 (void) ThrowMagickException (
2965 pfx->exception, GetMagickModule(), OptionError,
2966 "ValStack overflow at addr=",
"%i",
2971 pfxrt->ValStack[pfxrt->usedValStack++] = val;
2975static inline fxFltType PopVal (
FxInfo * pfx,
fxRtT * pfxrt,
int addr)
2977 if (pfxrt->usedValStack <= 0) {
2978 (void) ThrowMagickException (
2979 pfx->exception, GetMagickModule(), OptionError,
2980 "ValStack underflow at addr=",
"%i",
2982 return (fxFltType) 0;
2985 return pfxrt->ValStack[--pfxrt->usedValStack];
2988static inline fxFltType ImageStat (
2989 FxInfo * pfx, ssize_t ImgNum, PixelChannel channel, ImgAttrE ia)
2993 MagickBooleanType NeedRelinq = MagickFalse;
2997 (void) ThrowMagickException(pfx->exception,GetMagickModule(),
2998 OptionError,
"NoSuchImage",
"%lu",(
unsigned long) ImgNum);
3002 if (pfx->GotStats) {
3003 if ((channel < 0) || (channel > MaxPixelChannels))
3005 (void) ThrowMagickException(pfx->exception,GetMagickModule(),
3006 OptionError,
"NoSuchImageChannel",
"%i",channel);
3007 channel=(PixelChannel) 0;
3009 cs = pfx->statistics[ImgNum];
3010 }
else if (pfx->NeedStats) {
3012 if ((channel < 0) || (channel > MaxPixelChannels))
3014 (void) ThrowMagickException(pfx->exception,GetMagickModule(),
3015 OptionError,
"NoSuchImageChannel",
"%i",channel);
3016 channel=(PixelChannel) 0;
3018 cs = CollectOneImgStats (pfx, pfx->Images[ImgNum]);
3019 NeedRelinq = MagickTrue;
3024 ret = (fxFltType) GetImageDepth (pfx->Images[ImgNum], pfx->exception);
3027 ret = (fxFltType) GetBlobSize (pfx->image);
3031 ret = cs[channel].kurtosis;
3035 ret = cs[channel].maxima;
3039 ret = cs[channel].mean;
3043 ret = cs[channel].median;
3047 ret = cs[channel].minima;
3053 ret = (fxFltType) pfx->Images[ImgNum]->page.x;
3056 ret = (fxFltType) pfx->Images[ImgNum]->page.y;
3059 ret = (fxFltType) pfx->Images[ImgNum]->page.width;
3062 ret = (fxFltType) pfx->Images[ImgNum]->page.height;
3068 ret = (fxFltType) PerceptibleReciprocal (pfx->Images[ImgNum]->resolution.x)
3069 * pfx->Images[ImgNum]->columns;
3072 ret = (fxFltType) PerceptibleReciprocal (pfx->Images[ImgNum]->resolution.y)
3073 * pfx->Images[ImgNum]->rows;
3076 ret = (fxFltType) pfx->Images[ImgNum]->quality;
3082 ret = pfx->Images[ImgNum]->resolution.x;
3085 ret = pfx->Images[ImgNum]->resolution.y;
3089 ret = cs[channel].skewness;
3093 ret = cs[channel].standard_deviation;
3096 ret = (fxFltType) pfx->Images[ImgNum]->rows;
3099 ret = (fxFltType) pfx->ImgListLen;
3102 ret = (fxFltType) ImgNum;
3105 ret = (fxFltType) pfx->Images[ImgNum]->columns;
3108 ret = (fxFltType) GetImageDepth (pfx->Images[ImgNum], pfx->exception);
3111 (void) ThrowMagickException (pfx->exception,GetMagickModule(),OptionError,
3112 "Unknown ia=",
"%i",ia);
3119static inline fxFltType FxGcd (fxFltType x, fxFltType y,
const size_t depth)
3121#define FxMaxFunctionDepth 200
3124 return (FxGcd (y, x, depth+1));
3125 if ((fabs((
double) y) < 0.001) || (depth >= FxMaxFunctionDepth))
3127 return (FxGcd (y, x-y*floor((
double) (x/y)), depth+1));
3130static inline ssize_t ChkImgNum (
FxInfo * pfx, fxFltType f)
3133 ssize_t i = (ssize_t) floor ((
double) f + 0.5);
3134 if (i < 0) i += (ssize_t) pfx->ImgListLen;
3135 if (i < 0 || i >= (ssize_t) pfx->ImgListLen) {
3136 (void) ThrowMagickException (
3137 pfx->exception, GetMagickModule(), OptionError,
3138 "ImgNum",
"%lu bad for ImgListLen %lu",
3139 (
unsigned long) i, (
unsigned long) pfx->ImgListLen);
3145#define WHICH_ATTR_CHAN \
3146 (pel->channel_qual == NO_CHAN_QUAL) ? CompositePixelChannel : \
3147 (pel->channel_qual == THIS_CHANNEL) ? channel : pel->channel_qual
3149#define WHICH_NON_ATTR_CHAN \
3150 (pel->channel_qual == NO_CHAN_QUAL || \
3151 pel->channel_qual == THIS_CHANNEL || \
3152 pel->channel_qual == CompositePixelChannel \
3153 ) ? (channel == CompositePixelChannel ? RedPixelChannel: channel) \
3156static fxFltType GetHslFlt (
FxInfo * pfx, ssize_t ImgNum,
const fxFltType fx,
const fxFltType fy,
3157 PixelChannel channel)
3159 Image * img = pfx->Images[ImgNum];
3161 double red, green, blue;
3162 double hue=0, saturation=0, lightness=0;
3164 MagickBooleanType okay = MagickTrue;
3165 if(!InterpolatePixelChannel (img, pfx->Imgs[ImgNum].View, RedPixelChannel, img->interpolate,
3166 (
double) fx, (
double) fy, &red, pfx->exception)) okay = MagickFalse;
3167 if(!InterpolatePixelChannel (img, pfx->Imgs[ImgNum].View, GreenPixelChannel, img->interpolate,
3168 (
double) fx, (
double) fy, &green, pfx->exception)) okay = MagickFalse;
3169 if(!InterpolatePixelChannel (img, pfx->Imgs[ImgNum].View, BluePixelChannel, img->interpolate,
3170 (
double) fx, (
double) fy, &blue, pfx->exception)) okay = MagickFalse;
3173 (void) ThrowMagickException (
3174 pfx->exception, GetMagickModule(), OptionError,
3175 "GetHslFlt failure",
"%lu %g,%g %i", (
unsigned long) ImgNum,
3176 (
double) fx, (double) fy, channel);
3180 &hue, &saturation, &lightness);
3182 if (channel == HUE_CHANNEL)
return hue;
3183 if (channel == SAT_CHANNEL)
return saturation;
3184 if (channel == LIGHT_CHANNEL)
return lightness;
3189static fxFltType GetHslInt (
FxInfo * pfx, ssize_t ImgNum,
const ssize_t imgx,
const ssize_t imgy, PixelChannel channel)
3191 Image * img = pfx->Images[ImgNum];
3193 double hue=0, saturation=0, lightness=0;
3195 const Quantum * p = GetCacheViewVirtualPixels (pfx->Imgs[ImgNum].View, imgx, imgy, 1, 1, pfx->exception);
3196 if (p == (
const Quantum *) NULL)
3198 (void) ThrowMagickException (pfx->exception,GetMagickModule(),
3199 OptionError,
"GetHslInt failure",
"%lu %li,%li %i",(
unsigned long) ImgNum,
3200 (
long) imgx,(long) imgy,channel);
3205 GetPixelRed (img, p), GetPixelGreen (img, p), GetPixelBlue (img, p),
3206 &hue, &saturation, &lightness);
3208 if (channel == HUE_CHANNEL)
return hue;
3209 if (channel == SAT_CHANNEL)
return saturation;
3210 if (channel == LIGHT_CHANNEL)
return lightness;
3215static inline fxFltType GetIntensity (
FxInfo * pfx, ssize_t ImgNum,
const fxFltType fx,
const fxFltType fy)
3218 quantum_pixel[MaxPixelChannels];
3223 Image * img = pfx->Images[ImgNum];
3225 (void) GetPixelInfo (img, &pixelinf);
3227 if (!InterpolatePixelInfo (img, pfx->Imgs[ImgNum].View, img->interpolate,
3228 (
double) fx, (
double) fy, &pixelinf, pfx->exception))
3230 (void) ThrowMagickException (
3231 pfx->exception, GetMagickModule(), OptionError,
3232 "GetIntensity failure",
"%lu %g,%g", (
unsigned long) ImgNum,
3233 (
double) fx, (double) fy);
3236 SetPixelViaPixelInfo (img, &pixelinf, quantum_pixel);
3237 return QuantumScale * GetPixelIntensity (img, quantum_pixel);
3240static MagickBooleanType ExecuteRPN (
FxInfo * pfx,
fxRtT * pfxrt, fxFltType *result,
3241 const PixelChannel channel,
const ssize_t imgx,
const ssize_t imgy)
3243 const Quantum * p = pfxrt->thisPixel;
3244 fxFltType regA=0, regB=0, regC=0, regD=0, regE=0;
3245 Image * img = pfx->image;
3247 MagickBooleanType NeedRelinq = MagickFalse;
3248 double hue=0, saturation=0, lightness=0;
3255 if (!p) p = GetCacheViewVirtualPixels (
3256 pfx->Imgs[pfx->ImgNum].View, imgx, imgy, 1, 1, pfx->exception);
3258 if (p == (
const Quantum *) NULL)
3260 (void) ThrowMagickException (pfx->exception,GetMagickModule(),
3261 OptionError,
"Can't get virtual pixels",
"%lu %li,%li",(
unsigned long)
3262 pfx->ImgNum,(
long) imgx,(long) imgy);
3263 return(MagickFalse);
3266 if (pfx->GotStats) {
3267 cs = pfx->statistics[pfx->ImgNum];
3268 }
else if (pfx->NeedStats) {
3269 cs = CollectOneImgStats (pfx, pfx->Images[pfx->ImgNum]);
3270 NeedRelinq = MagickTrue;
3277 GetPixelRed (img, p), GetPixelGreen (img, p), GetPixelBlue (img, p),
3278 &hue, &saturation, &lightness);
3281 for (i=0; i < pfx->usedElements; i++) {
3286 (void) ThrowMagickException (
3287 pfx->exception, GetMagickModule(), OptionError,
3288 "Bad run-time address",
"%i", i);
3290 pel=&pfx->Elements[i];
3291 switch (pel->number_args) {
3295 regA = PopVal (pfx, pfxrt, i);
3298 regB = PopVal (pfx, pfxrt, i);
3299 regA = PopVal (pfx, pfxrt, i);
3302 regC = PopVal (pfx, pfxrt, i);
3303 regB = PopVal (pfx, pfxrt, i);
3304 regA = PopVal (pfx, pfxrt, i);
3307 regD = PopVal (pfx, pfxrt, i);
3308 regC = PopVal (pfx, pfxrt, i);
3309 regB = PopVal (pfx, pfxrt, i);
3310 regA = PopVal (pfx, pfxrt, i);
3313 regE = PopVal (pfx, pfxrt, i);
3314 regD = PopVal (pfx, pfxrt, i);
3315 regC = PopVal (pfx, pfxrt, i);
3316 regB = PopVal (pfx, pfxrt, i);
3317 regA = PopVal (pfx, pfxrt, i);
3320 (void) ThrowMagickException (
3321 pfx->exception, GetMagickModule(), OptionError,
3322 "Too many args:",
"%i", pel->number_args);
3326 switch (pel->operator_index) {
3328 regA = (pfxrt->UserSymVals[pel->element_index] += regA);
3331 regA = (pfxrt->UserSymVals[pel->element_index] -= regA);
3334 regA = (pfxrt->UserSymVals[pel->element_index] *= regA);
3337 regA = (pfxrt->UserSymVals[pel->element_index] *= PerceptibleReciprocal((
double)regA));
3340 regA = pfxrt->UserSymVals[pel->element_index]++;
3343 regA = pfxrt->UserSymVals[pel->element_index]--;
3355 regA *= PerceptibleReciprocal((
double)regB);
3358 regA = fmod ((
double) regA, fabs(floor((
double) regB+0.5)));
3367 if ((
size_t) (regB+0.5) >= (8*
sizeof(
size_t)))
3369 (void) ThrowMagickException ( pfx->exception, GetMagickModule(),
3370 OptionError,
"undefined shift",
"%g", (double) regB);
3371 regA = (fxFltType) 0.0;
3374 regA = (fxFltType) ((
size_t)(regA+0.5) << (
size_t)(regB+0.5));
3377 if ((
size_t) (regB+0.5) >= (8*
sizeof(
size_t)))
3379 (void) ThrowMagickException ( pfx->exception, GetMagickModule(),
3380 OptionError,
"undefined shift",
"%g", (double) regB);
3381 regA = (fxFltType) 0.0;
3384 regA = (fxFltType) ((
size_t)(regA+0.5) >> (
size_t)(regB+0.5));
3387 regA = fabs((
double) (regA-regB)) < MagickEpsilon ? 1.0 : 0.0;
3390 regA = fabs((
double) (regA-regB)) >= MagickEpsilon ? 1.0 : 0.0;
3393 regA = (regA <= regB) ? 1.0 : 0.0;
3396 regA = (regA >= regB) ? 1.0 : 0.0;
3399 regA = (regA < regB) ? 1.0 : 0.0;
3402 regA = (regA > regB) ? 1.0 : 0.0;
3405 regA = (regA<=0) ? 0.0 : (regB > 0) ? 1.0 : 0.0;
3408 regA = (regA>0) ? 1.0 : (regB > 0.0) ? 1.0 : 0.0;
3411 regA = (regA==0) ? 1.0 : 0.0;
3414 regA = (fxFltType) ((
size_t)(regA+0.5) & (
size_t)(regB+0.5));
3417 regA = (fxFltType) ((
size_t)(regA+0.5) | (
size_t)(regB+0.5));
3421 regA = (fxFltType) (~(
size_t)(regA+0.5));
3424 regA = pow ((
double) regA, (
double) regB);
3440 if (pel->type == etColourConstant) {
3441 switch (channel) {
default:
3442 case (PixelChannel) 0:
3445 case (PixelChannel) 1:
3448 case (PixelChannel) 2:
3458 regA = fabs ((
double) regA);
3460#if defined(MAGICKCORE_HAVE_ACOSH)
3462 regA = acosh ((
double) regA);
3466 regA = acos ((
double) regA);
3468#if defined(MAGICKCORE_HAVE_J1)
3470 if (regA==0) regA = 1.0;
3472 fxFltType gamma = 2.0 * j1 ((MagickPI*regA)) / (MagickPI*regA);
3473 regA = gamma * gamma;
3478 regA = (fxFltType) (((ssize_t) regA) & 0x01 ? -1.0 : 1.0);
3480#if defined(MAGICKCORE_HAVE_ASINH)
3482 regA = asinh ((
double) regA);
3486 regA = asin ((
double) regA);
3488#if defined(MAGICKCORE_HAVE_ATANH)
3490 regA = atanh ((
double) regA);
3494 regA = atan2 ((
double) regA, (
double) regB);
3497 regA = atan ((
double) regA);
3500 regA = ceil ((
double) regA);
3504 case (PixelChannel) 0:
break;
3505 case (PixelChannel) 1: regA = regB;
break;
3506 case (PixelChannel) 2: regA = regC;
break;
3507 case (PixelChannel) 3: regA = regD;
break;
3508 case (PixelChannel) 4: regA = regE;
break;
3509 default: regA = 0.0;
3513 if (regA < 0) regA = 0.0;
3514 else if (regA > 1.0) regA = 1.0;
3517 regA = cosh ((
double) regA);
3520 regA = cos ((
double) regA);
3525 (void) fprintf (stderr,
"%s[%g,%g].[%i]: %s=%.*g\n",
3526 img->filename, (
double) imgx, (double) imgy,
3527 channel, SetPtrShortExp (pfx, pel->exp_start, (
size_t) (pel->exp_len+1)),
3528 pfx->precision, (double) regA);
3531 regA = regA / (regB*(regA-1.0) + 1.0);
3533#if defined(MAGICKCORE_HAVE_ERF)
3535 regA = erf ((
double) regA);
3539 regA = exp ((
double) regA);
3542 regA = floor ((
double) regA);
3545 regA = exp((
double) (-regA*regA/2.0))/sqrt(2.0*MagickPI);
3549 regA = FxGcd (regA, regB, 0);
3552 regA = hypot ((
double) regA, (
double) regB);
3555 regA = floor ((
double) regA);
3558 regA = (fxFltType) (!!IsNaN (regA));
3560#if defined(MAGICKCORE_HAVE_J0)
3562 regA = j0 ((
double) regA);
3565#if defined(MAGICKCORE_HAVE_J1)
3567 regA = j1 ((
double) regA);
3570#if defined(MAGICKCORE_HAVE_J1)
3572 if (regA==0) regA = 1.0;
3573 else regA = 2.0 * j1 ((MagickPI*regA))/(MagickPI*regA);
3577 regA = log ((
double) regA);
3580 regA = MagickLog10((
double) regA) / log10(2.0);
3583 regA = MagickLog10 ((
double) regA);
3586 regA = (regA > regB) ? regA : regB;
3589 regA = (regA < regB) ? regA : regB;
3592 regA = regA - floor((
double) (regA*PerceptibleReciprocal((
double) regB)))*regB;
3595 regA = (fxFltType) (regA < MagickEpsilon);
3598 regA = pow ((
double) regA, (
double) regB);
3601#if defined(MAGICKCORE_OPENMP_SUPPORT)
3602 #pragma omp critical (MagickCore_ExecuteRPN)
3604 regA = GetPseudoRandomValue (pfxrt->random_info);
3608 regA = floor ((
double) regA + 0.5);
3611 regA = (regA < 0) ? -1.0 : 1.0;
3614 regA = sin ((
double) (MagickPI*regA)) / (MagickPI*regA);
3617 regA = sinh ((
double) regA);
3620 regA = sin ((
double) regA);
3623 regA = sqrt ((
double) regA);
3626 regA = 1.0 / (1.0 + exp ((
double) -regA));
3629 regA = tanh ((
double) regA);
3632 regA = tan ((
double) regA);
3635 if (regA >= 0) regA = floor ((
double) regA);
3636 else regA = ceil ((
double) regA);
3648 ssize_t ImgNum = ChkImgNum (pfx, regA);
3649 if (ImgNum < 0)
break;
3650 regA = (fxFltType) 0;
3652 Image * pimg = pfx->Images[0];
3653 if (pel->img_attr_qual == aNull) {
3654 if ((
int) pel->channel_qual < 0) {
3655 if (pel->channel_qual == NO_CHAN_QUAL || pel->channel_qual == THIS_CHANNEL) {
3656 if (pfx->ImgNum==0) {
3657 regA = QuantumScale * (double) p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3659 const Quantum * pv = GetCacheViewVirtualPixels (
3660 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3662 (void) ThrowMagickException (
3663 pfx->exception, GetMagickModule(), OptionError,
3664 "fU can't get cache",
"%lu", (
unsigned long) ImgNum);
3667 regA = QuantumScale * (double) pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3669 }
else if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL ||
3670 pel->channel_qual == LIGHT_CHANNEL) {
3671 regA = GetHslInt (pfx, ImgNum, imgx, imgy, pel->channel_qual);
3673 }
else if (pel->channel_qual == INTENSITY_CHANNEL) {
3674 regA = GetIntensity (pfx, 0, (
double) imgx, (
double) imgy);
3678 if (pfx->ImgNum==0) {
3679 regA = QuantumScale * (double) p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3681 const Quantum * pv = GetCacheViewVirtualPixels (
3682 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3684 (void) ThrowMagickException (
3685 pfx->exception, GetMagickModule(), OptionError,
3686 "fU can't get cache",
"%lu", (
unsigned long) ImgNum);
3689 regA = QuantumScale * (double) pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3694 regA = ImageStat (pfx, 0, WHICH_ATTR_CHAN, pel->img_attr_qual);
3698 if (pel->img_attr_qual == aNull) {
3700 if ((
int) pel->channel_qual < 0) {
3701 if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL ||
3702 pel->channel_qual == LIGHT_CHANNEL)
3704 regA = GetHslInt (pfx, ImgNum, imgx, imgy, pel->channel_qual);
3706 }
else if (pel->channel_qual == INTENSITY_CHANNEL)
3708 regA = GetIntensity (pfx, ImgNum, (fxFltType) imgx, (fxFltType) imgy);
3713 pv = GetCacheViewVirtualPixels (
3714 pfx->Imgs[ImgNum].View, imgx, imgy, 1,1, pfx->exception);
3716 (void) ThrowMagickException (
3717 pfx->exception, GetMagickModule(), OptionError,
3718 "fU can't get cache",
"%lu", (
unsigned long) ImgNum);
3721 regA = QuantumScale * (double)
3722 pv[pfx->Images[ImgNum]->channel_map[WHICH_NON_ATTR_CHAN].offset];
3724 regA = ImageStat (pfx, ImgNum, WHICH_ATTR_CHAN, pel->img_attr_qual);
3733 Image * pimg = pfx->Images[0];
3734 if ((
int) pel->channel_qual < 0) {
3735 if (pel->channel_qual == NO_CHAN_QUAL || pel->channel_qual == THIS_CHANNEL) {
3737 if (pfx->ImgNum==0) {
3738 regA = QuantumScale * (double) p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3740 const Quantum * pv = GetCacheViewVirtualPixels (
3741 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3743 (void) ThrowMagickException (
3744 pfx->exception, GetMagickModule(), OptionError,
3745 "fU0 can't get cache",
"%i", 0);
3748 regA = QuantumScale * (double) pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3751 }
else if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL ||
3752 pel->channel_qual == LIGHT_CHANNEL) {
3753 regA = GetHslInt (pfx, 0, imgx, imgy, pel->channel_qual);
3755 }
else if (pel->channel_qual == INTENSITY_CHANNEL) {
3756 regA = GetIntensity (pfx, 0, (fxFltType) imgx, (fxFltType) imgy);
3759 if (pfx->ImgNum==0) {
3760 regA = QuantumScale * (double) p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3762 const Quantum * pv = GetCacheViewVirtualPixels (
3763 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3765 (void) ThrowMagickException (
3766 pfx->exception, GetMagickModule(), OptionError,
3767 "fU0 can't get cache",
"%i", 0);
3770 regA = QuantumScale * (double) pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3777 ssize_t ImgNum = ChkImgNum (pfx, regA);
3780 if (ImgNum < 0)
break;
3782 if (pel->is_relative) {
3790 if ((
int) pel->channel_qual < 0) {
3791 if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL
3792 || pel->channel_qual == LIGHT_CHANNEL) {
3793 regA = GetHslFlt (pfx, ImgNum, fx, fy, pel->channel_qual);
3795 }
else if (pel->channel_qual == INTENSITY_CHANNEL) {
3796 regA = GetIntensity (pfx, ImgNum, fx, fy);
3803 Image * imUP = pfx->Images[ImgNum];
3804 if (! InterpolatePixelChannel (imUP, pfx->Imgs[ImgNum].View, WHICH_NON_ATTR_CHAN,
3805 imUP->interpolate, (
double) fx, (
double) fy, &v, pfx->exception))
3807 (void) ThrowMagickException (
3808 pfx->exception, GetMagickModule(), OptionError,
3809 "fUP can't get interpolate",
"%lu", (
unsigned long) ImgNum);
3812 regA = v * QuantumScale;
3821 if (pel->operator_index == fS) ImgNum = pfx->ImgNum;
3823 if (pel->img_attr_qual == aNull) {
3824 const Quantum * pv = GetCacheViewVirtualPixels (
3825 pfx->Imgs[ImgNum].View, imgx, imgy, 1,1, pfx->exception);
3827 (void) ThrowMagickException (
3828 pfx->exception, GetMagickModule(), OptionError,
3829 "fV can't get cache",
"%lu", (
unsigned long) ImgNum);
3833 if ((
int) pel->channel_qual < 0) {
3834 if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL ||
3835 pel->channel_qual == LIGHT_CHANNEL) {
3836 regA = GetHslInt (pfx, ImgNum, imgx, imgy, pel->channel_qual);
3838 }
else if (pel->channel_qual == INTENSITY_CHANNEL) {
3839 regA = GetIntensity (pfx, ImgNum, (
double) imgx, (
double) imgy);
3844 regA = QuantumScale * (double)
3845 pv[pfx->Images[ImgNum]->channel_map[WHICH_NON_ATTR_CHAN].offset];
3847 regA = ImageStat (pfx, ImgNum, WHICH_ATTR_CHAN, pel->img_attr_qual);
3857 ssize_t ImgNum = pfx->ImgNum;
3858 if (pel->operator_index == fVP) ImgNum = 1;
3859 if (pel->is_relative) {
3866 if ((
int) pel->channel_qual < 0) {
3867 if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL ||
3868 pel->channel_qual == LIGHT_CHANNEL) {
3869 regA = GetHslFlt (pfx, ImgNum, fx, fy, pel->channel_qual);
3871 }
else if (pel->channel_qual == INTENSITY_CHANNEL) {
3872 regA = GetIntensity (pfx, ImgNum, fx, fy);
3880 if (! InterpolatePixelChannel (pfx->Images[ImgNum], pfx->Imgs[ImgNum].View,
3881 WHICH_NON_ATTR_CHAN, pfx->Images[ImgNum]->interpolate,
3882 (
double) fx, (
double) fy, &v, pfx->exception)
3885 (void) ThrowMagickException (
3886 pfx->exception, GetMagickModule(), OptionError,
3887 "fSP or fVP can't get interp",
"%lu", (
unsigned long) ImgNum);
3890 regA = v * (fxFltType)QuantumScale;
3898 regA = (fxFltType) GetImageDepth (img, pfx->exception);
3901 regA = (fxFltType) img->extent;
3905 regA = cs[WHICH_ATTR_CHAN].kurtosis;
3909 regA = cs[WHICH_ATTR_CHAN].maxima;
3913 regA = cs[WHICH_ATTR_CHAN].mean;
3917 regA = cs[WHICH_ATTR_CHAN].median;
3921 regA = cs[WHICH_ATTR_CHAN].minima;
3926 regA = (fxFltType) img->page.x;
3929 regA = (fxFltType) img->page.y;
3932 regA = (fxFltType) img->page.width;
3935 regA = (fxFltType) img->page.height;
3940 regA = (fxFltType) PerceptibleReciprocal (img->resolution.x) * img->columns;
3943 regA = (fxFltType) PerceptibleReciprocal (img->resolution.y) * img->rows;
3946 regA = (fxFltType) img->quality;
3951 regA = (fxFltType) img->resolution.x;
3954 regA = (fxFltType) img->resolution.y;
3958 regA = cs[WHICH_ATTR_CHAN].skewness;
3962 regA = cs[WHICH_ATTR_CHAN].standard_deviation;
3965 regA = (fxFltType) img->rows;
3968 regA = (fxFltType) pfx->ImgListLen;
3971 regA = (fxFltType) pfx->ImgNum;
3974 regA = (fxFltType) img->columns;
3977 regA = (fxFltType) GetImageDepth (img, pfx->exception);
3985 regA = GetIntensity (pfx, pfx->ImgNum, (
double) imgx, (
double) imgy);
3992 regA = QuantumScale * (0.212656 * (double) GetPixelRed (img,p) +
3993 0.715158 * (double) GetPixelGreen (img,p) +
3994 0.072186 * (double) GetPixelBlue (img,p));
4000 regA = QuantumScale * (double) GetPixelAlpha (img, p);
4003 regA = QuantumScale * (double) GetPixelBlue (img, p);
4006 regA = QuantumScale * (double) GetPixelCyan (img, p);
4009 regA = QuantumScale * (double) GetPixelGreen (img, p);
4012 regA = (fxFltType) imgx;
4015 regA = (fxFltType) imgy;
4018 regA = QuantumScale * (double) GetPixelBlack (img, p);
4021 regA = QuantumScale * (double) GetPixelGreen (img, p);
4024 regA = QuantumScale * (double) GetPixelAlpha (img, p);
4027 regA = QuantumScale * (double) GetPixelRed (img, p);
4030 regA = QuantumScale * (double) GetPixelYellow (img, p);
4036 assert (pel->element_index >= 0);
4037 i = pel->element_index-1;
4040 assert (pel->element_index >= 0);
4041 i = pel->element_index-1;
4042 if (IsImageTTLExpired(img) != MagickFalse) {
4043 i = pfx->usedElements-1;
4044 (void) ThrowMagickException (pfx->exception, GetMagickModule(),
4045 ResourceLimitFatalError,
"TimeLimitExceeded",
"`%s'", img->filename);
4049 assert (pel->element_index >= 0);
4050 if (fabs((
double) regA) < MagickEpsilon) i = pel->element_index-1;
4052 case rIfNotZeroGoto:
4053 assert (pel->element_index >= 0);
4054 if (fabs((
double) regA) > MagickEpsilon) i = pel->element_index-1;
4057 assert (pel->element_index >= 0);
4058 regA = pfxrt->UserSymVals[pel->element_index];
4061 assert (pel->element_index >= 0);
4062 pfxrt->UserSymVals[pel->element_index] = regA;
4065 pfxrt->usedValStack = 0;
4071 (void) ThrowMagickException (
4072 pfx->exception, GetMagickModule(), OptionError,
4073 "pel->oprNum",
"%i '%s' not yet implemented",
4074 (int)pel->operator_index, OprStr(pel->operator_index));
4078 if (!PushVal (pfx, pfxrt, regA, i))
break;
4081 if (pfxrt->usedValStack > 0) regA = PopVal (pfx, pfxrt, 9999);
4087 if (pfx->exception->severity >= ErrorException)
4090 if (pfxrt->usedValStack != 0) {
4091 (void) ThrowMagickException (
4092 pfx->exception, GetMagickModule(), OptionError,
4093 "ValStack not empty",
"(%i)", pfxrt->usedValStack);
4102MagickPrivate MagickBooleanType FxEvaluateChannelExpression (
4104 const PixelChannel channel,
const ssize_t x,
const ssize_t y,
4108 id = GetOpenMPThreadId();
4112 assert (pfx != NULL);
4113 assert (pfx->image != NULL);
4114 assert (pfx->Images != NULL);
4115 assert (pfx->Imgs != NULL);
4116 assert (pfx->fxrts != NULL);
4118 pfx->fxrts[id].thisPixel = NULL;
4120 if (!ExecuteRPN (pfx, &pfx->fxrts[
id], &ret, channel, x, y)) {
4121 (void) ThrowMagickException (
4122 exception, GetMagickModule(), OptionError,
4123 "ExecuteRPN failed",
" ");
4127 *result = (double) ret;
4132static FxInfo *AcquireFxInfoPrivate (
const Image * images,
const char * expression,
4137 FxInfo * pfx = (
FxInfo*) AcquireCriticalMemory (
sizeof (*pfx));
4139 memset (pfx, 0,
sizeof (*pfx));
4141 if (!InitFx (pfx, images, CalcAllStats, exception)) {
4142 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4146 if (!BuildRPN (pfx)) {
4147 (void) DeInitFx (pfx);
4148 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4152 if ((*expression ==
'@') && (strlen(expression) > 1))
4153 pfx->expression=FileToString(expression,~0UL,exception);
4154 if (pfx->expression == (
char *) NULL)
4155 pfx->expression=ConstantString(expression);
4156 pfx->pex = (
char *) pfx->expression;
4159 if (!TranslateStatementList (pfx,
";", &chLimit)) {
4160 (void) DestroyRPN (pfx);
4161 pfx->expression = DestroyString (pfx->expression);
4163 (void) DeInitFx (pfx);
4164 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4169 (void) ThrowMagickException (
4170 pfx->exception, GetMagickModule(), OptionError,
4171 "Translate expression depth",
"(%i) not 0",
4174 (void) DestroyRPN (pfx);
4175 pfx->expression = DestroyString (pfx->expression);
4177 (void) DeInitFx (pfx);
4178 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4182 if (chLimit !=
'\0' && chLimit !=
';') {
4183 (void) ThrowMagickException (
4184 pfx->exception, GetMagickModule(), OptionError,
4185 "AcquireFxInfo: TranslateExpression did not exhaust input",
"(chLimit=%i) at'%s'",
4186 (int)chLimit, pfx->pex);
4188 (void) DestroyRPN (pfx);
4189 pfx->expression = DestroyString (pfx->expression);
4191 (void) DeInitFx (pfx);
4192 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4196 if (pfx->NeedStats && pfx->runType == rtEntireImage && !pfx->statistics) {
4197 if (!CollectStatistics (pfx)) {
4198 (void) DestroyRPN (pfx);
4199 pfx->expression = DestroyString (pfx->expression);
4201 (void) DeInitFx (pfx);
4202 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4207 if (pfx->DebugOpt) {
4208 DumpTables (stderr);
4209 DumpUserSymbols (pfx, stderr);
4210 (void) DumpRPN (pfx, stderr);
4214 size_t number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
4217 pfx->fxrts = (
fxRtT *)AcquireQuantumMemory (number_threads,
sizeof(
fxRtT));
4219 (void) ThrowMagickException (
4220 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
4222 (
unsigned long) number_threads);
4223 (void) DestroyRPN (pfx);
4224 pfx->expression = DestroyString (pfx->expression);
4226 (void) DeInitFx (pfx);
4227 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4230 for (t=0; t < (ssize_t) number_threads; t++) {
4231 if (!AllocFxRt (pfx, &pfx->fxrts[t])) {
4232 (void) ThrowMagickException (
4233 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
4234 "AllocFxRt t=",
"%g",
4238 for (t2 = t-1; t2 >= 0; t2--) {
4239 DestroyFxRt (&pfx->fxrts[t2]);
4242 pfx->fxrts = (
fxRtT *) RelinquishMagickMemory (pfx->fxrts);
4243 (void) DestroyRPN (pfx);
4244 pfx->expression = DestroyString (pfx->expression);
4246 (void) DeInitFx (pfx);
4247 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4257 return AcquireFxInfoPrivate (images, expression, MagickFalse, exception);
4264 assert (pfx != NULL);
4265 assert (pfx->image != NULL);
4266 assert (pfx->Images != NULL);
4267 assert (pfx->Imgs != NULL);
4268 assert (pfx->fxrts != NULL);
4270 for (t=0; t < (ssize_t) GetMagickResourceLimit(ThreadResource); t++) {
4271 DestroyFxRt (&pfx->fxrts[t]);
4273 pfx->fxrts = (
fxRtT *) RelinquishMagickMemory (pfx->fxrts);
4277 pfx->expression = DestroyString (pfx->expression);
4280 (void) DeInitFx (pfx);
4282 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4289MagickExport
Image *FxImage(
const Image *image,
const char *expression,
4292#define FxImageTag "FxNew/Image"
4313 assert(image != (
Image *) NULL);
4314 assert(image->signature == MagickCoreSignature);
4315 if (IsEventLogging() != MagickFalse)
4316 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4317 if (expression == (
const char *) NULL)
4318 return(CloneImage(image,0,0,MagickTrue,exception));
4319 fx_image=CloneImage(image,0,0,MagickTrue,exception);
4320 if (!fx_image)
return NULL;
4321 if (SetImageStorageClass(fx_image,DirectClass,exception) == MagickFalse) {
4322 fx_image=DestroyImage(fx_image);
4326 pfx = AcquireFxInfoPrivate (image, expression, MagickTrue, exception);
4329 fx_image=DestroyImage(fx_image);
4333 assert (pfx->image != NULL);
4334 assert (pfx->Images != NULL);
4335 assert (pfx->Imgs != NULL);
4336 assert (pfx->fxrts != NULL);
4340 image_view = AcquireVirtualCacheView (image, pfx->exception);
4341 fx_view = AcquireAuthenticCacheView (fx_image, pfx->exception);
4342#if defined(MAGICKCORE_OPENMP_SUPPORT)
4343 #pragma omp parallel for schedule(dynamic) shared(progress,status) \
4344 magick_number_threads(image,fx_image,fx_image->rows, \
4345 pfx->ContainsDebug ? 0 : 1)
4347 for (y=0; y < (ssize_t) fx_image->rows; y++)
4350 id = GetOpenMPThreadId();
4364 if (status == MagickFalse)
4366 p = GetCacheViewVirtualPixels (image_view, 0, y, image->columns, 1, pfx->exception);
4367 q = QueueCacheViewAuthenticPixels (fx_view, 0, y, fx_image->columns, 1, pfx->exception);
4368 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL)) {
4372 for (x=0; x < (ssize_t) fx_image->columns; x++) {
4375 pfx->fxrts[id].thisPixel = (Quantum *)p;
4377 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4379 PixelChannel channel = GetPixelChannelChannel (image, i);
4380 PixelTrait traits = GetPixelChannelTraits (image, channel);
4381 PixelTrait fx_traits = GetPixelChannelTraits (fx_image, channel);
4382 if ((traits == UndefinedPixelTrait) ||
4383 (fx_traits == UndefinedPixelTrait))
4385 if ((fx_traits & CopyPixelTrait) != 0) {
4386 SetPixelChannel (fx_image, channel, p[i], q);
4390 if (!ExecuteRPN (pfx, &pfx->fxrts[
id], &result, channel, x, y)) {
4395 q[i] = ClampToQuantum ((MagickRealType) (QuantumRange*result));
4397 p+=(ptrdiff_t) GetPixelChannels (image);
4398 q+=(ptrdiff_t) GetPixelChannels (fx_image);
4400 if (SyncCacheViewAuthenticPixels(fx_view, pfx->exception) == MagickFalse)
4402 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4407#if defined(MAGICKCORE_OPENMP_SUPPORT)
4411 proceed = SetImageProgress (image, FxImageTag, progress, image->rows);
4412 if (proceed == MagickFalse)
4417 fx_view = DestroyCacheView (fx_view);
4418 image_view = DestroyCacheView (image_view);
4422 if (pfx->DebugOpt && pfx->usedUserSymbols) {
4424 char UserSym[MagickPathExtent];
4425 fprintf (stderr,
"User symbols (%i):\n", pfx->usedUserSymbols);
4426 for (t=0; t < (int) GetMagickResourceLimit(ThreadResource); t++) {
4427 for (i = 0; i < (int) pfx->usedUserSymbols; i++) {
4428 fprintf (stderr,
"th=%i us=%i '%s': %.*Lg\n",
4429 t, i, NameOfUserSym (pfx, i, UserSym), pfx->precision, pfx->fxrts[t].UserSymVals[i]);
4434 if ((status == MagickFalse) || (pfx->exception->severity >= ErrorException))
4435 fx_image=DestroyImage(fx_image);
4437 pfx=DestroyFxInfo(pfx);