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;
162 {oAddEq,
"+=", 12, 1},
163 {oSubtractEq,
"-=", 12, 1},
164 {oMultiplyEq,
"*=", 13, 1},
165 {oDivideEq,
"/=", 13, 1},
166 {oPlusPlus,
"++", 12, 0},
167 {oSubSub,
"--", 12, 0},
169 {oSubtract,
"-", 12, 2},
170 {oMultiply,
"*", 13, 2},
171 {oDivide,
"/", 13, 2},
172 {oModulus,
"%", 13, 2},
173 {oUnaryPlus,
"+", 14, 1},
174 {oUnaryMinus,
"-", 14, 1},
175 {oLshift,
"<<", 11, 2},
176 {oRshift,
">>", 11, 2},
178 {oNotEq,
"!=", 9, 2},
179 {oLtEq,
"<=", 10, 2},
180 {oGtEq,
">=", 10, 2},
183 {oLogAnd,
"&&", 6, 2},
184 {oLogOr,
"||", 5, 2},
185 {oLogNot,
"!", 16, 1},
186 {oBitAnd,
"&", 8, 2},
188 {oBitNot,
"~", 16, 1},
192 {oOpenParen,
"(", 0, 0},
193 {oCloseParen,
")", 0, 0},
194 {oOpenBracket,
"[", 0, 0},
195 {oCloseBracket,
"]", 0, 0},
196 {oOpenBrace,
"{", 0, 0},
197 {oCloseBrace,
"}", 0, 0},
198 {oAssign,
"=", 3, 1},
199 {oNull,
"onull", 17, 0}
222 {cEpsilon, MagickEpsilon,
"epsilon"},
223 {cE, 2.7182818284590452354,
"e"},
224 {cOpaque, 1.0,
"opaque"},
225 {cPhi, MagickPHI,
"phi"},
226 {cPi, MagickPI,
"pi"},
227 {cQuantumRange, QuantumRange,
"quantumrange"},
228 {cQuantumScale, QuantumScale,
"quantumscale"},
229 {cTransparent, 0.0,
"transparent"},
230 {cMaxRgb, QuantumRange,
"MaxRGB"},
231 {cNull, 0.0,
"cnull"}
234#define FirstFunc ((FunctionE) (oNull+1))
238#if defined(MAGICKCORE_HAVE_ACOSH)
242#if defined(MAGICKCORE_HAVE_J1)
246#if defined(MAGICKCORE_HAVE_ASINH)
250#if defined(MAGICKCORE_HAVE_ATANH)
262#if defined(MAGICKCORE_HAVE_ERF)
272#if defined(MAGICKCORE_HAVE_J0)
275#if defined(MAGICKCORE_HAVE_J1)
278#if defined(MAGICKCORE_HAVE_J1)
324#if defined(MAGICKCORE_HAVE_ACOSH)
325 {fAcosh,
"acosh" , 1},
328#if defined(MAGICKCORE_HAVE_J1)
332#if defined(MAGICKCORE_HAVE_ASINH)
333 {fAsinh,
"asinh" , 1},
336#if defined(MAGICKCORE_HAVE_ATANH)
337 {fAtanh,
"atanh" , 1},
339 {fAtan2,
"atan2" , 2},
342 {fChannel,
"channel", 5},
343 {fClamp,
"clamp" , 1},
346 {fDebug,
"debug" , 1},
348#if defined(MAGICKCORE_HAVE_ERF)
352 {fFloor,
"floor" , 1},
353 {fGauss,
"gauss" , 1},
355 {fHypot,
"hypot" , 2},
357 {fIsnan,
"isnan" , 1},
358#if defined(MAGICKCORE_HAVE_J0)
361#if defined(MAGICKCORE_HAVE_J1)
364#if defined(MAGICKCORE_HAVE_J1)
368 {fLogtwo,
"logtwo", 1},
376 {fRound,
"round" , 1},
382 {fSquish,
"squish", 1},
385 {fTrunc,
"trunc" , 1},
389 {fWhile,
"while", 2},
402#define FirstImgAttr ((ImgAttrE) (fNull+1))
441 {aDepth,
"depth", 1},
442 {aExtent,
"extent", 0},
443 {aKurtosis,
"kurtosis", 1},
444 {aMaxima,
"maxima", 1},
446 {aMedian,
"median", 1},
447 {aMinima,
"minima", 1},
449 {aPageX,
"page.x", 0},
450 {aPageY,
"page.y", 0},
451 {aPageWid,
"page.width", 0},
452 {aPageHt,
"page.height", 0},
453 {aPrintsize,
"printsize", 0},
454 {aPrintsizeX,
"printsize.x", 0},
455 {aPrintsizeY,
"printsize.y", 0},
456 {aQuality,
"quality", 0},
457 {aRes,
"resolution", 0},
458 {aResX,
"resolution.x", 0},
459 {aResY,
"resolution.y", 0},
460 {aSkewness,
"skewness", 1},
461 {aStdDev,
"standard_deviation", 1},
473#define FirstSym ((SymbolE) (aNull+1))
501static const SymbolT Symbols[] = {
503 {sIntensity,
"intensity"},
504 {sLightness,
"lightness"},
506 {sLuminance,
"luminance"},
507 {sSaturation,
"saturation"},
528#define FirstCont (sNull+1)
550 {rGotoChk,
"gotochk", 0},
551 {rIfZeroGoto,
"ifzerogoto", 1},
552 {rIfNotZeroGoto,
"ifnotzerogoto", 1},
553 {rCopyFrom,
"copyfrom", 0},
554 {rCopyTo,
"copyto", 1},
555 {rZerStk,
"zerstk", 0},
559#define NULL_ADDRESS -2
568 PixelChannel pixChan;
571#define NO_CHAN_QUAL ((PixelChannel) (-1))
572#define THIS_CHANNEL ((PixelChannel) (-2))
573#define HUE_CHANNEL ((PixelChannel) (-3))
574#define SAT_CHANNEL ((PixelChannel) (-4))
575#define LIGHT_CHANNEL ((PixelChannel) (-5))
576#define INTENSITY_CHANNEL ((PixelChannel) (-6))
579 {
"r", RedPixelChannel},
580 {
"g", GreenPixelChannel},
581 {
"b", BluePixelChannel},
582 {
"c", CyanPixelChannel},
583 {
"m", MagentaPixelChannel},
584 {
"y", YellowPixelChannel},
585 {
"k", BlackPixelChannel},
586 {
"a", AlphaPixelChannel},
587 {
"o", AlphaPixelChannel},
588 {
"hue", HUE_CHANNEL},
589 {
"saturation", SAT_CHANNEL},
590 {
"lightness", LIGHT_CHANNEL},
591 {
"intensity", INTENSITY_CHANNEL},
592 {
"all", CompositePixelChannel},
593 {
"this", THIS_CHANNEL},
614static const char * sElementTypes[] = {
630 MagickBooleanType IsRelative;
631 MagickBooleanType DoPush;
634 PixelChannel ChannelQual;
635 ImgAttrE ImgAttrQual;
655 fxFltType * ValStack;
656 fxFltType * UserSymVals;
664 MagickBooleanType NeedStats;
665 MagickBooleanType GotStats;
666 MagickBooleanType NeedHsl;
667 MagickBooleanType DebugOpt;
668 MagickBooleanType ContainsDebug;
671 char ShortExp[MagickPathExtent];
673 char token[MagickPathExtent];
684 OperatorE * OperatorStack;
690 **magick_restrict random_infos;
702static MagickBooleanType TranslateStatementList
703 (
FxInfo * pfx,
const char * strLimit,
char * chLimit);
705static MagickBooleanType TranslateExpression
706 (
FxInfo * pfx,
const char * strLimit,
char * chLimit, MagickBooleanType * needPopAll);
708static MagickBooleanType GetFunction (
FxInfo * pfx, FunctionE fe);
710static inline MagickBooleanType ChanIsVirtual (PixelChannel pc)
712 if (pc==HUE_CHANNEL || pc==SAT_CHANNEL || pc==LIGHT_CHANNEL || pc==INTENSITY_CHANNEL)
718static MagickBooleanType InitFx (
FxInfo * pfx,
const Image * img,
724 pfx->ImgListLen = GetImageListLength (img);
725 pfx->ImgNum = GetImageIndexInList (img);
726 pfx->image = (
Image *)img;
728 pfx->NeedStats = MagickFalse;
729 pfx->GotStats = MagickFalse;
730 pfx->NeedHsl = MagickFalse;
731 pfx->DebugOpt = IsStringTrue (GetImageArtifact (img,
"fx:debug"));
732 pfx->statistics = NULL;
735 pfx->exception = exception;
736 pfx->precision = GetMagickPrecision ();
737 pfx->random_infos = AcquireRandomInfoTLS ();
738 pfx->ContainsDebug = MagickFalse;
739 pfx->runType = (CalcAllStats) ? rtEntireImage : rtCornerOnly;
740 pfx->Imgs = (
ImgT *)AcquireQuantumMemory (pfx->ImgListLen, sizeof (
ImgT));
742 (void) ThrowMagickException (
743 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
745 (
unsigned long) pfx->ImgListLen);
749 next = GetFirstImageInList (img);
750 for ( ; next != (
Image *) NULL; next=next->next)
752 ImgT * pimg = &pfx->Imgs[i];
753 pimg->View = AcquireVirtualCacheView (next, pfx->exception);
755 (void) ThrowMagickException (
756 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
760 for ( ; i > 0; i--) {
761 pimg = &pfx->Imgs[i-1];
762 pimg->View = DestroyCacheView (pimg->View);
764 pfx->Imgs=(
ImgT *) RelinquishMagickMemory (pfx->Imgs);
770 pfx->Images = ImageListToArray (img, pfx->exception);
775static MagickBooleanType DeInitFx (
FxInfo * pfx)
779 if (pfx->Images) pfx->Images = (
Image**) RelinquishMagickMemory (pfx->Images);
782 for (i = (ssize_t)GetImageListLength(pfx->image); i > 0; i--) {
783 ImgT * pimg = &pfx->Imgs[i-1];
784 pimg->View = DestroyCacheView (pimg->View);
786 pfx->Imgs=(
ImgT *) RelinquishMagickMemory (pfx->Imgs);
788 pfx->random_infos = DestroyRandomInfoTLS (pfx->random_infos);
790 if (pfx->statistics) {
791 for (i = (ssize_t)GetImageListLength(pfx->image); i > 0; i--) {
792 pfx->statistics[i-1]=(
ChannelStatistics *) RelinquishMagickMemory (pfx->statistics[i-1]);
801static ElementTypeE TypeOfOpr (
int op)
803 if (op < oNull)
return etOperator;
804 if (op == oNull)
return etConstant;
805 if (op <= fNull)
return etFunction;
806 if (op <= aNull)
return etImgAttr;
807 if (op <= sNull)
return etSymbol;
808 if (op <= rNull)
return etControl;
810 return (ElementTypeE) 0;
813static char * SetPtrShortExp (
FxInfo * pfx,
char * pExp,
size_t len)
820 *pfx->ShortExp =
'\0';
823 slen = CopyMagickString (pfx->ShortExp, pExp, len);
825 (void) CopyMagickString (pfx->ShortExp+MaxLen,
"...", 4);
827 p = strchr (pfx->ShortExp,
'\n');
828 if (p) (void) CopyMagickString (p,
"...", 4);
829 p = strchr (pfx->ShortExp,
'\r');
830 if (p) (void) CopyMagickString (p,
"...", 4);
832 return pfx->ShortExp;
835static char * SetShortExp (
FxInfo * pfx)
837 return SetPtrShortExp (pfx, pfx->pex, MaxTokenLen-1);
840static int FindUserSymbol (
FxInfo * pfx,
char * name)
847 lenName = strlen (name);
848 for (i=0; i < pfx->usedUserSymbols; i++) {
850 if (lenName == pus->len && LocaleNCompare (name, pus->pex, lenName)==0)
break;
852 if (i == pfx->usedUserSymbols)
return NULL_ADDRESS;
856static MagickBooleanType ExtendUserSymbols (
FxInfo * pfx)
858 pfx->numUserSymbols = (int) ceil (pfx->numUserSymbols * (1 + TableExtend));
859 pfx->UserSymbols = (
UserSymbolT*) ResizeMagickMemory (pfx->UserSymbols, (
size_t) pfx->numUserSymbols *
sizeof(
UserSymbolT));
860 if (!pfx->UserSymbols) {
861 (void) ThrowMagickException (
862 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
864 pfx->numUserSymbols);
871static int AddUserSymbol (
FxInfo * pfx,
char * pex,
size_t len)
874 if (++pfx->usedUserSymbols >= pfx->numUserSymbols) {
875 if (!ExtendUserSymbols (pfx))
return -1;
877 pus = &pfx->UserSymbols[pfx->usedUserSymbols-1];
881 return pfx->usedUserSymbols-1;
884static void DumpTables (FILE * fh)
888 for (i=0; i <= rNull; i++) {
889 const char * str =
"";
890 if ( i < oNull) str = Operators[i].str;
891 if (i >= (
int) FirstFunc && i < fNull) str = Functions[i-(int) FirstFunc].str;
892 if (i >= (
int) FirstImgAttr && i < aNull) str = ImgAttrs[i-(
int) FirstImgAttr].str;
893 if (i >= (
int) FirstSym && i < sNull) str = Symbols[i-(
int) FirstSym].str;
894 if (i >= (
int) FirstCont && i < rNull) str = Controls[i-(
int) FirstCont].str;
895 if (i==0 ) fprintf (stderr,
"Operators:\n ");
896 else if (i==oNull) fprintf (stderr,
"\nFunctions:\n ");
897 else if (i==fNull) fprintf (stderr,
"\nImage attributes:\n ");
898 else if (i==aNull) fprintf (stderr,
"\nSymbols:\n ");
899 else if (i==sNull) fprintf (stderr,
"\nControls:\n ");
900 fprintf (fh,
" %s", str);
905static char * NameOfUserSym (
FxInfo * pfx,
int ndx,
char * buf)
908 assert (ndx >= 0 && ndx < pfx->usedUserSymbols);
909 pus = &pfx->UserSymbols[ndx];
910 (void) CopyMagickString (buf, pus->pex, pus->len+1);
914static void DumpUserSymbols (
FxInfo * pfx, FILE * fh)
916 char UserSym[MagickPathExtent];
918 fprintf (fh,
"UserSymbols (%i)\n", pfx->usedUserSymbols);
919 for (i=0; i < pfx->usedUserSymbols; i++) {
920 fprintf (fh,
" %i: '%s'\n", i, NameOfUserSym (pfx, i, UserSym));
924static MagickBooleanType BuildRPN (
FxInfo * pfx)
926 pfx->numUserSymbols = InitNumUserSymbols;
927 pfx->usedUserSymbols = 0;
928 pfx->UserSymbols = (
UserSymbolT*) AcquireMagickMemory ((
size_t) pfx->numUserSymbols *
sizeof(
UserSymbolT));
929 if (!pfx->UserSymbols) {
930 (void) ThrowMagickException (
931 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
933 pfx->numUserSymbols);
937 pfx->numElements = RpnInit;
938 pfx->usedElements = 0;
939 pfx->Elements = NULL;
941 pfx->Elements = (
ElementT*) AcquireMagickMemory ((
size_t) pfx->numElements *
sizeof(
ElementT));
943 if (!pfx->Elements) {
944 (void) ThrowMagickException (
945 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
951 pfx->usedOprStack = 0;
952 pfx->maxUsedOprStack = 0;
953 pfx->numOprStack = InitNumOprStack;
954 pfx->OperatorStack = (OperatorE*) AcquireMagickMemory ((
size_t) pfx->numOprStack *
sizeof(OperatorE));
955 if (!pfx->OperatorStack) {
956 (void) ThrowMagickException (
957 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
958 "OperatorStack",
"%i",
966static MagickBooleanType AllocFxRt (
FxInfo * pfx,
fxRtT * pfxrt)
970 pfxrt->random_info = AcquireRandomInfo ();
971 pfxrt->thisPixel = NULL;
973 nRnd = 20 + 10 * (int) GetPseudoRandomValue (pfxrt->random_info);
974 for (i=0; i < nRnd; i++) (
void) GetPseudoRandomValue (pfxrt->random_info);;
976 pfxrt->usedValStack = 0;
977 pfxrt->numValStack = 2 * pfx->maxUsedOprStack;
978 if (pfxrt->numValStack < MinValStackSize) pfxrt->numValStack = MinValStackSize;
979 pfxrt->ValStack = (fxFltType*) AcquireMagickMemory ((
size_t) pfxrt->numValStack *
sizeof(fxFltType));
980 if (!pfxrt->ValStack) {
981 (void) ThrowMagickException (
982 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
988 pfxrt->UserSymVals = NULL;
990 if (pfx->usedUserSymbols) {
991 pfxrt->UserSymVals = (fxFltType*) AcquireMagickMemory ((
size_t) pfx->usedUserSymbols *
sizeof(fxFltType));
992 if (!pfxrt->UserSymVals) {
993 (void) ThrowMagickException (
994 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
996 pfx->usedUserSymbols);
999 for (i = 0; i < pfx->usedUserSymbols; i++) pfxrt->UserSymVals[i] = (fxFltType) 0;
1005static MagickBooleanType ExtendRPN (
FxInfo * pfx)
1007 pfx->numElements = (int) ceil (pfx->numElements * (1 + TableExtend));
1008 pfx->Elements = (
ElementT*) ResizeMagickMemory (pfx->Elements, (
size_t) pfx->numElements *
sizeof(
ElementT));
1009 if (!pfx->Elements) {
1010 (void) ThrowMagickException (
1011 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1019static inline MagickBooleanType OprInPlace (
int op)
1021 return (op >= oAddEq && op <= oSubSub ? MagickTrue : MagickFalse);
1024static const char * OprStr (
int oprNum)
1027 if (oprNum < 0) str =
"bad OprStr";
1028 else if (oprNum <= oNull) str = Operators[oprNum].str;
1029 else if (oprNum <= fNull) str = Functions[oprNum-(int) FirstFunc].str;
1030 else if (oprNum <= aNull) str = ImgAttrs[oprNum-(int) FirstImgAttr].str;
1031 else if (oprNum <= sNull) str = Symbols[oprNum-(int) FirstSym].str;
1032 else if (oprNum <= rNull) str = Controls[oprNum-(int) FirstCont].str;
1039static MagickBooleanType DumpRPN (
FxInfo * pfx, FILE * fh)
1043 fprintf (fh,
"DumpRPN:");
1044 fprintf (fh,
" numElements=%i", pfx->numElements);
1045 fprintf (fh,
" usedElements=%i", pfx->usedElements);
1046 fprintf (fh,
" maxUsedOprStack=%i", pfx->maxUsedOprStack);
1047 fprintf (fh,
" ImgListLen=%g", (
double) pfx->ImgListLen);
1048 fprintf (fh,
" NeedStats=%s", pfx->NeedStats ?
"yes" :
"no");
1049 fprintf (fh,
" GotStats=%s", pfx->GotStats ?
"yes" :
"no");
1050 fprintf (fh,
" NeedHsl=%s\n", pfx->NeedHsl ?
"yes" :
"no");
1051 if (pfx->runType==rtEntireImage) fprintf (stderr,
"EntireImage");
1052 else if (pfx->runType==rtCornerOnly) fprintf (stderr,
"CornerOnly");
1056 for (i=0; i < pfx->usedElements; i++) {
1057 ElementT * pel = &pfx->Elements[i];
1060 for (i=0; i < pfx->usedElements; i++) {
1061 ElementT * pel = &pfx->Elements[i];
1062 if (pel->oprNum == rGoto || pel->oprNum == rGotoChk || pel->oprNum == rIfZeroGoto || pel->oprNum == rIfNotZeroGoto) {
1063 if (pel->EleNdx >= 0 && pel->EleNdx < pfx->numElements) {
1064 ElementT * pelDest = &pfx->Elements[pel->EleNdx];
1069 for (i=0; i < pfx->usedElements; i++) {
1070 char UserSym[MagickPathExtent];
1072 ElementT * pel = &pfx->Elements[i];
1073 const char * str = OprStr (pel->oprNum);
1074 const char *sRelAbs =
"";
1076 if (pel->oprNum == fP || pel->oprNum == fUP || pel->oprNum == fVP || pel->oprNum == fSP)
1077 sRelAbs = pel->IsRelative ?
"[]" :
"{}";
1079 if (pel->type == etColourConstant)
1080 fprintf (fh,
" %i: %s vals=%.*Lg,%.*Lg,%.*Lg '%s%s' nArgs=%i ndx=%i %s",
1081 i, sElementTypes[pel->type],
1082 pfx->precision, pel->val, pfx->precision, pel->val1, pfx->precision, pel->val2,
1083 str, sRelAbs, pel->nArgs, pel->EleNdx,
1084 pel->DoPush ?
"push" :
"NO push");
1086 fprintf (fh,
" %i: %s val=%.*Lg '%s%s' nArgs=%i ndx=%i %s",
1087 i, sElementTypes[pel->type], pfx->precision, pel->val, str, sRelAbs,
1088 pel->nArgs, pel->EleNdx,
1089 pel->DoPush ?
"push" :
"NO push");
1091 if (pel->ImgAttrQual != aNull)
1092 fprintf (fh,
" ia=%s", OprStr((
int) pel->ImgAttrQual));
1094 if (pel->ChannelQual != NO_CHAN_QUAL) {
1095 if (pel->ChannelQual == THIS_CHANNEL) fprintf (stderr,
" ch=this");
1096 else fprintf (stderr,
" ch=%i", pel->ChannelQual);
1099 if (pel->oprNum == rCopyTo) {
1100 fprintf (fh,
" CopyTo ==> %s", NameOfUserSym (pfx, pel->EleNdx, UserSym));
1101 }
else if (pel->oprNum == rCopyFrom) {
1102 fprintf (fh,
" CopyFrom <== %s", NameOfUserSym (pfx, pel->EleNdx, UserSym));
1103 }
else if (OprInPlace (pel->oprNum)) {
1104 fprintf (fh,
" <==> %s", NameOfUserSym (pfx, pel->EleNdx, UserSym));
1106 if (pel->nDest > 0) fprintf (fh,
" <==dest(%i)", pel->nDest);
1112static void DestroyRPN (
FxInfo * pfx)
1114 pfx->numOprStack = 0;
1115 pfx->usedOprStack = 0;
1116 if (pfx->OperatorStack) pfx->OperatorStack = (OperatorE*) RelinquishMagickMemory (pfx->OperatorStack);
1118 pfx->numElements = 0;
1119 pfx->usedElements = 0;
1120 if (pfx->Elements) pfx->Elements = (
ElementT*) RelinquishMagickMemory (pfx->Elements);
1122 pfx->usedUserSymbols = 0;
1123 if (pfx->UserSymbols) pfx->UserSymbols = (
UserSymbolT*) RelinquishMagickMemory (pfx->UserSymbols);
1126static void DestroyFxRt (
fxRtT * pfxrt)
1128 pfxrt->usedValStack = 0;
1129 if (pfxrt->ValStack) pfxrt->ValStack = (fxFltType*) RelinquishMagickMemory (pfxrt->ValStack);
1130 if (pfxrt->UserSymVals) pfxrt->UserSymVals = (fxFltType*) RelinquishMagickMemory (pfxrt->UserSymVals);
1132 pfxrt->random_info = DestroyRandomInfo (pfxrt->random_info);
1135static size_t GetToken (
FxInfo * pfx)
1146 char * p = pfx->pex;
1150 if (!isalpha((
int)*p))
return 0;
1157 if (LocaleNCompare (p,
"icc-", 4) == 0) {
1160 while (isalpha ((
int)*p)) { len++; p++; }
1161 }
else if (LocaleNCompare (p,
"device-", 7) == 0) {
1164 while (isalpha ((
int)*p)) { len++; p++; }
1166 while (isalpha ((
int)*p)) { len++; p++; }
1167 if (*p ==
'_') { len++; p++; }
1168 while (isalpha ((
int)*p)) { len++; p++; }
1169 while (isdigit ((
int)*p)) { len++; p++; }
1171 if (len >= MaxTokenLen) {
1172 (void) ThrowMagickException (
1173 pfx->exception, GetMagickModule(), OptionError,
1174 "GetToken: too long",
"%g at '%s'",
1175 (double) len, SetShortExp(pfx));
1179 (void) CopyMagickString (pfx->token, pfx->pex, (len+1<MaxTokenLen)?len+1:MaxTokenLen);
1182 pfx->lenToken = strlen (pfx->token);
1186static MagickBooleanType TokenMaybeUserSymbol (
FxInfo * pfx)
1188 char * p = pfx->token;
1191 if (!isalpha ((
int)*p++))
return MagickFalse;
1194 if (i < 2)
return MagickFalse;
1198static MagickBooleanType AddElement (
FxInfo * pfx, fxFltType val,
int oprNum)
1202 assert (oprNum <= rNull);
1204 if (++pfx->usedElements >= pfx->numElements) {
1205 if (!ExtendRPN (pfx))
return MagickFalse;
1208 pel = &pfx->Elements[pfx->usedElements-1];
1209 pel->type = TypeOfOpr (oprNum);
1211 pel->val1 = (fxFltType) 0;
1212 pel->val2 = (fxFltType) 0;
1213 pel->oprNum = oprNum;
1214 pel->DoPush = MagickTrue;
1216 pel->ChannelQual = NO_CHAN_QUAL;
1217 pel->ImgAttrQual = aNull;
1219 pel->pExpStart = NULL;
1222 if (oprNum <= oNull) pel->nArgs = Operators[oprNum].nArgs;
1223 else if (oprNum <= fNull) pel->nArgs = Functions[oprNum-(int) FirstFunc].nArgs;
1224 else if (oprNum <= aNull) pel->nArgs = 0;
1225 else if (oprNum <= sNull) pel->nArgs = 0;
1226 else pel->nArgs = Controls[oprNum-(int) FirstCont].nArgs;
1231static MagickBooleanType AddAddressingElement (
FxInfo * pfx,
int oprNum,
int EleNdx)
1234 if (!AddElement (pfx, (fxFltType) 0, oprNum))
return MagickFalse;
1235 pel = &pfx->Elements[pfx->usedElements-1];
1236 pel->EleNdx = EleNdx;
1237 if (oprNum == rGoto || oprNum == rGotoChk || oprNum == rIfZeroGoto || oprNum == rIfNotZeroGoto
1238 || oprNum == rZerStk)
1240 pel->DoPush = MagickFalse;
1250static MagickBooleanType AddColourElement (
FxInfo * pfx, fxFltType val0, fxFltType val1, fxFltType val2)
1253 if (!AddElement (pfx, val0, oNull))
return MagickFalse;
1254 pel = &pfx->Elements[pfx->usedElements-1];
1257 pel->type = etColourConstant;
1261static inline void SkipSpaces (
FxInfo * pfx)
1263 while (isspace ((
int)*pfx->pex)) pfx->pex++;
1266static inline char PeekChar (
FxInfo * pfx)
1272static inline MagickBooleanType PeekStr (
FxInfo * pfx,
const char * str)
1276 return (LocaleNCompare (pfx->pex, str, strlen(str))==0 ? MagickTrue : MagickFalse);
1279static MagickBooleanType ExpectChar (
FxInfo * pfx,
char c)
1281 if (PeekChar (pfx) != c) {
1282 (void) ThrowMagickException (
1283 pfx->exception, GetMagickModule(), OptionError,
1284 "Expected char",
"'%c' at '%s'", c, SetShortExp (pfx));
1291static int MaybeXYWH (
FxInfo * pfx, ImgAttrE * pop)
1298 if (*pop != aPage && *pop != aPrintsize && *pop != aRes)
return 0;
1300 if (PeekChar (pfx) !=
'.')
return 0;
1302 if (!ExpectChar (pfx,
'.'))
return 0;
1304 (void) GetToken (pfx);
1305 if (LocaleCompare (
"x", pfx->token)==0) ret=1;
1306 else if (LocaleCompare (
"y", pfx->token)==0) ret=2;
1307 else if (LocaleCompare (
"width", pfx->token)==0) ret=3;
1308 else if (LocaleCompare (
"height", pfx->token)==0) ret=4;
1311 (void) ThrowMagickException (
1312 pfx->exception, GetMagickModule(), OptionError,
1313 "Invalid 'x' or 'y' or 'width' or 'height' token=",
"'%s' at '%s'",
1314 pfx->token, SetShortExp(pfx));
1316 if (*pop == aPage) (*pop) = (ImgAttrE) ((
int) *pop + ret);
1319 (void) ThrowMagickException (
1320 pfx->exception, GetMagickModule(), OptionError,
1321 "Invalid 'width' or 'height' token=",
"'%s' at '%s'",
1322 pfx->token, SetShortExp(pfx));
1324 (*pop) = (ImgAttrE) ((
int) *pop + ret);
1327 pfx->pex+=pfx->lenToken;
1332static MagickBooleanType ExtendOperatorStack (
FxInfo * pfx)
1334 pfx->numOprStack = (int) ceil (pfx->numOprStack * (1 + TableExtend));
1335 pfx->OperatorStack = (OperatorE*) ResizeMagickMemory (pfx->OperatorStack, (
size_t) pfx->numOprStack *
sizeof(OperatorE));
1336 if (!pfx->OperatorStack) {
1337 (void) ThrowMagickException (
1338 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1346static MagickBooleanType PushOperatorStack (
FxInfo * pfx,
int op)
1348 if (++pfx->usedOprStack >= pfx->numOprStack) {
1349 if (!ExtendOperatorStack (pfx))
1352 pfx->OperatorStack[pfx->usedOprStack-1] = (OperatorE) op;
1354 if (pfx->maxUsedOprStack < pfx->usedOprStack)
1355 pfx->maxUsedOprStack = pfx->usedOprStack;
1359static OperatorE GetLeadingOp (
FxInfo * pfx)
1361 OperatorE op = oNull;
1363 if (*pfx->pex ==
'-') op = oUnaryMinus;
1364 else if (*pfx->pex ==
'+') op = oUnaryPlus;
1365 else if (*pfx->pex ==
'~') op = oBitNot;
1366 else if (*pfx->pex ==
'!') op = oLogNot;
1367 else if (*pfx->pex ==
'(') op = oOpenParen;
1372static inline MagickBooleanType OprIsUnaryPrefix (OperatorE op)
1374 return (op == oUnaryMinus || op == oUnaryPlus || op == oBitNot || op == oLogNot ? MagickTrue : MagickFalse);
1377static MagickBooleanType TopOprIsUnaryPrefix (
FxInfo * pfx)
1379 if (!pfx->usedOprStack)
return MagickFalse;
1381 return OprIsUnaryPrefix (pfx->OperatorStack[pfx->usedOprStack-1]);
1384static MagickBooleanType PopOprOpenParen (
FxInfo * pfx, OperatorE op)
1387 if (!pfx->usedOprStack)
return MagickFalse;
1389 if (pfx->OperatorStack[pfx->usedOprStack-1] != op)
return MagickFalse;
1391 pfx->usedOprStack--;
1396static int GetCoordQualifier (
FxInfo * pfx,
int op)
1400 if (op != fU && op != fV && op != fS)
return -1;
1402 (void) GetToken (pfx);
1404 if (pfx->lenToken != 1) {
1407 if (*pfx->token !=
'p' && *pfx->token !=
'P')
return -1;
1408 if (!GetFunction (pfx, fP))
return -1;
1413static PixelChannel GetChannelQualifier (
FxInfo * pfx,
int op)
1415 if (op == fU || op == fV || op == fP ||
1416 op == fUP || op == fVP ||
1417 op == fS || (op >= (
int) FirstImgAttr && op <= aNull)
1420 const ChannelT * pch = &Channels[0];
1421 (void) GetToken (pfx);
1424 if (LocaleCompare (pch->str, pfx->token)==0) {
1426 if (op >= (
int) FirstImgAttr && op <= (int) ((OperatorE)aNull) &&
1427 ChanIsVirtual (pch->pixChan)
1430 (void) ThrowMagickException (
1431 pfx->exception, GetMagickModule(), OptionError,
1432 "Can't have image attribute with channel qualifier at",
"'%s' at '%s'",
1433 pfx->token, SetShortExp(pfx));
1434 return NO_CHAN_QUAL;
1437 pfx->pex += pfx->lenToken;
1438 return pch->pixChan;
1443 return NO_CHAN_QUAL;
1446static ImgAttrE GetImgAttrToken (
FxInfo * pfx)
1448 ImgAttrE ia = aNull;
1450 for (ia = FirstImgAttr; ia < aNull; ia=(ImgAttrE) (ia+1)) {
1451 iaStr = ImgAttrs[ia-(int) FirstImgAttr].str;
1452 if (LocaleCompare (iaStr, pfx->token)==0) {
1453 pfx->pex += strlen(pfx->token);
1454 if (ImgAttrs[ia-(
int) FirstImgAttr].NeedStats == 1) pfx->NeedStats = MagickTrue;
1455 MaybeXYWH (pfx, &ia);
1460 if (ia == aPage || ia == aPrintsize || ia == aRes) {
1461 (void) ThrowMagickException (
1462 pfx->exception, GetMagickModule(), OptionError,
1463 "Attribute",
"'%s' needs qualifier at '%s'",
1464 iaStr, SetShortExp(pfx));
1470static ImgAttrE GetImgAttrQualifier (
FxInfo * pfx,
int op)
1472 ImgAttrE ia = aNull;
1473 if (op == (OperatorE)fU || op == (OperatorE)fV || op == (OperatorE)fP || op == (OperatorE)fS) {
1474 (void) GetToken (pfx);
1475 if (pfx->lenToken == 0) {
1478 ia = GetImgAttrToken (pfx);
1483static MagickBooleanType IsQualifier (
FxInfo * pfx)
1485 if (PeekChar (pfx) ==
'.') {
1492static ssize_t GetProperty (
FxInfo * pfx, fxFltType *val)
1498 if (PeekStr (pfx,
"%[")) {
1501 char sProperty [MagickPathExtent];
1502 char * p = pfx->pex + 2;
1506 if (*p ==
'[') level++;
1507 else if (*p ==
']') {
1508 if (level == 0)
break;
1513 if (!*p || level != 0) {
1514 (void) ThrowMagickException (
1515 pfx->exception, GetMagickModule(), OptionError,
1516 "After '%[' expected ']' at",
"'%s'",
1521 len = (size_t) (p - pfx->pex + 1);
1522 if (len > MaxTokenLen) {
1523 (void) ThrowMagickException (
1524 pfx->exception, GetMagickModule(), OptionError,
1525 "Too much text between '%[' and ']' at",
"'%s'",
1530 (void) CopyMagickString (sProperty, pfx->pex, len+1);
1531 sProperty[len] =
'\0';
1535 text = InterpretImageProperties (pfx->image->image_info, pfx->image,
1536 sProperty, pfx->exception);
1537 if (!text || !*text) {
1538 text = DestroyString(text);
1539 (void) ThrowMagickException (
1540 pfx->exception, GetMagickModule(), OptionError,
1541 "Unknown property",
"'%s' at '%s'",
1542 sProperty, SetShortExp(pfx));
1546 *val = strtold (text, &tailptr);
1547 if (text == tailptr) {
1548 text = DestroyString(text);
1549 (void) ThrowMagickException (
1550 pfx->exception, GetMagickModule(), OptionError,
1551 "Property",
"'%s' text '%s' is not a number at '%s'",
1552 sProperty, text, SetShortExp(pfx));
1556 text = DestroyString(text);
1558 return ((ssize_t) len);
1564static inline ssize_t GetConstantColour (
FxInfo * pfx, fxFltType *v0, fxFltType *v1, fxFltType *v2)
1575 *dummy_exception = AcquireExceptionInfo ();
1585 char ColSp[MagickPathExtent];
1586 (void) CopyMagickString (ColSp, pfx->token, MaxTokenLen);
1587 p = ColSp + pfx->lenToken - 1;
1588 if (*p ==
'a' || *p ==
'A') *p =
'\0';
1590 (void) GetPixelInfo (pfx->image, &colour);
1594 IsGray = (LocaleCompare (ColSp,
"gray") == 0) ? MagickTrue : MagickFalse;
1595 IsIcc = (LocaleCompare (ColSp,
"icc-color") == 0) ? MagickTrue : MagickFalse;
1596 IsDev = (LocaleNCompare (ColSp,
"device-", 7) == 0) ? MagickTrue : MagickFalse;
1600 if (!QueryColorCompliance (pfx->token, AllCompliance, &colour, dummy_exception) || IsGray) {
1601 ssize_t type = ParseCommandOption (MagickColorspaceOptions, MagickFalse, ColSp);
1602 if (type >= 0 || IsIcc || IsDev) {
1603 char * q = pfx->pex + pfx->lenToken;
1604 while (isspace((
int) ((
unsigned char) *q))) q++;
1607 char sFunc[MagickPathExtent];
1608 while (*q && *q !=
')') q++;
1610 (void) ThrowMagickException (
1611 pfx->exception, GetMagickModule(), OptionError,
1612 "constant color missing ')'",
"at '%s'",
1614 dummy_exception = DestroyExceptionInfo (dummy_exception);
1617 lenfun = (size_t) (q - pfx->pex + 1);
1618 if (lenfun > MaxTokenLen) {
1619 (void) ThrowMagickException (
1620 pfx->exception, GetMagickModule(), OptionError,
1621 "lenfun too long",
"'%lu' at '%s'",
1622 (
unsigned long) lenfun, SetShortExp(pfx));
1623 dummy_exception = DestroyExceptionInfo (dummy_exception);
1626 (void) CopyMagickString (sFunc, pfx->pex, lenfun+1);
1627 if (QueryColorCompliance (sFunc, AllCompliance, &colour, dummy_exception)) {
1628 *v0 = QuantumScale*colour.red;
1629 *v1 = QuantumScale*colour.green;
1630 *v2 = QuantumScale*colour.blue;
1631 dummy_exception = DestroyExceptionInfo (dummy_exception);
1632 return (ssize_t)lenfun;
1635 (void) ThrowMagickException (
1636 pfx->exception, GetMagickModule(), OptionError,
1637 "colorspace but not a valid color with '(...)' at",
"'%s'",
1639 dummy_exception = DestroyExceptionInfo (dummy_exception);
1644 dummy_exception = DestroyExceptionInfo (dummy_exception);
1649 *v0 = QuantumScale*colour.red;
1650 *v1 = QuantumScale*colour.green;
1651 *v2 = QuantumScale*colour.blue;
1653 dummy_exception = DestroyExceptionInfo (dummy_exception);
1654 return (ssize_t)strlen (pfx->token);
1657static inline ssize_t GetHexColour (
FxInfo * pfx, fxFltType *v0, fxFltType *v1, fxFltType *v2)
1666 if (*pfx->pex !=
'#')
return 0;
1670 while (isxdigit ((
int)*p)) p++;
1671 if (isalpha ((
int)*p)) {
1672 (void) ThrowMagickException (
1673 pfx->exception, GetMagickModule(), OptionError,
1674 "Bad hex number at",
"'%s'",
1679 len = (size_t) (p - pfx->pex);
1680 if (len < 1)
return 0;
1681 if (len >= MaxTokenLen) {
1682 (void) ThrowMagickException (
1683 pfx->exception, GetMagickModule(), OptionError,
1684 "Hex colour too long at",
"'%s'",
1688 (void) CopyMagickString (pfx->token, pfx->pex, len+1);
1690 (void) GetPixelInfo (pfx->image, &colour);
1692 if (!QueryColorCompliance (pfx->token, AllCompliance, &colour, pfx->exception)) {
1693 (void) ThrowMagickException (
1694 pfx->exception, GetMagickModule(), OptionError,
1695 "QueryColorCompliance rejected",
"'%s' at '%s'",
1696 pfx->token, SetShortExp(pfx));
1700 *v0 = QuantumScale*colour.red;
1701 *v1 = QuantumScale*colour.green;
1702 *v2 = QuantumScale*colour.blue;
1704 return (ssize_t) len;
1707static MagickBooleanType GetFunction (
FxInfo * pfx, FunctionE fe)
1711 const char * funStr = Functions[fe-(int) FirstFunc].str;
1712 int nArgs = Functions[fe-(int) FirstFunc].nArgs;
1714 char expChLimit =
')';
1715 const char *strLimit =
",)";
1716 OperatorE pushOp = oOpenParen;
1723 int ndx0 = NULL_ADDRESS, ndx1 = NULL_ADDRESS, ndx2 = NULL_ADDRESS, ndx3 = NULL_ADDRESS;
1725 MagickBooleanType coordQual = MagickFalse;
1726 PixelChannel chQual = NO_CHAN_QUAL;
1727 ImgAttrE iaQual = aNull;
1729 pfx->pex += pfx->lenToken;
1732 char p = PeekChar (pfx);
1734 (void) ExpectChar (pfx,
'{');
1735 pushOp = oOpenBrace;
1739 }
else if (p==
'[') {
1740 (void) ExpectChar (pfx,
'[');
1741 pushOp = oOpenBracket;
1750 }
else if (fe == fU) {
1751 char p = PeekChar (pfx);
1753 (void) ExpectChar (pfx,
'[');
1754 pushOp = oOpenBracket;
1763 }
else if (fe == fV || fe == fS) {
1765 pushOp = oOpenBracket;
1769 if (!ExpectChar (pfx,
'('))
return MagickFalse;
1771 if (!PushOperatorStack (pfx, (
int) pushOp))
return MagickFalse;
1773 pExpStart = pfx->pex;
1774 ndx0 = pfx->usedElements;
1776 (void) AddAddressingElement (pfx, rGoto, NULL_ADDRESS);
1780 if (TranslateStatementList (pfx, strLimit, &chLimit)) {
1784 (void) ThrowMagickException (
1785 pfx->exception, GetMagickModule(), OptionError,
1786 "For function",
"'%s' expected ')' at '%s'",
1787 funStr, SetShortExp(pfx));
1791 if (!chLimit)
break;
1792 if (fe == fP || fe == fS|| fe == fIf) {
1793 (void) AddElement (pfx, (fxFltType) 0, oNull);
1798 if (strchr (strLimit, chLimit)==NULL) {
1799 (void) ThrowMagickException (
1800 pfx->exception, GetMagickModule(), OptionError,
1801 "For function",
"'%s' expected one of '%s' after expression but found '%c' at '%s'",
1802 funStr, strLimit, chLimit ? chLimit :
' ', SetShortExp(pfx));
1811 if (ndx1 != NULL_ADDRESS) {
1812 (void) ThrowMagickException (
1813 pfx->exception, GetMagickModule(), OptionError,
1814 "For function",
"'%s' required argument is missing at '%s'",
1815 funStr, SetShortExp(pfx));
1818 ndx1 = pfx->usedElements;
1819 if (fe==fWhile || fe==fIf) {
1820 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
1821 }
else if (fe==fDo) {
1822 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
1823 }
else if (fe==fFor) {
1824 pfx->Elements[pfx->usedElements-1].DoPush = MagickFalse;
1828 if (ndx2 != NULL_ADDRESS) {
1829 (void) ThrowMagickException (
1830 pfx->exception, GetMagickModule(), OptionError,
1831 "For function",
"'%s' required argument is missing at '%s'",
1832 funStr, SetShortExp(pfx));
1835 ndx2 = pfx->usedElements;
1837 pfx->Elements[pfx->usedElements-1].DoPush = MagickFalse;
1838 (void) AddAddressingElement (pfx, rGotoChk, ndx0);
1839 }
else if (fe==fDo) {
1840 pfx->Elements[pfx->usedElements-1].DoPush = MagickFalse;
1841 (void) AddAddressingElement (pfx, rGotoChk, ndx0 + 1);
1842 }
else if (fe==fFor) {
1843 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
1844 pfx->Elements[pfx->usedElements-1].DoPush = MagickTrue;
1845 (void) AddAddressingElement (pfx, rZerStk, NULL_ADDRESS);
1846 }
else if (fe==fIf) {
1847 (void) AddAddressingElement (pfx, rGoto, NULL_ADDRESS);
1851 if (ndx3 != NULL_ADDRESS) {
1852 (void) ThrowMagickException (
1853 pfx->exception, GetMagickModule(), OptionError,
1854 "For function",
"'%s' required argument is missing at '%s'",
1855 funStr, SetShortExp(pfx));
1859 pfx->Elements[pfx->usedElements-1].DoPush = MagickFalse;
1860 (void) AddAddressingElement (pfx, rGotoChk, ndx1);
1862 ndx3 = pfx->usedElements;
1867 if (chLimit == expChLimit) {
1868 lenExp = (size_t) (pfx->pex - pExpStart - 1);
1872 if (chLimit && chLimit != expChLimit && chLimit !=
',' ) {
1873 (void) ThrowMagickException (
1874 pfx->exception, GetMagickModule(), OptionError,
1875 "For function",
"'%s' expected '%c', found '%c' at '%s'",
1876 funStr, expChLimit, chLimit ? chLimit :
' ', SetShortExp(pfx));
1880 if (fe == fP || fe == fS || fe == fU || fe == fChannel) {
1881 while (FndArgs < Functions[fe-(
int) FirstFunc].nArgs) {
1882 (void) AddElement (pfx, (fxFltType) 0, oNull);
1887 if (FndArgs > Functions[fe-(
int) FirstFunc].nArgs)
1890 (void) ThrowMagickException (
1891 pfx->exception, GetMagickModule(), OptionError,
1892 "For function",
"'%s' expected up to %i arguments, found '%i' at '%s'",
1893 funStr, Functions[fe-(int) FirstFunc].nArgs, FndArgs, SetShortExp(pfx));
1895 (void) ThrowMagickException (
1896 pfx->exception, GetMagickModule(), OptionError,
1897 "For function",
"'%s' expected %i arguments, found '%i' at '%s'",
1898 funStr, Functions[fe-(int) FirstFunc].nArgs, FndArgs, SetShortExp(pfx));
1902 if (FndArgs < Functions[fe-(
int) FirstFunc].nArgs) {
1903 (void) ThrowMagickException (
1904 pfx->exception, GetMagickModule(), OptionError,
1905 "For function",
"'%s' expected %i arguments, found too few (%i) at '%s'",
1906 funStr, Functions[fe-(int) FirstFunc].nArgs, FndArgs, SetShortExp(pfx));
1909 if (fe != fS && fe != fV && FndArgs == 0 && Functions[fe-(
int) FirstFunc].nArgs == 0) {
1911 chLimit = expChLimit;
1912 if (!ExpectChar (pfx,
')'))
return MagickFalse;
1915 if (chLimit != expChLimit) {
1916 (void) ThrowMagickException (
1917 pfx->exception, GetMagickModule(), OptionError,
1918 "For function",
"'%s', arguments don't end with '%c' at '%s'",
1919 funStr, expChLimit, SetShortExp(pfx));
1922 if (!PopOprOpenParen (pfx, pushOp)) {
1923 (void) ThrowMagickException (
1924 pfx->exception, GetMagickModule(), OptionError,
1925 "Bug: For function",
"'%s' tos not '%s' at '%s'",
1926 funStr, Operators[pushOp].str, SetShortExp(pfx));
1930 if (IsQualifier (pfx)) {
1932 if (fe == fU || fe == fV || fe == fS) {
1934 coordQual = (GetCoordQualifier (pfx, (
int) fe) == 1) ? MagickTrue : MagickFalse;
1939 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
1940 if (pel->oprNum != fP) {
1941 (void) ThrowMagickException (
1942 pfx->exception, GetMagickModule(), OptionError,
1943 "Bug: For function",
"'%s' last element not 'p' at '%s'",
1944 funStr, SetShortExp(pfx));
1947 chQual = pel->ChannelQual;
1948 expChLimit = (pel->IsRelative) ?
']' :
'}';
1949 pfx->usedElements--;
1950 if (fe == fU) fe = fUP;
1951 else if (fe == fV) fe = fVP;
1952 else if (fe == fS) fe = fSP;
1953 funStr = Functions[fe-(int) FirstFunc].str;
1957 if ( chQual == NO_CHAN_QUAL &&
1958 (fe == fP || fe == fS || fe == fSP || fe == fU || fe == fUP || fe == fV || fe == fVP)
1961 chQual = GetChannelQualifier (pfx, (
int) fe);
1964 if (chQual == NO_CHAN_QUAL && (fe == fU || fe == fV || fe == fS)) {
1966 iaQual = GetImgAttrQualifier (pfx, (
int) fe);
1968 if (IsQualifier (pfx) && chQual == NO_CHAN_QUAL && iaQual != aNull) {
1969 chQual = GetChannelQualifier (pfx, (
int) fe);
1971 if (coordQual && iaQual != aNull) {
1972 (void) ThrowMagickException (
1973 pfx->exception, GetMagickModule(), OptionError,
1974 "For function",
"'%s', can't have qualifiers 'p' and image attribute '%s' at '%s'",
1975 funStr, pfx->token, SetShortExp(pfx));
1978 if (!coordQual && chQual == NO_CHAN_QUAL && iaQual == aNull) {
1979 (void) ThrowMagickException (
1980 pfx->exception, GetMagickModule(), OptionError,
1981 "For function",
"'%s', bad qualifier '%s' at '%s'",
1982 funStr, pfx->token, SetShortExp(pfx));
1985 if (!coordQual && chQual == CompositePixelChannel && iaQual == aNull) {
1986 (void) ThrowMagickException (
1987 pfx->exception, GetMagickModule(), OptionError,
1988 "For function",
"'%s', bad composite qualifier '%s' at '%s'",
1989 funStr, pfx->token, SetShortExp(pfx));
1993 if (chQual == HUE_CHANNEL || chQual == SAT_CHANNEL || chQual == LIGHT_CHANNEL) {
1994 pfx->NeedHsl = MagickTrue;
1996 if (iaQual >= FirstImgAttr && iaQual < aNull) {
1997 (void) ThrowMagickException (
1998 pfx->exception, GetMagickModule(), OptionError,
1999 "Can't have image attribute with HLS qualifier at",
"'%s'",
2006 if (iaQual != aNull && chQual != NO_CHAN_QUAL) {
2007 if (ImgAttrs[iaQual-(
int) FirstImgAttr].NeedStats==0) {
2008 (void) ThrowMagickException (
2009 pfx->exception, GetMagickModule(), OptionError,
2010 "Can't have image attribute ",
"'%s' with channel qualifier '%s' at '%s'",
2011 ImgAttrs[iaQual-(int) FirstImgAttr].str,
2012 pfx->token, SetShortExp(pfx));
2015 if (ChanIsVirtual (chQual)) {
2016 (void) ThrowMagickException (
2017 pfx->exception, GetMagickModule(), OptionError,
2018 "Can't have statistical image attribute ",
"'%s' with virtual channel qualifier '%s' at '%s'",
2019 ImgAttrs[iaQual-(int) FirstImgAttr].str,
2020 pfx->token, SetShortExp(pfx));
2027 pfx->Elements[ndx1].EleNdx = ndx2+1;
2028 }
else if (fe==fDo) {
2029 pfx->Elements[ndx0].EleNdx = ndx1+1;
2030 pfx->Elements[ndx1].EleNdx = ndx2+1;
2031 }
else if (fe==fFor) {
2032 pfx->Elements[ndx2].EleNdx = ndx3;
2033 }
else if (fe==fIf) {
2034 pfx->Elements[ndx1].EleNdx = ndx2 + 1;
2035 pfx->Elements[ndx2].EleNdx = ndx3;
2037 if (fe == fU && iaQual == aNull) {
2038 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2039 if (pel->type == etConstant && pel->val == 0.0) {
2040 pfx->usedElements--;
2044 (void) AddElement (pfx, (fxFltType) 0, (int) fe);
2045 if (fe == fP || fe == fU || fe == fU0 || fe == fUP ||
2046 fe == fV || fe == fVP || fe == fS || fe == fSP)
2048 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2049 pel->IsRelative = (expChLimit ==
']' ? MagickTrue : MagickFalse);
2050 if (chQual >= 0) pel->ChannelQual = chQual;
2051 if (iaQual != aNull && (fe == fU || fe == fV || fe == fS)) {
2053 pel->ImgAttrQual = iaQual;
2058 if (pExpStart && lenExp) {
2059 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2060 pel->pExpStart = pExpStart;
2061 pel->lenExp = lenExp;
2065 pfx->ContainsDebug = MagickTrue;
2070static MagickBooleanType IsStealth (
int op)
2072 return (op == fU0 || op == fUP || op == fSP || op == fVP ||
2073 (op >= FirstCont && op <= rNull) ? MagickTrue : MagickFalse
2077static MagickBooleanType GetOperand (
2078 FxInfo * pfx, MagickBooleanType * UserSymbol, MagickBooleanType * NewUserSymbol,
int * UserSymNdx,
2079 MagickBooleanType * needPopAll)
2082 *NewUserSymbol = *UserSymbol = MagickFalse;
2083 *UserSymNdx = NULL_ADDRESS;
2086 if (!*pfx->pex)
return MagickFalse;
2087 (void) GetToken (pfx);
2089 if (pfx->lenToken==0) {
2093 OperatorE op = GetLeadingOp (pfx);
2094 if (op==oOpenParen) {
2095 char chLimit =
'\0';
2096 if (!PushOperatorStack (pfx, (
int) op))
return MagickFalse;
2098 if (!TranslateExpression (pfx,
")", &chLimit, needPopAll)) {
2099 (void) ThrowMagickException (
2100 pfx->exception, GetMagickModule(), OptionError,
2101 "Empty expression in parentheses at",
"'%s'",
2105 if (chLimit !=
')') {
2106 (void) ThrowMagickException (
2107 pfx->exception, GetMagickModule(), OptionError,
2108 "'(' but no ')' at",
"'%s'",
2113 if (!PopOprOpenParen (pfx, oOpenParen)) {
2114 (void) ThrowMagickException (
2115 pfx->exception, GetMagickModule(), OptionError,
2116 "Bug: tos not '(' at",
"'%s'",
2121 }
else if (OprIsUnaryPrefix (op)) {
2122 if (!PushOperatorStack (pfx, (
int) op))
return MagickFalse;
2125 if (!*pfx->pex)
return MagickFalse;
2127 if (!GetOperand (pfx, UserSymbol, NewUserSymbol, UserSymNdx, needPopAll)) {
2128 (void) ThrowMagickException (
2129 pfx->exception, GetMagickModule(), OptionError,
2130 "After unary, bad operand at",
"'%s'",
2135 if (*NewUserSymbol) {
2136 (void) ThrowMagickException (
2137 pfx->exception, GetMagickModule(), OptionError,
2138 "After unary, NewUserSymbol at",
"'%s'",
2144 (void) AddAddressingElement (pfx, rCopyFrom, *UserSymNdx);
2145 *UserSymNdx = NULL_ADDRESS;
2147 *UserSymbol = MagickFalse;
2148 *NewUserSymbol = MagickFalse;
2151 (void) GetToken (pfx);
2153 }
else if (*pfx->pex ==
'#') {
2154 fxFltType v0=0, v1=0, v2=0;
2155 ssize_t lenToken = GetHexColour (pfx, &v0, &v1, &v2);
2157 (void) ThrowMagickException (
2158 pfx->exception, GetMagickModule(), OptionError,
2159 "Bad hex number at",
"'%s'",
2162 }
else if (lenToken > 0) {
2163 (void) AddColourElement (pfx, v0, v1, v2);
2174 fxFltType val = strtold (pfx->pex, &tailptr);
2175 if (pfx->pex != tailptr) {
2183 const char Prefixes[] =
"yzafpnum.kMGTPEZY";
2184 const char * pSi = strchr (Prefixes, *tailptr);
2185 if (pSi && *pSi !=
'.') Pow = (double) ((pSi - Prefixes) * 3 - 24);
2186 else if (*tailptr ==
'c') Pow = -2;
2187 else if (*tailptr ==
'h') Pow = 2;
2188 else if (*tailptr ==
'k') Pow = 3;
2190 if (*(++pfx->pex) ==
'i') {
2191 val *= pow (2.0, Pow/0.3);
2194 val *= pow (10.0, Pow);
2198 (void) AddElement (pfx, val, oNull);
2202 val = (fxFltType) 0;
2203 lenOptArt = GetProperty (pfx, &val);
2204 if (lenOptArt < 0)
return MagickFalse;
2205 if (lenOptArt > 0) {
2206 (void) AddElement (pfx, val, oNull);
2207 pfx->pex += lenOptArt;
2214 if (pfx->lenToken > 0) {
2219 for (ce = (ConstantE)0; ce < cNull; ce=(ConstantE) (ce+1)) {
2220 const char * ceStr = Constants[ce].str;
2221 if (LocaleCompare (ceStr, pfx->token)==0) {
2227 (void) AddElement (pfx, Constants[ce].val, oNull);
2228 pfx->pex += pfx->lenToken;
2237 for (fe = FirstFunc; fe < fNull; fe=(FunctionE) (fe+1)) {
2238 const char * feStr = Functions[fe-(int) FirstFunc].str;
2239 if (LocaleCompare (feStr, pfx->token)==0) {
2244 if (fe == fV && pfx->ImgListLen < 2) {
2245 (void) ThrowMagickException (
2246 pfx->exception, GetMagickModule(), OptionError,
2247 "Symbol 'v' but fewer than two images at",
"'%s'",
2252 if (IsStealth ((
int) fe)) {
2253 (void) ThrowMagickException (
2254 pfx->exception, GetMagickModule(), OptionError,
2255 "Function",
"'%s' not permitted at '%s'",
2256 pfx->token, SetShortExp(pfx));
2259 if (fe == fDo || fe == fFor || fe == fIf || fe == fWhile) {
2260 *needPopAll = MagickTrue;
2263 if (fe != fNull)
return (GetFunction (pfx, fe));
2269 ImgAttrE ia = GetImgAttrToken (pfx);
2272 (void) AddElement (pfx, val, (
int) ia);
2274 if (ImgAttrs[ia-(
int) FirstImgAttr].NeedStats==1) {
2275 if (IsQualifier (pfx)) {
2276 PixelChannel chQual = GetChannelQualifier (pfx, (
int) ia);
2278 if (chQual == NO_CHAN_QUAL) {
2279 (void) ThrowMagickException (
2280 pfx->exception, GetMagickModule(), OptionError,
2281 "Bad channel qualifier at",
"'%s'",
2286 pel = &pfx->Elements[pfx->usedElements-1];
2287 pel->ChannelQual = chQual;
2298 for (se = FirstSym; se < sNull; se=(SymbolE) (se+1)) {
2299 const char * seStr = Symbols[se-(int) FirstSym].str;
2300 if (LocaleCompare (seStr, pfx->token)==0) {
2306 (void) AddElement (pfx, val, (
int) se);
2307 pfx->pex += pfx->lenToken;
2309 if (se==sHue || se==sSaturation || se==sLightness) pfx->NeedHsl = MagickTrue;
2317 fxFltType v0, v1, v2;
2318 ssize_t ColLen = GetConstantColour (pfx, &v0, &v1, &v2);
2319 if (ColLen < 0)
return MagickFalse;
2321 (void) AddColourElement (pfx, v0, v1, v2);
2330 const char *artifact;
2331 artifact = GetImageArtifact (pfx->image, pfx->token);
2332 if (artifact != (
const char *) NULL) {
2334 fxFltType val = strtold (artifact, &tailptr);
2335 if (pfx->token == tailptr) {
2336 (void) ThrowMagickException (
2337 pfx->exception, GetMagickModule(), OptionError,
2338 "Artifact",
"'%s' has value '%s', not a number, at '%s'",
2339 pfx->token, artifact, SetShortExp(pfx));
2342 (void) AddElement (pfx, val, oNull);
2343 pfx->pex+=pfx->lenToken;
2350 if (TokenMaybeUserSymbol (pfx)) {
2351 *UserSymbol = MagickTrue;
2352 *UserSymNdx = FindUserSymbol (pfx, pfx->token);
2353 if (*UserSymNdx == NULL_ADDRESS) {
2354 *UserSymNdx = AddUserSymbol (pfx, pfx->pex, pfx->lenToken);
2355 *NewUserSymbol = MagickTrue;
2358 pfx->pex += pfx->lenToken;
2364 (void) ThrowMagickException (
2365 pfx->exception, GetMagickModule(), OptionError,
2366 "Expected operand at",
"'%s'",
2372static inline MagickBooleanType IsRealOperator (OperatorE op)
2374 return (op < oOpenParen || op > oCloseBrace) ? MagickTrue : MagickFalse;
2377static inline MagickBooleanType ProcessTernaryOpr (
FxInfo * pfx,
TernaryT * ptern)
2382 if (pfx->usedOprStack == 0)
2384 if (pfx->OperatorStack[pfx->usedOprStack-1] == oQuery) {
2385 if (ptern->addrQuery != NULL_ADDRESS) {
2386 (void) ThrowMagickException (
2387 pfx->exception, GetMagickModule(), OptionError,
2388 "Already have '?' in sub-expression at",
"'%s'",
2392 if (ptern->addrColon != NULL_ADDRESS) {
2393 (void) ThrowMagickException (
2394 pfx->exception, GetMagickModule(), OptionError,
2395 "Already have ':' in sub-expression at",
"'%s'",
2399 pfx->usedOprStack--;
2400 ptern->addrQuery = pfx->usedElements;
2401 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
2404 else if (pfx->OperatorStack[pfx->usedOprStack-1] == oColon) {
2405 if (ptern->addrQuery == NULL_ADDRESS) {
2406 (void) ThrowMagickException (
2407 pfx->exception, GetMagickModule(), OptionError,
2408 "Need '?' in sub-expression at",
"'%s'",
2412 if (ptern->addrColon != NULL_ADDRESS) {
2413 (void) ThrowMagickException (
2414 pfx->exception, GetMagickModule(), OptionError,
2415 "Already have ':' in sub-expression at",
"'%s'",
2419 pfx->usedOprStack--;
2420 ptern->addrColon = pfx->usedElements;
2421 pfx->Elements[pfx->usedElements-1].DoPush = MagickTrue;
2422 (void) AddAddressingElement (pfx, rGoto, NULL_ADDRESS);
2428static MagickBooleanType GetOperator (
2430 MagickBooleanType * Assign, MagickBooleanType * Update, MagickBooleanType * IncrDecr)
2434 MagickBooleanType DoneIt = MagickFalse;
2436 for (op = (OperatorE)0; op != oNull; op=(OperatorE) (op+1)) {
2437 const char * opStr = Operators[op].str;
2438 len = strlen(opStr);
2439 if (LocaleNCompare (opStr, pfx->pex, len)==0) {
2444 if (!IsRealOperator (op)) {
2445 (void) ThrowMagickException (
2446 pfx->exception, GetMagickModule(), OptionError,
2447 "Not a real operator at",
"'%s'",
2453 (void) ThrowMagickException (
2454 pfx->exception, GetMagickModule(), OptionError,
2455 "Expected operator at",
"'%s'",
2460 *Assign = (op==oAssign) ? MagickTrue : MagickFalse;
2461 *Update = OprInPlace ((
int) op);
2462 *IncrDecr = (op == oPlusPlus || op == oSubSub) ? MagickTrue : MagickFalse;
2469 while (pfx->usedOprStack > 0) {
2470 OperatorE top = pfx->OperatorStack[pfx->usedOprStack-1];
2471 int precTop, precNew;
2472 if (top == oOpenParen || top == oAssign || OprInPlace ((
int) top))
break;
2473 precTop = Operators[top].precedence;
2474 precNew = Operators[op].precedence;
2478 if (precTop < precNew)
break;
2479 (void) AddElement (pfx, (fxFltType) 0, (int) top);
2480 pfx->usedOprStack--;
2486 if (op==oCloseParen) {
2487 if (pfx->usedOprStack == 0) {
2488 (void) ThrowMagickException (
2489 pfx->exception, GetMagickModule(), OptionError,
2490 "Found ')' but nothing on stack at",
"'%s'",
2495 if (pfx->OperatorStack[pfx->usedOprStack-1] != oOpenParen) {
2496 (void) ThrowMagickException (
2497 pfx->exception, GetMagickModule(), OptionError,
2498 "Found ')' but no '(' on stack at",
"'%s'",
2502 pfx->usedOprStack--;
2503 DoneIt = MagickTrue;
2507 if (!PushOperatorStack (pfx, (
int) op))
return MagickFalse;
2515static MagickBooleanType ResolveTernaryAddresses (
FxInfo * pfx,
TernaryT * ptern)
2517 if (ptern->addrQuery == NULL_ADDRESS && ptern->addrColon == NULL_ADDRESS)
2520 if (ptern->addrQuery != NULL_ADDRESS && ptern->addrColon != NULL_ADDRESS) {
2521 pfx->Elements[ptern->addrQuery].EleNdx = ptern->addrColon + 1;
2522 pfx->Elements[ptern->addrColon].EleNdx = pfx->usedElements;
2523 ptern->addrQuery = NULL_ADDRESS;
2524 ptern->addrColon = NULL_ADDRESS;
2525 }
else if (ptern->addrQuery != NULL_ADDRESS) {
2526 (void) ThrowMagickException (
2527 pfx->exception, GetMagickModule(), OptionError,
2528 "'?' with no corresponding ':'",
"'%s' at '%s'",
2529 pfx->token, SetShortExp(pfx));
2531 }
else if (ptern->addrColon != NULL_ADDRESS) {
2532 (void) ThrowMagickException (
2533 pfx->exception, GetMagickModule(), OptionError,
2534 "':' with no corresponding '?'",
"'%s' at '%s'",
2535 pfx->token, SetShortExp(pfx));
2541static MagickBooleanType TranslateExpression (
2542 FxInfo * pfx,
const char * strLimit,
char * chLimit, MagickBooleanType * needPopAll)
2546 MagickBooleanType UserSymbol, NewUserSymbol;
2547 int UserSymNdx0, UserSymNdx1;
2550 Assign = MagickFalse,
2551 Update = MagickFalse,
2552 IncrDecr = MagickFalse;
2557 ternary.addrQuery = NULL_ADDRESS;
2558 ternary.addrColon = NULL_ADDRESS;
2564 StartEleNdx = pfx->usedElements-1;
2565 if (StartEleNdx < 0) StartEleNdx = 0;
2574 if (strchr(strLimit,*pfx->pex)!=NULL) {
2575 *chLimit = *pfx->pex;
2582 if (!GetOperand (pfx, &UserSymbol, &NewUserSymbol, &UserSymNdx0, needPopAll))
return MagickFalse;
2587 while (*pfx->pex && (!*strLimit || (strchr(strLimit,*pfx->pex)==NULL))) {
2588 if (!GetOperator (pfx, &Assign, &Update, &IncrDecr))
return MagickFalse;
2590 if (NewUserSymbol && !Assign) {
2591 (void) ThrowMagickException (
2592 pfx->exception, GetMagickModule(), OptionError,
2593 "Expected assignment after new UserSymbol",
"'%s' at '%s'",
2594 pfx->token, SetShortExp(pfx));
2597 if (!UserSymbol && Assign) {
2598 (void) ThrowMagickException (
2599 pfx->exception, GetMagickModule(), OptionError,
2600 "Attempted assignment to non-UserSymbol",
"'%s' at '%s'",
2601 pfx->token, SetShortExp(pfx));
2604 if (!UserSymbol && Update) {
2605 (void) ThrowMagickException (
2606 pfx->exception, GetMagickModule(), OptionError,
2607 "Attempted update to non-UserSymbol",
"'%s' at '%s'",
2608 pfx->token, SetShortExp(pfx));
2611 if (UserSymbol && (Assign || Update) && !IncrDecr) {
2613 if (!TranslateExpression (pfx, strLimit, chLimit, needPopAll))
return MagickFalse;
2614 if (!*pfx->pex)
break;
2615 if (!*strLimit)
break;
2616 if (strchr(strLimit,*chLimit)!=NULL)
break;
2618 if (UserSymbol && !Assign && !Update && UserSymNdx0 != NULL_ADDRESS) {
2620 (void) AddAddressingElement (pfx, rCopyFrom, UserSymNdx0);
2621 UserSymNdx0 = NULL_ADDRESS;
2622 pel = &pfx->Elements[pfx->usedElements-1];
2623 pel->DoPush = MagickTrue;
2627 while (TopOprIsUnaryPrefix (pfx)) {
2628 OperatorE op = pfx->OperatorStack[pfx->usedOprStack-1];
2629 (void) AddElement (pfx, (fxFltType) 0, (int) op);
2630 pfx->usedOprStack--;
2634 if (!ProcessTernaryOpr (pfx, &ternary))
return MagickFalse;
2636 if (ternary.addrColon != NULL_ADDRESS) {
2637 if (!TranslateExpression (pfx,
",);", chLimit, needPopAll))
return MagickFalse;
2641 UserSymbol = NewUserSymbol = MagickFalse;
2643 if ( (!*pfx->pex) || (*strLimit && (strchr(strLimit,*pfx->pex)!=NULL) ) )
2645 if (IncrDecr)
break;
2647 (void) ThrowMagickException (
2648 pfx->exception, GetMagickModule(), OptionError,
2649 "Expected operand after operator",
"at '%s'",
2655 (void) ThrowMagickException (
2656 pfx->exception, GetMagickModule(), OptionError,
2657 "'++' and '--' must be the final operators in an expression at",
"'%s'",
2662 if (!GetOperand (pfx, &UserSymbol, &NewUserSymbol, &UserSymNdx1, needPopAll)) {
2663 (void) ThrowMagickException (
2664 pfx->exception, GetMagickModule(), OptionError,
2665 "Expected operand at",
"'%s'",
2670 if (NewUserSymbol && !Assign) {
2671 (void) ThrowMagickException (
2672 pfx->exception, GetMagickModule(), OptionError,
2673 "NewUserSymbol",
"'%s' after non-assignment operator at '%s'",
2674 pfx->token, SetShortExp(pfx));
2677 if (UserSymbol && !NewUserSymbol) {
2678 (void) AddAddressingElement (pfx, rCopyFrom, UserSymNdx1);
2679 UserSymNdx1 = NULL_ADDRESS;
2681 UserSymNdx0 = UserSymNdx1;
2684 if (UserSymbol && !Assign && !Update && UserSymNdx0 != NULL_ADDRESS) {
2686 if (NewUserSymbol) {
2687 (void) ThrowMagickException (
2688 pfx->exception, GetMagickModule(), OptionError,
2689 "NewUserSymbol",
"'%s' needs assignment operator at '%s'",
2690 pfx->token, SetShortExp(pfx));
2693 (void) AddAddressingElement (pfx, rCopyFrom, UserSymNdx0);
2694 pel = &pfx->Elements[pfx->usedElements-1];
2695 pel->DoPush = MagickTrue;
2698 if (*pfx->pex && !*chLimit && (strchr(strLimit,*pfx->pex)!=NULL)) {
2699 *chLimit = *pfx->pex;
2702 while (pfx->usedOprStack) {
2703 OperatorE op = pfx->OperatorStack[pfx->usedOprStack-1];
2704 if (op == oOpenParen || op == oOpenBracket || op == oOpenBrace) {
2707 if ( (op==oAssign && !Assign) || (OprInPlace((
int) op) && !Update) ) {
2710 pfx->usedOprStack--;
2711 (void) AddElement (pfx, (fxFltType) 0, (int) op);
2712 if (op == oAssign) {
2713 if (UserSymNdx0 < 0) {
2714 (void) ThrowMagickException (
2715 pfx->exception, GetMagickModule(), OptionError,
2716 "Assignment to unknown user symbol at",
"'%s'",
2722 pfx->usedElements--;
2723 (void) AddAddressingElement (pfx, rCopyTo, UserSymNdx0);
2725 }
else if (OprInPlace ((
int) op)) {
2726 if (UserSymNdx0 < 0) {
2727 (void) ThrowMagickException (
2728 pfx->exception, GetMagickModule(), OptionError,
2729 "Operator-in-place to unknown user symbol at",
"'%s'",
2735 pfx->Elements[pfx->usedElements-1].EleNdx = UserSymNdx0;
2740 if (ternary.addrQuery != NULL_ADDRESS) *needPopAll = MagickTrue;
2742 (void) ResolveTernaryAddresses (pfx, &ternary);
2746 if (!pfx->teDepth && *needPopAll) {
2747 (void) AddAddressingElement (pfx, rZerStk, NULL_ADDRESS);
2748 *needPopAll = MagickFalse;
2751 if (pfx->exception->severity != UndefinedException)
2758static MagickBooleanType TranslateStatement (
FxInfo * pfx,
char * strLimit,
char * chLimit)
2760 MagickBooleanType NeedPopAll = MagickFalse;
2764 if (!*pfx->pex)
return MagickFalse;
2766 if (!TranslateExpression (pfx, strLimit, chLimit, &NeedPopAll)) {
2769 if (pfx->usedElements && *chLimit==
';') {
2774 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2775 if (pel->DoPush) pel->DoPush = MagickFalse;
2781static MagickBooleanType TranslateStatementList (
FxInfo * pfx,
const char * strLimit,
char * chLimit)
2783#define MAX_SLIMIT 10
2784 char sLimits[MAX_SLIMIT];
2787 if (!*pfx->pex)
return MagickFalse;
2788 (void) CopyMagickString (sLimits, strLimit, MAX_SLIMIT-1);
2790 if (strchr(strLimit,
';')==NULL)
2791 (
void) ConcatenateMagickString (sLimits,
";", MAX_SLIMIT);
2794 if (!TranslateStatement (pfx, sLimits, chLimit))
return MagickFalse;
2796 if (!*pfx->pex)
break;
2798 if (*chLimit !=
';') {
2803 if (pfx->exception->severity != UndefinedException)
2822 for (ch=0; ch <= (int) MaxPixelChannels; ch++) {
2823 cs[ch].mean *= QuantumScale;
2824 cs[ch].median *= QuantumScale;
2825 cs[ch].maxima *= QuantumScale;
2826 cs[ch].minima *= QuantumScale;
2827 cs[ch].standard_deviation *= QuantumScale;
2833static MagickBooleanType CollectStatistics (
FxInfo * pfx)
2835 Image * img = GetFirstImageInList (pfx->image);
2840 if (!pfx->statistics) {
2841 (void) ThrowMagickException (
2842 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
2843 "Statistics",
"%lu",
2844 (
unsigned long) pfx->ImgListLen);
2849 pfx->statistics[imgNum] = CollectOneImgStats (pfx, img);
2851 if (++imgNum == pfx->ImgListLen)
break;
2852 img = GetNextImageInList (img);
2853 assert (img != (
Image *) NULL);
2855 pfx->GotStats = MagickTrue;
2860static inline MagickBooleanType PushVal (
FxInfo * pfx,
fxRtT * pfxrt, fxFltType val,
int addr)
2862 if (pfxrt->usedValStack >=pfxrt->numValStack) {
2863 (void) ThrowMagickException (
2864 pfx->exception, GetMagickModule(), OptionError,
2865 "ValStack overflow at addr=",
"%i",
2870 pfxrt->ValStack[pfxrt->usedValStack++] = val;
2874static inline fxFltType PopVal (
FxInfo * pfx,
fxRtT * pfxrt,
int addr)
2876 if (pfxrt->usedValStack <= 0) {
2877 (void) ThrowMagickException (
2878 pfx->exception, GetMagickModule(), OptionError,
2879 "ValStack underflow at addr=",
"%i",
2881 return (fxFltType) 0;
2884 return pfxrt->ValStack[--pfxrt->usedValStack];
2887static inline fxFltType ImageStat (
2888 FxInfo * pfx, ssize_t ImgNum, PixelChannel channel, ImgAttrE ia)
2892 MagickBooleanType NeedRelinq = MagickFalse;
2896 (void) ThrowMagickException(pfx->exception,GetMagickModule(),
2897 OptionError,
"NoSuchImage",
"%lu",(
unsigned long) ImgNum);
2901 if (pfx->GotStats) {
2902 if ((channel < 0) || (channel > MaxPixelChannels))
2904 (void) ThrowMagickException(pfx->exception,GetMagickModule(),
2905 OptionError,
"NoSuchImageChannel",
"%i",channel);
2906 channel=(PixelChannel) 0;
2908 cs = pfx->statistics[ImgNum];
2909 }
else if (pfx->NeedStats) {
2911 if ((channel < 0) || (channel > MaxPixelChannels))
2913 (void) ThrowMagickException(pfx->exception,GetMagickModule(),
2914 OptionError,
"NoSuchImageChannel",
"%i",channel);
2915 channel=(PixelChannel) 0;
2917 cs = CollectOneImgStats (pfx, pfx->Images[ImgNum]);
2918 NeedRelinq = MagickTrue;
2923 ret = (fxFltType) GetImageDepth (pfx->Images[ImgNum], pfx->exception);
2926 ret = (fxFltType) GetBlobSize (pfx->image);
2930 ret = cs[channel].kurtosis;
2934 ret = cs[channel].maxima;
2938 ret = cs[channel].mean;
2942 ret = cs[channel].median;
2946 ret = cs[channel].minima;
2952 ret = (fxFltType) pfx->Images[ImgNum]->page.x;
2955 ret = (fxFltType) pfx->Images[ImgNum]->page.y;
2958 ret = (fxFltType) pfx->Images[ImgNum]->page.width;
2961 ret = (fxFltType) pfx->Images[ImgNum]->page.height;
2967 ret = (fxFltType) PerceptibleReciprocal (pfx->Images[ImgNum]->resolution.x)
2968 * pfx->Images[ImgNum]->columns;
2971 ret = (fxFltType) PerceptibleReciprocal (pfx->Images[ImgNum]->resolution.y)
2972 * pfx->Images[ImgNum]->rows;
2975 ret = (fxFltType) pfx->Images[ImgNum]->quality;
2981 ret = pfx->Images[ImgNum]->resolution.x;
2984 ret = pfx->Images[ImgNum]->resolution.y;
2988 ret = cs[channel].skewness;
2992 ret = cs[channel].standard_deviation;
2995 ret = (fxFltType) pfx->Images[ImgNum]->rows;
2998 ret = (fxFltType) pfx->ImgListLen;
3001 ret = (fxFltType) ImgNum;
3004 ret = (fxFltType) pfx->Images[ImgNum]->columns;
3007 ret = (fxFltType) GetImageDepth (pfx->Images[ImgNum], pfx->exception);
3010 (void) ThrowMagickException (pfx->exception,GetMagickModule(),OptionError,
3011 "Unknown ia=",
"%i",ia);
3018static inline fxFltType FxGcd (fxFltType x, fxFltType y,
const size_t depth)
3020#define FxMaxFunctionDepth 200
3023 return (FxGcd (y, x, depth+1));
3024 if ((fabs((
double) y) < 0.001) || (depth >= FxMaxFunctionDepth))
3026 return (FxGcd (y, x-y*floor((
double) (x/y)), depth+1));
3029static inline ssize_t ChkImgNum (
FxInfo * pfx, fxFltType f)
3032 ssize_t i = (ssize_t) floor ((
double) f + 0.5);
3033 if (i < 0) i += (ssize_t) pfx->ImgListLen;
3034 if (i < 0 || i >= (ssize_t) pfx->ImgListLen) {
3035 (void) ThrowMagickException (
3036 pfx->exception, GetMagickModule(), OptionError,
3037 "ImgNum",
"%lu bad for ImgListLen %lu",
3038 (
unsigned long) i, (
unsigned long) pfx->ImgListLen);
3044#define WHICH_ATTR_CHAN \
3045 (pel->ChannelQual == NO_CHAN_QUAL) ? CompositePixelChannel : \
3046 (pel->ChannelQual == THIS_CHANNEL) ? channel : pel->ChannelQual
3048#define WHICH_NON_ATTR_CHAN \
3049 (pel->ChannelQual == NO_CHAN_QUAL || \
3050 pel->ChannelQual == THIS_CHANNEL || \
3051 pel->ChannelQual == CompositePixelChannel \
3052 ) ? (channel == CompositePixelChannel ? RedPixelChannel: channel) \
3055static fxFltType GetHslFlt (
FxInfo * pfx, ssize_t ImgNum,
const fxFltType fx,
const fxFltType fy,
3056 PixelChannel channel)
3058 Image * img = pfx->Images[ImgNum];
3060 double red, green, blue;
3061 double hue=0, saturation=0, lightness=0;
3063 MagickBooleanType okay = MagickTrue;
3064 if(!InterpolatePixelChannel (img, pfx->Imgs[ImgNum].View, RedPixelChannel, img->interpolate,
3065 (
double) fx, (
double) fy, &red, pfx->exception)) okay = MagickFalse;
3066 if(!InterpolatePixelChannel (img, pfx->Imgs[ImgNum].View, GreenPixelChannel, img->interpolate,
3067 (
double) fx, (
double) fy, &green, pfx->exception)) okay = MagickFalse;
3068 if(!InterpolatePixelChannel (img, pfx->Imgs[ImgNum].View, BluePixelChannel, img->interpolate,
3069 (
double) fx, (
double) fy, &blue, pfx->exception)) okay = MagickFalse;
3072 (void) ThrowMagickException (
3073 pfx->exception, GetMagickModule(), OptionError,
3074 "GetHslFlt failure",
"%lu %g,%g %i", (
unsigned long) ImgNum,
3075 (
double) fx, (double) fy, channel);
3079 &hue, &saturation, &lightness);
3081 if (channel == HUE_CHANNEL)
return hue;
3082 if (channel == SAT_CHANNEL)
return saturation;
3083 if (channel == LIGHT_CHANNEL)
return lightness;
3088static fxFltType GetHslInt (
FxInfo * pfx, ssize_t ImgNum,
const ssize_t imgx,
const ssize_t imgy, PixelChannel channel)
3090 Image * img = pfx->Images[ImgNum];
3092 double hue=0, saturation=0, lightness=0;
3094 const Quantum * p = GetCacheViewVirtualPixels (pfx->Imgs[ImgNum].View, imgx, imgy, 1, 1, pfx->exception);
3095 if (p == (
const Quantum *) NULL)
3097 (void) ThrowMagickException (pfx->exception,GetMagickModule(),
3098 OptionError,
"GetHslInt failure",
"%lu %li,%li %i",(
unsigned long) ImgNum,
3099 (
long) imgx,(long) imgy,channel);
3104 GetPixelRed (img, p), GetPixelGreen (img, p), GetPixelBlue (img, p),
3105 &hue, &saturation, &lightness);
3107 if (channel == HUE_CHANNEL)
return hue;
3108 if (channel == SAT_CHANNEL)
return saturation;
3109 if (channel == LIGHT_CHANNEL)
return lightness;
3114static inline fxFltType GetIntensity (
FxInfo * pfx, ssize_t ImgNum,
const fxFltType fx,
const fxFltType fy)
3117 quantum_pixel[MaxPixelChannels];
3122 Image * img = pfx->Images[ImgNum];
3124 (void) GetPixelInfo (img, &pixelinf);
3126 if (!InterpolatePixelInfo (img, pfx->Imgs[pfx->ImgNum].View, img->interpolate,
3127 (
double) fx, (
double) fy, &pixelinf, pfx->exception))
3129 (void) ThrowMagickException (
3130 pfx->exception, GetMagickModule(), OptionError,
3131 "GetIntensity failure",
"%lu %g,%g", (
unsigned long) ImgNum,
3132 (
double) fx, (double) fy);
3135 SetPixelViaPixelInfo (img, &pixelinf, quantum_pixel);
3136 return QuantumScale * GetPixelIntensity (img, quantum_pixel);
3139static MagickBooleanType ExecuteRPN (
FxInfo * pfx,
fxRtT * pfxrt, fxFltType *result,
3140 const PixelChannel channel,
const ssize_t imgx,
const ssize_t imgy)
3142 const Quantum * p = pfxrt->thisPixel;
3143 fxFltType regA=0, regB=0, regC=0, regD=0, regE=0;
3144 Image * img = pfx->image;
3146 MagickBooleanType NeedRelinq = MagickFalse;
3147 double hue=0, saturation=0, lightness=0;
3154 if (!p) p = GetCacheViewVirtualPixels (
3155 pfx->Imgs[pfx->ImgNum].View, imgx, imgy, 1, 1, pfx->exception);
3157 if (p == (
const Quantum *) NULL)
3159 (void) ThrowMagickException (pfx->exception,GetMagickModule(),
3160 OptionError,
"GetHslInt failure",
"%lu %li,%li",(
unsigned long)
3161 pfx->ImgNum,(
long) imgx,(long) imgy);
3162 return(MagickFalse);
3165 if (pfx->GotStats) {
3166 cs = pfx->statistics[pfx->ImgNum];
3167 }
else if (pfx->NeedStats) {
3168 cs = CollectOneImgStats (pfx, pfx->Images[pfx->ImgNum]);
3169 NeedRelinq = MagickTrue;
3176 GetPixelRed (img, p), GetPixelGreen (img, p), GetPixelBlue (img, p),
3177 &hue, &saturation, &lightness);
3180 for (i=0; i < pfx->usedElements; i++) {
3185 (void) ThrowMagickException (
3186 pfx->exception, GetMagickModule(), OptionError,
3187 "Bad run-time address",
"%i", i);
3189 pel=&pfx->Elements[i];
3190 switch (pel->nArgs) {
3194 regA = PopVal (pfx, pfxrt, i);
3197 regB = PopVal (pfx, pfxrt, i);
3198 regA = PopVal (pfx, pfxrt, i);
3201 regC = PopVal (pfx, pfxrt, i);
3202 regB = PopVal (pfx, pfxrt, i);
3203 regA = PopVal (pfx, pfxrt, i);
3206 regD = PopVal (pfx, pfxrt, i);
3207 regC = PopVal (pfx, pfxrt, i);
3208 regB = PopVal (pfx, pfxrt, i);
3209 regA = PopVal (pfx, pfxrt, i);
3212 regE = PopVal (pfx, pfxrt, i);
3213 regD = PopVal (pfx, pfxrt, i);
3214 regC = PopVal (pfx, pfxrt, i);
3215 regB = PopVal (pfx, pfxrt, i);
3216 regA = PopVal (pfx, pfxrt, i);
3219 (void) ThrowMagickException (
3220 pfx->exception, GetMagickModule(), OptionError,
3221 "Too many args:",
"%i", pel->nArgs);
3225 switch (pel->oprNum) {
3227 regA = (pfxrt->UserSymVals[pel->EleNdx] += regA);
3230 regA = (pfxrt->UserSymVals[pel->EleNdx] -= regA);
3233 regA = (pfxrt->UserSymVals[pel->EleNdx] *= regA);
3236 regA = (pfxrt->UserSymVals[pel->EleNdx] *= PerceptibleReciprocal((
double)regA));
3239 regA = pfxrt->UserSymVals[pel->EleNdx]++;
3242 regA = pfxrt->UserSymVals[pel->EleNdx]--;
3254 regA *= PerceptibleReciprocal((
double)regB);
3257 regA = fmod ((
double) regA, fabs(floor((
double) regB+0.5)));
3266 if ((
size_t) (regB+0.5) >= (8*
sizeof(
size_t)))
3268 (void) ThrowMagickException ( pfx->exception, GetMagickModule(),
3269 OptionError,
"undefined shift",
"%g", (double) regB);
3270 regA = (fxFltType) 0.0;
3273 regA = (fxFltType) ((
size_t)(regA+0.5) << (
size_t)(regB+0.5));
3276 if ((
size_t) (regB+0.5) >= (8*
sizeof(
size_t)))
3278 (void) ThrowMagickException ( pfx->exception, GetMagickModule(),
3279 OptionError,
"undefined shift",
"%g", (double) regB);
3280 regA = (fxFltType) 0.0;
3283 regA = (fxFltType) ((
size_t)(regA+0.5) >> (
size_t)(regB+0.5));
3286 regA = fabs((
double) (regA-regB)) < MagickEpsilon ? 1.0 : 0.0;
3289 regA = fabs((
double) (regA-regB)) >= MagickEpsilon ? 1.0 : 0.0;
3292 regA = (regA <= regB) ? 1.0 : 0.0;
3295 regA = (regA >= regB) ? 1.0 : 0.0;
3298 regA = (regA < regB) ? 1.0 : 0.0;
3301 regA = (regA > regB) ? 1.0 : 0.0;
3304 regA = (regA<=0) ? 0.0 : (regB > 0) ? 1.0 : 0.0;
3307 regA = (regA>0) ? 1.0 : (regB > 0.0) ? 1.0 : 0.0;
3310 regA = (regA==0) ? 1.0 : 0.0;
3313 regA = (fxFltType) ((
size_t)(regA+0.5) & (
size_t)(regB+0.5));
3316 regA = (fxFltType) ((
size_t)(regA+0.5) | (
size_t)(regB+0.5));
3320 regA = (fxFltType) (~(
size_t)(regA+0.5));
3323 regA = pow ((
double) regA, (
double) regB);
3339 if (pel->type == etColourConstant) {
3340 switch (channel) {
default:
3341 case (PixelChannel) 0:
3344 case (PixelChannel) 1:
3347 case (PixelChannel) 2:
3357 regA = fabs ((
double) regA);
3359#if defined(MAGICKCORE_HAVE_ACOSH)
3361 regA = acosh ((
double) regA);
3365 regA = acos ((
double) regA);
3367#if defined(MAGICKCORE_HAVE_J1)
3369 if (regA==0) regA = 1.0;
3371 fxFltType gamma = 2.0 * j1 ((MagickPI*regA)) / (MagickPI*regA);
3372 regA = gamma * gamma;
3377 regA = (fxFltType) (((ssize_t) regA) & 0x01 ? -1.0 : 1.0);
3379#if defined(MAGICKCORE_HAVE_ASINH)
3381 regA = asinh ((
double) regA);
3385 regA = asin ((
double) regA);
3387#if defined(MAGICKCORE_HAVE_ATANH)
3389 regA = atanh ((
double) regA);
3393 regA = atan2 ((
double) regA, (
double) regB);
3396 regA = atan ((
double) regA);
3399 regA = ceil ((
double) regA);
3403 case (PixelChannel) 0:
break;
3404 case (PixelChannel) 1: regA = regB;
break;
3405 case (PixelChannel) 2: regA = regC;
break;
3406 case (PixelChannel) 3: regA = regD;
break;
3407 case (PixelChannel) 4: regA = regE;
break;
3408 default: regA = 0.0;
3412 if (regA < 0) regA = 0.0;
3413 else if (regA > 1.0) regA = 1.0;
3416 regA = cosh ((
double) regA);
3419 regA = cos ((
double) regA);
3424 (void) fprintf (stderr,
"%s[%g,%g].[%i]: %s=%.*g\n",
3425 img->filename, (
double) imgx, (double) imgy,
3426 channel, SetPtrShortExp (pfx, pel->pExpStart, (
size_t) (pel->lenExp+1)),
3427 pfx->precision, (double) regA);
3430 regA = regA / (regB*(regA-1.0) + 1.0);
3432#if defined(MAGICKCORE_HAVE_ERF)
3434 regA = erf ((
double) regA);
3438 regA = exp ((
double) regA);
3441 regA = floor ((
double) regA);
3444 regA = exp((
double) (-regA*regA/2.0))/sqrt(2.0*MagickPI);
3448 regA = FxGcd (regA, regB, 0);
3451 regA = hypot ((
double) regA, (
double) regB);
3454 regA = floor ((
double) regA);
3457 regA = (fxFltType) (!!IsNaN (regA));
3459#if defined(MAGICKCORE_HAVE_J0)
3461 regA = j0 ((
double) regA);
3464#if defined(MAGICKCORE_HAVE_J1)
3466 regA = j1 ((
double) regA);
3469#if defined(MAGICKCORE_HAVE_J1)
3471 if (regA==0) regA = 1.0;
3472 else regA = 2.0 * j1 ((MagickPI*regA))/(MagickPI*regA);
3476 regA = log ((
double) regA);
3479 regA = MagickLog10((
double) regA) / log10(2.0);
3482 regA = MagickLog10 ((
double) regA);
3485 regA = (regA > regB) ? regA : regB;
3488 regA = (regA < regB) ? regA : regB;
3491 regA = regA - floor((
double) (regA*PerceptibleReciprocal((
double) regB)))*regB;
3494 regA = (fxFltType) (regA < MagickEpsilon);
3497 regA = pow ((
double) regA, (
double) regB);
3500#if defined(MAGICKCORE_OPENMP_SUPPORT)
3501 #pragma omp critical (MagickCore_ExecuteRPN)
3503 regA = GetPseudoRandomValue (pfxrt->random_info);
3507 regA = floor ((
double) regA + 0.5);
3510 regA = (regA < 0) ? -1.0 : 1.0;
3513 regA = sin ((
double) (MagickPI*regA)) / (MagickPI*regA);
3516 regA = sinh ((
double) regA);
3519 regA = sin ((
double) regA);
3522 regA = sqrt ((
double) regA);
3525 regA = 1.0 / (1.0 + exp ((
double) -regA));
3528 regA = tanh ((
double) regA);
3531 regA = tan ((
double) regA);
3534 if (regA >= 0) regA = floor ((
double) regA);
3535 else regA = ceil ((
double) regA);
3547 ssize_t ImgNum = ChkImgNum (pfx, regA);
3548 if (ImgNum < 0)
break;
3549 regA = (fxFltType) 0;
3551 Image * pimg = pfx->Images[0];
3552 if (pel->ImgAttrQual == aNull) {
3553 if ((
int) pel->ChannelQual < 0) {
3554 if (pel->ChannelQual == NO_CHAN_QUAL || pel->ChannelQual == THIS_CHANNEL) {
3555 if (pfx->ImgNum==0) {
3556 regA = QuantumScale * (double) p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3558 const Quantum * pv = GetCacheViewVirtualPixels (
3559 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3561 (void) ThrowMagickException (
3562 pfx->exception, GetMagickModule(), OptionError,
3563 "fU can't get cache",
"%lu", (
unsigned long) ImgNum);
3566 regA = QuantumScale * (double) pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3568 }
else if (pel->ChannelQual == HUE_CHANNEL || pel->ChannelQual == SAT_CHANNEL ||
3569 pel->ChannelQual == LIGHT_CHANNEL) {
3570 regA = GetHslInt (pfx, ImgNum, imgx, imgy, pel->ChannelQual);
3572 }
else if (pel->ChannelQual == INTENSITY_CHANNEL) {
3573 regA = GetIntensity (pfx, 0, (
double) imgx, (
double) imgy);
3577 if (pfx->ImgNum==0) {
3578 regA = QuantumScale * (double) p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3580 const Quantum * pv = GetCacheViewVirtualPixels (
3581 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3583 (void) ThrowMagickException (
3584 pfx->exception, GetMagickModule(), OptionError,
3585 "fU can't get cache",
"%lu", (
unsigned long) ImgNum);
3588 regA = QuantumScale * (double) pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3593 regA = ImageStat (pfx, 0, WHICH_ATTR_CHAN, pel->ImgAttrQual);
3597 if (pel->ImgAttrQual == aNull) {
3599 if ((
int) pel->ChannelQual < 0) {
3600 if (pel->ChannelQual == HUE_CHANNEL || pel->ChannelQual == SAT_CHANNEL ||
3601 pel->ChannelQual == LIGHT_CHANNEL)
3603 regA = GetHslInt (pfx, ImgNum, imgx, imgy, pel->ChannelQual);
3605 }
else if (pel->ChannelQual == INTENSITY_CHANNEL)
3607 regA = GetIntensity (pfx, ImgNum, (fxFltType) imgx, (fxFltType) imgy);
3612 pv = GetCacheViewVirtualPixels (
3613 pfx->Imgs[ImgNum].View, imgx, imgy, 1,1, pfx->exception);
3615 (void) ThrowMagickException (
3616 pfx->exception, GetMagickModule(), OptionError,
3617 "fU can't get cache",
"%lu", (
unsigned long) ImgNum);
3620 regA = QuantumScale * (double)
3621 pv[pfx->Images[ImgNum]->channel_map[WHICH_NON_ATTR_CHAN].offset];
3623 regA = ImageStat (pfx, ImgNum, WHICH_ATTR_CHAN, pel->ImgAttrQual);
3632 Image * pimg = pfx->Images[0];
3633 if ((
int) pel->ChannelQual < 0) {
3634 if (pel->ChannelQual == NO_CHAN_QUAL || pel->ChannelQual == THIS_CHANNEL) {
3636 if (pfx->ImgNum==0) {
3637 regA = QuantumScale * (double) p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3639 const Quantum * pv = GetCacheViewVirtualPixels (
3640 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3642 (void) ThrowMagickException (
3643 pfx->exception, GetMagickModule(), OptionError,
3644 "fU0 can't get cache",
"%i", 0);
3647 regA = QuantumScale * (double) pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3650 }
else if (pel->ChannelQual == HUE_CHANNEL || pel->ChannelQual == SAT_CHANNEL ||
3651 pel->ChannelQual == LIGHT_CHANNEL) {
3652 regA = GetHslInt (pfx, 0, imgx, imgy, pel->ChannelQual);
3654 }
else if (pel->ChannelQual == INTENSITY_CHANNEL) {
3655 regA = GetIntensity (pfx, 0, (fxFltType) imgx, (fxFltType) imgy);
3658 if (pfx->ImgNum==0) {
3659 regA = QuantumScale * (double) p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3661 const Quantum * pv = GetCacheViewVirtualPixels (
3662 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3664 (void) ThrowMagickException (
3665 pfx->exception, GetMagickModule(), OptionError,
3666 "fU0 can't get cache",
"%i", 0);
3669 regA = QuantumScale * (double) pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3676 ssize_t ImgNum = ChkImgNum (pfx, regA);
3679 if (ImgNum < 0)
break;
3681 if (pel->IsRelative) {
3689 if ((
int) pel->ChannelQual < 0) {
3690 if (pel->ChannelQual == HUE_CHANNEL || pel->ChannelQual == SAT_CHANNEL
3691 || pel->ChannelQual == LIGHT_CHANNEL) {
3692 regA = GetHslFlt (pfx, ImgNum, fx, fy, pel->ChannelQual);
3694 }
else if (pel->ChannelQual == INTENSITY_CHANNEL) {
3695 regA = GetIntensity (pfx, ImgNum, fx, fy);
3702 Image * imUP = pfx->Images[ImgNum];
3703 if (! InterpolatePixelChannel (imUP, pfx->Imgs[ImgNum].View, WHICH_NON_ATTR_CHAN,
3704 imUP->interpolate, (
double) fx, (
double) fy, &v, pfx->exception))
3706 (void) ThrowMagickException (
3707 pfx->exception, GetMagickModule(), OptionError,
3708 "fUP can't get interpolate",
"%lu", (
unsigned long) ImgNum);
3711 regA = v * QuantumScale;
3720 if (pel->oprNum == fS) ImgNum = pfx->ImgNum;
3722 if (pel->ImgAttrQual == aNull) {
3723 const Quantum * pv = GetCacheViewVirtualPixels (
3724 pfx->Imgs[ImgNum].View, imgx, imgy, 1,1, pfx->exception);
3726 (void) ThrowMagickException (
3727 pfx->exception, GetMagickModule(), OptionError,
3728 "fV can't get cache",
"%lu", (
unsigned long) ImgNum);
3732 if ((
int) pel->ChannelQual < 0) {
3733 if (pel->ChannelQual == HUE_CHANNEL || pel->ChannelQual == SAT_CHANNEL ||
3734 pel->ChannelQual == LIGHT_CHANNEL) {
3735 regA = GetHslInt (pfx, ImgNum, imgx, imgy, pel->ChannelQual);
3737 }
else if (pel->ChannelQual == INTENSITY_CHANNEL) {
3738 regA = GetIntensity (pfx, ImgNum, (
double) imgx, (
double) imgy);
3743 regA = QuantumScale * (double)
3744 pv[pfx->Images[ImgNum]->channel_map[WHICH_NON_ATTR_CHAN].offset];
3746 regA = ImageStat (pfx, ImgNum, WHICH_ATTR_CHAN, pel->ImgAttrQual);
3756 ssize_t ImgNum = pfx->ImgNum;
3757 if (pel->oprNum == fVP) ImgNum = 1;
3758 if (pel->IsRelative) {
3765 if ((
int) pel->ChannelQual < 0) {
3766 if (pel->ChannelQual == HUE_CHANNEL || pel->ChannelQual == SAT_CHANNEL ||
3767 pel->ChannelQual == LIGHT_CHANNEL) {
3768 regA = GetHslFlt (pfx, ImgNum, fx, fy, pel->ChannelQual);
3770 }
else if (pel->ChannelQual == INTENSITY_CHANNEL) {
3771 regA = GetIntensity (pfx, ImgNum, fx, fy);
3779 if (! InterpolatePixelChannel (pfx->Images[ImgNum], pfx->Imgs[ImgNum].View,
3780 WHICH_NON_ATTR_CHAN, pfx->Images[ImgNum]->interpolate,
3781 (
double) fx, (
double) fy, &v, pfx->exception)
3784 (void) ThrowMagickException (
3785 pfx->exception, GetMagickModule(), OptionError,
3786 "fSP or fVP can't get interp",
"%lu", (
unsigned long) ImgNum);
3789 regA = v * (fxFltType)QuantumScale;
3797 regA = (fxFltType) GetImageDepth (img, pfx->exception);
3800 regA = (fxFltType) img->extent;
3804 regA = cs[WHICH_ATTR_CHAN].kurtosis;
3808 regA = cs[WHICH_ATTR_CHAN].maxima;
3812 regA = cs[WHICH_ATTR_CHAN].mean;
3816 regA = cs[WHICH_ATTR_CHAN].median;
3820 regA = cs[WHICH_ATTR_CHAN].minima;
3825 regA = (fxFltType) img->page.x;
3828 regA = (fxFltType) img->page.y;
3831 regA = (fxFltType) img->page.width;
3834 regA = (fxFltType) img->page.height;
3839 regA = (fxFltType) PerceptibleReciprocal (img->resolution.x) * img->columns;
3842 regA = (fxFltType) PerceptibleReciprocal (img->resolution.y) * img->rows;
3845 regA = (fxFltType) img->quality;
3850 regA = (fxFltType) img->resolution.x;
3853 regA = (fxFltType) img->resolution.y;
3857 regA = cs[WHICH_ATTR_CHAN].skewness;
3861 regA = cs[WHICH_ATTR_CHAN].standard_deviation;
3864 regA = (fxFltType) img->rows;
3867 regA = (fxFltType) pfx->ImgListLen;
3870 regA = (fxFltType) pfx->ImgNum;
3873 regA = (fxFltType) img->columns;
3876 regA = (fxFltType) GetImageDepth (img, pfx->exception);
3884 regA = GetIntensity (pfx, pfx->ImgNum, (
double) imgx, (
double) imgy);
3891 regA = QuantumScale * (0.212656 * (double) GetPixelRed (img,p) +
3892 0.715158 * (double) GetPixelGreen (img,p) +
3893 0.072186 * (double) GetPixelBlue (img,p));
3899 regA = QuantumScale * (double) GetPixelAlpha (img, p);
3902 regA = QuantumScale * (double) GetPixelBlue (img, p);
3905 regA = QuantumScale * (double) GetPixelCyan (img, p);
3908 regA = QuantumScale * (double) GetPixelGreen (img, p);
3911 regA = (fxFltType) imgx;
3914 regA = (fxFltType) imgy;
3917 regA = QuantumScale * (double) GetPixelBlack (img, p);
3920 regA = QuantumScale * (double) GetPixelGreen (img, p);
3923 regA = QuantumScale * (double) GetPixelAlpha (img, p);
3926 regA = QuantumScale * (double) GetPixelRed (img, p);
3929 regA = QuantumScale * (double) GetPixelYellow (img, p);
3935 assert (pel->EleNdx >= 0);
3939 assert (pel->EleNdx >= 0);
3941 if (IsImageTTLExpired(img) != MagickFalse) {
3942 i = pfx->usedElements-1;
3943 (void) ThrowMagickException (pfx->exception, GetMagickModule(),
3944 ResourceLimitFatalError,
"TimeLimitExceeded",
"`%s'", img->filename);
3948 assert (pel->EleNdx >= 0);
3949 if (fabs((
double) regA) < MagickEpsilon) i = pel->EleNdx-1;
3951 case rIfNotZeroGoto:
3952 assert (pel->EleNdx >= 0);
3953 if (fabs((
double) regA) > MagickEpsilon) i = pel->EleNdx-1;
3956 assert (pel->EleNdx >= 0);
3957 regA = pfxrt->UserSymVals[pel->EleNdx];
3960 assert (pel->EleNdx >= 0);
3961 pfxrt->UserSymVals[pel->EleNdx] = regA;
3964 pfxrt->usedValStack = 0;
3970 (void) ThrowMagickException (
3971 pfx->exception, GetMagickModule(), OptionError,
3972 "pel->oprNum",
"%i '%s' not yet implemented",
3973 (int)pel->oprNum, OprStr(pel->oprNum));
3977 if (!PushVal (pfx, pfxrt, regA, i))
break;
3980 if (pfxrt->usedValStack > 0) regA = PopVal (pfx, pfxrt, 9999);
3986 if (pfx->exception->severity != UndefinedException) {
3990 if (pfxrt->usedValStack != 0) {
3991 (void) ThrowMagickException (
3992 pfx->exception, GetMagickModule(), OptionError,
3993 "ValStack not empty",
"(%i)", pfxrt->usedValStack);
4002MagickPrivate MagickBooleanType FxEvaluateChannelExpression (
4004 const PixelChannel channel,
const ssize_t x,
const ssize_t y,
4008 id = GetOpenMPThreadId();
4012 assert (pfx != NULL);
4013 assert (pfx->image != NULL);
4014 assert (pfx->Images != NULL);
4015 assert (pfx->Imgs != NULL);
4016 assert (pfx->fxrts != NULL);
4018 pfx->fxrts[id].thisPixel = NULL;
4020 if (!ExecuteRPN (pfx, &pfx->fxrts[
id], &ret, channel, x, y)) {
4021 (void) ThrowMagickException (
4022 exception, GetMagickModule(), OptionError,
4023 "ExecuteRPN failed",
" ");
4027 *result = (double) ret;
4032static FxInfo *AcquireFxInfoPrivate (
const Image * images,
const char * expression,
4037 FxInfo * pfx = (
FxInfo*) AcquireCriticalMemory (
sizeof (*pfx));
4039 memset (pfx, 0,
sizeof (*pfx));
4041 if (!InitFx (pfx, images, CalcAllStats, exception)) {
4042 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4046 if (!BuildRPN (pfx)) {
4047 (void) DeInitFx (pfx);
4048 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4052 if ((*expression ==
'@') && (strlen(expression) > 1))
4053 pfx->expression=FileToString(expression,~0UL,exception);
4054 if (pfx->expression == (
char *) NULL)
4055 pfx->expression=ConstantString(expression);
4056 pfx->pex = (
char *) pfx->expression;
4059 if (!TranslateStatementList (pfx,
";", &chLimit)) {
4060 (void) DestroyRPN (pfx);
4061 pfx->expression = DestroyString (pfx->expression);
4063 (void) DeInitFx (pfx);
4064 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4069 (void) ThrowMagickException (
4070 pfx->exception, GetMagickModule(), OptionError,
4071 "Translate expression depth",
"(%i) not 0",
4074 (void) DestroyRPN (pfx);
4075 pfx->expression = DestroyString (pfx->expression);
4077 (void) DeInitFx (pfx);
4078 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4082 if (chLimit !=
'\0' && chLimit !=
';') {
4083 (void) ThrowMagickException (
4084 pfx->exception, GetMagickModule(), OptionError,
4085 "AcquireFxInfo: TranslateExpression did not exhaust input",
"(chLimit=%i) at'%s'",
4086 (int)chLimit, pfx->pex);
4088 (void) DestroyRPN (pfx);
4089 pfx->expression = DestroyString (pfx->expression);
4091 (void) DeInitFx (pfx);
4092 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4096 if (pfx->NeedStats && pfx->runType == rtEntireImage && !pfx->statistics) {
4097 if (!CollectStatistics (pfx)) {
4098 (void) DestroyRPN (pfx);
4099 pfx->expression = DestroyString (pfx->expression);
4101 (void) DeInitFx (pfx);
4102 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4107 if (pfx->DebugOpt) {
4108 DumpTables (stderr);
4109 DumpUserSymbols (pfx, stderr);
4110 (void) DumpRPN (pfx, stderr);
4114 size_t number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
4117 pfx->fxrts = (
fxRtT *)AcquireQuantumMemory (number_threads,
sizeof(
fxRtT));
4119 (void) ThrowMagickException (
4120 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
4122 (
unsigned long) number_threads);
4123 (void) DestroyRPN (pfx);
4124 pfx->expression = DestroyString (pfx->expression);
4126 (void) DeInitFx (pfx);
4127 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4130 for (t=0; t < (ssize_t) number_threads; t++) {
4131 if (!AllocFxRt (pfx, &pfx->fxrts[t])) {
4132 (void) ThrowMagickException (
4133 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
4134 "AllocFxRt t=",
"%g",
4138 for (t2 = t-1; t2 >= 0; t2--) {
4139 DestroyFxRt (&pfx->fxrts[t]);
4142 pfx->fxrts = (
fxRtT *) RelinquishMagickMemory (pfx->fxrts);
4143 (void) DestroyRPN (pfx);
4144 pfx->expression = DestroyString (pfx->expression);
4146 (void) DeInitFx (pfx);
4147 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4157 return AcquireFxInfoPrivate (images, expression, MagickFalse, exception);
4164 assert (pfx != NULL);
4165 assert (pfx->image != NULL);
4166 assert (pfx->Images != NULL);
4167 assert (pfx->Imgs != NULL);
4168 assert (pfx->fxrts != NULL);
4170 for (t=0; t < (ssize_t) GetMagickResourceLimit(ThreadResource); t++) {
4171 DestroyFxRt (&pfx->fxrts[t]);
4173 pfx->fxrts = (
fxRtT *) RelinquishMagickMemory (pfx->fxrts);
4177 pfx->expression = DestroyString (pfx->expression);
4180 (void) DeInitFx (pfx);
4182 pfx = (
FxInfo*) RelinquishMagickMemory(pfx);
4189MagickExport
Image *FxImage(
const Image *image,
const char *expression,
4192#define FxImageTag "FxNew/Image"
4213 assert(image != (
Image *) NULL);
4214 assert(image->signature == MagickCoreSignature);
4215 if (IsEventLogging() != MagickFalse)
4216 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4217 if (expression == (
const char *) NULL)
4218 return(CloneImage(image,0,0,MagickTrue,exception));
4219 fx_image=CloneImage(image,0,0,MagickTrue,exception);
4220 if (!fx_image)
return NULL;
4221 if (SetImageStorageClass(fx_image,DirectClass,exception) == MagickFalse) {
4222 fx_image=DestroyImage(fx_image);
4226 pfx = AcquireFxInfoPrivate (image, expression, MagickTrue, exception);
4229 fx_image=DestroyImage(fx_image);
4233 assert (pfx->image != NULL);
4234 assert (pfx->Images != NULL);
4235 assert (pfx->Imgs != NULL);
4236 assert (pfx->fxrts != NULL);
4240 image_view = AcquireVirtualCacheView (image, pfx->exception);
4241 fx_view = AcquireAuthenticCacheView (fx_image, pfx->exception);
4242#if defined(MAGICKCORE_OPENMP_SUPPORT)
4243 #pragma omp parallel for schedule(dynamic) shared(progress,status) \
4244 magick_number_threads(image,fx_image,fx_image->rows, \
4245 pfx->ContainsDebug ? 0 : 1)
4247 for (y=0; y < (ssize_t) fx_image->rows; y++)
4250 id = GetOpenMPThreadId();
4264 if (status == MagickFalse)
4266 p = GetCacheViewVirtualPixels (image_view, 0, y, image->columns, 1, pfx->exception);
4267 q = QueueCacheViewAuthenticPixels (fx_view, 0, y, fx_image->columns, 1, pfx->exception);
4268 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL)) {
4272 for (x=0; x < (ssize_t) fx_image->columns; x++) {
4275 pfx->fxrts[id].thisPixel = (Quantum *)p;
4277 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4279 PixelChannel channel = GetPixelChannelChannel (image, i);
4280 PixelTrait traits = GetPixelChannelTraits (image, channel);
4281 PixelTrait fx_traits = GetPixelChannelTraits (fx_image, channel);
4282 if ((traits == UndefinedPixelTrait) ||
4283 (fx_traits == UndefinedPixelTrait))
4285 if ((fx_traits & CopyPixelTrait) != 0) {
4286 SetPixelChannel (fx_image, channel, p[i], q);
4290 if (!ExecuteRPN (pfx, &pfx->fxrts[
id], &result, channel, x, y)) {
4295 q[i] = ClampToQuantum ((MagickRealType) (QuantumRange*result));
4297 p+=GetPixelChannels (image);
4298 q+=GetPixelChannels (fx_image);
4300 if (SyncCacheViewAuthenticPixels(fx_view, pfx->exception) == MagickFalse)
4302 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4307#if defined(MAGICKCORE_OPENMP_SUPPORT)
4311 proceed = SetImageProgress (image, FxImageTag, progress, image->rows);
4312 if (proceed == MagickFalse)
4317 fx_view = DestroyCacheView (fx_view);
4318 image_view = DestroyCacheView (image_view);
4322 if (pfx->DebugOpt && pfx->usedUserSymbols) {
4324 char UserSym[MagickPathExtent];
4325 fprintf (stderr,
"User symbols (%i):\n", pfx->usedUserSymbols);
4326 for (t=0; t < (int) GetMagickResourceLimit(ThreadResource); t++) {
4327 for (i = 0; i < (int) pfx->usedUserSymbols; i++) {
4328 fprintf (stderr,
"th=%i us=%i '%s': %.*Lg\n",
4329 t, i, NameOfUserSym (pfx, i, UserSym), pfx->precision, pfx->fxrts[t].UserSymVals[i]);
4334 if (pfx->exception->severity != UndefinedException) {
4335 status = MagickFalse;
4338 if (status == MagickFalse)
4339 fx_image = DestroyImage (fx_image);
4341 pfx = DestroyFxInfo (pfx);