44#include "MagickCore/studio.h"
45#include "MagickCore/accelerate-private.h"
46#include "MagickCore/annotate.h"
47#include "MagickCore/artifact.h"
48#include "MagickCore/attribute.h"
49#include "MagickCore/cache.h"
50#include "MagickCore/cache-view.h"
51#include "MagickCore/channel.h"
52#include "MagickCore/color.h"
53#include "MagickCore/color-private.h"
54#include "MagickCore/colorspace-private.h"
55#include "MagickCore/composite.h"
56#include "MagickCore/decorate.h"
57#include "MagickCore/distort.h"
58#include "MagickCore/draw.h"
59#include "MagickCore/effect.h"
60#include "MagickCore/enhance.h"
61#include "MagickCore/exception.h"
62#include "MagickCore/exception-private.h"
63#include "MagickCore/fx.h"
64#include "MagickCore/fx-private.h"
65#include "MagickCore/gem.h"
66#include "MagickCore/gem-private.h"
67#include "MagickCore/geometry.h"
68#include "MagickCore/layer.h"
69#include "MagickCore/list.h"
70#include "MagickCore/log.h"
71#include "MagickCore/image.h"
72#include "MagickCore/image-private.h"
73#include "MagickCore/magick.h"
74#include "MagickCore/memory_.h"
75#include "MagickCore/memory-private.h"
76#include "MagickCore/monitor.h"
77#include "MagickCore/monitor-private.h"
78#include "MagickCore/option.h"
79#include "MagickCore/pixel.h"
80#include "MagickCore/pixel-accessor.h"
81#include "MagickCore/policy.h"
82#include "MagickCore/property.h"
83#include "MagickCore/quantum.h"
84#include "MagickCore/quantum-private.h"
85#include "MagickCore/random_.h"
86#include "MagickCore/random-private.h"
87#include "MagickCore/resample.h"
88#include "MagickCore/resample-private.h"
89#include "MagickCore/resize.h"
90#include "MagickCore/resource_.h"
91#include "MagickCore/splay-tree.h"
92#include "MagickCore/statistic.h"
93#include "MagickCore/string_.h"
94#include "MagickCore/string-private.h"
95#include "MagickCore/thread-private.h"
96#include "MagickCore/threshold.h"
97#include "MagickCore/timer-private.h"
98#include "MagickCore/token.h"
99#include "MagickCore/transform.h"
100#include "MagickCore/transform-private.h"
101#include "MagickCore/utility.h"
104#define MaxTokenLen 100
106#define TableExtend 0.1
107#define InitNumOprStack 50
108#define MinValStackSize 100
109#define InitNumUserSymbols 50
111#if defined(MAGICKCORE_WINDOWS_SUPPORT)
119#define SECONDS_ERR -FLT_MAX
121typedef long double fxFltType;
177 {oAddEq,
"+=", 12, 1},
178 {oSubtractEq,
"-=", 12, 1},
179 {oMultiplyEq,
"*=", 13, 1},
180 {oDivideEq,
"/=", 13, 1},
181 {oPlusPlus,
"++", 12, 0},
182 {oSubSub,
"--", 12, 0},
184 {oSubtract,
"-", 12, 2},
185 {oMultiply,
"*", 13, 2},
186 {oDivide,
"/", 13, 2},
187 {oModulus,
"%", 13, 2},
188 {oUnaryPlus,
"+", 14, 1},
189 {oUnaryMinus,
"-", 14, 1},
190 {oLshift,
"<<", 11, 2},
191 {oRshift,
">>", 11, 2},
193 {oNotEq,
"!=", 9, 2},
194 {oLtEq,
"<=", 10, 2},
195 {oGtEq,
">=", 10, 2},
198 {oLogAnd,
"&&", 6, 2},
199 {oLogOr,
"||", 5, 2},
200 {oLogNot,
"!", 16, 1},
201 {oBitAnd,
"&", 8, 2},
203 {oBitNot,
"~", 16, 1},
207 {oOpenParen,
"(", 0, 0},
208 {oCloseParen,
")", 0, 0},
209 {oOpenBracket,
"[", 0, 0},
210 {oCloseBracket,
"]", 0, 0},
211 {oOpenBrace,
"{", 0, 0},
212 {oCloseBrace,
"}", 0, 0},
213 {oAssign,
"=", 3, 1},
214 {oNull,
"onull", 17, 0}
242 {cEpsilon, MagickEpsilon,
"epsilon"},
243 {cE, 2.7182818284590452354,
"e"},
244 {cOpaque, 1.0,
"opaque"},
245 {cPhi, MagickPHI,
"phi"},
246 {cPi, MagickPI,
"pi"},
247 {cQuantumRange, QuantumRange,
"quantumrange"},
248 {cQuantumScale, QuantumScale,
"quantumscale"},
249 {cTransparent, 0.0,
"transparent"},
250 {cMaxRgb, QuantumRange,
"MaxRGB"},
251 {cNull, 0.0,
"cnull"}
254#define FirstFunc ((FunctionE) (oNull+1))
258#if defined(MAGICKCORE_HAVE_ACOSH)
262#if defined(MAGICKCORE_HAVE_J1)
266#if defined(MAGICKCORE_HAVE_ASINH)
270#if defined(MAGICKCORE_HAVE_ATANH)
282#if defined(MAGICKCORE_HAVE_ERF)
293#if defined(MAGICKCORE_HAVE_J0)
296#if defined(MAGICKCORE_HAVE_J1)
299#if defined(MAGICKCORE_HAVE_J1)
351#if defined(MAGICKCORE_HAVE_ACOSH)
352 {fAcosh,
"acosh" , 1},
355#if defined(MAGICKCORE_HAVE_J1)
359#if defined(MAGICKCORE_HAVE_ASINH)
360 {fAsinh,
"asinh" , 1},
363#if defined(MAGICKCORE_HAVE_ATANH)
364 {fAtanh,
"atanh" , 1},
366 {fAtan2,
"atan2" , 2},
369 {fChannel,
"channel", 5},
370 {fClamp,
"clamp" , 1},
373 {fDebug,
"debug" , 1},
375#if defined(MAGICKCORE_HAVE_ERF)
378 {fEpoch,
"epoch" , 1},
380 {fFloor,
"floor" , 1},
381 {fGauss,
"gauss" , 1},
383 {fHypot,
"hypot" , 2},
385 {fIsnan,
"isnan" , 1},
386#if defined(MAGICKCORE_HAVE_J0)
389#if defined(MAGICKCORE_HAVE_J1)
392#if defined(MAGICKCORE_HAVE_J1)
396 {fLogtwo,
"logtwo", 1},
398 {fMagickTime,
"magicktime", 0},
405 {fRound,
"round" , 1},
411 {fSquish,
"squish", 1},
414 {fTrunc,
"trunc" , 1},
418 {fWhile,
"while", 2},
431#define FirstImgAttr ((ImgAttrE) (fNull+1))
475 {aDepth,
"depth", MagickTrue},
476 {aExtent,
"extent", MagickFalse},
477 {aKurtosis,
"kurtosis", MagickTrue},
478 {aMaxima,
"maxima", MagickTrue},
479 {aMean,
"mean", MagickTrue},
480 {aMedian,
"median", MagickTrue},
481 {aMinima,
"minima", MagickTrue},
482 {aPage,
"page", MagickFalse},
483 {aPageX,
"page.x", MagickFalse},
484 {aPageY,
"page.y", MagickFalse},
485 {aPageWid,
"page.width", MagickFalse},
486 {aPageHt,
"page.height", MagickFalse},
487 {aPrintsize,
"printsize", MagickFalse},
488 {aPrintsizeX,
"printsize.x", MagickFalse},
489 {aPrintsizeY,
"printsize.y", MagickFalse},
490 {aQuality,
"quality", MagickFalse},
491 {aRes,
"resolution", MagickFalse},
492 {aResX,
"resolution.x", MagickFalse},
493 {aResY,
"resolution.y", MagickFalse},
494 {aSkewness,
"skewness", MagickTrue},
495 {aStdDev,
"standard_deviation", MagickTrue},
496 {aH,
"h", MagickFalse},
497 {aN,
"n", MagickFalse},
498 {aT,
"t", MagickFalse},
499 {aW,
"w", MagickFalse},
500 {aZ,
"z", MagickFalse},
501 {aNull,
"anull", MagickFalse},
502 {aNull,
"anull", MagickFalse},
503 {aNull,
"anull", MagickFalse},
504 {aNull,
"anull", MagickFalse}
507#define FirstSym ((SymbolE) (aNull+1))
538static const SymbolT Symbols[] = {
540 {sIntensity,
"intensity"},
541 {sLightness,
"lightness"},
543 {sLuminance,
"luminance"},
544 {sSaturation,
"saturation"},
565#define FirstCont (sNull+1)
592 {rGotoChk,
"gotochk", 0},
593 {rIfZeroGoto,
"ifzerogoto", 1},
594 {rIfNotZeroGoto,
"ifnotzerogoto", 1},
595 {rCopyFrom,
"copyfrom", 0},
596 {rCopyTo,
"copyto", 1},
597 {rZerStk,
"zerstk", 0},
601#define NULL_ADDRESS -2
617#define NO_CHAN_QUAL ((PixelChannel) (-1))
618#define THIS_CHANNEL ((PixelChannel) (-2))
619#define HUE_CHANNEL ((PixelChannel) (-3))
620#define SAT_CHANNEL ((PixelChannel) (-4))
621#define LIGHT_CHANNEL ((PixelChannel) (-5))
622#define INTENSITY_CHANNEL ((PixelChannel) (-6))
625 {
"r", RedPixelChannel},
626 {
"g", GreenPixelChannel},
627 {
"b", BluePixelChannel},
628 {
"c", CyanPixelChannel},
629 {
"m", MagentaPixelChannel},
630 {
"y", YellowPixelChannel},
631 {
"k", BlackPixelChannel},
632 {
"a", AlphaPixelChannel},
633 {
"o", AlphaPixelChannel},
634 {
"hue", HUE_CHANNEL},
635 {
"saturation", SAT_CHANNEL},
636 {
"lightness", LIGHT_CHANNEL},
637 {
"intensity", INTENSITY_CHANNEL},
638 {
"all", CompositePixelChannel},
639 {
"this", THIS_CHANNEL},
663static const char * sElementTypes[] = {
717 RandomInfo * magick_restrict random_info;
720 fxFltType * ValStack;
721 fxFltType * UserSymVals;
729 MagickBooleanType NeedStats;
730 MagickBooleanType GotStats;
731 MagickBooleanType NeedHsl;
732 MagickBooleanType DebugOpt;
733 MagickBooleanType ContainsDebug;
736 char ShortExp[MagickPathExtent];
738 char token[MagickPathExtent];
749 OperatorE * OperatorStack;
750 ChannelStatistics ** statistics;
755 **magick_restrict random_infos;
760 ExceptionInfo * exception;
767static MagickBooleanType TranslateStatementList
768 (FxInfo * pfx,
const char * strLimit,
char * chLimit);
770static MagickBooleanType TranslateExpression
771 (FxInfo * pfx,
const char * strLimit,
char * chLimit, MagickBooleanType * needPopAll);
773static MagickBooleanType GetFunction (FxInfo * pfx, FunctionE fe);
775static inline MagickBooleanType ChanIsVirtual (PixelChannel pc)
777 if (pc==HUE_CHANNEL || pc==SAT_CHANNEL || pc==LIGHT_CHANNEL || pc==INTENSITY_CHANNEL)
783static MagickBooleanType InitFx (FxInfo * pfx,
const Image * img,
784 MagickBooleanType CalcAllStats, ExceptionInfo *exception)
789 pfx->ImgListLen = GetImageListLength (img);
790 pfx->ImgNum = GetImageIndexInList (img);
791 pfx->image = (Image *)img;
793 pfx->NeedStats = MagickFalse;
794 pfx->GotStats = MagickFalse;
795 pfx->NeedHsl = MagickFalse;
796 pfx->DebugOpt = IsStringTrue (GetImageArtifact (img,
"fx:debug"));
797 pfx->statistics = NULL;
800 pfx->exception = exception;
801 pfx->precision = GetMagickPrecision ();
802 pfx->random_infos = AcquireRandomInfoTLS ();
803 pfx->ContainsDebug = MagickFalse;
804 pfx->runType = (CalcAllStats) ? rtEntireImage : rtCornerOnly;
805 pfx->Imgs = (
ImgT *)AcquireQuantumMemory (pfx->ImgListLen, sizeof (
ImgT));
807 (void) ThrowMagickException (
808 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
810 (
unsigned long) pfx->ImgListLen);
814 next = GetFirstImageInList (img);
815 for ( ; next != (Image *) NULL; next=next->next)
817 ImgT * pimg = &pfx->Imgs[i];
818 pimg->View = AcquireVirtualCacheView (next, pfx->exception);
820 (void) ThrowMagickException (
821 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
825 for ( ; i > 0; i--) {
826 pimg = &pfx->Imgs[i-1];
827 pimg->View = DestroyCacheView (pimg->View);
829 pfx->Imgs=(
ImgT *) RelinquishMagickMemory (pfx->Imgs);
835 pfx->Images = ImageListToArray (img, pfx->exception);
840static MagickBooleanType DeInitFx (FxInfo * pfx)
844 if (pfx->Images) pfx->Images = (Image**) RelinquishMagickMemory (pfx->Images);
847 for (i = (ssize_t)GetImageListLength(pfx->image); i > 0; i--) {
848 ImgT * pimg = &pfx->Imgs[i-1];
849 pimg->View = DestroyCacheView (pimg->View);
851 pfx->Imgs=(
ImgT *) RelinquishMagickMemory (pfx->Imgs);
853 pfx->random_infos = DestroyRandomInfoTLS (pfx->random_infos);
855 if (pfx->statistics) {
856 for (i = (ssize_t)GetImageListLength(pfx->image); i > 0; i--) {
857 pfx->statistics[i-1]=(ChannelStatistics *) RelinquishMagickMemory (pfx->statistics[i-1]);
860 pfx->statistics = (ChannelStatistics**) RelinquishMagickMemory(pfx->statistics);
866static ElementTypeE TypeOfOpr (
int op)
868 if (op < oNull)
return etOperator;
869 if (op == oNull)
return etConstant;
870 if (op <= fNull)
return etFunction;
871 if (op <= aNull)
return etImgAttr;
872 if (op <= sNull)
return etSymbol;
873 if (op <= rNull)
return etControl;
875 return (ElementTypeE) 0;
878static char * SetPtrShortExp (FxInfo *pfx,
char *pExp,
size_t len)
885 *pfx->ShortExp =
'\0';
888 slen = CopyMagickString(pfx->ShortExp, pExp, MagickPathExtent);
891 (void) CopyMagickString(pfx->ShortExp + MaxLen,
"...", 4);
894 p = strchr(pfx->ShortExp,
'\n');
895 if (p) (void) CopyMagickString(p,
"...", 4);
897 p = strchr(pfx->ShortExp,
'\r');
898 if (p) (void) CopyMagickString(p,
"...", 4);
901 return pfx->ShortExp;
904static char * SetShortExp (FxInfo * pfx)
906 return SetPtrShortExp (pfx, pfx->pex, MaxTokenLen-1);
909static int FindUserSymbol (FxInfo * pfx,
char * name)
916 lenName = strlen (name);
917 for (i=0; i < pfx->usedUserSymbols; i++) {
919 if (lenName == pus->len && LocaleNCompare (name, pus->pex, lenName)==0)
break;
921 if (i == pfx->usedUserSymbols)
return NULL_ADDRESS;
925static MagickBooleanType ExtendUserSymbols (FxInfo * pfx)
927 pfx->numUserSymbols = (int) ceil (pfx->numUserSymbols * (1 + TableExtend));
928 pfx->UserSymbols = (
UserSymbolT*) ResizeMagickMemory (pfx->UserSymbols, (
size_t) pfx->numUserSymbols *
sizeof(
UserSymbolT));
929 if (!pfx->UserSymbols) {
930 (void) ThrowMagickException (
931 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
933 pfx->numUserSymbols);
940static int AddUserSymbol (FxInfo * pfx,
char * pex,
size_t len)
943 if (++pfx->usedUserSymbols >= pfx->numUserSymbols) {
944 if (!ExtendUserSymbols (pfx))
return -1;
946 pus = &pfx->UserSymbols[pfx->usedUserSymbols-1];
950 return pfx->usedUserSymbols-1;
953static void DumpTables (FILE * fh)
957 for (i=0; i <= rNull; i++) {
958 const char * str =
"";
959 if ( i < oNull) str = Operators[i].str;
960 if (i >= (
int) FirstFunc && i < fNull) str = Functions[i-(int) FirstFunc].str;
961 if (i >= (
int) FirstImgAttr && i < aNull) str = ImgAttrs[i-(int) FirstImgAttr].str;
962 if (i >= (
int) FirstSym && i < sNull) str = Symbols[i-(int) FirstSym].str;
963 if (i >= (
int) FirstCont && i < rNull) str = Controls[i-(int) FirstCont].str;
964 if (i==0 ) fprintf (stderr,
"Operators:\n ");
965 else if (i==oNull) fprintf (stderr,
"\nFunctions:\n ");
966 else if (i==fNull) fprintf (stderr,
"\nImage attributes:\n ");
967 else if (i==aNull) fprintf (stderr,
"\nSymbols:\n ");
968 else if (i==sNull) fprintf (stderr,
"\nControls:\n ");
969 fprintf (fh,
" %s", str);
974static char * NameOfUserSym (FxInfo * pfx,
int ndx,
char * buf)
977 assert (ndx >= 0 && ndx < pfx->usedUserSymbols);
978 pus = &pfx->UserSymbols[ndx];
979 (void) CopyMagickString (buf, pus->pex, pus->len+1);
983static void DumpUserSymbols (FxInfo * pfx, FILE * fh)
985 char UserSym[MagickPathExtent];
987 fprintf (fh,
"UserSymbols (%i)\n", pfx->usedUserSymbols);
988 for (i=0; i < pfx->usedUserSymbols; i++) {
989 fprintf (fh,
" %i: '%s'\n", i, NameOfUserSym (pfx, i, UserSym));
993static MagickBooleanType BuildRPN (FxInfo * pfx)
995 pfx->numUserSymbols = InitNumUserSymbols;
996 pfx->usedUserSymbols = 0;
997 pfx->UserSymbols = (
UserSymbolT*) AcquireMagickMemory ((
size_t) pfx->numUserSymbols *
sizeof(
UserSymbolT));
998 if (!pfx->UserSymbols) {
999 (void) ThrowMagickException (
1000 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1001 "UserSymbols",
"%i",
1002 pfx->numUserSymbols);
1006 pfx->numElements = RpnInit;
1007 pfx->usedElements = 0;
1008 pfx->Elements = NULL;
1010 pfx->Elements = (
ElementT*) AcquireMagickMemory ((
size_t) pfx->numElements *
sizeof(
ElementT));
1012 if (!pfx->Elements) {
1013 (void) ThrowMagickException (
1014 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1020 pfx->usedOprStack = 0;
1021 pfx->maxUsedOprStack = 0;
1022 pfx->numOprStack = InitNumOprStack;
1023 pfx->OperatorStack = (OperatorE*) AcquireMagickMemory ((
size_t) pfx->numOprStack *
sizeof(OperatorE));
1024 if (!pfx->OperatorStack) {
1025 (void) ThrowMagickException (
1026 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1027 "OperatorStack",
"%i",
1035static MagickBooleanType AllocFxRt (FxInfo * pfx,
fxRtT * pfxrt)
1039 pfxrt->random_info = AcquireRandomInfo ();
1040 pfxrt->thisPixel = NULL;
1042 nRnd = 20 + 10 * (int) GetPseudoRandomValue (pfxrt->random_info);
1043 for (i=0; i < nRnd; i++) (
void) GetPseudoRandomValue (pfxrt->random_info);;
1045 pfxrt->usedValStack = 0;
1046 pfxrt->numValStack = 2 * pfx->maxUsedOprStack;
1047 if (pfxrt->numValStack < MinValStackSize) pfxrt->numValStack = MinValStackSize;
1048 pfxrt->ValStack = (fxFltType*) AcquireMagickMemory ((
size_t) pfxrt->numValStack *
sizeof(fxFltType));
1049 if (!pfxrt->ValStack) {
1050 (void) ThrowMagickException (
1051 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1053 pfxrt->numValStack);
1057 pfxrt->UserSymVals = NULL;
1059 if (pfx->usedUserSymbols) {
1060 pfxrt->UserSymVals = (fxFltType*) AcquireMagickMemory ((
size_t) pfx->usedUserSymbols *
sizeof(fxFltType));
1061 if (!pfxrt->UserSymVals) {
1062 (void) ThrowMagickException (
1063 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1064 "UserSymVals",
"%i",
1065 pfx->usedUserSymbols);
1068 for (i = 0; i < pfx->usedUserSymbols; i++) pfxrt->UserSymVals[i] = (fxFltType) 0;
1074static MagickBooleanType ExtendRPN(FxInfo * pfx)
1085 element_count=(int) ceil(pfx->numElements*(1+TableExtend));
1086 new_elements=(
ElementT *) AcquireQuantumMemory((
size_t) element_count,
1087 sizeof(*new_elements));
1088 if (new_elements == (
ElementT *) NULL)
1090 (void) ThrowMagickException(pfx->exception,GetMagickModule(),
1091 ResourceLimitError,
"MemoryAllocationFailed",
"`%s'",
"RPN table");
1092 return(MagickFalse);
1094 (void) memcpy(new_elements,pfx->Elements,(
size_t) pfx->usedElements*
1095 sizeof(*new_elements));
1096 pfx->Elements=(
ElementT *) RelinquishMagickMemory(pfx->Elements);
1097 pfx->Elements=new_elements;
1098 pfx->numElements=element_count;
1101 (void) ThrowMagickException(pfx->exception,GetMagickModule(),
1102 ResourceLimitFatalError,
"Elements",
"%i",pfx->numElements);
1103 return(MagickFalse);
1108static inline MagickBooleanType OprInPlace(
int op)
1110 return(op >= oAddEq && op <= oSubSub ? MagickTrue : MagickFalse);
1113static const char * OprStr (
int oprNum)
1116 if (oprNum < 0) str =
"bad OprStr";
1117 else if (oprNum <= oNull) str = Operators[oprNum].str;
1118 else if (oprNum <= fNull) str = Functions[oprNum-(int) FirstFunc].str;
1119 else if (oprNum <= aNull) str = ImgAttrs[oprNum-(int) FirstImgAttr].str;
1120 else if (oprNum <= sNull) str = Symbols[oprNum-(int) FirstSym].str;
1121 else if (oprNum <= rNull) str = Controls[oprNum-(int) FirstCont].str;
1128static MagickBooleanType DumpRPN (FxInfo * pfx, FILE * fh)
1132 fprintf (fh,
"DumpRPN:");
1133 fprintf (fh,
" numElements=%i", pfx->numElements);
1134 fprintf (fh,
" usedElements=%i", pfx->usedElements);
1135 fprintf (fh,
" maxUsedOprStack=%i", pfx->maxUsedOprStack);
1136 fprintf (fh,
" ImgListLen=%g", (
double) pfx->ImgListLen);
1137 fprintf (fh,
" NeedStats=%s", pfx->NeedStats ?
"yes" :
"no");
1138 fprintf (fh,
" GotStats=%s", pfx->GotStats ?
"yes" :
"no");
1139 fprintf (fh,
" NeedHsl=%s\n", pfx->NeedHsl ?
"yes" :
"no");
1140 if (pfx->runType==rtEntireImage) fprintf (stderr,
"EntireImage");
1141 else if (pfx->runType==rtCornerOnly) fprintf (stderr,
"CornerOnly");
1145 for (i=0; i < pfx->usedElements; i++) {
1146 ElementT * pel = &pfx->Elements[i];
1147 pel->number_dest = 0;
1149 for (i=0; i < pfx->usedElements; i++) {
1150 ElementT * pel = &pfx->Elements[i];
1151 if (pel->operator_index == rGoto || pel->operator_index == rGotoChk || pel->operator_index == rIfZeroGoto || pel->operator_index == rIfNotZeroGoto) {
1152 if (pel->element_index >= 0 && pel->element_index < pfx->numElements) {
1153 ElementT * pelDest = &pfx->Elements[pel->element_index];
1154 pelDest->number_dest++;
1158 for (i=0; i < pfx->usedElements; i++) {
1159 char UserSym[MagickPathExtent];
1161 ElementT * pel = &pfx->Elements[i];
1162 const char * str = OprStr (pel->operator_index);
1163 const char *sRelAbs =
"";
1165 if (pel->operator_index == fP || pel->operator_index == fUP || pel->operator_index == fVP || pel->operator_index == fSP)
1166 sRelAbs = pel->is_relative ?
"[]" :
"{}";
1168 if (pel->type == etColourConstant)
1169 fprintf (fh,
" %i: %s vals=%.*Lg,%.*Lg,%.*Lg '%s%s' nArgs=%i ndx=%i %s",
1170 i, sElementTypes[pel->type],
1171 pfx->precision, pel->val, pfx->precision, pel->val1, pfx->precision, pel->val2,
1172 str, sRelAbs, pel->number_args, pel->element_index,
1173 pel->do_push ?
"push" :
"NO push");
1175 fprintf (fh,
" %i: %s val=%.*Lg '%s%s' nArgs=%i ndx=%i %s",
1176 i, sElementTypes[pel->type], pfx->precision, pel->val, str, sRelAbs,
1177 pel->number_args, pel->element_index,
1178 pel->do_push ?
"push" :
"NO push");
1180 if (pel->img_attr_qual != aNull)
1181 fprintf (fh,
" ia=%s", OprStr((
int) pel->img_attr_qual));
1183 if (pel->channel_qual != NO_CHAN_QUAL) {
1184 if (pel->channel_qual == THIS_CHANNEL) fprintf (stderr,
" ch=this");
1185 else fprintf (stderr,
" ch=%i", pel->channel_qual);
1188 if (pel->operator_index == rCopyTo) {
1189 fprintf (fh,
" CopyTo ==> %s", NameOfUserSym (pfx, pel->element_index, UserSym));
1190 }
else if (pel->operator_index == rCopyFrom) {
1191 fprintf (fh,
" CopyFrom <== %s", NameOfUserSym (pfx, pel->element_index, UserSym));
1192 }
else if (OprInPlace (pel->operator_index)) {
1193 fprintf (fh,
" <==> %s", NameOfUserSym (pfx, pel->element_index, UserSym));
1195 if (pel->number_dest > 0) fprintf (fh,
" <==dest(%i)", pel->number_dest);
1201static void DestroyRPN (FxInfo * pfx)
1203 pfx->numOprStack = 0;
1204 pfx->usedOprStack = 0;
1205 if (pfx->OperatorStack) pfx->OperatorStack = (OperatorE*) RelinquishMagickMemory (pfx->OperatorStack);
1207 pfx->numElements = 0;
1208 pfx->usedElements = 0;
1209 if (pfx->Elements) pfx->Elements = (
ElementT*) RelinquishMagickMemory (pfx->Elements);
1211 pfx->usedUserSymbols = 0;
1212 if (pfx->UserSymbols) pfx->UserSymbols = (
UserSymbolT*) RelinquishMagickMemory (pfx->UserSymbols);
1215static void DestroyFxRt (
fxRtT * pfxrt)
1217 pfxrt->usedValStack = 0;
1218 if (pfxrt->ValStack) pfxrt->ValStack = (fxFltType*) RelinquishMagickMemory (pfxrt->ValStack);
1219 if (pfxrt->UserSymVals) pfxrt->UserSymVals = (fxFltType*) RelinquishMagickMemory (pfxrt->UserSymVals);
1221 pfxrt->random_info = DestroyRandomInfo (pfxrt->random_info);
1224static size_t GetToken (FxInfo * pfx)
1235 char * p = pfx->pex;
1239 if (!isalpha((
int)*p))
return 0;
1246 if (LocaleNCompare (p,
"icc-", 4) == 0) {
1249 while (isalpha ((
int)*p)) { len++; p++; }
1250 }
else if (LocaleNCompare (p,
"device-", 7) == 0) {
1253 while (isalpha ((
int)*p)) { len++; p++; }
1255 while (isalpha ((
int)*p)) { len++; p++; }
1256 if (*p ==
'_') { len++; p++; }
1257 while (isalpha ((
int)*p)) { len++; p++; }
1258 while (isdigit ((
int)*p)) { len++; p++; }
1260 if (len >= MaxTokenLen) {
1261 (void) ThrowMagickException (
1262 pfx->exception, GetMagickModule(), OptionError,
1263 "GetToken: too long",
"%g at '%s'",
1264 (
double) len, SetShortExp(pfx));
1268 (void) CopyMagickString (pfx->token, pfx->pex, (len+1<MaxTokenLen)?len+1:MaxTokenLen);
1271 pfx->lenToken = strlen (pfx->token);
1275static MagickBooleanType TokenMaybeUserSymbol (FxInfo * pfx)
1277 char * p = pfx->token;
1280 if (!isalpha ((
int)*p++))
return MagickFalse;
1283 if (i < 2)
return MagickFalse;
1287static MagickBooleanType AddElement(FxInfo * pfx,fxFltType val,
int oprNum)
1291 assert (oprNum <= rNull);
1293 if (++pfx->usedElements >= pfx->numElements)
1295 if (ExtendRPN(pfx) == MagickFalse)
1297 pfx->usedElements--;
1298 return(MagickFalse);
1301 if (pfx->Elements == (
ElementT *) NULL)
1303 pfx->usedElements--;
1304 return(MagickFalse);
1306 pel = &pfx->Elements[pfx->usedElements-1];
1307 pel->type = TypeOfOpr (oprNum);
1309 pel->val1 = (fxFltType) 0;
1310 pel->val2 = (fxFltType) 0;
1311 pel->operator_index = oprNum;
1312 pel->do_push = MagickTrue;
1313 pel->element_index = 0;
1314 pel->channel_qual = NO_CHAN_QUAL;
1315 pel->img_attr_qual = aNull;
1316 pel->number_dest = 0;
1317 pel->exp_start = NULL;
1320 if (oprNum <= oNull) pel->number_args = Operators[oprNum].number_args;
1321 else if (oprNum <= fNull) pel->number_args = Functions[oprNum-(int) FirstFunc].number_args;
1322 else if (oprNum <= aNull) pel->number_args = 0;
1323 else if (oprNum <= sNull) pel->number_args = 0;
1324 else pel->number_args = Controls[oprNum-(int) FirstCont].number_args;
1329static MagickBooleanType AddAddressingElement (FxInfo * pfx,
int oprNum,
int EleNdx)
1332 if (!AddElement (pfx, (fxFltType) 0, oprNum))
return MagickFalse;
1333 pel = &pfx->Elements[pfx->usedElements-1];
1334 pel->element_index = EleNdx;
1335 if (oprNum == rGoto || oprNum == rGotoChk || oprNum == rIfZeroGoto || oprNum == rIfNotZeroGoto
1336 || oprNum == rZerStk)
1338 pel->do_push = MagickFalse;
1348static MagickBooleanType AddColourElement (FxInfo * pfx, fxFltType val0, fxFltType val1, fxFltType val2)
1351 if (!AddElement (pfx, val0, oNull))
return MagickFalse;
1352 pel = &pfx->Elements[pfx->usedElements-1];
1355 pel->type = etColourConstant;
1359static inline void SkipSpaces (FxInfo * pfx)
1361 while (isspace ((
int)*pfx->pex)) pfx->pex++;
1364static inline char PeekChar (FxInfo * pfx)
1370static inline MagickBooleanType PeekStr (FxInfo * pfx,
const char * str)
1374 return (LocaleNCompare (pfx->pex, str, strlen(str))==0 ? MagickTrue : MagickFalse);
1377static MagickBooleanType ExpectChar (FxInfo * pfx,
char c)
1379 if (PeekChar (pfx) != c) {
1380 (void) ThrowMagickException (
1381 pfx->exception, GetMagickModule(), OptionError,
1382 "Expected char",
"'%c' at '%s'", c, SetShortExp (pfx));
1389static int MaybeXYWH (FxInfo * pfx, ImgAttrE * pop)
1396 if (*pop != aPage && *pop != aPrintsize && *pop != aRes)
return 0;
1398 if (PeekChar (pfx) !=
'.')
return 0;
1400 if (!ExpectChar (pfx,
'.'))
return 0;
1402 (void) GetToken (pfx);
1403 if (LocaleCompare (
"x", pfx->token)==0) ret=1;
1404 else if (LocaleCompare (
"y", pfx->token)==0) ret=2;
1405 else if (LocaleCompare (
"width", pfx->token)==0) ret=3;
1406 else if (LocaleCompare (
"height", pfx->token)==0) ret=4;
1409 (void) ThrowMagickException (
1410 pfx->exception, GetMagickModule(), OptionError,
1411 "Invalid 'x' or 'y' or 'width' or 'height' token=",
"'%s' at '%s'",
1412 pfx->token, SetShortExp(pfx));
1414 if (*pop == aPage) (*pop) = (ImgAttrE) ((
int) *pop + ret);
1417 (void) ThrowMagickException (
1418 pfx->exception, GetMagickModule(), OptionError,
1419 "Invalid 'width' or 'height' token=",
"'%s' at '%s'",
1420 pfx->token, SetShortExp(pfx));
1422 (*pop) = (ImgAttrE) ((
int) *pop + ret);
1425 pfx->pex+=pfx->lenToken;
1430static MagickBooleanType ExtendOperatorStack (FxInfo * pfx)
1432 pfx->numOprStack = (int) ceil (pfx->numOprStack * (1 + TableExtend));
1433 pfx->OperatorStack = (OperatorE*) ResizeMagickMemory (pfx->OperatorStack, (
size_t) pfx->numOprStack *
sizeof(OperatorE));
1434 if (!pfx->OperatorStack) {
1435 (void) ThrowMagickException (
1436 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
1444static MagickBooleanType PushOperatorStack (FxInfo * pfx,
int op)
1446 if (++pfx->usedOprStack >= pfx->numOprStack) {
1447 if (!ExtendOperatorStack (pfx))
1450 pfx->OperatorStack[pfx->usedOprStack-1] = (OperatorE) op;
1452 if (pfx->maxUsedOprStack < pfx->usedOprStack)
1453 pfx->maxUsedOprStack = pfx->usedOprStack;
1457static OperatorE GetLeadingOp (FxInfo * pfx)
1459 OperatorE op = oNull;
1461 if (*pfx->pex ==
'-') op = oUnaryMinus;
1462 else if (*pfx->pex ==
'+') op = oUnaryPlus;
1463 else if (*pfx->pex ==
'~') op = oBitNot;
1464 else if (*pfx->pex ==
'!') op = oLogNot;
1465 else if (*pfx->pex ==
'(') op = oOpenParen;
1470static inline MagickBooleanType OprIsUnaryPrefix (OperatorE op)
1472 return (op == oUnaryMinus || op == oUnaryPlus || op == oBitNot || op == oLogNot ? MagickTrue : MagickFalse);
1475static MagickBooleanType TopOprIsUnaryPrefix (FxInfo * pfx)
1477 if (!pfx->usedOprStack)
return MagickFalse;
1479 return OprIsUnaryPrefix (pfx->OperatorStack[pfx->usedOprStack-1]);
1482static MagickBooleanType PopOprOpenParen (FxInfo * pfx, OperatorE op)
1485 if (!pfx->usedOprStack)
return MagickFalse;
1487 if (pfx->OperatorStack[pfx->usedOprStack-1] != op)
return MagickFalse;
1489 pfx->usedOprStack--;
1494static int GetCoordQualifier (FxInfo * pfx,
int op)
1498 if (op != fU && op != fV && op != fS)
return -1;
1500 (void) GetToken (pfx);
1502 if (pfx->lenToken != 1) {
1505 if (*pfx->token !=
'p' && *pfx->token !=
'P')
return -1;
1506 if (!GetFunction (pfx, fP))
return -1;
1511static PixelChannel GetChannelQualifier (FxInfo * pfx,
int op)
1513 if (op == fU || op == fV || op == fP ||
1514 op == fUP || op == fVP ||
1515 op == fS || (op >= (
int) FirstImgAttr && op <= aNull)
1518 const ChannelT * pch = &Channels[0];
1519 (void) GetToken (pfx);
1522 if (LocaleCompare (pch->str, pfx->token)==0) {
1524 if (op >= (
int) FirstImgAttr && op <= (
int) ((OperatorE)aNull) &&
1525 ChanIsVirtual (pch->pixel_channel)
1528 (void) ThrowMagickException (
1529 pfx->exception, GetMagickModule(), OptionError,
1530 "Can't have image attribute with channel qualifier at",
"'%s' at '%s'",
1531 pfx->token, SetShortExp(pfx));
1532 return NO_CHAN_QUAL;
1535 pfx->pex += pfx->lenToken;
1536 return pch->pixel_channel;
1541 return NO_CHAN_QUAL;
1544static ImgAttrE GetImgAttrToken (FxInfo * pfx)
1546 ImgAttrE ia = aNull;
1548 for (ia = FirstImgAttr; ia < aNull; ia=(ImgAttrE) (ia+1)) {
1549 iaStr = ImgAttrs[ia-(int) FirstImgAttr].str;
1550 if (LocaleCompare (iaStr, pfx->token)==0) {
1551 pfx->pex += strlen(pfx->token);
1552 if (ImgAttrs[ia-(
int) FirstImgAttr].need_stats != MagickFalse) pfx->NeedStats = MagickTrue;
1553 MaybeXYWH (pfx, &ia);
1558 if (ia == aPage || ia == aPrintsize || ia == aRes) {
1559 (void) ThrowMagickException (
1560 pfx->exception, GetMagickModule(), OptionError,
1561 "Attribute",
"'%s' needs qualifier at '%s'",
1562 iaStr, SetShortExp(pfx));
1568static ImgAttrE GetImgAttrQualifier (FxInfo * pfx,
int op)
1570 ImgAttrE ia = aNull;
1571 if (op == (OperatorE)fU || op == (OperatorE)fV || op == (OperatorE)fP || op == (OperatorE)fS) {
1572 (void) GetToken (pfx);
1573 if (pfx->lenToken == 0) {
1576 ia = GetImgAttrToken (pfx);
1581static MagickBooleanType IsQualifier (FxInfo * pfx)
1583 if (PeekChar (pfx) ==
'.') {
1590static MagickBooleanType ParseISO860(
const char* text,
struct tm* tp)
1600 memset(tp,0,
sizeof(
struct tm));
1601 if (MagickSscanf(text,
"%d-%d-%dT%d:%d:%d",&year,&month,&day,&hour,&min,&sec) != 6)
1602 return(MagickFalse);
1603 tp->tm_year=year-1900;
1613static ssize_t GetProperty (FxInfo * pfx, fxFltType *val, fxFltType *seconds)
1620 if (seconds != NULL) *seconds = SECONDS_ERR;
1622 if (PeekStr (pfx,
"%[")) {
1625 char sProperty [MagickPathExtent];
1626 char * p = pfx->pex + 2;
1630 if (*p ==
'[') level++;
1631 else if (*p ==
']') {
1632 if (level == 0)
break;
1637 if (!*p || level != 0) {
1638 (void) ThrowMagickException (
1639 pfx->exception, GetMagickModule(), OptionError,
1640 "After '%[' expected ']' at",
"'%s'",
1645 len = (size_t) (p - pfx->pex + 1);
1646 if (len > MaxTokenLen) {
1647 (void) ThrowMagickException (
1648 pfx->exception, GetMagickModule(), OptionError,
1649 "Too much text between '%[' and ']' at",
"'%s'",
1654 (void) CopyMagickString (sProperty, pfx->pex, len+1);
1655 sProperty[len] =
'\0';
1659 text = InterpretImageProperties (pfx->image->image_info, pfx->image,
1660 sProperty, pfx->exception);
1661 if (!text || !*text) {
1662 text = DestroyString(text);
1663 (void) ThrowMagickException (
1664 pfx->exception, GetMagickModule(), OptionError,
1665 "Unknown property",
"'%s' at '%s'",
1666 sProperty, SetShortExp(pfx));
1670 if (seconds != NULL) {
1672 if (ParseISO860(text,&tp) == MagickFalse) {
1673 (void) ThrowMagickException (
1674 pfx->exception, GetMagickModule(), OptionError,
1675 "Function 'epoch' expected date property, found ",
"'%s' at '%s'",
1676 text, SetShortExp(pfx));
1677 text = DestroyString(text);
1678 *seconds = SECONDS_ERR;
1681 *seconds = (fxFltType)mktime (&tp);
1684 *val = strtold (text, &tailptr);
1685 if (text == tailptr) {
1686 text = DestroyString(text);
1687 (void) ThrowMagickException (
1688 pfx->exception, GetMagickModule(), OptionError,
1689 "Property",
"'%s' text '%s' is not a number at '%s'",
1690 sProperty, text, SetShortExp(pfx));
1691 text = DestroyString(text);
1695 text = DestroyString(text);
1697 return ((ssize_t) len);
1703static inline ssize_t GetConstantColour (FxInfo * pfx, fxFltType *v0, fxFltType *v1, fxFltType *v2)
1714 *dummy_exception = AcquireExceptionInfo ();
1724 char ColSp[MagickPathExtent];
1725 (void) CopyMagickString (ColSp, pfx->token, MaxTokenLen);
1726 p = ColSp + pfx->lenToken - 1;
1727 if (*p ==
'a' || *p ==
'A') *p =
'\0';
1729 (void) GetPixelInfo (pfx->image, &colour);
1733 IsGray = (LocaleCompare (ColSp,
"gray") == 0) ? MagickTrue : MagickFalse;
1734 IsIcc = (LocaleCompare (ColSp,
"icc-color") == 0) ? MagickTrue : MagickFalse;
1735 IsDev = (LocaleNCompare (ColSp,
"device-", 7) == 0) ? MagickTrue : MagickFalse;
1739 if (!QueryColorCompliance (pfx->token, AllCompliance, &colour, dummy_exception) || IsGray) {
1740 ssize_t type = ParseCommandOption (MagickColorspaceOptions, MagickFalse, ColSp);
1741 if (type >= 0 || IsIcc || IsDev) {
1742 char * q = pfx->pex + pfx->lenToken;
1743 while (isspace((
int) ((
unsigned char) *q))) q++;
1746 char sFunc[MagickPathExtent];
1747 while (*q && *q !=
')') q++;
1749 (void) ThrowMagickException (
1750 pfx->exception, GetMagickModule(), OptionError,
1751 "constant color missing ')'",
"at '%s'",
1753 dummy_exception = DestroyExceptionInfo (dummy_exception);
1756 lenfun = (size_t) (q - pfx->pex + 1);
1757 if (lenfun > MaxTokenLen) {
1758 (void) ThrowMagickException (
1759 pfx->exception, GetMagickModule(), OptionError,
1760 "lenfun too long",
"'%lu' at '%s'",
1761 (
unsigned long) lenfun, SetShortExp(pfx));
1762 dummy_exception = DestroyExceptionInfo (dummy_exception);
1765 (void) CopyMagickString (sFunc, pfx->pex, lenfun+1);
1766 if (QueryColorCompliance (sFunc, AllCompliance, &colour, dummy_exception)) {
1767 *v0 = QuantumScale*colour.red;
1768 *v1 = QuantumScale*colour.green;
1769 *v2 = QuantumScale*colour.blue;
1770 dummy_exception = DestroyExceptionInfo (dummy_exception);
1771 return (ssize_t)lenfun;
1774 (void) ThrowMagickException (
1775 pfx->exception, GetMagickModule(), OptionError,
1776 "colorspace but not a valid color with '(...)' at",
"'%s'",
1778 dummy_exception = DestroyExceptionInfo (dummy_exception);
1783 dummy_exception = DestroyExceptionInfo (dummy_exception);
1788 *v0 = QuantumScale*colour.red;
1789 *v1 = QuantumScale*colour.green;
1790 *v2 = QuantumScale*colour.blue;
1792 dummy_exception = DestroyExceptionInfo (dummy_exception);
1793 return (ssize_t)strlen (pfx->token);
1796static inline ssize_t GetHexColour (FxInfo * pfx, fxFltType *v0, fxFltType *v1, fxFltType *v2)
1805 if (*pfx->pex !=
'#')
return 0;
1809 while (isxdigit ((
int)*p)) p++;
1810 if (isalpha ((
int)*p)) {
1811 (void) ThrowMagickException (
1812 pfx->exception, GetMagickModule(), OptionError,
1813 "Bad hex number at",
"'%s'",
1818 len = (size_t) (p - pfx->pex);
1819 if (len < 1)
return 0;
1820 if (len >= MaxTokenLen) {
1821 (void) ThrowMagickException (
1822 pfx->exception, GetMagickModule(), OptionError,
1823 "Hex colour too long at",
"'%s'",
1827 (void) CopyMagickString (pfx->token, pfx->pex, len+1);
1829 (void) GetPixelInfo (pfx->image, &colour);
1831 if (!QueryColorCompliance (pfx->token, AllCompliance, &colour, pfx->exception)) {
1832 (void) ThrowMagickException (
1833 pfx->exception, GetMagickModule(), OptionError,
1834 "QueryColorCompliance rejected",
"'%s' at '%s'",
1835 pfx->token, SetShortExp(pfx));
1839 *v0 = QuantumScale*colour.red;
1840 *v1 = QuantumScale*colour.green;
1841 *v2 = QuantumScale*colour.blue;
1843 return (ssize_t) len;
1846static MagickBooleanType GetFunction (FxInfo * pfx, FunctionE fe)
1850 const char * funStr = Functions[fe-(int) FirstFunc].str;
1851 int nArgs = Functions[fe-(int) FirstFunc].number_args;
1853 char expChLimit =
')';
1854 const char *strLimit =
",)";
1855 OperatorE pushOp = oOpenParen;
1862 int ndx0 = NULL_ADDRESS, ndx1 = NULL_ADDRESS, ndx2 = NULL_ADDRESS, ndx3 = NULL_ADDRESS;
1864 MagickBooleanType coordQual = MagickFalse;
1865 PixelChannel chQual = NO_CHAN_QUAL;
1866 ImgAttrE iaQual = aNull;
1868 pfx->pex += pfx->lenToken;
1871 char p = PeekChar (pfx);
1873 (void) ExpectChar (pfx,
'{');
1874 pushOp = oOpenBrace;
1878 }
else if (p==
'[') {
1879 (void) ExpectChar (pfx,
'[');
1880 pushOp = oOpenBracket;
1889 }
else if (fe == fU) {
1890 char p = PeekChar (pfx);
1892 (void) ExpectChar (pfx,
'[');
1893 pushOp = oOpenBracket;
1902 }
else if (fe == fV || fe == fS) {
1904 pushOp = oOpenBracket;
1908 if (!ExpectChar (pfx,
'('))
return MagickFalse;
1910 if (!PushOperatorStack (pfx, (
int) pushOp))
return MagickFalse;
1912 pExpStart = pfx->pex;
1913 ndx0 = pfx->usedElements;
1915 (void) AddAddressingElement (pfx, rGoto, NULL_ADDRESS);
1922 lenOptArt = GetProperty (pfx, &val, &seconds);
1923 if (seconds == SECONDS_ERR) {
1925 (void) ThrowMagickException (
1926 pfx->exception, GetMagickModule(), OptionError,
1927 "Function 'epoch' expected date property",
"at '%s'",
1931 if (lenOptArt < 0)
return MagickFalse;
1932 if (lenOptArt > 0) {
1933 (void) AddElement (pfx, seconds, oNull);
1934 pfx->pex += lenOptArt;
1935 if (!ExpectChar (pfx,
')'))
return MagickFalse;
1936 if (!PopOprOpenParen (pfx, pushOp))
return MagickFalse;
1943 if (TranslateStatementList (pfx, strLimit, &chLimit)) {
1947 (void) ThrowMagickException (
1948 pfx->exception, GetMagickModule(), OptionError,
1949 "For function",
"'%s' expected ')' at '%s'",
1950 funStr, SetShortExp(pfx));
1954 if (!chLimit)
break;
1955 if (fe == fP || fe == fS|| fe == fIf) {
1956 (void) AddElement (pfx, (fxFltType) 0, oNull);
1961 if (strchr (strLimit, chLimit)==NULL) {
1962 (void) ThrowMagickException (
1963 pfx->exception, GetMagickModule(), OptionError,
1964 "For function",
"'%s' expected one of '%s' after expression but found '%c' at '%s'",
1965 funStr, strLimit, chLimit ? chLimit :
' ', SetShortExp(pfx));
1974 if (ndx1 != NULL_ADDRESS) {
1975 (void) ThrowMagickException (
1976 pfx->exception, GetMagickModule(), OptionError,
1977 "For function",
"'%s' required argument is missing at '%s'",
1978 funStr, SetShortExp(pfx));
1981 ndx1 = pfx->usedElements;
1982 if (fe==fWhile || fe==fIf) {
1983 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
1984 }
else if (fe==fDo) {
1985 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
1986 }
else if (fe==fFor) {
1987 pfx->Elements[pfx->usedElements-1].do_push = MagickFalse;
1991 if (ndx2 != NULL_ADDRESS) {
1992 (void) ThrowMagickException (
1993 pfx->exception, GetMagickModule(), OptionError,
1994 "For function",
"'%s' required argument is missing at '%s'",
1995 funStr, SetShortExp(pfx));
1998 ndx2 = pfx->usedElements;
2000 pfx->Elements[pfx->usedElements-1].do_push = MagickFalse;
2001 (void) AddAddressingElement (pfx, rGotoChk, ndx0);
2002 }
else if (fe==fDo) {
2003 pfx->Elements[pfx->usedElements-1].do_push = MagickFalse;
2004 (void) AddAddressingElement (pfx, rGotoChk, ndx0 + 1);
2005 }
else if (fe==fFor) {
2006 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
2007 pfx->Elements[pfx->usedElements-1].do_push = MagickTrue;
2008 (void) AddAddressingElement (pfx, rZerStk, NULL_ADDRESS);
2009 }
else if (fe==fIf) {
2010 (void) AddAddressingElement (pfx, rGoto, NULL_ADDRESS);
2014 if (ndx3 != NULL_ADDRESS) {
2015 (void) ThrowMagickException (
2016 pfx->exception, GetMagickModule(), OptionError,
2017 "For function",
"'%s' required argument is missing at '%s'",
2018 funStr, SetShortExp(pfx));
2022 pfx->Elements[pfx->usedElements-1].do_push = MagickFalse;
2023 (void) AddAddressingElement (pfx, rGotoChk, ndx1);
2025 ndx3 = pfx->usedElements;
2030 if (chLimit == expChLimit) {
2031 lenExp = (size_t) (pfx->pex - pExpStart - 1);
2035 if (chLimit && chLimit != expChLimit && chLimit !=
',' ) {
2036 (void) ThrowMagickException (
2037 pfx->exception, GetMagickModule(), OptionError,
2038 "For function",
"'%s' expected '%c', found '%c' at '%s'",
2039 funStr, expChLimit, chLimit ? chLimit :
' ', SetShortExp(pfx));
2043 if (fe == fP || fe == fS || fe == fU || fe == fChannel) {
2044 while (FndArgs < Functions[fe-(
int) FirstFunc].number_args) {
2045 (void) AddElement (pfx, (fxFltType) 0, oNull);
2050 if (FndArgs > Functions[fe-(
int) FirstFunc].number_args)
2053 (void) ThrowMagickException (
2054 pfx->exception, GetMagickModule(), OptionError,
2055 "For function",
"'%s' expected up to %i arguments, found '%i' at '%s'",
2056 funStr, Functions[fe-(
int) FirstFunc].number_args, FndArgs, SetShortExp(pfx));
2058 (void) ThrowMagickException (
2059 pfx->exception, GetMagickModule(), OptionError,
2060 "For function",
"'%s' expected %i arguments, found '%i' at '%s'",
2061 funStr, Functions[fe-(
int) FirstFunc].number_args, FndArgs, SetShortExp(pfx));
2065 if (FndArgs < Functions[fe-(
int) FirstFunc].number_args) {
2066 (void) ThrowMagickException (
2067 pfx->exception, GetMagickModule(), OptionError,
2068 "For function",
"'%s' expected %i arguments, found too few (%i) at '%s'",
2069 funStr, Functions[fe-(
int) FirstFunc].number_args, FndArgs, SetShortExp(pfx));
2072 if (fe != fS && fe != fV && FndArgs == 0 && Functions[fe-(
int) FirstFunc].number_args == 0) {
2074 chLimit = expChLimit;
2075 if (!ExpectChar (pfx,
')'))
return MagickFalse;
2078 if (chLimit != expChLimit) {
2079 (void) ThrowMagickException (
2080 pfx->exception, GetMagickModule(), OptionError,
2081 "For function",
"'%s', arguments don't end with '%c' at '%s'",
2082 funStr, expChLimit, SetShortExp(pfx));
2085 if (!PopOprOpenParen (pfx, pushOp)) {
2086 (void) ThrowMagickException (
2087 pfx->exception, GetMagickModule(), OptionError,
2088 "Bug: For function",
"'%s' tos not '%s' at '%s'",
2089 funStr, Operators[pushOp].str, SetShortExp(pfx));
2093 if (IsQualifier (pfx)) {
2095 if (fe == fU || fe == fV || fe == fS) {
2097 coordQual = (GetCoordQualifier (pfx, (
int) fe) == 1) ? MagickTrue : MagickFalse;
2102 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2103 if (pel->operator_index != fP) {
2104 (void) ThrowMagickException (
2105 pfx->exception, GetMagickModule(), OptionError,
2106 "Bug: For function",
"'%s' last element not 'p' at '%s'",
2107 funStr, SetShortExp(pfx));
2110 chQual = pel->channel_qual;
2111 expChLimit = (pel->is_relative) ?
']' :
'}';
2112 pfx->usedElements--;
2113 if (fe == fU) fe = fUP;
2114 else if (fe == fV) fe = fVP;
2115 else if (fe == fS) fe = fSP;
2116 funStr = Functions[fe-(int) FirstFunc].str;
2120 if ( chQual == NO_CHAN_QUAL &&
2121 (fe == fP || fe == fS || fe == fSP || fe == fU || fe == fUP || fe == fV || fe == fVP)
2124 chQual = GetChannelQualifier (pfx, (
int) fe);
2127 if (chQual == NO_CHAN_QUAL && (fe == fU || fe == fV || fe == fS)) {
2129 iaQual = GetImgAttrQualifier (pfx, (
int) fe);
2131 if (IsQualifier (pfx) && chQual == NO_CHAN_QUAL && iaQual != aNull) {
2132 chQual = GetChannelQualifier (pfx, (
int) fe);
2134 if (coordQual && iaQual != aNull) {
2135 (void) ThrowMagickException (
2136 pfx->exception, GetMagickModule(), OptionError,
2137 "For function",
"'%s', can't have qualifiers 'p' and image attribute '%s' at '%s'",
2138 funStr, pfx->token, SetShortExp(pfx));
2141 if (!coordQual && chQual == NO_CHAN_QUAL && iaQual == aNull) {
2142 (void) ThrowMagickException (
2143 pfx->exception, GetMagickModule(), OptionError,
2144 "For function",
"'%s', bad qualifier '%s' at '%s'",
2145 funStr, pfx->token, SetShortExp(pfx));
2148 if (!coordQual && chQual == CompositePixelChannel && iaQual == aNull) {
2149 (void) ThrowMagickException (
2150 pfx->exception, GetMagickModule(), OptionError,
2151 "For function",
"'%s', bad composite qualifier '%s' at '%s'",
2152 funStr, pfx->token, SetShortExp(pfx));
2156 if (chQual == HUE_CHANNEL || chQual == SAT_CHANNEL || chQual == LIGHT_CHANNEL) {
2157 pfx->NeedHsl = MagickTrue;
2159 if (iaQual >= FirstImgAttr && iaQual < aNull) {
2160 (void) ThrowMagickException (
2161 pfx->exception, GetMagickModule(), OptionError,
2162 "Can't have image attribute with HLS qualifier at",
"'%s'",
2169 if (iaQual != aNull && chQual != NO_CHAN_QUAL) {
2170 if (ImgAttrs[iaQual-(
int) FirstImgAttr].need_stats == MagickFalse) {
2171 (void) ThrowMagickException (
2172 pfx->exception, GetMagickModule(), OptionError,
2173 "Can't have image attribute ",
"'%s' with channel qualifier '%s' at '%s'",
2174 ImgAttrs[iaQual-(
int) FirstImgAttr].str,
2175 pfx->token, SetShortExp(pfx));
2178 if (ChanIsVirtual (chQual)) {
2179 (void) ThrowMagickException (
2180 pfx->exception, GetMagickModule(), OptionError,
2181 "Can't have statistical image attribute ",
"'%s' with virtual channel qualifier '%s' at '%s'",
2182 ImgAttrs[iaQual-(
int) FirstImgAttr].str,
2183 pfx->token, SetShortExp(pfx));
2190 pfx->Elements[ndx1].element_index = ndx2+1;
2191 }
else if (fe==fDo) {
2192 pfx->Elements[ndx0].element_index = ndx1+1;
2193 pfx->Elements[ndx1].element_index = ndx2+1;
2194 }
else if (fe==fFor) {
2195 pfx->Elements[ndx2].element_index = ndx3;
2196 }
else if (fe==fIf) {
2197 pfx->Elements[ndx1].element_index = ndx2 + 1;
2198 pfx->Elements[ndx2].element_index = ndx3;
2200 if (fe == fU && iaQual == aNull) {
2201 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2202 if (pel->type == etConstant && pel->val == 0.0) {
2203 pfx->usedElements--;
2207 (void) AddElement (pfx, (fxFltType) 0, (
int) fe);
2208 if (fe == fP || fe == fU || fe == fU0 || fe == fUP ||
2209 fe == fV || fe == fVP || fe == fS || fe == fSP)
2211 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2212 pel->is_relative = (expChLimit ==
']' ? MagickTrue : MagickFalse);
2213 if (chQual >= 0) pel->channel_qual = chQual;
2214 if (iaQual != aNull && (fe == fU || fe == fV || fe == fS)) {
2216 pel->img_attr_qual = iaQual;
2221 if (pExpStart && lenExp) {
2222 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2223 pel->exp_start = pExpStart;
2224 pel->exp_len = lenExp;
2228 pfx->ContainsDebug = MagickTrue;
2233static MagickBooleanType IsStealth (
int op)
2235 return (op == fU0 || op == fUP || op == fSP || op == fVP ||
2236 (op >= FirstCont && op <= rNull) ? MagickTrue : MagickFalse
2240static MagickBooleanType GetOperand (
2241 FxInfo * pfx, MagickBooleanType * UserSymbol, MagickBooleanType * NewUserSymbol,
int * UserSymNdx,
2242 MagickBooleanType * needPopAll)
2245 *NewUserSymbol = *UserSymbol = MagickFalse;
2246 *UserSymNdx = NULL_ADDRESS;
2249 if (!*pfx->pex)
return MagickFalse;
2250 (void) GetToken (pfx);
2252 if (pfx->lenToken==0) {
2256 OperatorE op = GetLeadingOp (pfx);
2257 if (op==oOpenParen) {
2258 char chLimit =
'\0';
2259 if (!PushOperatorStack (pfx, (
int) op))
return MagickFalse;
2261 if (!TranslateExpression (pfx,
")", &chLimit, needPopAll)) {
2262 (void) ThrowMagickException (
2263 pfx->exception, GetMagickModule(), OptionError,
2264 "Empty expression in parentheses at",
"'%s'",
2268 if (chLimit !=
')') {
2269 (void) ThrowMagickException (
2270 pfx->exception, GetMagickModule(), OptionError,
2271 "'(' but no ')' at",
"'%s'",
2276 if (!PopOprOpenParen (pfx, oOpenParen)) {
2277 (void) ThrowMagickException (
2278 pfx->exception, GetMagickModule(), OptionError,
2279 "Bug: tos not '(' at",
"'%s'",
2284 }
else if (OprIsUnaryPrefix (op)) {
2285 MagickBooleanType operand_ok;
2286 if (!PushOperatorStack (pfx, (
int) op))
return MagickFalse;
2289 if (!*pfx->pex)
return MagickFalse;
2290 if (pfx->teDepth >= MagickMaxRecursionDepth) {
2291 (void) ThrowMagickException (
2292 pfx->exception, GetMagickModule(), OptionError,
2293 "Expression too deeply nested",
"(depth %i exceeds limit %i)",
2294 pfx->teDepth, MagickMaxRecursionDepth);
2298 operand_ok=GetOperand (pfx, UserSymbol, NewUserSymbol, UserSymNdx, needPopAll);
2301 (void) ThrowMagickException (
2302 pfx->exception, GetMagickModule(), OptionError,
2303 "After unary, bad operand at",
"'%s'",
2308 if (*NewUserSymbol) {
2309 (void) ThrowMagickException (
2310 pfx->exception, GetMagickModule(), OptionError,
2311 "After unary, NewUserSymbol at",
"'%s'",
2317 (void) AddAddressingElement (pfx, rCopyFrom, *UserSymNdx);
2318 *UserSymNdx = NULL_ADDRESS;
2320 *UserSymbol = MagickFalse;
2321 *NewUserSymbol = MagickFalse;
2324 (void) GetToken (pfx);
2326 }
else if (*pfx->pex ==
'#') {
2327 fxFltType v0=0, v1=0, v2=0;
2328 ssize_t lenToken = GetHexColour (pfx, &v0, &v1, &v2);
2330 (void) ThrowMagickException (
2331 pfx->exception, GetMagickModule(), OptionError,
2332 "Bad hex number at",
"'%s'",
2335 }
else if (lenToken > 0) {
2336 (void) AddColourElement (pfx, v0, v1, v2);
2347 fxFltType val = strtold (pfx->pex, &tailptr);
2348 if (pfx->pex != tailptr) {
2356 const char Prefixes[] =
"yzafpnum.kMGTPEZY";
2357 const char * pSi = strchr (Prefixes, *tailptr);
2358 if (pSi && *pSi !=
'.') Pow = (double) ((pSi - Prefixes) * 3 - 24);
2359 else if (*tailptr ==
'c') Pow = -2;
2360 else if (*tailptr ==
'h') Pow = 2;
2361 else if (*tailptr ==
'k') Pow = 3;
2363 if (*(++pfx->pex) ==
'i') {
2364 val *= pow (2.0, Pow/0.3);
2367 val *= pow (10.0, Pow);
2371 (void) AddElement (pfx, val, oNull);
2375 val = (fxFltType) 0;
2376 lenOptArt = GetProperty (pfx, &val, NULL);
2377 if (lenOptArt < 0)
return MagickFalse;
2378 if (lenOptArt > 0) {
2379 (void) AddElement (pfx, val, oNull);
2380 pfx->pex += lenOptArt;
2387 if (pfx->lenToken > 0) {
2392 for (ce = (ConstantE)0; ce < cNull; ce=(ConstantE) (ce+1)) {
2393 const char * ceStr = Constants[ce].str;
2394 if (LocaleCompare (ceStr, pfx->token)==0) {
2400 (void) AddElement (pfx, Constants[ce].val, oNull);
2401 pfx->pex += pfx->lenToken;
2410 for (fe = FirstFunc; fe < fNull; fe=(FunctionE) (fe+1)) {
2411 const char * feStr = Functions[fe-(int) FirstFunc].str;
2412 if (LocaleCompare (feStr, pfx->token)==0) {
2417 if (fe == fV && pfx->ImgListLen < 2) {
2418 (void) ThrowMagickException (
2419 pfx->exception, GetMagickModule(), OptionError,
2420 "Symbol 'v' but fewer than two images at",
"'%s'",
2425 if (IsStealth ((
int) fe)) {
2426 (void) ThrowMagickException (
2427 pfx->exception, GetMagickModule(), OptionError,
2428 "Function",
"'%s' not permitted at '%s'",
2429 pfx->token, SetShortExp(pfx));
2432 if (fe == fDo || fe == fFor || fe == fIf || fe == fWhile) {
2433 *needPopAll = MagickTrue;
2436 if (fe != fNull)
return (GetFunction (pfx, fe));
2442 ImgAttrE ia = GetImgAttrToken (pfx);
2445 (void) AddElement (pfx, val, (
int) ia);
2447 if (ImgAttrs[ia-(
int) FirstImgAttr].need_stats != MagickFalse) {
2448 if (IsQualifier (pfx)) {
2449 PixelChannel chQual = GetChannelQualifier (pfx, (
int) ia);
2451 if (chQual == NO_CHAN_QUAL) {
2452 (void) ThrowMagickException (
2453 pfx->exception, GetMagickModule(), OptionError,
2454 "Bad channel qualifier at",
"'%s'",
2459 pel = &pfx->Elements[pfx->usedElements-1];
2460 pel->channel_qual = chQual;
2471 for (se = FirstSym; se < sNull; se=(SymbolE) (se+1)) {
2472 const char * seStr = Symbols[se-(int) FirstSym].str;
2473 if (LocaleCompare (seStr, pfx->token)==0) {
2479 (void) AddElement (pfx, val, (
int) se);
2480 pfx->pex += pfx->lenToken;
2482 if (se==sHue || se==sSaturation || se==sLightness) pfx->NeedHsl = MagickTrue;
2490 fxFltType v0, v1, v2;
2491 ssize_t ColLen = GetConstantColour (pfx, &v0, &v1, &v2);
2492 if (ColLen < 0)
return MagickFalse;
2494 (void) AddColourElement (pfx, v0, v1, v2);
2503 const char *artifact;
2504 artifact = GetImageArtifact (pfx->image, pfx->token);
2505 if (artifact != (
const char *) NULL) {
2507 fxFltType val = strtold (artifact, &tailptr);
2508 if (pfx->token == tailptr) {
2509 (void) ThrowMagickException (
2510 pfx->exception, GetMagickModule(), OptionError,
2511 "Artifact",
"'%s' has value '%s', not a number, at '%s'",
2512 pfx->token, artifact, SetShortExp(pfx));
2515 (void) AddElement (pfx, val, oNull);
2516 pfx->pex+=pfx->lenToken;
2523 if (TokenMaybeUserSymbol (pfx)) {
2524 *UserSymbol = MagickTrue;
2525 *UserSymNdx = FindUserSymbol (pfx, pfx->token);
2526 if (*UserSymNdx == NULL_ADDRESS) {
2527 *UserSymNdx = AddUserSymbol (pfx, pfx->pex, pfx->lenToken);
2528 *NewUserSymbol = MagickTrue;
2531 pfx->pex += pfx->lenToken;
2537 (void) ThrowMagickException (
2538 pfx->exception, GetMagickModule(), OptionError,
2539 "Expected operand at",
"'%s'",
2545static inline MagickBooleanType IsRealOperator (OperatorE op)
2547 return (op < oOpenParen || op > oCloseBrace) ? MagickTrue : MagickFalse;
2550static inline MagickBooleanType ProcessTernaryOpr (FxInfo * pfx,
TernaryT * ptern)
2555 if (pfx->usedOprStack == 0)
2557 if (pfx->OperatorStack[pfx->usedOprStack-1] == oQuery) {
2558 if (ptern->addr_query != NULL_ADDRESS) {
2559 (void) ThrowMagickException (
2560 pfx->exception, GetMagickModule(), OptionError,
2561 "Already have '?' in sub-expression at",
"'%s'",
2565 if (ptern->addr_colon != NULL_ADDRESS) {
2566 (void) ThrowMagickException (
2567 pfx->exception, GetMagickModule(), OptionError,
2568 "Already have ':' in sub-expression at",
"'%s'",
2572 pfx->usedOprStack--;
2573 ptern->addr_query = pfx->usedElements;
2574 (void) AddAddressingElement (pfx, rIfZeroGoto, NULL_ADDRESS);
2577 else if (pfx->OperatorStack[pfx->usedOprStack-1] == oColon) {
2578 if (ptern->addr_query == NULL_ADDRESS) {
2579 (void) ThrowMagickException (
2580 pfx->exception, GetMagickModule(), OptionError,
2581 "Need '?' in sub-expression at",
"'%s'",
2585 if (ptern->addr_colon != NULL_ADDRESS) {
2586 (void) ThrowMagickException (
2587 pfx->exception, GetMagickModule(), OptionError,
2588 "Already have ':' in sub-expression at",
"'%s'",
2592 pfx->usedOprStack--;
2593 ptern->addr_colon = pfx->usedElements;
2594 pfx->Elements[pfx->usedElements-1].do_push = MagickTrue;
2595 (void) AddAddressingElement (pfx, rGoto, NULL_ADDRESS);
2601static MagickBooleanType GetOperator (
2603 MagickBooleanType * Assign, MagickBooleanType * Update, MagickBooleanType * IncrDecr)
2607 MagickBooleanType DoneIt = MagickFalse;
2609 for (op = (OperatorE)0; op != oNull; op=(OperatorE) (op+1)) {
2610 const char * opStr = Operators[op].str;
2611 len = strlen(opStr);
2612 if (LocaleNCompare (opStr, pfx->pex, len)==0) {
2617 if (!IsRealOperator (op)) {
2618 (void) ThrowMagickException (
2619 pfx->exception, GetMagickModule(), OptionError,
2620 "Not a real operator at",
"'%s'",
2626 (void) ThrowMagickException (
2627 pfx->exception, GetMagickModule(), OptionError,
2628 "Expected operator at",
"'%s'",
2633 *Assign = (op==oAssign) ? MagickTrue : MagickFalse;
2634 *Update = OprInPlace ((
int) op);
2635 *IncrDecr = (op == oPlusPlus || op == oSubSub) ? MagickTrue : MagickFalse;
2642 while (pfx->usedOprStack > 0) {
2643 OperatorE top = pfx->OperatorStack[pfx->usedOprStack-1];
2644 int precTop, precNew;
2645 if (top == oOpenParen || top == oAssign || OprInPlace ((
int) top))
break;
2646 precTop = Operators[top].precedence;
2647 precNew = Operators[op].precedence;
2651 if (precTop < precNew)
break;
2652 (void) AddElement (pfx, (fxFltType) 0, (
int) top);
2653 pfx->usedOprStack--;
2659 if (op==oCloseParen) {
2660 if (pfx->usedOprStack == 0) {
2661 (void) ThrowMagickException (
2662 pfx->exception, GetMagickModule(), OptionError,
2663 "Found ')' but nothing on stack at",
"'%s'",
2668 if (pfx->OperatorStack[pfx->usedOprStack-1] != oOpenParen) {
2669 (void) ThrowMagickException (
2670 pfx->exception, GetMagickModule(), OptionError,
2671 "Found ')' but no '(' on stack at",
"'%s'",
2675 pfx->usedOprStack--;
2676 DoneIt = MagickTrue;
2680 if (!PushOperatorStack (pfx, (
int) op))
return MagickFalse;
2688static MagickBooleanType ResolveTernaryAddresses (FxInfo * pfx,
TernaryT * ptern)
2690 if (ptern->addr_query == NULL_ADDRESS && ptern->addr_colon == NULL_ADDRESS)
2693 if (ptern->addr_query != NULL_ADDRESS && ptern->addr_colon != NULL_ADDRESS) {
2694 pfx->Elements[ptern->addr_query].element_index = ptern->addr_colon + 1;
2695 pfx->Elements[ptern->addr_colon].element_index = pfx->usedElements;
2696 ptern->addr_query = NULL_ADDRESS;
2697 ptern->addr_colon = NULL_ADDRESS;
2698 }
else if (ptern->addr_query != NULL_ADDRESS) {
2699 (void) ThrowMagickException (
2700 pfx->exception, GetMagickModule(), OptionError,
2701 "'?' with no corresponding ':'",
"'%s' at '%s'",
2702 pfx->token, SetShortExp(pfx));
2704 }
else if (ptern->addr_colon != NULL_ADDRESS) {
2705 (void) ThrowMagickException (
2706 pfx->exception, GetMagickModule(), OptionError,
2707 "':' with no corresponding '?'",
"'%s' at '%s'",
2708 pfx->token, SetShortExp(pfx));
2714static MagickBooleanType TranslateExpression (
2715 FxInfo * pfx,
const char * strLimit,
char * chLimit, MagickBooleanType * needPopAll)
2719 MagickBooleanType UserSymbol, NewUserSymbol;
2720 int UserSymNdx0, UserSymNdx1;
2723 Assign = MagickFalse,
2724 Update = MagickFalse,
2725 IncrDecr = MagickFalse;
2730 ternary.addr_query = NULL_ADDRESS;
2731 ternary.addr_colon = NULL_ADDRESS;
2733 if (pfx->teDepth >= MagickMaxRecursionDepth) {
2734 (void) ThrowMagickException(pfx->exception, GetMagickModule(), OptionError,
2735 "Expression too deeply nested",
"(depth %i exceeds limit %i)",
2736 pfx->teDepth, MagickMaxRecursionDepth);
2744 StartEleNdx = pfx->usedElements-1;
2745 if (StartEleNdx < 0) StartEleNdx = 0;
2754 if (strchr(strLimit,*pfx->pex)!=NULL) {
2755 *chLimit = *pfx->pex;
2762 if (!GetOperand (pfx, &UserSymbol, &NewUserSymbol, &UserSymNdx0, needPopAll))
return MagickFalse;
2767 while (*pfx->pex && (!*strLimit || (strchr(strLimit,*pfx->pex)==NULL))) {
2768 if (!GetOperator (pfx, &Assign, &Update, &IncrDecr))
return MagickFalse;
2770 if (NewUserSymbol && !Assign) {
2771 (void) ThrowMagickException (
2772 pfx->exception, GetMagickModule(), OptionError,
2773 "Expected assignment after new UserSymbol",
"'%s' at '%s'",
2774 pfx->token, SetShortExp(pfx));
2777 if (!UserSymbol && Assign) {
2778 (void) ThrowMagickException (
2779 pfx->exception, GetMagickModule(), OptionError,
2780 "Attempted assignment to non-UserSymbol",
"'%s' at '%s'",
2781 pfx->token, SetShortExp(pfx));
2784 if (!UserSymbol && Update) {
2785 (void) ThrowMagickException (
2786 pfx->exception, GetMagickModule(), OptionError,
2787 "Attempted update to non-UserSymbol",
"'%s' at '%s'",
2788 pfx->token, SetShortExp(pfx));
2791 if (UserSymbol && (Assign || Update) && !IncrDecr) {
2793 if (!TranslateExpression (pfx, strLimit, chLimit, needPopAll))
return MagickFalse;
2794 if (!*pfx->pex)
break;
2795 if (!*strLimit)
break;
2796 if (strchr(strLimit,*chLimit)!=NULL)
break;
2798 if (UserSymbol && !Assign && !Update && UserSymNdx0 != NULL_ADDRESS) {
2800 (void) AddAddressingElement (pfx, rCopyFrom, UserSymNdx0);
2801 UserSymNdx0 = NULL_ADDRESS;
2802 pel = &pfx->Elements[pfx->usedElements-1];
2803 pel->do_push = MagickTrue;
2807 while (TopOprIsUnaryPrefix (pfx)) {
2808 OperatorE op = pfx->OperatorStack[pfx->usedOprStack-1];
2809 (void) AddElement (pfx, (fxFltType) 0, (
int) op);
2810 pfx->usedOprStack--;
2814 if (!ProcessTernaryOpr (pfx, &ternary))
return MagickFalse;
2816 if (ternary.addr_colon != NULL_ADDRESS) {
2817 if (!TranslateExpression (pfx,
",);", chLimit, needPopAll))
return MagickFalse;
2821 UserSymbol = NewUserSymbol = MagickFalse;
2823 if ( (!*pfx->pex) || (*strLimit && (strchr(strLimit,*pfx->pex)!=NULL) ) )
2825 if (IncrDecr)
break;
2827 (void) ThrowMagickException (
2828 pfx->exception, GetMagickModule(), OptionError,
2829 "Expected operand after operator",
"at '%s'",
2835 (void) ThrowMagickException (
2836 pfx->exception, GetMagickModule(), OptionError,
2837 "'++' and '--' must be the final operators in an expression at",
"'%s'",
2842 if (!GetOperand (pfx, &UserSymbol, &NewUserSymbol, &UserSymNdx1, needPopAll)) {
2843 (void) ThrowMagickException (
2844 pfx->exception, GetMagickModule(), OptionError,
2845 "Expected operand at",
"'%s'",
2850 if (NewUserSymbol && !Assign) {
2851 (void) ThrowMagickException (
2852 pfx->exception, GetMagickModule(), OptionError,
2853 "NewUserSymbol",
"'%s' after non-assignment operator at '%s'",
2854 pfx->token, SetShortExp(pfx));
2857 if (UserSymbol && !NewUserSymbol) {
2858 (void) AddAddressingElement (pfx, rCopyFrom, UserSymNdx1);
2859 UserSymNdx1 = NULL_ADDRESS;
2861 UserSymNdx0 = UserSymNdx1;
2864 if (UserSymbol && !Assign && !Update && UserSymNdx0 != NULL_ADDRESS) {
2866 if (NewUserSymbol) {
2867 (void) ThrowMagickException (
2868 pfx->exception, GetMagickModule(), OptionError,
2869 "NewUserSymbol",
"'%s' needs assignment operator at '%s'",
2870 pfx->token, SetShortExp(pfx));
2873 (void) AddAddressingElement (pfx, rCopyFrom, UserSymNdx0);
2874 pel = &pfx->Elements[pfx->usedElements-1];
2875 pel->do_push = MagickTrue;
2878 if (*pfx->pex && !*chLimit && (strchr(strLimit,*pfx->pex)!=NULL)) {
2879 *chLimit = *pfx->pex;
2882 while (pfx->usedOprStack) {
2883 OperatorE op = pfx->OperatorStack[pfx->usedOprStack-1];
2884 if (op == oOpenParen || op == oOpenBracket || op == oOpenBrace) {
2887 if ( (op==oAssign && !Assign) || (OprInPlace((
int) op) && !Update) ) {
2890 pfx->usedOprStack--;
2891 (void) AddElement (pfx, (fxFltType) 0, (
int) op);
2892 if (op == oAssign) {
2893 if (UserSymNdx0 < 0) {
2894 (void) ThrowMagickException (
2895 pfx->exception, GetMagickModule(), OptionError,
2896 "Assignment to unknown user symbol at",
"'%s'",
2902 pfx->usedElements--;
2903 (void) AddAddressingElement (pfx, rCopyTo, UserSymNdx0);
2905 }
else if (OprInPlace ((
int) op)) {
2906 if (UserSymNdx0 < 0) {
2907 (void) ThrowMagickException (
2908 pfx->exception, GetMagickModule(), OptionError,
2909 "Operator-in-place to unknown user symbol at",
"'%s'",
2915 pfx->Elements[pfx->usedElements-1].element_index = UserSymNdx0;
2920 if (ternary.addr_query != NULL_ADDRESS) *needPopAll = MagickTrue;
2922 (void) ResolveTernaryAddresses (pfx, &ternary);
2926 if (!pfx->teDepth && *needPopAll) {
2927 (void) AddAddressingElement (pfx, rZerStk, NULL_ADDRESS);
2928 *needPopAll = MagickFalse;
2931 if (pfx->exception->severity >= ErrorException)
2938static MagickBooleanType TranslateStatement (FxInfo * pfx,
char * strLimit,
char * chLimit)
2940 MagickBooleanType NeedPopAll = MagickFalse;
2944 if (!*pfx->pex)
return MagickFalse;
2946 if (!TranslateExpression (pfx, strLimit, chLimit, &NeedPopAll)) {
2949 if (pfx->usedElements && *chLimit==
';') {
2954 ElementT * pel = &pfx->Elements[pfx->usedElements-1];
2955 if (pel->do_push) pel->do_push = MagickFalse;
2961static MagickBooleanType TranslateStatementList (FxInfo * pfx,
const char * strLimit,
char * chLimit)
2963#define MAX_SLIMIT 10
2964 char sLimits[MAX_SLIMIT];
2967 if (!*pfx->pex)
return MagickFalse;
2968 (void) CopyMagickString (sLimits, strLimit, MAX_SLIMIT-1);
2970 if (strchr(strLimit,
';')==NULL)
2971 (void) ConcatenateMagickString (sLimits,
";", MAX_SLIMIT);
2974 if (!TranslateStatement (pfx, sLimits, chLimit))
return MagickFalse;
2976 if (!*pfx->pex)
break;
2978 if (*chLimit !=
';') {
2983 if (pfx->exception->severity >= ErrorException)
2993static ChannelStatistics *CollectOneImgStats (FxInfo * pfx, Image * img)
2996 ChannelStatistics * cs = GetImageStatistics (img, pfx->exception);
2999 if (cs == (ChannelStatistics *) NULL)
3000 return((ChannelStatistics *) NULL);
3002 for (ch=0; ch <= (int) MaxPixelChannels; ch++) {
3003 cs[ch].mean *= QuantumScale;
3004 cs[ch].median *= QuantumScale;
3005 cs[ch].maxima *= QuantumScale;
3006 cs[ch].minima *= QuantumScale;
3007 cs[ch].standard_deviation *= QuantumScale;
3013static MagickBooleanType CollectStatistics (FxInfo * pfx)
3015 Image * img = GetFirstImageInList (pfx->image);
3019 pfx->statistics = (ChannelStatistics**) AcquireMagickMemory ((
size_t) pfx->ImgListLen * sizeof (ChannelStatistics *));
3020 if (!pfx->statistics) {
3021 (void) ThrowMagickException (
3022 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
3023 "Statistics",
"%lu",
3024 (
unsigned long) pfx->ImgListLen);
3029 pfx->statistics[imgNum] = CollectOneImgStats (pfx, img);
3031 if (++imgNum == pfx->ImgListLen)
break;
3032 img = GetNextImageInList (img);
3033 assert (img != (Image *) NULL);
3035 pfx->GotStats = MagickTrue;
3040static inline MagickBooleanType PushVal (FxInfo * pfx,
fxRtT * pfxrt, fxFltType val,
int addr)
3042 if (pfxrt->usedValStack >=pfxrt->numValStack) {
3043 (void) ThrowMagickException (
3044 pfx->exception, GetMagickModule(), OptionError,
3045 "ValStack overflow at addr=",
"%i",
3050 pfxrt->ValStack[pfxrt->usedValStack++] = val;
3054static inline fxFltType PopVal (FxInfo * pfx,
fxRtT * pfxrt,
int addr)
3056 if (pfxrt->usedValStack <= 0) {
3057 (void) ThrowMagickException (
3058 pfx->exception, GetMagickModule(), OptionError,
3059 "ValStack underflow at addr=",
"%i",
3061 return (fxFltType) 0;
3064 return pfxrt->ValStack[--pfxrt->usedValStack];
3067static inline fxFltType ImageStat (
3068 FxInfo * pfx, ssize_t ImgNum, PixelChannel channel, ImgAttrE ia)
3070 ChannelStatistics * cs = NULL;
3072 MagickBooleanType NeedRelinq = MagickFalse;
3076 (void) ThrowMagickException(pfx->exception,GetMagickModule(),
3077 OptionError,
"NoSuchImage",
"%lu",(
unsigned long) ImgNum);
3081 if (pfx->GotStats) {
3082 if ((channel < 0) || (channel > MaxPixelChannels))
3084 (void) ThrowMagickException(pfx->exception,GetMagickModule(),
3085 OptionError,
"NoSuchImageChannel",
"%i",channel);
3086 channel=(PixelChannel) 0;
3088 cs = pfx->statistics[ImgNum];
3089 }
else if (pfx->NeedStats) {
3091 if ((channel < 0) || (channel > MaxPixelChannels))
3093 (void) ThrowMagickException(pfx->exception,GetMagickModule(),
3094 OptionError,
"NoSuchImageChannel",
"%i",channel);
3095 channel=(PixelChannel) 0;
3097 cs = CollectOneImgStats (pfx, pfx->Images[ImgNum]);
3098 NeedRelinq = MagickTrue;
3103 ret = (fxFltType) GetImageDepth (pfx->Images[ImgNum], pfx->exception);
3106 ret = (fxFltType) GetBlobSize (pfx->image);
3109 if ((cs != (ChannelStatistics *) NULL) && (channel >= 0))
3110 ret = cs[channel].kurtosis;
3113 if ((cs != (ChannelStatistics *) NULL) && (channel >= 0))
3114 ret = cs[channel].maxima;
3117 if ((cs != (ChannelStatistics *) NULL) && (channel >= 0))
3118 ret = cs[channel].mean;
3121 if ((cs != (ChannelStatistics *) NULL) && (channel >= 0))
3122 ret = cs[channel].median;
3125 if ((cs != (ChannelStatistics *) NULL) && (channel >= 0))
3126 ret = cs[channel].minima;
3132 ret = (fxFltType) pfx->Images[ImgNum]->page.x;
3135 ret = (fxFltType) pfx->Images[ImgNum]->page.y;
3138 ret = (fxFltType) pfx->Images[ImgNum]->page.width;
3141 ret = (fxFltType) pfx->Images[ImgNum]->page.height;
3147 ret = (fxFltType) MagickSafeReciprocal (pfx->Images[ImgNum]->resolution.x)
3148 * pfx->Images[ImgNum]->columns;
3151 ret = (fxFltType) MagickSafeReciprocal (pfx->Images[ImgNum]->resolution.y)
3152 * pfx->Images[ImgNum]->rows;
3155 ret = (fxFltType) pfx->Images[ImgNum]->quality;
3161 ret = pfx->Images[ImgNum]->resolution.x;
3164 ret = pfx->Images[ImgNum]->resolution.y;
3167 if ((cs != (ChannelStatistics *) NULL) && (channel >= 0))
3168 ret = cs[channel].skewness;
3171 if ((cs != (ChannelStatistics *) NULL) && (channel >= 0))
3172 ret = cs[channel].standard_deviation;
3175 ret = (fxFltType) pfx->Images[ImgNum]->rows;
3178 ret = (fxFltType) pfx->ImgListLen;
3181 ret = (fxFltType) ImgNum;
3184 ret = (fxFltType) pfx->Images[ImgNum]->columns;
3187 ret = (fxFltType) GetImageDepth (pfx->Images[ImgNum], pfx->exception);
3190 (void) ThrowMagickException (pfx->exception,GetMagickModule(),OptionError,
3191 "Unknown ia=",
"%i",ia);
3193 if (NeedRelinq) cs = (ChannelStatistics *)RelinquishMagickMemory (cs);
3198static inline fxFltType FxGcd (fxFltType x, fxFltType y,
const size_t depth)
3200#define FxMaxFunctionDepth 200
3203 return (FxGcd (y, x, depth+1));
3204 if ((fabs((
double) y) < 0.001) || (depth >= FxMaxFunctionDepth))
3206 return (FxGcd (y, x-y*floor((
double) (x/y)), depth+1));
3209static inline ssize_t ChkImgNum (FxInfo * pfx, fxFltType f)
3212 ssize_t i = (ssize_t) floor ((
double) f + 0.5);
3213 if (i < 0) i += (ssize_t) pfx->ImgListLen;
3214 if (i < 0 || i >= (ssize_t) pfx->ImgListLen) {
3215 (void) ThrowMagickException (
3216 pfx->exception, GetMagickModule(), OptionError,
3217 "ImgNum",
"%lu bad for ImgListLen %lu",
3218 (
unsigned long) i, (
unsigned long) pfx->ImgListLen);
3224#define WHICH_ATTR_CHAN \
3225 (pel->channel_qual == NO_CHAN_QUAL) ? CompositePixelChannel : \
3226 (pel->channel_qual == THIS_CHANNEL) ? channel : pel->channel_qual
3228#define WHICH_NON_ATTR_CHAN \
3229 (pel->channel_qual == NO_CHAN_QUAL || \
3230 pel->channel_qual == THIS_CHANNEL || \
3231 pel->channel_qual == CompositePixelChannel \
3232 ) ? (channel == CompositePixelChannel ? RedPixelChannel: channel) \
3235static fxFltType GetHslFlt (FxInfo * pfx, ssize_t ImgNum,
const fxFltType fx,
const fxFltType fy,
3236 PixelChannel channel)
3238 Image * img = pfx->Images[ImgNum];
3240 double red, green, blue;
3241 double hue=0, saturation=0, lightness=0;
3243 MagickBooleanType okay = MagickTrue;
3244 if(!InterpolatePixelChannel (img, pfx->Imgs[ImgNum].View, RedPixelChannel, img->interpolate,
3245 (
double) fx, (
double) fy, &red, pfx->exception)) okay = MagickFalse;
3246 if(!InterpolatePixelChannel (img, pfx->Imgs[ImgNum].View, GreenPixelChannel, img->interpolate,
3247 (
double) fx, (
double) fy, &green, pfx->exception)) okay = MagickFalse;
3248 if(!InterpolatePixelChannel (img, pfx->Imgs[ImgNum].View, BluePixelChannel, img->interpolate,
3249 (
double) fx, (
double) fy, &blue, pfx->exception)) okay = MagickFalse;
3252 (void) ThrowMagickException (
3253 pfx->exception, GetMagickModule(), OptionError,
3254 "GetHslFlt failure",
"%lu %g,%g %i", (
unsigned long) ImgNum,
3255 (
double) fx, (
double) fy, channel);
3259 &hue, &saturation, &lightness);
3261 if (channel == HUE_CHANNEL)
return hue;
3262 if (channel == SAT_CHANNEL)
return saturation;
3263 if (channel == LIGHT_CHANNEL)
return lightness;
3268static fxFltType GetHslInt (FxInfo * pfx, ssize_t ImgNum,
const ssize_t imgx,
const ssize_t imgy, PixelChannel channel)
3270 Image * img = pfx->Images[ImgNum];
3272 double hue=0, saturation=0, lightness=0;
3274 const Quantum * p = GetCacheViewVirtualPixels (pfx->Imgs[ImgNum].View, imgx, imgy, 1, 1, pfx->exception);
3275 if (p == (
const Quantum *) NULL)
3277 (void) ThrowMagickException (pfx->exception,GetMagickModule(),
3278 OptionError,
"GetHslInt failure",
"%lu %li,%li %i",(
unsigned long) ImgNum,
3279 (
long) imgx,(
long) imgy,channel);
3284 GetPixelRed (img, p), GetPixelGreen (img, p), GetPixelBlue (img, p),
3285 &hue, &saturation, &lightness);
3287 if (channel == HUE_CHANNEL)
return hue;
3288 if (channel == SAT_CHANNEL)
return saturation;
3289 if (channel == LIGHT_CHANNEL)
return lightness;
3294static inline fxFltType GetIntensity (FxInfo * pfx, ssize_t ImgNum,
const fxFltType fx,
const fxFltType fy)
3297 quantum_pixel[MaxPixelChannels];
3302 Image * img = pfx->Images[ImgNum];
3304 (void) GetPixelInfo (img, &pixelinf);
3306 if (!InterpolatePixelInfo (img, pfx->Imgs[ImgNum].View, img->interpolate,
3307 (
double) fx, (
double) fy, &pixelinf, pfx->exception))
3309 (void) ThrowMagickException (
3310 pfx->exception, GetMagickModule(), OptionError,
3311 "GetIntensity failure",
"%lu %g,%g", (
unsigned long) ImgNum,
3312 (
double) fx, (
double) fy);
3315 SetPixelViaPixelInfo (img, &pixelinf, quantum_pixel);
3316 return QuantumScale * GetPixelIntensity (img, quantum_pixel);
3319static MagickBooleanType ExecuteRPN (FxInfo * pfx,
fxRtT * pfxrt, fxFltType *result,
3320 const PixelChannel channel,
const ssize_t imgx,
const ssize_t imgy)
3322 const Quantum * p = pfxrt->thisPixel;
3323 fxFltType regA=0, regB=0, regC=0, regD=0, regE=0;
3324 Image * img = pfx->image;
3325 ChannelStatistics * cs = NULL;
3326 MagickBooleanType NeedRelinq = MagickFalse;
3327 double hue=0, saturation=0, lightness=0;
3334 if (!p) p = GetCacheViewVirtualPixels (
3335 pfx->Imgs[pfx->ImgNum].View, imgx, imgy, 1, 1, pfx->exception);
3337 if (p == (
const Quantum *) NULL)
3339 (void) ThrowMagickException (pfx->exception,GetMagickModule(),
3340 OptionError,
"Can't get virtual pixels",
"%lu %li,%li",(
unsigned long)
3341 pfx->ImgNum,(
long) imgx,(
long) imgy);
3342 return(MagickFalse);
3345 if (pfx->GotStats) {
3346 cs = pfx->statistics[pfx->ImgNum];
3347 }
else if (pfx->NeedStats) {
3348 cs = CollectOneImgStats (pfx, pfx->Images[pfx->ImgNum]);
3349 NeedRelinq = MagickTrue;
3356 GetPixelRed (img, p), GetPixelGreen (img, p), GetPixelBlue (img, p),
3357 &hue, &saturation, &lightness);
3360 for (i=0; i < pfx->usedElements; i++) {
3365 (void) ThrowMagickException (
3366 pfx->exception, GetMagickModule(), OptionError,
3367 "Bad run-time address",
"%i", i);
3369 pel=&pfx->Elements[i];
3370 switch (pel->number_args) {
3374 regA = PopVal (pfx, pfxrt, i);
3377 regB = PopVal (pfx, pfxrt, i);
3378 regA = PopVal (pfx, pfxrt, i);
3381 regC = PopVal (pfx, pfxrt, i);
3382 regB = PopVal (pfx, pfxrt, i);
3383 regA = PopVal (pfx, pfxrt, i);
3386 regD = PopVal (pfx, pfxrt, i);
3387 regC = PopVal (pfx, pfxrt, i);
3388 regB = PopVal (pfx, pfxrt, i);
3389 regA = PopVal (pfx, pfxrt, i);
3392 regE = PopVal (pfx, pfxrt, i);
3393 regD = PopVal (pfx, pfxrt, i);
3394 regC = PopVal (pfx, pfxrt, i);
3395 regB = PopVal (pfx, pfxrt, i);
3396 regA = PopVal (pfx, pfxrt, i);
3399 (void) ThrowMagickException (
3400 pfx->exception, GetMagickModule(), OptionError,
3401 "Too many args:",
"%i", pel->number_args);
3405 switch (pel->operator_index) {
3407 regA = (pfxrt->UserSymVals[pel->element_index] += regA);
3410 regA = (pfxrt->UserSymVals[pel->element_index] -= regA);
3413 regA = (pfxrt->UserSymVals[pel->element_index] *= regA);
3416 regA = (pfxrt->UserSymVals[pel->element_index] /= regA);
3419 regA = pfxrt->UserSymVals[pel->element_index]++;
3422 regA = pfxrt->UserSymVals[pel->element_index]--;
3437 regA = fmod ((
double) regA, fabs(floor((
double) regB+0.5)));
3446 if (CastDoubleToSizeT((
double) regB+0.5) >= (8*
sizeof(
size_t)))
3448 (void) ThrowMagickException ( pfx->exception, GetMagickModule(),
3449 OptionError,
"undefined shift",
"%g", (
double) regB);
3450 regA = (fxFltType) 0.0;
3453 regA = (fxFltType) (CastDoubleToSizeT((
double) regA+0.5) << CastDoubleToSizeT((
double) regB+0.5));
3456 if (CastDoubleToSizeT((
double) regB+0.5) >= (8*
sizeof(
size_t)))
3458 (void) ThrowMagickException ( pfx->exception, GetMagickModule(),
3459 OptionError,
"undefined shift",
"%g", (
double) regB);
3460 regA = (fxFltType) 0.0;
3463 regA = (fxFltType) (CastDoubleToSizeT((
double) regA+0.5) >> CastDoubleToSizeT((
double) regB+0.5));
3466 regA = fabs((
double) (regA-regB)) < MagickEpsilon ? 1.0 : 0.0;
3469 regA = fabs((
double) (regA-regB)) >= MagickEpsilon ? 1.0 : 0.0;
3472 regA = (regA <= regB) ? 1.0 : 0.0;
3475 regA = (regA >= regB) ? 1.0 : 0.0;
3478 regA = (regA < regB) ? 1.0 : 0.0;
3481 regA = (regA > regB) ? 1.0 : 0.0;
3484 regA = (regA<=0) ? 0.0 : (regB > 0) ? 1.0 : 0.0;
3487 regA = (regA>0) ? 1.0 : (regB > 0.0) ? 1.0 : 0.0;
3490 regA = (regA==0) ? 1.0 : 0.0;
3493 regA = (fxFltType) (CastDoubleToSizeT((
double) regA+0.5) & CastDoubleToSizeT((
double) regB+0.5));
3496 regA = (fxFltType) (CastDoubleToSizeT((
double) regA+0.5) | CastDoubleToSizeT((
double) regB+0.5));
3504 new_value=~CastDoubleToSizeT((
double) regA+0.5);
3505 regA=(fxFltType) new_value;
3509 regA = pow ((
double) regA, (
double) regB);
3525 if (pel->type == etColourConstant) {
3526 switch (channel) {
default:
3527 case (PixelChannel) 0:
3530 case (PixelChannel) 1:
3533 case (PixelChannel) 2:
3543 regA = fabs ((
double) regA);
3545#if defined(MAGICKCORE_HAVE_ACOSH)
3547 regA = acosh ((
double) regA);
3551 regA = acos ((
double) regA);
3553#if defined(MAGICKCORE_HAVE_J1)
3555 if (regA==0) regA = 1.0;
3557 fxFltType gamma = 2.0 * __j1((
double) (MagickPI*regA)) / (MagickPI*regA);
3558 regA = gamma * gamma;
3563 regA = (fxFltType) (((ssize_t) regA) & 0x01 ? -1.0 : 1.0);
3565#if defined(MAGICKCORE_HAVE_ASINH)
3567 regA = asinh ((
double) regA);
3571 regA = asin ((
double) regA);
3573#if defined(MAGICKCORE_HAVE_ATANH)
3575 regA = atanh ((
double) regA);
3579 regA = atan2 ((
double) regA, (
double) regB);
3582 regA = atan ((
double) regA);
3585 regA = ceil ((
double) regA);
3589 case (PixelChannel) 0:
break;
3590 case (PixelChannel) 1: regA = regB;
break;
3591 case (PixelChannel) 2: regA = regC;
break;
3592 case (PixelChannel) 3: regA = regD;
break;
3593 case (PixelChannel) 4: regA = regE;
break;
3594 default: regA = 0.0;
3598 if (regA < 0) regA = 0.0;
3599 else if (regA > 1.0) regA = 1.0;
3602 regA = cosh ((
double) regA);
3605 regA = cos ((
double) regA);
3610 (void) fprintf (stderr,
"%s[%g,%g].[%i]: %s=%.*g\n",
3611 img->filename, (
double) imgx, (
double) imgy,
3612 channel, SetPtrShortExp (pfx, pel->exp_start, (
size_t) (pel->exp_len+1)),
3613 pfx->precision, (
double) regA);
3616 regA = regA / (regB*(regA-1.0) + 1.0);
3618#if defined(MAGICKCORE_HAVE_ERF)
3620 regA = erf ((
double) regA);
3627 regA = exp ((
double) regA);
3630 regA = floor ((
double) regA);
3633 regA = exp((
double) (-regA*regA/2.0))/sqrt(2.0*MagickPI);
3636 if (!IsNaN((
double) regA))
3637 regA = FxGcd (regA, regB, 0);
3640 regA = hypot ((
double) regA, (
double) regB);
3643 regA = floor ((
double) regA);
3646 regA = (fxFltType) (!!IsNaN ((
double) regA));
3648#if defined(MAGICKCORE_HAVE_J0)
3650 regA = __j0((
double) regA);
3653#if defined(MAGICKCORE_HAVE_J1)
3655 regA = __j1((
double) regA);
3658#if defined(MAGICKCORE_HAVE_J1)
3660 if (regA==0) regA = 1.0;
3661 else regA = 2.0 * __j1((
double) (MagickPI*regA))/(MagickPI*regA);
3665 regA = log ((
double) regA);
3668 regA = log10((
double) regA) / log10(2.0);
3671 regA = log10 ((
double) regA);
3674 regA = (fxFltType) GetMagickTime();
3677 regA = (regA > regB) ? regA : regB;
3680 regA = (regA < regB) ? regA : regB;
3686 regA = regA - floor((
double) (regA/regB))*regB;
3690 regA = (fxFltType) (regA < MagickEpsilon);
3693 regA = pow ((
double) regA, (
double) regB);
3696#if defined(MAGICKCORE_OPENMP_SUPPORT)
3697 #pragma omp critical (MagickCore_ExecuteRPN)
3699 regA = GetPseudoRandomValue (pfxrt->random_info);
3703 regA = floor ((
double) regA + 0.5);
3706 regA = (regA < 0) ? -1.0 : 1.0;
3709 regA = sin ((
double) (MagickPI*regA)) / (MagickPI*regA);
3712 regA = sinh ((
double) regA);
3715 regA = sin ((
double) regA);
3718 regA = sqrt ((
double) regA);
3721 regA = 1.0 / (1.0 + exp ((
double) -regA));
3724 regA = tanh ((
double) regA);
3727 regA = tan ((
double) regA);
3730 if (regA >= 0) regA = floor ((
double) regA);
3731 else regA = ceil ((
double) regA);
3743 ssize_t ImgNum = ChkImgNum (pfx, regA);
3744 if (ImgNum < 0)
break;
3745 regA = (fxFltType) 0;
3747 Image * pimg = pfx->Images[0];
3748 if (pel->img_attr_qual == aNull) {
3749 if ((
int) pel->channel_qual < 0) {
3750 if (pel->channel_qual == NO_CHAN_QUAL || pel->channel_qual == THIS_CHANNEL) {
3751 if (pfx->ImgNum==0) {
3752 regA = QuantumScale * (double) p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3754 const Quantum * pv = GetCacheViewVirtualPixels (
3755 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3757 (void) ThrowMagickException (
3758 pfx->exception, GetMagickModule(), OptionError,
3759 "fU can't get cache",
"%lu", (
unsigned long) ImgNum);
3762 regA = QuantumScale * (double) pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3764 }
else if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL ||
3765 pel->channel_qual == LIGHT_CHANNEL) {
3766 regA = GetHslInt (pfx, ImgNum, imgx, imgy, pel->channel_qual);
3768 }
else if (pel->channel_qual == INTENSITY_CHANNEL) {
3769 regA = GetIntensity (pfx, 0, (
double) imgx, (
double) imgy);
3773 if (pfx->ImgNum==0) {
3774 regA = QuantumScale * (double) p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3776 const Quantum * pv = GetCacheViewVirtualPixels (
3777 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3779 (void) ThrowMagickException (
3780 pfx->exception, GetMagickModule(), OptionError,
3781 "fU can't get cache",
"%lu", (
unsigned long) ImgNum);
3784 regA = QuantumScale * (double) pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3789 regA = ImageStat (pfx, 0, WHICH_ATTR_CHAN, pel->img_attr_qual);
3793 if (pel->img_attr_qual == aNull) {
3795 if ((
int) pel->channel_qual < 0) {
3796 if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL ||
3797 pel->channel_qual == LIGHT_CHANNEL)
3799 regA = GetHslInt (pfx, ImgNum, imgx, imgy, pel->channel_qual);
3801 }
else if (pel->channel_qual == INTENSITY_CHANNEL)
3803 regA = GetIntensity (pfx, ImgNum, (fxFltType) imgx, (fxFltType) imgy);
3808 pv = GetCacheViewVirtualPixels (
3809 pfx->Imgs[ImgNum].View, imgx, imgy, 1,1, pfx->exception);
3811 (void) ThrowMagickException (
3812 pfx->exception, GetMagickModule(), OptionError,
3813 "fU can't get cache",
"%lu", (
unsigned long) ImgNum);
3816 regA = QuantumScale * (double)
3817 pv[pfx->Images[ImgNum]->channel_map[WHICH_NON_ATTR_CHAN].offset];
3819 regA = ImageStat (pfx, ImgNum, WHICH_ATTR_CHAN, pel->img_attr_qual);
3828 Image * pimg = pfx->Images[0];
3829 if ((
int) pel->channel_qual < 0) {
3830 if (pel->channel_qual == NO_CHAN_QUAL || pel->channel_qual == THIS_CHANNEL) {
3832 if (pfx->ImgNum==0) {
3833 regA = QuantumScale * (double) p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3835 const Quantum * pv = GetCacheViewVirtualPixels (
3836 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3838 (void) ThrowMagickException (
3839 pfx->exception, GetMagickModule(), OptionError,
3840 "fU0 can't get cache",
"%i", 0);
3843 regA = QuantumScale * (double) pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3846 }
else if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL ||
3847 pel->channel_qual == LIGHT_CHANNEL) {
3848 regA = GetHslInt (pfx, 0, imgx, imgy, pel->channel_qual);
3850 }
else if (pel->channel_qual == INTENSITY_CHANNEL) {
3851 regA = GetIntensity (pfx, 0, (fxFltType) imgx, (fxFltType) imgy);
3854 if (pfx->ImgNum==0) {
3855 regA = QuantumScale * (double) p[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3857 const Quantum * pv = GetCacheViewVirtualPixels (
3858 pfx->Imgs[0].View, imgx, imgy, 1,1, pfx->exception);
3860 (void) ThrowMagickException (
3861 pfx->exception, GetMagickModule(), OptionError,
3862 "fU0 can't get cache",
"%i", 0);
3865 regA = QuantumScale * (double) pv[pimg->channel_map[WHICH_NON_ATTR_CHAN].offset];
3872 ssize_t ImgNum = ChkImgNum (pfx, regA);
3875 if (ImgNum < 0)
break;
3877 if (pel->is_relative) {
3885 if ((
int) pel->channel_qual < 0) {
3886 if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL
3887 || pel->channel_qual == LIGHT_CHANNEL) {
3888 regA = GetHslFlt (pfx, ImgNum, fx, fy, pel->channel_qual);
3890 }
else if (pel->channel_qual == INTENSITY_CHANNEL) {
3891 regA = GetIntensity (pfx, ImgNum, fx, fy);
3898 Image * imUP = pfx->Images[ImgNum];
3899 if (! InterpolatePixelChannel (imUP, pfx->Imgs[ImgNum].View, WHICH_NON_ATTR_CHAN,
3900 imUP->interpolate, (
double) fx, (
double) fy, &v, pfx->exception))
3902 (void) ThrowMagickException (
3903 pfx->exception, GetMagickModule(), OptionError,
3904 "fUP can't get interpolate",
"%lu", (
unsigned long) ImgNum);
3907 regA = v * QuantumScale;
3916 if (pel->operator_index == fS) ImgNum = pfx->ImgNum;
3918 if (pel->img_attr_qual == aNull) {
3919 const Quantum * pv = GetCacheViewVirtualPixels (
3920 pfx->Imgs[ImgNum].View, imgx, imgy, 1,1, pfx->exception);
3922 (void) ThrowMagickException (
3923 pfx->exception, GetMagickModule(), OptionError,
3924 "fV can't get cache",
"%lu", (
unsigned long) ImgNum);
3928 if ((
int) pel->channel_qual < 0) {
3929 if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL ||
3930 pel->channel_qual == LIGHT_CHANNEL) {
3931 regA = GetHslInt (pfx, ImgNum, imgx, imgy, pel->channel_qual);
3933 }
else if (pel->channel_qual == INTENSITY_CHANNEL) {
3934 regA = GetIntensity (pfx, ImgNum, (
double) imgx, (
double) imgy);
3939 regA = QuantumScale * (double)
3940 pv[pfx->Images[ImgNum]->channel_map[WHICH_NON_ATTR_CHAN].offset];
3942 regA = ImageStat (pfx, ImgNum, WHICH_ATTR_CHAN, pel->img_attr_qual);
3952 ssize_t ImgNum = pfx->ImgNum;
3953 if (pel->operator_index == fVP) ImgNum = 1;
3954 if (pel->is_relative) {
3961 if ((
int) pel->channel_qual < 0) {
3962 if (pel->channel_qual == HUE_CHANNEL || pel->channel_qual == SAT_CHANNEL ||
3963 pel->channel_qual == LIGHT_CHANNEL) {
3964 regA = GetHslFlt (pfx, ImgNum, fx, fy, pel->channel_qual);
3966 }
else if (pel->channel_qual == INTENSITY_CHANNEL) {
3967 regA = GetIntensity (pfx, ImgNum, fx, fy);
3975 if (! InterpolatePixelChannel (pfx->Images[ImgNum], pfx->Imgs[ImgNum].View,
3976 WHICH_NON_ATTR_CHAN, pfx->Images[ImgNum]->interpolate,
3977 (
double) fx, (
double) fy, &v, pfx->exception)
3980 (void) ThrowMagickException (
3981 pfx->exception, GetMagickModule(), OptionError,
3982 "fSP or fVP can't get interp",
"%lu", (
unsigned long) ImgNum);
3985 regA = v * (fxFltType)QuantumScale;
3993 regA = (fxFltType) GetImageDepth (img, pfx->exception);
3996 regA = (fxFltType) img->extent;
3999 if ((cs != (ChannelStatistics *) NULL) && (channel > 0))
4000 regA = cs[WHICH_ATTR_CHAN].kurtosis;
4003 if ((cs != (ChannelStatistics *) NULL) && (channel > 0))
4004 regA = cs[WHICH_ATTR_CHAN].maxima;
4007 if ((cs != (ChannelStatistics *) NULL) && (channel > 0))
4008 regA = cs[WHICH_ATTR_CHAN].mean;
4011 if ((cs != (ChannelStatistics *) NULL) && (channel > 0))
4012 regA = cs[WHICH_ATTR_CHAN].median;
4015 if ((cs != (ChannelStatistics *) NULL) && (channel > 0))
4016 regA = cs[WHICH_ATTR_CHAN].minima;
4021 regA = (fxFltType) img->page.x;
4024 regA = (fxFltType) img->page.y;
4027 regA = (fxFltType) img->page.width;
4030 regA = (fxFltType) img->page.height;
4035 regA = (fxFltType) MagickSafeReciprocal (img->resolution.x) * img->columns;
4038 regA = (fxFltType) MagickSafeReciprocal (img->resolution.y) * img->rows;
4041 regA = (fxFltType) img->quality;
4046 regA = (fxFltType) img->resolution.x;
4049 regA = (fxFltType) img->resolution.y;
4052 if ((cs != (ChannelStatistics *) NULL) && (channel > 0))
4053 regA = cs[WHICH_ATTR_CHAN].skewness;
4056 if ((cs != (ChannelStatistics *) NULL) && (channel > 0))
4057 regA = cs[WHICH_ATTR_CHAN].standard_deviation;
4060 regA = (fxFltType) img->rows;
4063 regA = (fxFltType) pfx->ImgListLen;
4066 regA = (fxFltType) pfx->ImgNum;
4069 regA = (fxFltType) img->columns;
4072 regA = (fxFltType) GetImageDepth (img, pfx->exception);
4080 regA = GetIntensity (pfx, pfx->ImgNum, (
double) imgx, (
double) imgy);
4087 regA = QuantumScale * (0.212656 * (double) GetPixelRed (img,p) +
4088 0.715158 * (double) GetPixelGreen (img,p) +
4089 0.072186 * (double) GetPixelBlue (img,p));
4095 regA = QuantumScale * (double) GetPixelAlpha (img, p);
4098 regA = QuantumScale * (double) GetPixelBlue (img, p);
4101 regA = QuantumScale * (double) GetPixelCyan (img, p);
4104 regA = QuantumScale * (double) GetPixelGreen (img, p);
4107 regA = (fxFltType) imgx;
4110 regA = (fxFltType) imgy;
4113 regA = QuantumScale * (double) GetPixelBlack (img, p);
4116 regA = QuantumScale * (double) GetPixelGreen (img, p);
4119 regA = QuantumScale * (double) GetPixelAlpha (img, p);
4122 regA = QuantumScale * (double) GetPixelRed (img, p);
4125 regA = QuantumScale * (double) GetPixelYellow (img, p);
4131 assert (pel->element_index >= 0);
4132 i = pel->element_index-1;
4135 assert (pel->element_index >= 0);
4136 i = pel->element_index-1;
4137 if (IsImageTTLExpired(img) != MagickFalse) {
4138 i = pfx->usedElements-1;
4139 (void) ThrowMagickException (pfx->exception, GetMagickModule(),
4140 ResourceLimitFatalError,
"TimeLimitExceeded",
"`%s'", img->filename);
4144 assert (pel->element_index >= 0);
4145 if (fabs((
double) regA) < MagickEpsilon) i = pel->element_index-1;
4147 case rIfNotZeroGoto:
4148 assert (pel->element_index >= 0);
4149 if (fabs((
double) regA) > MagickEpsilon) i = pel->element_index-1;
4152 assert (pel->element_index >= 0);
4153 regA = pfxrt->UserSymVals[pel->element_index];
4156 assert (pel->element_index >= 0);
4157 pfxrt->UserSymVals[pel->element_index] = regA;
4160 pfxrt->usedValStack = 0;
4166 (void) ThrowMagickException (
4167 pfx->exception, GetMagickModule(), OptionError,
4168 "pel->oprNum",
"%i '%s' not yet implemented",
4169 (
int)pel->operator_index, OprStr(pel->operator_index));
4173 if (!PushVal (pfx, pfxrt, regA, i))
break;
4176 if (pfxrt->usedValStack > 0) regA = PopVal (pfx, pfxrt, 9999);
4180 if (NeedRelinq) cs = (ChannelStatistics *)RelinquishMagickMemory (cs);
4182 if (pfx->exception->severity >= ErrorException)
4185 if (pfxrt->usedValStack != 0) {
4186 (void) ThrowMagickException (
4187 pfx->exception, GetMagickModule(), OptionError,
4188 "ValStack not empty",
"(%i)", pfxrt->usedValStack);
4197MagickPrivate MagickBooleanType FxEvaluateChannelExpression (
4199 const PixelChannel channel,
const ssize_t x,
const ssize_t y,
4200 double *result, ExceptionInfo *exception)
4203 id = GetOpenMPThreadId();
4207 assert (pfx != NULL);
4208 assert (pfx->image != NULL);
4209 assert (pfx->Images != NULL);
4210 assert (pfx->Imgs != NULL);
4211 assert (pfx->fxrts != NULL);
4213 pfx->fxrts[id].thisPixel = NULL;
4216 if (!ExecuteRPN (pfx, &pfx->fxrts[
id], &ret, channel, x, y)) {
4217 (void) ThrowMagickException (
4218 exception, GetMagickModule(), OptionError,
4219 "ExecuteRPN failed",
" ");
4223 *result = (double) ret;
4228static FxInfo *AcquireFxInfoPrivate (
const Image * images,
const char * expression,
4229 MagickBooleanType CalcAllStats, ExceptionInfo *exception)
4233 FxInfo * pfx = (FxInfo*) AcquireCriticalMemory (
sizeof (*pfx));
4235 memset (pfx, 0,
sizeof (*pfx));
4237 if (!InitFx (pfx, images, CalcAllStats, exception)) {
4238 pfx = (FxInfo*) RelinquishMagickMemory(pfx);
4242 if (!BuildRPN (pfx)) {
4243 (void) DeInitFx (pfx);
4244 pfx = (FxInfo*) RelinquishMagickMemory(pfx);
4245 return((FxInfo *) NULL);
4248 if ((*expression ==
'@') && (strlen(expression) > 1))
4249 pfx->expression=FileToString(expression,~0UL,exception);
4250 if (pfx->expression == (
char *) NULL)
4251 pfx->expression=ConstantString(expression);
4252 pfx->pex = (
char *) pfx->expression;
4255 if (!TranslateStatementList (pfx,
";", &chLimit)) {
4256 (void) DestroyRPN (pfx);
4257 pfx->expression = DestroyString (pfx->expression);
4259 (void) DeInitFx (pfx);
4260 pfx = (FxInfo*) RelinquishMagickMemory(pfx);
4265 (void) ThrowMagickException (
4266 pfx->exception, GetMagickModule(), OptionError,
4267 "Translate expression depth",
"(%i) not 0",
4270 (void) DestroyRPN (pfx);
4271 pfx->expression = DestroyString (pfx->expression);
4273 (void) DeInitFx (pfx);
4274 pfx = (FxInfo*) RelinquishMagickMemory(pfx);
4278 if (chLimit !=
'\0' && chLimit !=
';') {
4279 (void) ThrowMagickException (
4280 pfx->exception, GetMagickModule(), OptionError,
4281 "AcquireFxInfo: TranslateExpression did not exhaust input",
"(chLimit=%i) at'%s'",
4282 (
int)chLimit, pfx->pex);
4284 (void) DestroyRPN (pfx);
4285 pfx->expression = DestroyString (pfx->expression);
4287 (void) DeInitFx (pfx);
4288 pfx = (FxInfo*) RelinquishMagickMemory(pfx);
4292 if (pfx->NeedStats && pfx->runType == rtEntireImage && !pfx->statistics) {
4293 if (!CollectStatistics (pfx)) {
4294 (void) DestroyRPN (pfx);
4295 pfx->expression = DestroyString (pfx->expression);
4297 (void) DeInitFx (pfx);
4298 pfx = (FxInfo*) RelinquishMagickMemory(pfx);
4303 if (pfx->DebugOpt) {
4304 DumpTables (stderr);
4305 DumpUserSymbols (pfx, stderr);
4306 (void) DumpRPN (pfx, stderr);
4310 size_t number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
4313 pfx->fxrts = (
fxRtT *)AcquireQuantumMemory (number_threads,
sizeof(
fxRtT));
4315 (void) ThrowMagickException (
4316 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
4318 (
unsigned long) number_threads);
4319 (void) DestroyRPN (pfx);
4320 pfx->expression = DestroyString (pfx->expression);
4322 (void) DeInitFx (pfx);
4323 pfx = (FxInfo*) RelinquishMagickMemory(pfx);
4326 for (t=0; t < (ssize_t) number_threads; t++) {
4327 if (!AllocFxRt (pfx, &pfx->fxrts[t])) {
4328 (void) ThrowMagickException (
4329 pfx->exception, GetMagickModule(), ResourceLimitFatalError,
4330 "AllocFxRt t=",
"%g",
4334 for (t2 = t-1; t2 >= 0; t2--) {
4335 DestroyFxRt (&pfx->fxrts[t]);
4338 pfx->fxrts = (
fxRtT *) RelinquishMagickMemory (pfx->fxrts);
4339 (void) DestroyRPN (pfx);
4340 pfx->expression = DestroyString (pfx->expression);
4342 (void) DeInitFx (pfx);
4343 pfx = (FxInfo*) RelinquishMagickMemory(pfx);
4351FxInfo *AcquireFxInfo (
const Image * images,
const char * expression, ExceptionInfo *exception)
4353 return AcquireFxInfoPrivate (images, expression, MagickFalse, exception);
4356FxInfo *DestroyFxInfo (FxInfo * pfx)
4360 assert (pfx != NULL);
4361 assert (pfx->image != NULL);
4362 assert (pfx->Images != NULL);
4363 assert (pfx->Imgs != NULL);
4364 assert (pfx->fxrts != NULL);
4366 for (t=0; t < (ssize_t) GetMagickResourceLimit(ThreadResource); t++) {
4367 DestroyFxRt (&pfx->fxrts[t]);
4369 pfx->fxrts = (
fxRtT *) RelinquishMagickMemory (pfx->fxrts);
4373 pfx->expression = DestroyString (pfx->expression);
4376 (void) DeInitFx (pfx);
4378 pfx = (FxInfo*) RelinquishMagickMemory(pfx);
4385MagickExport Image *FxImage(
const Image *image,
const char *expression,
4386 ExceptionInfo *exception)
4388#define FxImageTag "FxNew/Image"
4409 assert(image != (Image *) NULL);
4410 assert(image->signature == MagickCoreSignature);
4411 if (IsEventLogging() != MagickFalse)
4412 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4413 if (expression == (
const char *) NULL)
4414 return(CloneImage(image,0,0,MagickTrue,exception));
4415 fx_image=CloneImage(image,0,0,MagickTrue,exception);
4416 if (!fx_image)
return NULL;
4417 if (SetImageStorageClass(fx_image,DirectClass,exception) == MagickFalse) {
4418 fx_image=DestroyImage(fx_image);
4422 pfx = AcquireFxInfoPrivate (image, expression, MagickTrue, exception);
4425 fx_image=DestroyImage(fx_image);
4429 assert (pfx->image != NULL);
4430 assert (pfx->Images != NULL);
4431 assert (pfx->Imgs != NULL);
4432 assert (pfx->fxrts != NULL);
4436 image_view = AcquireVirtualCacheView (image, pfx->exception);
4437 fx_view = AcquireAuthenticCacheView (fx_image, pfx->exception);
4438#if defined(MAGICKCORE_OPENMP_SUPPORT)
4439 #pragma omp parallel for schedule(dynamic) shared(progress,status) \
4440 magick_number_threads(image,fx_image,fx_image->rows, \
4441 pfx->ContainsDebug ? 0 : 1)
4443 for (y=0; y < (ssize_t) fx_image->rows; y++)
4446 id = GetOpenMPThreadId();
4460 if (status == MagickFalse)
4462 p = GetCacheViewVirtualPixels (image_view, 0, y, image->columns, 1, pfx->exception);
4463 q = QueueCacheViewAuthenticPixels (fx_view, 0, y, fx_image->columns, 1, pfx->exception);
4464 if ((p == (
const Quantum *) NULL) || (q == (Quantum *) NULL)) {
4468 for (x=0; x < (ssize_t) fx_image->columns; x++) {
4471 pfx->fxrts[id].thisPixel = (Quantum *)p;
4473 for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
4475 PixelChannel channel = GetPixelChannelChannel (image, i);
4476 PixelTrait traits = GetPixelChannelTraits (image, channel);
4477 PixelTrait fx_traits = GetPixelChannelTraits (fx_image, channel);
4478 if ((traits == UndefinedPixelTrait) ||
4479 (fx_traits == UndefinedPixelTrait))
4481 if ((fx_traits & CopyPixelTrait) != 0) {
4482 SetPixelChannel (fx_image, channel, p[i], q);
4486 if (!ExecuteRPN (pfx, &pfx->fxrts[
id], &result, channel, x, y)) {
4491 q[i] = ClampToQuantum ((MagickRealType) (QuantumRange*result));
4493 p+=(ptrdiff_t) GetPixelChannels (image);
4494 q+=(ptrdiff_t) GetPixelChannels (fx_image);
4496 if (SyncCacheViewAuthenticPixels(fx_view, pfx->exception) == MagickFalse)
4498 if (image->progress_monitor != (MagickProgressMonitor) NULL)
4503#if defined(MAGICKCORE_OPENMP_SUPPORT)
4507 proceed = SetImageProgress (image, FxImageTag, progress, image->rows);
4508 if (proceed == MagickFalse)
4513 fx_view = DestroyCacheView (fx_view);
4514 image_view = DestroyCacheView (image_view);
4518 if (pfx->DebugOpt && pfx->usedUserSymbols) {
4520 char UserSym[MagickPathExtent];
4521 fprintf (stderr,
"User symbols (%i):\n", pfx->usedUserSymbols);
4522 for (t=0; t < (int) GetMagickResourceLimit(ThreadResource); t++) {
4523 for (i = 0; i < (int) pfx->usedUserSymbols; i++) {
4524 fprintf (stderr,
"th=%i us=%i '%s': %.*Lg\n",
4525 t, i, NameOfUserSym (pfx, i, UserSym), pfx->precision, pfx->fxrts[t].UserSymVals[i]);
4530 if ((status == MagickFalse) || (pfx->exception->severity >= ErrorException))
4531 fx_image=DestroyImage(fx_image);
4533 pfx=DestroyFxInfo(pfx);